1. 单位

1.1. 常用单位

  • wei 是以太币(ETH)的最小单位(1 wei == 1)
  • gwei 是描述汽油价格时常用的单位(1 gwei == 1e9)
  • 以太 单位 (1 以太 == 1e18)
注:
在 Solidity 中,我们将使用整数进行计算,且该语言不支持 浮点数 类型。浮点数表示法的问题会导致舍入误差(四舍五入) 从而为攻击者制造了逻辑漏洞。

1.2. 时间单位

  • 1 == 1
  • 1 会议纪要 == 60
  • 1 小时 == 60 会议纪要
  • 1 == 24 小时
  • 1 == 7

示例

function f(uint start, uint daysAfter) public {
          if (block.timestamp >= start + daysAfter * 1 days) {
                    // ...
     
     }
}

2. 全局变量

2.1. 区块和交易属性

  • blockhash(uint blockNumber) 返回 (bytes32):给定区块的哈希值,当 区块号 是最近的 256 个区块之一;否则返回零
  • block.basefee (uint): 当前区块的基础手续费
  • block.chainid (uint): 当前链 ID
  • block.coinbase(收款地址): 当前区块矿工的地址
  • block.gaslimit (uint): 当前区块的 gas 限制
  • 区块号 (uint): 当前区块号
  • block.timestamp (uint): 当前区块时间戳(以自Unix纪元以来的秒数表示)
  • gasleft() 返回 (uint256): 剩余燃气
  • msg.data(字节 calldata): 完整的调用数据
  • msg.sender (地址): 消息发送者(当前通话)
  • msg.sig (4字节):调用数据的头四个字节(即函数标识符)
  • msg.value (uint): 随消息发送的wei数量
  • tx.gasprice (uint): 交易的手续费
  • tx.origin(地址): 交易发起者(完整调用链)

2.2. 错误处理

  • assert(bool condition): 如果条件未满足,将引发 Panic 错误并导致状态回滚——用于内部错误。
  • require(bool condition): 如果条件未满足则回退——用于处理输入或外部组件中的错误。
  • require(bool 条件, string 内存提示): 如果条件未满足则回退——用于处理输入或外部组件中的错误。同时会显示一条错误信息。
  • revert():中止执行并回滚状态变更
  • revert(字符串 内存 原因):中止执行并回滚状态变更,同时提供一条说明性字符串

2.3. 地址类型的成员

  • <address>.balance (uint256):魏国诏书的其余部分
  • <address>.code (bytes memory): 地址处的代码(可以为空)
  • <address>.codehash (bytes32):该地址的代码哈希值
  • <address payable>.transfer(uint256 amount): 将指定数量的 Wei 发送至指定地址,若操作失败则回滚,并支付 2300 gas 费用,该数值不可调整
  • <address payable>.send(uint256 amount) returns (bool): 将指定数量的 Wei 发送至指定地址,失败时返回 false,预付 2300 gas,不可调整
  • <address>.call(bytes memory) returns (bool, bytes memory): 使用给定的有效载荷调用低级 CALL 函数,返回成功状态和返回数据,转发所有可用 gas,可调整
  • <address>.delegatecall(bytes memory) returns (bool, bytes memory): 使用给定的有效载荷调用低级 DELEGATECALL,返回成功状态和返回数据,转发所有可用 gas,可调整
  • <address>.staticcall(bytes memory) returns (bool, bytes memory): 使用给定的有效载荷发出低级 STATICCALL 调用,返回成功状态和返回数据,转发所有可用 gas,可调整

2.4. 与合同相关的关键词

  • 这个: 当前合约,可明确转换为 Address
  • 超级: 在继承层次结构中比当前级别高一级别的契约
  • selfdestruct(收款人地址): 销毁当前合约,将资金转至指定的地址,并终止执行。请注意,selfdestruct 继承了 EVM 的一些特殊性:
    • 接收合同的接收函数未被执行。
    • 合约实际上只有在交易结束时才会被销毁,而回滚操作可能会“撤销”这一销毁。

3. 表达式与控制结构

3.1. 支持的关键词

有: 如果, 否则, 虽然, , , 换行, 继续, 返回, 试一试/捕获 采用与 C 或 JavaScript 中相同的语义。

3.2. 函数调用

我们可以称 函数 第 1 页 合同 来自另一个 合同. 下面是一个包含 2 份合同的示例 来电者 以及 卡莉.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Callee {
    uint public x;
    uint public value;

    function setX(uint _x) public returns (uint) {
        x = _x;
        return x;
    }

    function setXandSendEther(uint _x) public payable returns (uint, uint) {
        x = _x;
        value = msg.value;

        return (x, value);
    }
}

contract Caller {
    function setX(Callee _callee, uint _x) public {
        uint x = _callee.setX(_x);
    }

    function setXFromAddress(address _addr, uint _x) public {
        Callee callee = Callee(_addr);
        callee.setX(_x);
    }

    function setXandSendEther(Callee _callee, uint _x) public payable {
        (uint x, uint value) = _callee.setXandSendEther{value: msg.value}(_x);
    }
}

3.3. 使用关键字创建新合约

我们可以使用关键词 创建一份新合同。 AdvancedStorage.sol 下面这个例子将对此进行更详细的说明。

4. 高级存储

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

contract AdvancedStorage {
    // Declare the address of a vault manager
    address public vaultManager;

    // Declare an error type for unauthorized access
    error OwnableUnauthorizedAccount(address account);

    // Constructor is a function that runs when the contract is initialized
    constructor() {
        // Assign the address of the deployer to the vault manager variable
        vaultManager = msg.sender;
    }

    // Declare the InvestmentVault Struct data type
    struct InvestmentVault {
        uint256 investmentDuration; // Thời gian đầu tư
        int256 returnOnInvestment; // % lãi suất trả về
        bool initialized; // Đã khởi tạo
        address identityCard; // Địa chỉ thẻ thông tin
    }
    // Declare a variable with the InvestmentVault type
    InvestmentVault private investmentVault;

    // This function initializes the investment vault
    function setInitialInvestmentVault(uint256 daysAfter, int256 _returnOnInvestment, address _vaultOwner) public {
        // We check if the initiator is the vaultManager
        if (msg.sender != vaultManager) {
            // This reverts all actions and reverts the transaction
            revert OwnableUnauthorizedAccount(msg.sender);
        }
        // Declare the investment duration
        uint256 _investmentDuration = block.timestamp + daysAfter * 1 days;

        // Create a new identity card for the customer
        CustomerIdentityCard customerIdentityCard = new CustomerIdentityCard(_vaultOwner);
        // Assign the address of the vault owner/customer to the mapping with the vault information
        investmentVault = InvestmentVault({investmentDuration: _investmentDuration, returnOnInvestment: _returnOnInvestment, initialized: true, identityCard: address(customerIdentityCard)});
    }

    // Function to change the return on investment
    function editReturnOnInvestment(int256 _newReturnOnInvestment) public {
        // require keyword works similarly to if and revert above
        require (msg.sender == vaultManager, "Unauthorized Manager");
        // Change the value of the interest rate
        investmentVault.returnOnInvestment = _newReturnOnInvestment;
    }

    // Function to return investmentVault information
    function retrieveInvestmentVault() public view returns (InvestmentVault memory _investmentVault) {
        return investmentVault;
    }

    // Function to return the address of the IdentityCard
    function retrieveCustomerInformation() public view returns (address) {
        return CustomerIdentityCard(investmentVault.identityCard).customer();
    }
}

// Contract that stores the address of the vault owner
contract CustomerIdentityCard {
    //  declares a variable to store the address of the customer
    address public customer;

    // initialize the contract and assign the address of the customer
    constructor(address _customer) {
        customer = _customer;
    }
}