从零学习Web3.0

143 阅读6分钟

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.160.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 事件,记录代币的转移。

菲菲时光机 回复 web3 啦! ☺️ 恁 一起 学习共同进步