solidity 学习第一步: 阅读代码
学习一个新的语言的第一步是阅读现有的基础代码,能够帮住你快速的理解并后面的教程.
存储合约示例
- 这个合约提供了一个简单的存储和检索功能,允许用户通过
set
函数存储一个整数,并使用get
函数获取存储的值。 - 它演示了基本的 Solidity 合约结构以及如何在区块链上存储和读取数据。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
这个 Solidity 合约 SimpleStorage
是一个非常简单的智能合约,用于存储和检索一个无符号整数 (uint
)。下面是代码的逐行解释:
1. 许可证声明
// SPDX-License-Identifier: GPL-3.0
- SPDX 是许可证声明,用于指定合约代码的许可证类型。这里使用的是
GPL-3.0
,它要求所有基于这个合约的派生工作都必须遵循相同的许可证规则。
2. Solidity 版本声明
pragma solidity >=0.4.16 <0.9.0;
- 这行代码指定了该合约适用的 Solidity 编译器版本范围。它要求编译器的版本必须在
0.4.16
到0.9.0
之间。这有助于确保代码在不同版本的编译器中保持兼容性。
3. 合约定义
contract SimpleStorage {
SimpleStorage
是智能合约的名称。它定义了一个非常基础的合约,用于实现简单的存储功能。
4. 状态变量声明
uint storedData;
- 这是一个无符号整数类型的状态变量
storedData
,用于存储数据在合约中的值。状态变量会被永久存储在区块链上,修改后的值也会保存在区块链的状态中。
5. set
函数
function set(uint x) public {
storedData = x;
}
set
函数允许用户通过传递一个无符号整数x
来设置状态变量storedData
的值。public
:表示该函数可以被外部用户或合约调用。storedData = x;
:将传入的值x
赋给状态变量storedData
,从而更新区块链上的存储数据。
6. get
函数
function get() public view returns (uint) {
return storedData;
}
get
函数用于检索并返回storedData
的当前值。view
:表示该函数不会修改区块链上的状态,属于只读操作,因此不会消耗 Gas。returns (uint)
:声明该函数返回一个无符号整数类型 (uint
) 的值,即当前存储的storedData
。
子货币(Subcurrency)例子
下面的合约实现了一个最简单的加密货币。 这里,币确实可以无中生有地产生,但是只有创建合约的人才能做到(实现一个不同的发行计划也不难)。 而且,任何人都可以给其他人转币,不需要注册用户名和密码,所需要的只是以太坊密钥对。
代码说明
- 这个合约定义了一个简单的代币系统,包含铸造(
mint
)和发送(send
)功能。只有合约的创建者可以铸造新的代币,其他用户可以通过send
函数将他们拥有的代币转移给其他地址。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Coin {
// 关键字 "public" 使变量可以从其他合约中访问。
address public minter;
mapping(address => uint) public balances;
// 事件允许客户端对您声明的特定合约变化做出反应
event Sent(address from, address to, uint amount);
// 构造函数代码只有在合约创建时运行
constructor() {
minter = msg.sender;
}
// 向一个地址发送一定数量的新创建的代币
// 但只能由合约创建者调用
// 加钱
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
balances[receiver] += amount;
}
// 错误类型变量允许您提供关于操作失败原因的信息。
// 它们会返回给函数的调用者。
error InsufficientBalance(uint requested, uint available);
// 从任何调用者那里发送一定数量的代币到一个地址
function send(address receiver, uint amount) public {
if (amount > balances[msg.sender])
revert InsufficientBalance({
requested: amount,
available: balances[msg.sender]
});
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}
这个 Solidity 合约实现了一个简单的代币系统,允许合约的创建者(minter
)铸造新的代币,并且用户之间可以发送这些代币。下面逐行解释代码的功能:
1. 许可证声明
// SPDX-License-Identifier: GPL-3.0
- SPDX 是软件包数据交换的缩写,用于声明合约的许可证类型。
GPL-3.0
表示此代码受 GNU 通用公共许可证 3.0 的保护,要求任何使用该代码的程序必须遵守 GPL 许可的条款。
2. Solidity 版本声明
pragma solidity ^0.8.4;
- 该语句指定了使用的 Solidity 编译器版本为 0.8.4 或更高。
^0.8.4
表示它可以使用 0.8.x 系列中任何版本的编译器(除非是 0.9.x 或更高)。
3. 合约定义
contract Coin {
Coin
是这个智能合约的名称。一个合约类似于一个类,定义了状态和行为。
4. 变量声明
address public minter;
mapping(address => uint) public balances;
minter
:这是一个address
类型的变量,用于存储合约创建者的地址。public
修饰符表示此变量的值可以被外部合约读取,并且 Solidity 会自动生成一个 getter 函数来访问该变量。balances
:这是一个mapping
,用于存储每个地址(address
)的余额(uint
)。mapping
类似于哈希表,将地址映射到余额。这个变量也是public
,可以被外部查询。
5. 事件声明
event Sent(address from, address to, uint amount);
- 事件
Sent
用于在代币从一个地址发送到另一个地址时触发通知。事件是合约中的日志功能,外部应用可以监听事件。这里记录了发送者(from
)、接收者(to
)以及发送的代币数量(amount
)。
6. 构造函数
constructor() {
minter = msg.sender;
}
- 构造函数
constructor
是一个特殊的函数,只在合约创建时执行。msg.sender
表示调用合约的地址(通常是合约的部署者)。这里的构造函数将部署合约的人的地址赋值给minter
,使其成为铸币权的拥有者。
7. mint
函数
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
balances[receiver] += amount;
}
mint
函数允许minter
给某个receiver
地址增加代币数量(相当于“铸造”新的代币)。require(msg.sender == minter)
:该行确保只有合约创建者(minter
)可以调用mint
函数。如果不是minter
调用,这个操作会被拒绝。balances[receiver] += amount
:给指定的receiver
增加代币。
8. 自定义错误
error InsufficientBalance(uint requested, uint available);
- 自定义错误
InsufficientBalance
用于在send
函数中,当用户尝试发送超过其余额的代币时抛出错误。它会返回两个参数:请求的代币数量requested
和用户实际拥有的available
数量。自定义错误比字符串错误节省 Gas。
9. send
函数
function send(address receiver, uint amount) public {
if (amount > balances[msg.sender])
revert InsufficientBalance({
requested: amount,
available: balances[msg.sender]
});
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
send
函数允许用户将他们的代币发送给另一个地址。if (amount > balances[msg.sender])
:如果发送的数量amount
超过了调用者的余额,则抛出InsufficientBalance
错误,并提供详细信息(请求的数量和可用余额)。balances[msg.sender] -= amount;
:从调用者的账户中减去发送的代币数量。balances[receiver] += amount;
:将代币数量加到接收者的余额中。emit Sent(msg.sender, receiver, amount);
:触发Sent
事件,记录代币的转移。