Solidity基础【多知识点详解】

18-函数返回值

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

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;
    }

    uint public _x;
    bool public _b1;
    bool public _b2;
    function destructingAssigments() public{
        (uint x, bool b1) = returnMany();
        (, bool b2) = returnMany();
        _x = x;
        _b1 = b1;
        _b2 = b2; 
    }
}

19-数组

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

contract Array {
    // Array - dynamic or fixed size
    // Initialization
    uint[] public nums = [1, 2, 3];
    uint[3] public numsFixed = [4, 5, 6];
    // Insert(push) get update delete pop length
    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 array in memory
        uint[] memory a = new uint[](5);
        a[1] = 123;
    }
    // returning array from function
    function returnArray() external view returns (uint[] memory) {
        return nums;
    }
}

20-数组删除元素通过移动位置

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

contract ArrayShift {
    uint[] public arr;

    function example() public {
        arr = [1, 2, 3];
        delete arr[1]; // [1, 0, 3] => [1, 3]
    }

    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);
    }
}

21-删除数组中元素通过替换

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

contract ArrayReplaceLast {
    uint[] public arr;

    // 优点:消耗较少的gas,缺点:会打乱数组顺序
    function example() public {
        arr = [1, 2, 3, 4];
        remove(1);
        assert(arr[0] == 1);
        assert(arr[1] == 4);
        assert(arr[2] == 3);
    }

    function remove(uint _index) public {
        arr[_index] = arr[arr.length - 1];
        arr.pop();
    }
}

22-映射

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

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

    uint public bal1;
    uint public bal2;
    function examples() external {
        balances[msg.sender] = 123;
        bal1 = balances[msg.sender];
        bal2 = balances[address(1)];

        balances[msg.sender] += 456;

        // 删除并不会真的删除,而是变成初始值
        delete balances[msg.sender];

        // 嵌套映射
        isFriend[msg.sender][msg.sender] = true;
    }
}

23-映射迭代

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

// 由于映射不能遍历
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]];
    }
}

24-结构体

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

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: "Lamborhini", owner: msg.sender, year: 1980});
        Car memory tesla;
        tesla.model = "Tesla";
        tesla.year = 2015;
        tesla.owner = msg.sender;

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

        Car memory _car = cars[0];
        _car.owner;
        _car.year = 1969;
        // 可以删除结构体数组中的某一个结构体,也可以删除结构体中的一个参数
        delete _car.model;
        delete cars[1];
    }
}

25-枚举

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

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

    Status public status;

    struct Order {
        address buyer;
        Status status;
    }

    Order[] public orders;

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

    function set(Status _status) external {
        status = _status;
    }

    function ship() external {
        status = Status.Shipped;
    }

    function reset() external {
        delete status;
    }
}

26-部署合约

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

contract TestContract1 {
    address public owner = msg.sender;

    function setOwner(address _owner) public {
        require(msg.sender == owner, "not owner");
        owner = _owner;
    }
}

contract TestContract2 {
    address public owner = msg.sender;
    uint public value = msg.value;
    uint public x;
    uint public y;

    constructor(uint _x, uint _y) payable {
        x = _x;
        y = _y;
    }
}

contract Proxy {
    event Deploy(address);
    fallback() external payable { }

    function deploy(bytes memory _code) external payable returns (address addr) {
        assembly {
            // create(v, p, n)
            // v = amount of ETH to send
            // p = pointer in memory to start of code
            // n = size of code
            addr := create(callvalue(), add(_code, 0x20), mload(_code))
        }
        require(addr != address(0), "deploy failed");

        emit Deploy(addr);
    }

    function execute(address _target, bytes memory _data) external payable {
        (bool success, ) = _target.call{value: msg.value}(_data);
        require(success, "failed");
    }
}

contract Helper {
    function getBytecode1() external pure returns (bytes memory) {
        // 得到部署合约的机器码
        bytes memory bytecode = type(TestContract1).creationCode;
        return bytecode;
    }

    function getBytecode2(uint _x, uint _y) external pure returns (bytes memory) {
        bytes memory bytecode = type(TestContract2).creationCode;
        // 将传入的参数通过的打包的方式形成新的bytecode
        return abi.encodePacked(bytecode, abi.encode(_x, _y));
    }

    function getCalldata(address _owner) external pure returns (bytes memory) {
        return abi.encodeWithSignature("setOwner(address)", _owner);
    }
}