Solidity零基础速学

配套视频教程

https://www.youtube.com/@benson8836/featured

1.Hello World

// SPDX-License-Identifier: MIT
// compiler version must be greater than or equal to 0.8.10 and less than 0.9.0
pragma solidity ^0.8.10;

contract HelloWorld {
    string public greet = "Hello World!";
}

2.类型和值

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

contract Primitives {
    bool public boo = true;

    /*
    uint stands for unsigned integer, meaning non negative integers
    different sizes are available
        uint8   ranges from 0 to 2 ** 8 - 1
        uint16  ranges from 0 to 2 ** 16 - 1
        ...
        uint256 ranges from 0 to 2 ** 256 - 1
    */
    uint8 public u8 = 1;
    uint public u256 = 456;
    uint public u = 123; // uint is an alias for uint256

    /*
    Negative numbers are allowed for int types.
    Like uint, different ranges are available from int8 to int256
    
    int256 ranges from -2 ** 255 to 2 ** 255 - 1
    int128 ranges from -2 ** 127 to 2 ** 127 - 1
    */
    int8 public i8 = -1;
    int public i256 = 456;
    int public i = -123; // int is same as int256

    // minimum and maximum of int
    int public minInt = type(int).min;
    int public maxInt = type(int).max;

    address public addr = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;

    /*
    In Solidity, the data type byte represent a sequence of bytes. 
    Solidity presents two type of bytes types :

     - fixed-sized byte arrays
     - dynamically-sized byte arrays.
     
     The term bytes in Solidity represents a dynamic array of bytes. 
     It’s a shorthand for byte[] .
    */
    bytes1 a = 0xb5; //  [10110101]
    bytes1 b = 0x56; //  [01010110]

    // Default values
    // Unassigned variables have a default value
    bool public defaultBoo; // false
    uint public defaultUint; // 0
    int public defaultInt; // 0
    address public defaultAddr; // 0x0000000000000000000000000000000000000000
}

3.函数

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

contract Function {
    function add(uint x, uint y) external pure returns (uint) {
        return x + y;
    }
    function sub(uint x, uint y) external pure returns (uint) {
        return x - y;
    }
}

4.状态变量

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
//function <function name>(<parameter types>) {internal|external|public|private} [pure|view|payable] [returns (<return types>)]
contract StateVariables {
    uint public myUint = 123;

    function foo() external pure returns(int) {
        int s = 321;
        return s;
    }
}

5.局部变量

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
//function <function name>(<parameter types>) {internal|external|public|private} [pure|view|payable] [returns (<return types>)]
contract StateVariables {
    uint public i;
    bool public b;
    address public myAddress;
    function foo() external {
            uint x = 123;
            bool f = false; 
            x +=456;
            f= true;
            i = 321;
            b = true;
            myAddress = address(1);                  
    }

}

6.全局变量

contract GlobalVariables {
    function globalVars() external view returns (address, uint, uint) {
        address sender = msg.sender;
        uint timestamp = block.timestamp;
        uint blockNum = block.number;
        return (sender,timestamp,blockNum);              
    }

}

7.只读函数

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

contract ViewAndPureFunction {
    uint public num;

    function viewFunc() external view returns (uint) {
        return num;
    }
    function pureFunc() external pure returns (uint) {
        return 1;
    }
    function addToNum(uint x) external view returns (uint) {
        return num + x;
    }
    function add(uint x, uint y) external pure returns (uint) {
        return x + y;
    }
}

8.计数器合约

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

contract Counter {
    uint public count;

    function inc() external {
        count += 1;
    }

    function dec() external {
        count -= 1;
    }

}

9.默认值

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

contract DefaultValues {
    bool public b; // false
    uint public u; // 0
    int public i; // 0
    address public a; // 0x0000000000000000000000000000000000000000
    bytes32 public b32; // 0x0000000000000000000000000000000000000000000000000000000000000000
}

10.常量

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

contract Constants {
    address public constant MY_ADDRESS = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
    uint public constant MY_UINT = 123;
}

contract Var {
    address public MY_ADDRESS = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
}

11.结构控制

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

contract IfElse {
    function example(uint _x) external pure returns (uint) {
        if (_x < 10) {
            return 1;
        } else if (_x < 20) {
            return 2;
        } else {
            return 3;
        }
    }

    function ternary(uint _x) external pure returns (uint) {
        // if (_x < 10) {
        //     return 1;
        // }
        // return 2;
        return _x < 10 ? 1 : 2;
    }

}

12.循环

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

contract ForAndWhileLoops {
    function loops() external pure {
        for (uint i = 0; i< 10; i++) {
            // code
            if (i == 3) {
                continue;
            }
            // more code
            if (i == 5) {
                break;
            }
        }

        uint j = 0;
        while (j < 10) {
            // code
            j++;
        }
    }

    function sum(uint _n) external pure returns (uint) {
        uint s;
        for (uint i = 1; i <= _n; i++) {
            s += i;
        }
        return s;
    }
}

13.报错控制

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

contract testError {
    function testRequire(uint _i) public pure {
        require(_i <= 10, "i > 10");
        // code     
    }

    function testRevert(uint _i) public pure {
        if (_i > 10) {
            revert("i > 10");
        }
    }

    uint public num = 123;

    function testAssert() public view {
        assert(num == 123);
    }

    function foo(uint _i) public {
        num += 1;
        require(_i < 10);
    }

    function testCustomError(uint _i) public pure {
        require(_i <= 10, "error msg xxxxxxxxxxxxxxxxxxxxxx");
        // code     
    }

    error MyError(address caller, uint i);

    function  testCustomSetError(uint _i) public view {
        if (_i > 10) {
            revert MyError(msg.sender, _i);
        }
    }
}

14.函数修改器

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

// basic input sandwich

// 原版本
contract FunctionModifier {
    bool public paused;
    uint public count;

    function setPause(bool _paused) external {
        paused = _paused;
    }

    function inc() external {
        require(!paused, "paused");
        count += 1;
    }

     function dec() external {
        require(!paused, "paused");
        count -= 1;   
    }
}

// 使用修改器后
contract FunctionModifier {
    bool public paused;
    uint public count;

    function setPause(bool _paused) external {
        paused = _paused;
    }
    
    modifier whenNotPaused() {
        require(!paused, "paused");
        _;
    }

    function inc() external whenNotPaused {
        count += 1;
    }

    function dec() external whenNotPaused{
        count -= 1;   
    }   


}

// 带参数修改器

contract FunctionModifier {
    bool public paused;
    uint public count;

    function setPause(bool _paused) external {
        paused = _paused;
    }
    
    modifier cap(uint _x) {
        require(_x < 100, "x > 100");
        _;
    
    
    }

    function incBy(uint _x) external whenNotPaused cap(_x) { 
        count += _x
    }


}

//三明治

contract FunctionModifier {
    bool public paused;
    uint public count;

    function setPause(bool _paused) external {
        paused = _paused;
    }
    
    modifier sandwitch() {
        // code
        count += 10;
        _;
        count *= 2;
    }

    function foo() external sandwitch{ 
        count += 1;
    }


}

15.构造函数

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

contract Constructor {
    address public owner;
    uint public x;

    constructor(uint _x) {
        owner = msg.sender;
        x = _x;
    }
}

16.Ownable

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

contract Ownable {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    function setOwner(address _newOwner) external onlyOwner {
        require(_newOwner != address(0), "invalid sender");
        owner = _newOwner;
    }

    function onlyOwnerCanCallThisFunc() external onlyOwner {
        // code
    }

    function anyOneCanCall() external {
        // code 
    } 

}

17.函数返回值

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

contract FunctionOutputs {
    function returnMany() public pure returns (uint, bool) {
        return (1, true);
    }

    function named() public pure returns (uint x, bool b) {
        return (1, true);
    }

    function assigned() public pure returns (uint x, bool b) {
        x = 1;
        b = true;
    }

    function destructingAssigments() public pure returns {
        (uint x, bool b) = returnMany();
        (, bool b) = returnMany();
    }

}

18.数组

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

contract Array {
    uint[] public nums = [1, 2, 3];
    uint[3] public numsFixed = [4, 5, 6];

    function examples() external {
        nums.push(4); // [1,2,3,4]
        uint x = nums[1];
        nums[2] = 777; // [1,2,777,4]
        delete nums[1]; // [1,0,777,4]
        nums.pop; // [1,0,777]
        uint len = nums.length;

        // create in memory 内存中只能创建定长数组,不能改变长度
        uint[] memory a = new uintUnsupported embed; 
        a[1] = 123;
    }

    function returnArray() external view returns (uint[] memory) {
        return nums;
    }

}


contract Array2 {
 
    // 通过元素移动位置删除数组元素(gas高,但顺序不乱)

    uint[] public arr;
    // [1,2,3] -remove(1)->[1,3,3]->[1,3]
    // [1,2,3,4,5,6] -removed(2)->[1,2,4,5,6,6]->[1,2,4,5,6]
    function remove(uint _index) public {
        require(_index < arr.length, "index out of bound");
        for (uint i = _index; i < arr.length - 1; i++) {
            arr[i] = arr[i + 1];           
        }
        arr.pop();
    }

    function test() external {
        arr = [1, 2, 3, 4, 5];
        remove(2);
        assert(arr[0] == 1);
        assert(arr[1] == 2);
        assert(arr[2] == 4);
        assert(arr[3] == 5);
        assert(arr.length == 4);

        arr = [1];
        remove(0);
        // []
        assert(arr.length == 0);
    }
}



contract Array3 {
    uint[] public arr;
    // 通过元素替换删除数组元素 (gas低,但顺序打乱)
    // 【1,2,3,4】-remove2(1) -> 【1,4,3,4】 ->[1,4,3]
    function remove(uint _index) public {
        arr[_index] = arr[arr.length - 1];
        arr.pop();
    }

    function test2() external {
        arr = [1, 2, 3, 4];

        remove(1);
        // [1, 4, 3]
        assert(arr.length == 3);
        assert(arr[0] == 1);
        assert(arr[1] == 4);
        assert(arr[2] == 3);
    }
}

19.映射

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

contract Mapping {
    mapping(address => uint) public balances;
    mapping(address => mapping(address => bool)) public isFriend;

    function examples() external {
        balances[msg.sender] = 123;
        uint bal = balances[msg.sender];
        uint bal2 = balances[address(1)]; // 0

        balances[msg.sender] += 456;

        delete balances[msg.sender];

        isFriend[msg.sender][address(this)] = true;
    }

}

// 结合遍历和映射
contract IterableMapping {
    mapping(address => uint) public balances;
    mapping(address => bool) public inserted; // 地址是否存在
    address[] public keys;

    function set(address _key, uint _val) external {
        balances[_key] = _val;

        if (!inserted[_key]) {
            inserted[_key] = true;
            keys.push(_key);
        }
    }

    function getSize() external view returns (uint) {
        return keys.length;
    }
    
    function first() external view returns (uint) {
        return balances[keys[0]];
    }

    function last() external view returns (uint) {
        return balances[keys[keys.length - 1]];
    }    

    function get(uint _i) external view returns (uint) {
        return balances[keys[_i]];
    }

}

20.结构体

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

contract Structs {
    struct Car {
        string model;
        uint year;
        address owner;
    }

    Car public car;
    Car[] public cars;
    mapping(address => Car[]) public carsByOwner;

    function examples() external {
        Car memory toyota = Car("Toyota", 1990, msg.sender);
        Car memory lambo = Car({model:"Lamborghini", year:1980, owner: msg.sender});
        Car memory tesla;
        tesla.model = "Tesla";
        tesla.year = 2010;
        tesla.owner = msg.sender;

        cars.push(toyota);
        cars.push(lambo);
        cars.push(tesla);

        cars.push(Car("Ferrari", 2020, msg.sender));

        //取读
        Car memory _car = cars[0];
        _car.model;

        //连带状态变量修改(带指针)
        Car storage _car2 = cars[0];
        _car2.year = 1999;        
        delete _car2.owner;
        
        delete cars[1];
    }
}

21.枚举

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

contract Enum {
    enum Status {
        None, // 默认
        Pending,
        Shipped,
        Completed,
        Rejected,
        Canceled
    }

    Status public status;

    struct Order {
        address buyer;
        Status status;
    }

    Order[] public orders;

    //获取
    function get() view external returns (Status) {
        return status;
    }

    //修改  通过索引
    function set(Status _status) external {
        status = _status;
    }

    //修改  通过值
    function ship() external {
        status = Status.Shipped;
    }

    //重置
    function reset() external {
        delete status;
    }


    
}

22.存储位置

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

// storage memory calldata

contract DataLocations {
    struct MyStruct {
        uint foo;
        string text;
    }

    mapping(address => MyStruct) public myStructs;

    function examples() external {
        myStructs[msg.sender] = MyStruct({foo: 123, text: "bar"});

        MyStruct storage myStruct = myStructs[msg.sender];
        myStruct.text = "foo";//存储:全局变量myStructs也被改变

        MyStruct memory myStructReadOnly = myStructs[msg.sender];
        myStruct.text = "xxx";//内存:局部变量myStructs不会改变        
    }

    //calldata
    function examples(uint[] memory y, string memory s) external return (uint[] memory){
        myStructs[msg.sender] = MyStruct({foo: 123, text: "bar"});

        MyStruct storage myStruct = myStructs[msg.sender];
        myStruct.text = "foo";//全局变量myStructs也被改变

        MyStruct memory myStructReadOnly = myStructs[msg.sender];
        myStruct.text = "xxx";//全局变量myStructs不会改变       

        uint[] memory memArr = new uintUnsupported embed;
        memArr[0] = 234;
        return memArr
    }

    //calldata 只能用在参数中,更节省gas
    function examples(uint[] calldata y, string calldata s) external return (uint[] memory){
        myStructs[msg.sender] = MyStruct({foo: 123, text: "bar"});

        MyStruct storage myStruct = myStructs[msg.sender];
        myStruct.text = "foo";//全局变量myStructs也被改变

        MyStruct memory myStructReadOnly = myStructs[msg.sender];
        myStruct.text = "xxx";//全局变量myStructs不会改变       

        _internal(y);

        uint[] memory memArr = new uintpUnsupported embed;
        memArr[0] = 234;
        return memArr;

        function _internal(uint[] calldata y) private {
            uint x = y[0];
        }
    }



}

23.事件

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

contract Event {
    event Log(string message, uint val);
    event IndexLog(address indexed sender, uint val); // 最多三个索引

    function example() external {
        emit Log("foo", 1234); //写入方法
        emit IndexLog(msg.sender, 789);
    }

    event Message(address indexed _from, address index _to, string message);

    function sendMessage(address _to, string calldata message) external {
        emit Message(msg.sender, _to, message);
    }
}

24.继承

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

contract A{
    function foo() public pure virtual returns (string memory) {
        return "A";
    }

    function bar() public pure virtual returns (string memory) {
        return "A";
    }

    // more code

}

contract B is A {
    function foo() public pure override returns (string memory) {
        return "B";
    }

    function bar() public pure virtual override returns (string memory) {
        return "B";
    }

    // more code
}

contract C is B {

    function bar() public pure override returns (string memory) {
        return "C";
    }


}

25.多线继承

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

/* 从最基础到最派生,从前到后

   X
 / | 
Y  |
 \ |
   Z

// X-Y-Z

   X
 /   \
Y     A
|     |
|     B
 \   /
   Z 

// X-Y-A-B-Z

*/

contract X {
    function foo() public pure virtual returns (string memory) {
        return "X";
    }

    function bar() public pure virtual returns (string memory) {
        return "X";
    }

    function x() public pure returns (string memory) {
        return "X";
    }

}

contract Y is X {
    function foo() public pure virtual override returns (string memory) {
        return "Y";
    }

    function bar() public pure virtual override returns (string memory) {
        return "Y";
    }

    function y() public pure returns (string memory) {
        return "Y";
    }

}

contract Z is X, Y {
    function foo() public pure override(X, Y) returns (string memory) {
        return "Z";
    }

    function bar() public pure override(X, Y) returns (string memory) {
        return "Z";
    }

}

26.父级合约构造函数及函数调用

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

contract S {
    string public name;

    constructor(string memory _name) {
        name = _name;
    }
}

contract T {
    string public text;

    constructor(string memory _text) {
        text = _text;
    }
}

// 知道需要什么初始参数的情况下
contract U is S("s"), T("t") {

}

// 不知道初始参数需要开始的时候输入
contract V is S, T {
    constructor(string memory _name, string memory _text) S(_name) T(_text) {
    }
}

// 混合的情况
contract VV is S("s"), T {
    constructor(string memory _text) T(_text) {

    }
}

// 初始化的顺序是根据继承顺序
// S-T-V0
contract V0 is S, T {
    constructor(string memory _name, string memory _text) S(_name) T(_text) {
    }
}
// S-T-V1
contract V1 is S, T {
    constructor(string memory _name, string memory _text) T(_text) S(_name) {
    }
}
// T-S-V2
contract V2 is T, S {
    constructor(string memory _name, string memory _text) T(_text) S(_name) {
    }
}


//调用父级

contract E {
    event Log(string message);

    function foo() public virtual {
        emit Log("E.foo");
    }

    function bar() public virtual {
        emit Log("E.bar");
    }
}

contract F is E {
    function foo() public virtual override {
        emit Log("F.foo");
        E.foo();
    }

    function bar() public virtual override {
        emit Log("F.bar");
        super.bar();
    }
}

contract G is E {
    function foo() public virtual override {
        emit Log("G.foo");
        E.foo();
    }

    function bar() public virtual override {
        emit Log("G.bar");
        super.bar();
    }
}

contract H is F, G {
    function foo() public override(F, G) {
        F.foo;
    }

    function bar() public override(F, G) {
        super.bar();
    }    
}