Solidity语言

DeeLMind大约 9 分钟

Solidity语言

HardHatopen in new window

  • 安装
npm install --save-dev hardhat
  • 编译工程
npx hardhat compile
  • 测试工程
npx hardhat test
  • 测试节点
npx hardhat node

Foundryopen in new window

  • 安装
forge init hello_foundry
  • 编译工程
forge build
  • 测试工程
forge test
  • 测试节点
anvil

Hello World

// SPDX-License-Identifier: MIT

/*
    comment
*/

pragma solidity ^0.8.0;

contract HelloWorld{
    string public _string = "Hello World";
}

数值类型

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// 定义一个名为Person的结构体
struct Person {
    string name; // 姓名
    uint age;    // 年龄
    address walletAddress; // 钱包地址
}

contract ValueTypes{
    // 布尔值
    bool public _bool = true;
    // 布尔运算
    bool public _bool1 = !_bool; //取非
    bool public _bool2 = _bool && _bool1; //与
    bool public _bool3 = _bool || _bool1; //或
    bool public _bool4 = _bool == _bool1; //相等
    bool public _bool5 = _bool != _bool1; //不相等


    // 整数
    int public _int = -1;
    uint public _uint = 1;
    uint256 public _number = 20220330;
    // 整数运算
    uint256 public _number1 = _number + 1; // +,-,*,/
    uint256 public _number2 = 2**2; // 指数
    uint256 public _number3 = 7 % 2; // 取余数
    bool public _numberbool = _number2 > _number3; // 比大小


    // 地址
    address public _address = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
    address payable public _address1 = payable(_address); // payable address,可以转账、查余额
    // 地址类型的成员
    uint256 public balance = _address1.balance; // balance of address
    
    
    // 固定长度的字节数组
    bytes32 public _byte32 = "DeeLMind"; // bytes32: 0x4465654c4d696e64000000000000000000000000000000000000000000000000
    bytes1 public _byte = _byte32[0];
    
    
    // Enum
    // 将uint 0, 1, Zero, One, Two
    enum ActionSet { Zero, One, Two }
    // 创建enum变量 action
    ActionSet action = ActionSet.Two;

    // enum可以和uint显式的转换
    function enumToUint() external view returns(uint){
        return uint(action);
    }

    // 声明一个Person类型的变量
    Person public myPerson;


    // 可以通过函数修改结构体的值
    function updatePerson(string memory _name, uint _age, address _walletAddress) public {
        myPerson.name = _name;
        myPerson.age = _age;
        myPerson.walletAddress = _walletAddress;
    }

    // 固定长度 Array
    uint[8] array1;
    bytes1[5] array2;
    address[100] array3;

    // 可变长度 Array
    uint[] array4;
    bytes1[] array5;
    address[] array6;
    bytes array7;

    // 初始化可变长度 Array
    uint[] array8 = new uint[](5);
    bytes array9 = new bytes(9);
    //  给可变长度数组赋值
    function initArray() external pure returns(uint[] memory){
        uint[] memory x = new uint[](3);
        x[0] = 1;
        x[1] = 3;
        x[2] = 4;
        return(x);
    }  

    // memory 存储在内存中
    function arrayPush() public returns(uint[] memory){
        uint[2] memory a = [uint(1),2];
        array4 = a;
        array4.push(3);
        return array4;
    }

    // calldata 不能修改
    function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){
        // calldata aaa;
        // _x = 1;
        return(_x);
    }

    uint[] x1 = [1,2,3]; // 状态变量:数组 x

    // 存储在链上
    function fStorage() public{
        uint[] storage xStorage = x1;
        xStorage[0] = 100;
    }

    // delete操作符
    bool public _bool21 = true; 
    function d() external {
        delete _bool21; // delete 会让_bool21变为默认值,false
    }

    // constant变量必须在声明的时候初始化,之后不能改变
    uint256 constant CONSTANT_NUM = 10;
    string constant CONSTANT_STRING = "0xAA";
    bytes constant CONSTANT_BYTES = "AA";
    address constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;

    // immutable变量可以在constructor里初始化,之后不能改变
    uint256 public immutable IMMUTABLE_NUM = 9999999999;
    address public immutable IMMUTABLE_ADDRESS;
    uint256 public immutable IMMUTABLE_BLOCK;
    uint256 public immutable IMMUTABLE_TEST;

    // 利用constructor初始化immutable变量,因此可以利用
    constructor(){
        myPerson = Person("DeeLMind", 18, address(0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71));
        IMMUTABLE_ADDRESS = address(this);
        IMMUTABLE_BLOCK = block.number;
        // CONSTANT_NUM = 11;
    }
}

函数类型

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract FunctionTypes{
    uint256 public number = 5;
    
    constructor() payable {}

    // 函数类型
    // function (<parameter types>) {internal|external} [pure|view|payable] [returns (<return types>)]
    function add() external{
        number = number + 1;
    }

    // public: 内部外部均可见。
    // private: 只能从本合约内部访问,继承的合约也不能用。
    // external: 只能从合约外部访问(但是可以用this.f()来调用,f是函数名)。
    // internal: 只能从合约内部访问,继承的合约可以用。
    function addPure(uint256 _number) external pure returns(uint256 new_number){
        new_number = _number+1;
    }
    
    function addView() external view returns(uint256) {
        uint256 new_number = number + 1;
        return new_number;
    }

    function minus() internal {
        number = number - 1;
    }

    function minusCall() external {
        minus();
    }

    function minusPayable() external payable returns(uint256 balance) {
        minus();    
        balance = address(this).balance;
    }

    function returnss() public pure  returns (uint256, bool) {
        return (1, true);
    }

    uint256 one1;
    bool tw1o;

    function callReturnss() public {
        (one1, tw1o) = returnss();
    }

}

发送接收

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract ReceiveETH {
    // 收到eth事件,记录amount和gas
    // 日志记录都包含主题topics和数据data两部分
    event XXXLOG(string name,uint amount, uint gas);
    event XXXLOG1(address indexed from,string name,uint amount, uint gas);
    // https://etherscan.io/tx/0xf23f89131cffe115ee20a9f4b039b2ffaf3c51ad17bfec301b1a975f9478030b#eventlog
    
    // receive方法,接收eth时被触发
    receive() external payable{
        emit XXXLOG1(msg.sender,"receive",msg.value, gasleft());
    }
    
    // fallback() external payable {
    //     emit XXXLOG("fallback",msg.value, gasleft());
    // }
    
    // 返回合约ETH余额
    function getBalance() view public returns(uint) {
        return address(this).balance;
    }
}

contract CallContract{
    // 对应每个用户的资产 key = value
    mapping(address => uint) private userBalances;

    // 存入资产
    function deposit() public payable {
        userBalances[msg.sender] += msg.value;
    }

    function getCurUBalance() public view returns (uint){
        return userBalances[msg.sender];
    }

    function getAllBalance() public payable returns (uint){
        return address(this).balance;
    }

    // send()发送ETH
    function sendETH_send(address payable _to, uint256 amount) external payable{
        // 处理下send的返回值,如果失败,revert交易并发送error
        // bool success = _to.send(amount);
        // if(!success){
        //     revert("send failed");
        // }
        // _to.transfer(amount);

        // (bool success ,)= _to.call{value:amount}("");
        // if(!success){
        //     revert("send failed");
        // }
    }

}

循环控制

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract Flow {
    // if else
    function ifElseTest(uint256 _number) public pure returns(bool){
        if(_number == 0){
            return(true);
        }else{
            return(false);
        }
    }

    // for loop
    function forLoopTest() public pure returns(uint256){
        uint sum = 0;
        for(uint i = 0; i < 10; i++){
            sum += i;
        }
        return(sum);
    }

    // while
    function whileTest() public pure returns(uint256){
        uint sum = 0;
        uint i = 0;
        while(i < 10){
            sum += i;
            i++;
        }
        return(sum);
    }

    // do-while
    function doWhileTest() public pure returns(uint256){
        uint sum = 0;
        uint i = 0;
        do{
            sum += i;
            i++;
        }while(i < 10);
        return(sum);
    }

    // 三元运算符 ternary/conditional operator
    function ternaryTest(uint256 x, uint256 y) public pure returns(uint256){
        // return the max of x and y
        return x >= y ? x: y; 
    }
}

修饰器

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

contract Owner {
   address public owner; // 定义owner变量

   // 构造函数
   constructor(address initialOwner) {
      owner = initialOwner; // 在部署合约的时候,将owner设置为传入的initialOwner地址
   }

   // 定义modifier
   modifier onlyOwner {
      require(msg.sender == owner); // 检查调用者是否为owner地址
      _; // 如果是的话,继续运行函数主体;否则报错并revert
   }

   // 定义一个带onlyOwner修饰符的函数
   function changeOwner(address _newOwner) external onlyOwner{
      owner = _newOwner; // 只有owner地址运行这个函数,并改变owner
   }
}

异常错误

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

// 自定义error
error TransferNotOwner();

// error TransferNotOwner(address sender);

contract Errors {
    // 一组映射,记录每个TokenId的Owner
    mapping(uint256 => address) private _owners;

    // Error方法: gas cost 24457
    // Error with parameter: gas cost 24660
    function transferOwner1(uint256 tokenId, address newOwner) public {
        if (_owners[tokenId] != msg.sender) {
            revert TransferNotOwner();
            // revert TransferNotOwner(msg.sender);
        }
        _owners[tokenId] = newOwner;
    }

    // require方法: gas cost 24755
    function transferOwner2(uint256 tokenId, address newOwner) public {
        require(_owners[tokenId] == msg.sender, "Transfer Not Owner");
        _owners[tokenId] = newOwner;
    }

    // assert方法: gas cost 24473
    function transferOwner3(uint256 tokenId, address newOwner) public {
        assert(_owners[tokenId] == msg.sender);
        _owners[tokenId] = newOwner;
    }
}

合约库

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

library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) public pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) public pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) public pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}


// 用函数调用另一个库合约
contract UseLibrary{    
    // 利用using for操作使用库
    using Strings for uint256;
    function getString1(uint256 _number) public pure returns(string memory){
        // 库函数会自动添加为uint256型变量的成员
        return _number.toHexString();
    }

    // 直接通过库合约名调用
    function getString2(uint256 _number) public pure returns(string memory){
        return Strings.toHexString(_number);
    }
}

合约代理

(bool success, bytes memory data) = _addr.delegatecall(abi.encodeWithSignature("setVars(uint256)", _num));

合约创建

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

contract A{

}

contract B{
    A public immutable a;
    A public immutable a1;
    constructor(){
        a = new A();
        a1 = new A{salt: keccak256('')}();
    }

    function getA() public view returns(address){
        return address(a);
    }

    function getA1() public view returns(address){
        return address(a1);
    }

    function calculateAddress() public view returns (address) {
        return address(uint160(uint(keccak256(abi.encodePacked(
            bytes1(0xff),
            address(this),
            keccak256(''),
            keccak256(type(A).creationCode)
        )))));
    }
}

合约调用

A a = new A{}();
address(this).call{value:amount}(abi.encodeWithSelector(0x6a627842, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4));

ABI

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

contract ABIEncode{
    uint x = 10;
    address addr = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
    string name = "b";
    uint[2] array = [5, 6]; 

    function encode() public view returns(bytes memory result) {
        result = abi.encode(x, addr, name, array);
    }

    function encodePacked() public view returns(bytes memory result) {
        result = abi.encodePacked(x, addr, name, array);
    }

    function encodeWithSignature() public view returns(bytes memory result) {
        result = abi.encodeWithSignature("test(uint256,address,string,uint256[2])", x, addr, name, array);
    }

    function encodeWithSelector() public view returns(bytes memory result) {
        result = abi.encodeWithSelector(bytes4(keccak256("test(uint256,address,string,uint256[2])")), x, addr, name, array);
    }
    function decode(bytes memory data)   public  payable returns(uint dx, address daddr, string memory dname, uint[2] memory darray) {
        (dx, daddr, dname, darray) = abi.decode(data, (uint, address, string, uint[2]));
    }
}

HASH计算

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

contract Hash{
    bytes32 _msg = keccak256(abi.encodePacked("0xAA"));

    // 唯一数字标识
    function hash(
        uint _num,
        string memory _string,
        address _addr
    ) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(_num, _string, _addr));
    }

    // 弱抗碰撞性
    function weak(
        string memory string1
    )public view returns (bool){
        return keccak256(abi.encodePacked(string1)) == _msg;
    }

    // 强抗碰撞性
    function strong(
        string memory string1,
        string memory string2
    )public pure returns (bool){
        return keccak256(abi.encodePacked(string1)) == keccak256(abi.encodePacked(string2));
    }
}

选择器

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

contract Selector{
    // event 返回msg.data
    event Log(string name,bytes data);

    // 输入参数 to: 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
    function mint(address /*to*/) external{
        emit Log("MySelectorLog",msg.data);
    }
    
    receive() external payable{
    }

    fallback() external payable {
    }

    // 输出selector
    // "mint(address)": 0x6a627842
    function mintSelector() external pure returns(bytes4 mSelector){
        return bytes4(keccak256("mint(address)"));
    }

    // 使用selector来调用函数
    function callWithSignature() external returns(bool, bytes memory){
        // 只需要利用`abi.encodeWithSelector`将`mint`函数的`selector`和参数打包编码
        (bool success, bytes memory data) = address(this).call(abi.encodeWithSelector(0x6a627842, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4));
        return(success, data);
    }
}

Openzeppelin

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

contract MyToken is ERC20, ERC20Permit {
    constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}
}

Yul

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

library GetCode {
    function at(address addr) public view returns (bytes memory code) {
        assembly {
            // 获取代码大小,这需要汇编语言
            let size := extcodesize(addr)
            // 分配输出字节数组 – 这也可以不用汇编语言来实现
            // 通过使用 code = new bytes(size)
            code := mload(0x40)
            // 包括补位在内新的 “memory end”
            mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            // 把长度保存到内存中
            mstore(code, size)
            // 实际获取代码,这需要汇编语言
            extcodecopy(addr, add(code, 0x20), 0, size)
        }
    }
}

ERC20

https://docs.openzeppelin.com/contracts/5.x/erc20

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

contract GEEKARKTOKEN is ERC20, ERC20Burnable, Ownable, ERC20Permit {
    constructor(address initialOwner)
        ERC20("GEEKARK TOKEN", "GKT")
        Ownable(initialOwner)
        ERC20Permit("GEEKARK TOKEN")
    {}

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

ERC721

// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC721URIStorage} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract GameItem is ERC721URIStorage {
    uint256 private _nextTokenId;

    constructor() ERC721("GameItem", "ITM") {}

    function awardItem(address player, string memory tokenURI)
        public
        returns (uint256)
    {
        uint256 tokenId = _nextTokenId++;
        _mint(player, tokenId);
        _setTokenURI(tokenId, tokenURI);

        return tokenId;
    }
}

ERC1155

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract GEEKTK is ERC1155, Ownable {
    constructor(address initialOwner) ERC1155("") Ownable(initialOwner) {}

    function mint(address account, uint256 id, uint256 amount, bytes memory data)
        public
        onlyOwner
    {
        _mint(account, id, amount, data);
    }

    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        public
        onlyOwner
    {
        _mintBatch(to, ids, amounts, data);
    }
}

闪电贷

LPFS上传文件

上次编辑于:
贡献者: DeeLMind