Solidityの基本文法と簡単な事例 20221201

1.ロールバック機能

        fallback(): フォールバック関数は、呼び出された関数が存在しない場合、または主要通貨がコントラクトに直接送信される場合に呼び出されます。

        accept(): データは受け入れられません。主要通貨がコントラクトに送信された場合にのみトリガーされます。

// 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. ETHを送信する

        メインペンは送信、転送、通話で送ることができます。

        send は true と false を返して、送信が失敗したかどうかを判断します。

        transfer は、revert を返し、送信が失敗したかどうかを判断します。

        呼び出しは true と false を返します。受信アドレスに情報がある場合は、情報データを返すことができます。

// 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. 小さなケース: 簡単なウォレット契約を確立する

// 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. 他の契約を呼び出す

        他の契約のアドレスを入力すると、他の契約をタイプとして直接使用できます。直接入力した変数の型として型を渡すことも可能です。

// 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. インターフェース契約

インターフェイス コントラクトは、別のコントラクトのソース コードが不明な場合、またはコード量が特に大きい場合に使用できます。

// 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. 低レベルの呼び出し 呼び出し

Call を使用して、コントラクト アドレスに従ってコントラクト関数を直接呼び出します。

// 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. 代表者通話:

        他のコントラクトの相互作用を観察するために使用されます。

        例: A が B に 100wei を送信し、B が C への呼び出しを委託します。C の観点からは、A は A が B に 100wei を送信していることがわかりますが、C 自身の状態変数は変化しません。

        通話の委任を使用して、契約のアップグレードを実装できます。

        デリゲートが実行関数を呼び出した後の値は、デリゲート呼び出しコントラクトで変更されます。

// 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. 工場契約

新しい契約を生成するために使用されます

// 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. 図書館契約

一般的に使用されるアルゴリズムの一部は抽象化されてデータベースを形成し、将来的には直接呼び出すことができるため、コードの再利用が回避されます。

// 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. ハッシュアルゴリズム

通常、署名の計算と特定の ID の取得に使用されます。

データをパッケージ化する際に api.encodePacked メソッドを使用すると、ハッシュ衝突(暗号化内容は同じではないがハッシュ演算結果は同じ)が発生する可能性があります。

2 つの梱包方法:

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

おすすめ

転載: blog.csdn.net/H_Roger/article/details/128130026