├── .solhint.json ├── CONTRIBUTING.md ├── README.md └── RELEASE.md /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "default", 3 | "rules": { 4 | "indent": ["error", 2], 5 | "bracket-align": false, 6 | "two-lines-top-level-separator": false, 7 | "max-line-length": 100 8 | } 9 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributors are welcome. Please use issues and pull requests to contribute to the project. And update [CHANGELOG.md](CHANGELOG.md) when committing. 4 | 5 | (Currently the changelog is pretty empty. Please study the format at https://github.com/fulldecent/FDWaveformView/blob/master/CHANGELOG.md for new additions.) 6 | 7 | # Release process 8 | 9 | 1. Create GitHub to tag and create release 10 | 2. Create pull request at https://github.com/0xcert/ethereum-erc721 to recognize new version and implement recommendations 11 | 3. Create pull request at https://github.com/0xcert/framework to recognize new version and implement recommendations 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 0xcert Solidity Style Guide 2 | 3 | ## Introduction 4 | 5 | This guide is based on the Solidity style guide that can be found here: 6 | https://github.com/ethereum/solidity/blob/v0.5.1/docs/style-guide.rst. It mostly follows the guide 7 | line but with slight changes and more specific restrictions. 8 | 9 | This guide is intended to provide coding conventions for writing solidity code. 10 | This guide should be thought of as an evolving document that will change over 11 | time as useful conventions are found and old conventions are rendered obsolete. 12 | 13 | ## Code Layout 14 | 15 | ### Indentation 16 | 17 | Use 2 spaces per indentation level. 18 | 19 | ### Tabs or Spaces 20 | 21 | Spaces are the preferred indentation method. 22 | 23 | Mixing tabs and spaces must be avoided. 24 | 25 | ### Multiple contracts in the same file 26 | 27 | Each smart contract should be in its own file. 28 | 29 | ### Maximum Line Length 30 | 31 | Maximum line length is 100 characters. 32 | 33 | ### Function Calls 34 | 35 | Yes 36 | 37 | thisFunctionCallIsReallyLong( 38 | longArgument1, 39 | longArgument2, 40 | longArgument3 41 | ); 42 | 43 | shortFunctionCall(arg1); 44 | 45 | No 46 | 47 | thisFunctionCallIsReallyLong(longArgument1, 48 | longArgument2, 49 | longArgument3 50 | ); 51 | 52 | thisFunctionCallIsReallyLong(longArgument1, 53 | longArgument2, 54 | longArgument3 55 | ); 56 | 57 | thisFunctionCallIsReallyLong( 58 | longArgument1, longArgument2, 59 | longArgument3 60 | ); 61 | 62 | thisFunctionCallIsReallyLong( 63 | longArgument1, 64 | longArgument2, 65 | longArgument3 66 | ); 67 | 68 | thisFunctionCallIsReallyLong( 69 | longArgument1, 70 | longArgument2, 71 | longArgument3); 72 | 73 | #### Assignment Statements 74 | 75 | Yes 76 | 77 | thisIsALongNestedMapping[being][set][to_some_value] = someFunction( 78 | argument1, 79 | argument2, 80 | argument3, 81 | argument4 82 | ); 83 | 84 | No 85 | 86 | thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1, 87 | argument2, 88 | argument3, 89 | argument4); 90 | 91 | #### Event Definitions and Event Emitters 92 | 93 | Yes 94 | 95 | event ShortOneArg( 96 | address _sender 97 | ); 98 | 99 | event LongAndLotsOfArgs( 100 | address _sender, 101 | address _recipient, 102 | uint256 _publicKey, 103 | uint256 _amount, 104 | bytes32[] _options 105 | ); 106 | 107 | emit LongAndLotsOfArgs( 108 | sender, 109 | recipient, 110 | publicKey, 111 | amount, 112 | options 113 | ); 114 | 115 | emit ShortOneArg(sender); 116 | 117 | No 118 | 119 | event ShortOneArg(address _sender); 120 | 121 | event LongAndLotsOfArgs(address _sender, 122 | address _recipient, 123 | uint256 _publicKey, 124 | uint256 _amount, 125 | bytes32[] _options); 126 | 127 | emit LongAndLotsOfArgs(sender, 128 | recipient, 129 | publicKey, 130 | amount, 131 | options); 132 | 133 | ### Source File Encoding 134 | 135 | UTF-8 or ASCII encoding is preferred. 136 | 137 | ### Imports 138 | 139 | Import statements must always be placed at the top of the file. 140 | 141 | ### Code Ordering 142 | 143 | Functions and declarations must be grouped according to their visibility and ordered: 144 | 145 | - constructor 146 | - fallback function (if exists) 147 | - external 148 | - public 149 | - internal 150 | - private 151 | 152 | Within a grouping, place the `view` and `pure` functions last. 153 | 154 | Yes 155 | 156 | pragma solidity >=0.4.0 <0.6.0; 157 | 158 | contract A 159 | { 160 | using SafeMath for uint256; 161 | 162 | uint256 someVariable; 163 | 164 | event SomeEvent( 165 | uint256 _arg1 166 | ); 167 | 168 | modifier SomeModifier( 169 | uint256 _arg1 170 | ) 171 | { 172 | // some check 173 | _; 174 | } 175 | 176 | constructor() 177 | public 178 | { 179 | // ... 180 | } 181 | 182 | function() 183 | external 184 | { 185 | // ... 186 | } 187 | 188 | // External functions 189 | // ... 190 | 191 | // External functions that are view 192 | // ... 193 | 194 | // External functions that are pure 195 | // ... 196 | 197 | // Public functions 198 | // ... 199 | 200 | // Internal functions 201 | // ... 202 | 203 | // Private functions 204 | // ... 205 | } 206 | 207 | No 208 | 209 | pragma solidity >=0.4.0 <0.6.0; 210 | 211 | contract A 212 | { 213 | 214 | // External functions 215 | // ... 216 | 217 | function() 218 | external 219 | { 220 | // ... 221 | } 222 | 223 | // Private functions 224 | // ... 225 | 226 | // Public functions 227 | // ... 228 | 229 | constructor() 230 | public 231 | { 232 | // ... 233 | } 234 | 235 | // Internal functions 236 | // ... 237 | } 238 | 239 | ### Whitespace in Expressions 240 | 241 | Avoid extraneous whitespace in the following situations: 242 | 243 | Yes 244 | 245 | spam(ham[1], Coin({ name: "ham" })); 246 | 247 | No 248 | 249 | spam( ham[ 1 ], Coin( { name: "ham" } ) ); 250 | 251 | More than one space around an assignment or other operator to align with 252 | another: 253 | 254 | Yes 255 | 256 | x = 1; 257 | y = 2; 258 | long_variable = 3; 259 | 260 | No 261 | 262 | x = 1; 263 | y = 2; 264 | long_variable = 3; 265 | 266 | 267 | Control Structures 268 | 269 | Yes 270 | 271 | pragma solidity >=0.4.0 <0.6.0; 272 | 273 | contract Coin 274 | { 275 | struct Bank 276 | { 277 | address owner; 278 | uint balance; 279 | } 280 | } 281 | 282 | No 283 | 284 | pragma solidity >=0.4.0 <0.6.0; 285 | 286 | contract Coin { 287 | struct Bank { 288 | address owner; 289 | uint balance; 290 | } 291 | } 292 | 293 | The same recommendations apply to the control structures `if`, `else`, `while`, 294 | and `for`. 295 | 296 | Additionally there must be a single space between the control structures 297 | `if`, `while`, and `for` and the parenthetic block representing the 298 | conditional, as well as a single space between the conditional parenthetic 299 | block and the opening brace. 300 | 301 | Yes 302 | 303 | if (...) 304 | { 305 | ... 306 | } 307 | 308 | No 309 | 310 | if (...) { 311 | ... 312 | } 313 | 314 | while(...){ 315 | } 316 | 317 | for (...) { 318 | ...;} 319 | 320 | For control structures whose body contains a single statement, omitting the 321 | braces is NOT ok in any condition. 322 | 323 | Yes 324 | 325 | if (x < 10) 326 | { 327 | x += 1; 328 | } 329 | 330 | No 331 | 332 | if (x < 10) 333 | x += 1; 334 | 335 | if (x < 10) 336 | someArray.push(Coin({ 337 | name: 'spam', 338 | value: 42 339 | })); 340 | 341 | For `if` blocks which have an `else` or `else if` clause, the `else` must be 342 | placed on the same line as the `if`'s closing brace. This is an exception compared 343 | to the rules of other block-like structures. 344 | 345 | Yes 346 | 347 | if (x < 3) 348 | { 349 | x += 1; 350 | } 351 | else if (x > 7) 352 | { 353 | x -= 1; 354 | } 355 | else 356 | { 357 | x = 5; 358 | } 359 | 360 | if (x < 3) 361 | { 362 | x += 1; 363 | } 364 | else 365 | { 366 | x -= 1; 367 | } 368 | 369 | No 370 | 371 | if (x < 3) { 372 | x += 1; 373 | } else { 374 | x -= 1; 375 | } 376 | 377 | if (x < 3) 378 | x += 1; 379 | else 380 | x -= 1; 381 | 382 | ### Function Declaration 383 | 384 | For every function declarations, it is recommended to drop each argument onto 385 | it's own line at the same indentation level as the function body. The closing 386 | parenthesis and opening bracket must be placed on their own line as well at 387 | the same indentation level as the function declaration. 388 | 389 | Yes 390 | 391 | function thisFunctionHasNoArguments() 392 | public 393 | { 394 | doSomething(); 395 | } 396 | 397 | function thisFunctionHasAnArgument( 398 | address _a 399 | ) 400 | public 401 | { 402 | doSomething(); 403 | } 404 | 405 | function thisFunctionHasLotsOfArguments( 406 | address _a, 407 | address _b, 408 | address _c, 409 | address _d, 410 | address _e, 411 | address _f 412 | ) 413 | public 414 | { 415 | doSomething(); 416 | } 417 | 418 | No 419 | 420 | function thisFunctionHasNoArguments() public 421 | { 422 | doSomething(); 423 | } 424 | 425 | function thisFunctionHasAnArgument(address _a) public { 426 | doSomething(); 427 | } 428 | 429 | function thisFunctionHasLotsOfArguments(address _a, address _b, address _c, 430 | address _d, address _e, address _f) public { 431 | doSomething(); 432 | } 433 | 434 | function thisFunctionHasLotsOfArguments(address _a, 435 | address _b, 436 | address _c, 437 | address _d, 438 | address _e, 439 | address _f) public { 440 | doSomething(); 441 | } 442 | 443 | function thisFunctionHasLotsOfArguments( 444 | address _a, 445 | address _b, 446 | address _c, 447 | address _d, 448 | address _e, 449 | address _f) public { 450 | doSomething(); 451 | } 452 | 453 | If a function declaration has modifiers, then each modifier must be 454 | dropped to its own line. 455 | 456 | Yes 457 | 458 | function thisFunctionNameIsReallyLong( 459 | address _x, 460 | address _y, 461 | address _z 462 | ) 463 | public 464 | onlyowner 465 | priced 466 | returns (address) 467 | { 468 | doSomething(); 469 | } 470 | 471 | function thisFunctionNameIsReallyLong( 472 | address _x, 473 | address _y, 474 | address _z, 475 | ) 476 | public 477 | onlyowner 478 | priced 479 | returns (address) 480 | { 481 | doSomething(); 482 | } 483 | 484 | No 485 | 486 | function thisFunctionNameIsReallyLong(address _x, address _y, address _z) 487 | public 488 | onlyowner 489 | priced 490 | returns (address) { 491 | doSomething(); 492 | } 493 | 494 | function thisFunctionNameIsReallyLong(address _x, address _y, address _z) 495 | public onlyowner priced returns (address) 496 | { 497 | doSomething(); 498 | } 499 | 500 | function thisFunctionNameIsReallyLong(address _x, address _y, address _z) 501 | public 502 | onlyowner 503 | priced 504 | returns (address) { 505 | doSomething(); 506 | } 507 | 508 | Multiline output parameters and return statements must follow the same style. 509 | 510 | Yes 511 | 512 | function thisFunctionNameIsReallyLong( 513 | address _a, 514 | address _b, 515 | address _c 516 | ) 517 | public 518 | returns ( 519 | address someAddressName, 520 | uint256 LongArgument, 521 | uint256 Argument 522 | ) 523 | { 524 | doSomething() 525 | 526 | return ( 527 | veryLongReturnArg1, 528 | veryLongReturnArg2, 529 | veryLongReturnArg3 530 | ); 531 | } 532 | 533 | No 534 | 535 | function thisFunctionNameIsReallyLong( 536 | address _a, 537 | address _b, 538 | address _c 539 | ) 540 | public 541 | returns (address someAddressName, 542 | uint256 LongArgument, 543 | uint256 Argument) 544 | { 545 | doSomething() 546 | 547 | return (veryLongReturnArg1, 548 | veryLongReturnArg1, 549 | veryLongReturnArg1); 550 | } 551 | 552 | For constructor functions on inherited contracts whose bases require arguments, 553 | it is recommended to drop the base constructors onto new lines in the same 554 | manner as modifiers. 555 | 556 | Yes 557 | 558 | pragma solidity >=0.4.0 <0.6.0; 559 | 560 | // Base contracts just to make this compile 561 | contract B { 562 | 563 | constructor( 564 | uint 565 | ) 566 | public 567 | { 568 | } 569 | 570 | } 571 | 572 | contract C { 573 | 574 | constructor( 575 | uint, 576 | uint 577 | ) 578 | public 579 | { 580 | } 581 | 582 | } 583 | 584 | contract D { 585 | 586 | constructor( 587 | uint 588 | ) 589 | public 590 | { 591 | } 592 | 593 | } 594 | 595 | contract A is 596 | B, 597 | C, 598 | D 599 | { 600 | uint x; 601 | 602 | constructor( 603 | uint _param1, 604 | uint _param2, 605 | uint _param3, 606 | uint _param4, 607 | uint _param5 608 | ) 609 | B(_param1) 610 | C(_param2, _param3) 611 | D(_param4) 612 | public 613 | { 614 | // do something with param5 615 | x = _param5; 616 | } 617 | } 618 | 619 | No 620 | 621 | pragma solidity >=0.4.0 <0.6.0; 622 | 623 | // Base contracts just to make this compile 624 | contract B { 625 | constructor(uint) public { 626 | } 627 | } 628 | contract C { 629 | constructor(uint, uint) public { 630 | } 631 | } 632 | contract D { 633 | constructor(uint) public { 634 | } 635 | } 636 | 637 | contract A is B, C, D { 638 | uint x; 639 | 640 | constructor(uint _param1, uint _param2, uint _param3, uint _param4, uint _param5) 641 | B(_param1) 642 | C(_param2, _param3) 643 | D(_param4) 644 | public 645 | { 646 | x = _param5; 647 | } 648 | } 649 | 650 | contract X is B, C, D { 651 | uint x; 652 | 653 | constructor(uint _param1, uint _param2, uint _param3, uint _param4, uint _param5) 654 | B(_param1) 655 | C(_param2, _param3) 656 | D(_param4) 657 | public { 658 | x = _param5; 659 | } 660 | 661 | ### Mappings 662 | 663 | In variable declarations, do not separate the keyword `mapping` from its 664 | type by a space. Do not separate any nested `mapping` keyword from its type by 665 | whitespace. 666 | 667 | Yes 668 | 669 | mapping(uint => uint) map; 670 | mapping(address => bool) registeredAddresses; 671 | mapping(uint => mapping(bool => Data[])) public data; 672 | mapping(uint => mapping(uint => s)) data; 673 | 674 | No 675 | 676 | mapping (uint => uint) map; 677 | mapping( address => bool ) registeredAddresses; 678 | mapping (uint => mapping (bool => Data[])) public data; 679 | mapping(uint => mapping (uint => s)) data; 680 | 681 | ### Variable Declarations 682 | 683 | Declarations of array variables must not have a space between the type and 684 | the brackets. 685 | 686 | Yes 687 | 688 | uint[] x; 689 | 690 | No 691 | 692 | uint [] x; 693 | 694 | ### Other Recommendations 695 | 696 | * Strings must be quoted with double-quotes instead of single-quotes. 697 | 698 | Yes 699 | 700 | str = "foo"; 701 | str = "Hamlet says, 'To be or not to be...'"; 702 | 703 | No 704 | 705 | str = 'bar'; 706 | str = '"Be yourself; everyone else is already taken." -Oscar Wilde'; 707 | 708 | * Surround operators with a single space on either side. 709 | 710 | Yes 711 | 712 | x = 3; 713 | x = 100 / 10; 714 | x += 3 + 4; 715 | x |= y && z; 716 | 717 | No 718 | 719 | x=3; 720 | x = 100/10; 721 | x += 3+4; 722 | x |= y&&z; 723 | 724 | * Operators with a higher priority than others can exclude surrounding 725 | whitespace in order to denote precedence. This is meant to allow for 726 | improved readability for complex statement. You should always use the same 727 | amount of whitespace on either side of an operator: 728 | 729 | Yes 730 | 731 | x = 2**3 + 5; 732 | x = 2*y + 3*z; 733 | x = (a+b) * (a-b); 734 | 735 | No 736 | 737 | x = 2** 3 + 5; 738 | x = y+z; 739 | x +=1; 740 | 741 | ## Order of Layout 742 | 743 | Layout contract elements in the following order: 744 | 745 | 1. Pragma statements 746 | 2. Import statements 747 | 3. Interfaces 748 | 4. Libraries 749 | 5. Contract 750 | 751 | Inside each contract, library or interface, use the following order: 752 | 753 | 1. Library declarations (`using` statements) 754 | 2. Constant variables 755 | 3. Type declarations 756 | 4. State variables 757 | 5. Events 758 | 6. Modifiers 759 | 7. Functions 760 | 761 | ## Naming Styles 762 | 763 | To avoid confusion, the following names will be used to refer to different 764 | naming styles. 765 | 766 | * `b` (single lowercase letter) 767 | * `B` (single uppercase letter) 768 | * `lowercase` 769 | * `lower_case_with_underscores` 770 | * `UPPERCASE` 771 | * `UPPER_CASE_WITH_UNDERSCORES` 772 | * `CapitalizedWords` (or CapWords) 773 | * `mixedCase` (differs from CapitalizedWords by initial lowercase character!) 774 | * `Capitalized_Words_With_Underscores` 775 | * `_underscoreMixedCase` 776 | 777 | When using initialisms in CapWords, capitalize all the letters of the initialisms. Thus HTTPServerError is better than HttpServerError. When using initialisms is mixedCase, capitalize all the letters of the initialisms, except keep the first one lower case if it is the beginning of the name. Thus xmlHTTPRequest is better than XMLHTTPRequest. 778 | 779 | ### Names to Avoid 780 | 781 | * `l` - Lowercase letter el 782 | * `O` - Uppercase letter oh 783 | * `I` - Uppercase letter eye 784 | 785 | Never use any of these for single letter variable names. They are often 786 | indistinguishable from the numerals one and zero. 787 | 788 | ### Contract and Library Names 789 | 790 | * Contracts and libraries must be named using the CapWords style. Examples: `SimpleToken`, `SmartBank`, `CertificateHashRepository`, `Player`, `Congress`, `Owned`. 791 | 792 | As shown in the example below, if the contract name is `Congress` and the library name is `Owned`, then their associated filenames should be `congress.sol` and `owned.sol`. 793 | 794 | Yes 795 | 796 | pragma solidity >=0.4.0 <0.6.0; 797 | 798 | // owned.sol 799 | contract Owned 800 | { 801 | address public owner; 802 | 803 | constructor() 804 | public 805 | { 806 | owner = msg.sender; 807 | } 808 | 809 | modifier onlyOwner 810 | { 811 | require(msg.sender == owner); 812 | _; 813 | } 814 | 815 | function transferOwnership( 816 | address _newOwner 817 | ) 818 | public 819 | onlyOwner 820 | { 821 | owner = _newOwner; 822 | } 823 | } 824 | 825 | // congress.sol 826 | import "./Owned.sol"; 827 | 828 | contract Congress is 829 | Owned, 830 | TokenRecipient 831 | { 832 | //... 833 | } 834 | 835 | No 836 | 837 | pragma solidity >=0.4.0 <0.6.0; 838 | 839 | // owned.sol 840 | contract owned 841 | { 842 | address public owner; 843 | 844 | constructor() 845 | public 846 | { 847 | owner = msg.sender; 848 | } 849 | 850 | modifier onlyOwner 851 | { 852 | require(msg.sender == owner); 853 | _; 854 | } 855 | 856 | function transferOwnership( 857 | address _newOwner 858 | ) 859 | public 860 | onlyOwner 861 | { 862 | owner = _newOwner; 863 | } 864 | } 865 | 866 | // Congress.sol 867 | import "./owned.sol"; 868 | 869 | contract Congress is 870 | owned, 871 | tokenRecipient 872 | { 873 | //... 874 | } 875 | 876 | ### Struct Names 877 | 878 | Structs must be named using the CapWords style. Examples: `MyCoin`, `Position`, `PositionXY`. 879 | 880 | ### Event Names 881 | 882 | Events must be named using the CapWords style. Examples: `Deposit`, `Transfer`, `Approval`, `BeforeTransfer`, `AfterTransfer`. 883 | 884 | ### Function Names 885 | 886 | Functions other than constructors must use mixedCase. Examples: `getBalance`, `transfer`, `verifyOwner`, `addMember`, `changeOwner`. 887 | If a function is `private` or `internal` function should use _underscoreMixedCase. Examples: `_calculateBalance` , `_doTransfer`. 888 | 889 | ### Function Argument Names 890 | 891 | Function arguments must use _underscoreMixedCase. Examples: `_initialSupply`, `_account`, `_recipientAddress`, `_senderAddress`, `_newOwner`. 892 | 893 | When writing library functions that operate on a custom struct, the struct 894 | should be the first argument and should always be named `self`. 895 | 896 | ### Local and State Variable Names 897 | 898 | Use mixedCase. Examples: `totalSupply`, `remainingSupply`, `balancesOf`, `creatorAddress`, `isPreSale`, `tokenExchangeRate`. 899 | 900 | ### Constants 901 | 902 | Constants must be named with all capital letters with underscores separating 903 | words. Examples: `MAX_BLOCKS`, `TOKEN_NAME`, `TOKEN_TICKER`, `CONTRACT_VERSION`. 904 | 905 | ### Modifier Names 906 | 907 | Use mixedCase. Examples: `onlyBy`, `onlyAfter`, `onlyDuringThePreSale`. 908 | 909 | ### Enums 910 | 911 | Enums, in the style of simple type declarations, must be named using the CapWords style. Examples: `TokenGroup`, `Frame`, `HashStyle`, `CharacterLocation`. 912 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | The release manager is responsible to follow this process for each release of this project. 4 | 5 | 1. Confirm that the [version we reference](https://github.com/0xcert/solidity-style-guide#introduction) of the Solidity style guide is the [latest released version](https://github.com/ethereum/solidity/releases). 6 | 2. Summarize the changes and create a release using [GitHub releases](https://github.com/0xcert/solidity-style-guide/releases). 7 | 3. Create a branch/pull request against https://github.com/0xcert/ethereum-erc721 to reference and implement the new style guide. 8 | 4. Create a branch/pull request against https://github.com/0xcert/framework to reference and implement the new style guide. 9 | --------------------------------------------------------------------------------