Solidity basic grammar and simple cases 20221201

1. Rollback function

        fallback(): The fallback function is called when the called function does not exist or when the main currency is sent directly to the contract.

        receive(): Data cannot be accepted, only triggered when the main currency is sent to the contract

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

contract Fallback {
    event Log(string func,address sender , uint value ,bytes data);

    fallback() external payable {
        emit Log("fallback", msg.sender, msg.value,msg.data);
    }

    //receive 不接受数据
    receive() external payable  {
        emit Log("receive", msg.sender, msg.value, "");
    }
}

2. Send ETH

        The main pen can be sent through send, transfer and call.

        send returns true and false to determine whether the sending fails;

        transfer returns revert to determine whether the sending fails;

        call returns true and false, if the receiving address has information, it can return information data

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

contract SendETH {
    constructor() payable{}

    receive() external payable {}

    function sendViaTransfer(address payable _to) external payable {
        _to.transfer(123);
    }

    function sendViaSend(address payable _to) external payable{
        bool sent = _to.send(123);
        require(sent,"send failde");
    }

    //发送所有的gas
    function sendViaCall(address payable _to) external payable{
        (bool success,) = _to.call{value: 123}("");
        require(success, "send failed")
    }
}

3. Small case: Establish a simple wallet contract

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

contract SimpleWallet{
    address payable public owner;

    constructor(){
        owner = payable(msg.sender);
    }

    receive() external payable{}

    function withdraw(uint amount) public{
        require(msg.sender == owner);
        owner.transfer(amount);
    }

    function getBalance() public view returns (uint){
        return address(this).balance;
    }
}

4. Call other contracts

        Enter the address of other contracts, and then you can directly use other contracts as types. It is also possible to pass in the type as the type of the directly entered variable.

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

contract CallTestContract {
    //为调用函数传参
    function setX(address _test, uint _x) external {
        TestContract(_test).setX(_x);
    }
    //获取从方法得到的参数
    function getX(address _test) external view returns(uint x){
        return x = TestContract(_test).getX();
    }
    //传参并发送主币
    function setXandReceiveEther(address _test, uint _x) external payable {
        TestContract(_test).setXandReceiveEther(_x);
    }
    //获取两个参数
    function getXandValue(address _test) external returns(uint x,uint value) {
        (x,value) = TestContract(_test).getXandValue();
    }
}

contract TestContract {
    uint public x;
    uint public value = 123;

    function setX(uint _x) external {
        x = _x;
    }  

    function getX() external view returns (uint) {
        return x;
    }

    function setXandReceiveEther(uint _x) external payable {
        x = _x;
        value = msg.value;
    }

    function getXandValue() external view returns (uint,uint) {
        return(x,value);
    }
}

5. Interface contract

Interface contracts can be used when the source code of another contract is unknown or the code volume is particularly large.

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

contract Counter {
    uint public count;
    function inc() external {
        count += 1;
    }
    function dec() external {
        count -= 1;
    }
}

//在接口合约中调用了两个合约的函数
interface ICounter {
     function count() external view returns (uint);
     function inc() external;
}

contract CallInterface {
    uint public count;

    function examples(address _counter) external{
        ICounter(_counter).inc();
        count = ICounter(_counter).count();
    }
}

6. Low-level calling Call

Use Call to directly call the contract function according to the contract address.

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

contract TestCall{
    string public message;
    uint public x;

    event Log(string message);

    fallback() external payable{
        emit Log("fallback was called");
    }

    function foo(string memory _message, uint _x) external payable returns (bool,uint){
        message = _message;
        x = _x;
        return(true,999);
    }
}

contract Call{
    bytes public data;

    function callFoo(address _test) external {
        //使用call调用目标地址的函数,返回是否调用成功,以及一个返回值,该返回值转载了所有返回的数据
        //可以携带一定数量的主币和gas进行调用
        (bool success, bytes memory data) = _test.call{value: 111, gas:5000}(abi.encodeWithSignature(
            "foo(string,uint256)","call foo",123
        ));
        require(success,"call failed");
    } 

    function callDoesNotExit(address _test) external{
        (bool success,) = _test.call(abi.encodeWithSignature("DONTEXIST(string,uint)"));
        require(success,"call failed");
    }
}

7. Delegate call:

        Used to observe the interaction of other contracts.

        For example: A sends 100wei to B, and B entrusts to call C. From the perspective of C, A can see that A sends 100wei to B, but C's own state variables do not change.

        Delegating calls can be used to implement contract upgrades.

        The value after the delegate calls the execution function is modified in the delegate call contract.

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

contract TestDelegateCall {
    uint public num;
    address public sender;
    uint public value;

    function setVars(uint _num) external payable {
        num = _num;
        sender = msg.sender;
        value = msg.value;
    }
}

contract DelegateCall {
    uint public num;
    address public sender;
    uint public value;

    function setVars(address _test,uint _num) external payable{
        //使用签名进行编码
        // _test.delegatecall(
        //     abi.encodeWithSignature("setVars(uint256)",_num)
        // );
        //使用selector进行编码
        (bool success,bytes memory data) = _test.delegatecall(
            abi.encodeWithSelector(TestDelegateCall.setVars.selector, _num)
        );
        require(success,"delegatecall failed");

    }
}

8. Factory contract

Used to generate new contracts

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

contract Account {
    address public bank;
    address public owner;

    constructor(address _owner) payable{
        bank = msg.sender;
        owner = _owner;
    }
}

contract AccountFactory {
    Account[] public accounts;
    address public owner;

    constructor() payable{
        owner = msg.sender;
    }

    function createAccount(address _owner,uint amount) external {
        //account 变量记录了新建立的账户的地址,通过增加{value}来向新创建的合约中发送主币。
        //在构建包含主币的合约前应当向账户工厂发送一定数量的主币
        Account account = new Account{value:amount} (_owner);
        //构建accounts以记录所有由该合约生成的合约
        accounts.push(account);
    }
    function Val() external view returns(uint val){
        return address(this).balance;
    }
}

9. Library contract

Some commonly used algorithms are abstracted to form a database, which can be called directly in the future, thereby avoiding code reuse.

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

library Math{
    function max(uint x,uint y) internal pure returns (uint){
        return x>=y ? x:y;
    }
}

contract Test{
    function testMax(uint x,uint y) external pure returns (uint){
        return Math.max(x,y);
    }
}

library ArrayLib {
    function find(uint[] storage arr,uint x) internal view returns (uint){
        for (uint i =0;i<arr.length;i++){
            if(arr[i] == x){
                return x;
            }
        }
        revert("not found");
    }
}

contract TestArray{
    using ArrayLib for uint[];
    uint[] public arr = [3,2,1];

    function testFind() external view returns (uint i){
        // return ArrayLib.find(arr,2);
        return arr.find(2);
    }
}

10. Hash algorithm

Usually used for signature calculation and obtaining a specific ID

When the data is packaged, if the api.encodePacked method is used, it may cause a hash collision (the encrypted content is not the same but the hash operation result is the same).

Two packaging methods:

abi.encodePacked()

abi.encode()

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

contract HashFunc{
    function hash1(string memory text ,uint num ,address addr) external pure returns(bytes32){
        return keccak256(abi.encodePacked(text,num,addr));
    }
    function hash2(string memory text ,uint num ,address addr) external pure returns(bytes32){
        return keccak256(abi.encode(text,num,addr));
    }
}

Guess you like

Origin blog.csdn.net/H_Roger/article/details/128130026