良好统一的编程风格,有助于提高代码的可读性和可维护性。根据风格整理成规范,可以让团队之间更好的配合。
下面是我结合网络上别人分享的内容,以及参考 Vscode 代码格式化整理优化出的;抛砖引玉,仅供参考。
- 如果合约对状态变量进行了修改,需要抛出事件。
- 构造函数的参数必须是
storage
或memory
,不能使用calldata
; - 版权注释在文件的任何位置都可以被编译器识别,但建议把它放在文件的顶部第一行。
-
源码编码
- UTF-8
-
缩进
- 使用 4 个空格代替制表符作为缩进,避免空格与制表符混用。
-
2 个合约定义之间空 2 行。
pragma solidity ^0.5.0; contract LedgerBalance { //... } contract Updater { //... }
-
2 个函数之间空 1 行,在只有声明的情况下,不需要空行。
pragma solidity ^0.5.0; contract A { function balance() public pure; function account() public pure; } contract B is A { function balance() public pure { // ... } function account() public pure { // ... } }
-
单行不要太长,VScode 一行默认不超过 80 个字符。
-
函数声明如果太长,左括号不换行,每个参数一行并缩进,右括号换行,并对齐左括号所在行。
function_with_a_long_name( longArgument1, longArgument2, longArgument3 ); variable = function_with_a_long_name( longArgument1, longArgument2, longArgument3 ); event multipleArguments( address sender, address recipient, uint256 publicKey, uint256 amount, bytes32[] options ); MultipleArguments( sender, recipient, publicKey, amount, options );
-
避免在圆括号、方括号或大括号后有空格。
-
控制结构的大括号左括号不换行,右括号换行,与左括号所在行对齐。
pragma solidity ^0.5.0; contract Coin { struct Bank { address owner; uint balance; } } if (x < 3) { x += 1; } else if (x > 7) { x -= 1; } else { x = 5; } if (x < 3) x += 1; else x -= 1;
-
函数声明,添加可见性标签。可见性标签应该放在自定义修饰符之前。
function kill() public onlyowner { selfdestruct(owner); }
-
声明映射变量时避免多余空格。
mapping(uint => uint) map; // 不是 mapping (uint => uint) map; mapping(address => bool) registeredAddresses; mapping(uint => mapping(bool => Data[])) public data; mapping(uint => mapping(uint => s)) data;
-
声明数组变量时避免多余空格。
uint[] x; // 不是 unit [] x;
-
字符串声明,使用双引号声明字符串,而不是单引号。
str = "foo"; str = "Hamlet says, 'To be or not to be...'";
代码中各部分顺序如下:
- License
- Pragma
- import
- interface
- library
- contract
在 Interface、库或 Contract 中,各部分顺序应为:
-
Type declaration : 类型声明
-
State variable : 状态变量
-
Event : 事件
-
Modifier : 函数修改器
-
Errors : 自定义错误
-
Constructor : 构造函数
-
Function : 函数
- 函数按visibility:可见性进行排序:
External - Public - Internal - Private
- 同一可见性,按照 mutability:状态可变性 排序:
payable - 无 - view - pure
// External functions // ... // External view functions // ... // External pure functions // ... // Public functions // ... // Internal functions // ... // Private functions // ...
- 函数按visibility:可见性进行排序:
-
Helper : 辅助函数
我的文件结构,分享给大家,仅供参考,抛砖引玉。代码块分割主要是让合约的逻辑更清晰,团队合作写代码的时候,都能按照统一的约定来进行编码。
不同功能的代码块使用下面任意一种做明显标记。
第一种:
/*
* ========================================
* State Variables
* ========================================
*/
第二种:(两边各 12 个 =
)
/* ============ State Variables ============ */
如果需要写详细的 NetSpec 注释,我比较喜欢使用第一种。如果是不需要这样做,比较喜欢第二种。第一种写法,在第一章同志们好 那里已经演示过了,这里演示第二种写法。如下是写法的演示:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// import
// interface
// library
contract Demo {
/* ============ Type Declaration ============ */
struct Book {
string title;
string author;
uint256 book_id;
}
/* ============ State Variables ============ */
address public immutable owner;
Book[] public bookcase;
/* ============ Events ============ */
event Hello(string);
/* ============ Modifier ============ */
modifier onlyOwner() {
require(msg.sender == owner, "Only owner");
_;
}
/* ============ Errors ============ */
error MyError(string);
/* ============ Constructor ============ */
constructor() {
owner = msg.sender;
}
/* ============ Functions ============ */
/* ============ External Functions ============ */
function hello() external onlyOwner {
emit Hello("Hello Comrades");
}
/* ============ Helper ============ */
function getBalance() external view returns (uint256) {
return address(this).balance;
}
}
-
合约和库名: 大驼峰式命名。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; contract Owned { //... }
-
合约和库名: 匹配它们的文件名。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // 文件名:Owned.sol contract Owned { //... }
-
如果文件中有多个合约/库,使用核心合约/库的名称。🤔️
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; // 文件名:Owned.sol contract Owned { address public owner; constructor() public { owner = msg.sender; } modifier onlyOwner() { //.... _; } function transferOwnership(address newOwner) public onlyOwner returns(true){ //... return true; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./Owned.sol"; // Congress.sol contract Congress is Owned { //... }
-
结构体名称: 大驼峰式命名。
struct BookInfo { string title; string author; uint256 book_id; }
-
事件名称: 大驼峰式命名
event AfterTransfer(address ads);
-
函数名: 小驼峰命名
function balanceOf(address account) external view returns (uint256){};
-
internal
函数名:_
+小驼峰命名function _grantRole(address _ads, bytes32 _role) internal {}
-
internal
变量:_
+小驼峰 -
函数参数:小驼峰+
_
constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; }
-
局部变量和状态变量:小驼峰命名
mapping(address => uint256) public balanceOf;
-
常量:大写字母单词用下划线分隔。
address public constant MIN_BLOCKS;
-
函数修改器: 小驼峰命名
modifier onlyOwner(){ require(msg.sender==owner,"must owner address"); _; }
-
枚举的名字:大驼峰式命名
enum Status { None, Pending, Shiped, Completed, Rejected, Canceled }
重要需要总结的内容: