Try   HackMD

Data Structure 進階語法與資料結構教學程式碼共筆

Array

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Array {
    uint256[] arr_1;
    uint256[] arr_2 = [3,2,4];
    uint256[5] arr_3;
    uint256[][] array2D = [ [1,2,3], [4,5,6] ];
    
    constructor(uint256 _dynamicArrayLength) {
        arr_1 = new uint256[](_dynamicArrayLength);
    }
    
    function getValueOfIndex(uint256 _index) public view returns (uint256) {
        return arr_2[_index];
    }
    
    function addToArray(uint256 _value) public {
        arr_2.push(_value);
    }
    
    function valueCount() public view returns(uint256) {
        return arr_3.length;
    }
    
    function dynamicValueCount() public view returns(uint256) {
        return arr_1.length;
    }
}

Mapping

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Mapping {
    mapping(uint256 => address) public nfts;
    uint256 counter = 0;
    
    function ownerOf(uint256 _tokenId) public view returns (address) {
        return nfts[_tokenId];
    }
    
    function mintNFT() public {
        nfts[counter] = msg.sender;
        counter++;
    }
}

Struct

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Struct {
    struct User {
        address id;
        string name;
    }

    User owner;
    
    constructor() {
        owner = User(msg.sender, "KryptoCamp");
    }
    
    function getOwnerAddress() public view returns (address) {
        return owner.id;
    }
    
    function getOwnerName() public view returns (string memory) {
        return owner.name;
    }
}

Enum

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Enum {
    enum Rarity {
        original, // 0
        rare, // 1
        super_rare // 2
    }

    Rarity public rarity;

    constructor() {
        rarity = Rarity.original;
    }

    function makeSuperRare() public {
        rarity = Rarity.super_rare;
    }

    function reset() public {
        delete rarity;
    }
}

Returns

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Returns {
    uint256 public x;
    uint256 public y;
    uint256 public z;
    
    function getTrue() public pure returns (bool) {
        return true;
    }
    
    function multipleReturns() public view returns(uint256 a, uint256 b, uint256 c) {
        return (1, 2, 3);
    }
    
    function processMultipleReturns() public view returns(uint256 x, uint256 y, uint256 z) {
        (x,y,z) = multipleReturns();
    }
    
    function getLastReturnValue() public view returns(uint256 z) {
        (,,z) = multipleReturns();
    }
}

Visibility Function

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Visibility {
    function coreFunction() [visibility] {
        // do something...
    }
}

Visibility Function 02

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Math {
    function addOne(uint256 x) internal pure returns (uint256) {
        return x + 1;
    }
}

contract Visibility is Math {
    function coreFunction() public pure returns (string memory) {
        return "Hello World";
    }

    function calculate(uint256 y) public pure returns (uint256) { 
        return addOne(5) + y;
    }
}

State Mutability - 可變性

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract StateMutability {
    function coreFunction() [visibility] [mutability] returns (bool) {
        return true;
    }
}

Extends

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Math {
    function addOne(uint256 x) internal pure returns (uint256) {
        return x + 1;
    }
}

contract Visibility is Math {
    function coreFunction() public pure returns (string memory) {
        return "Hello World";
    }

    function calculate(uint256 y) public pure returns (uint256) {
        return addOne(5) + y;
    }
}

For Loop

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract ForLoop {
    uint256[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    function countEvenNumbers() public view returns (uint256) {
        uint256 count = 0;
        
        for (uint256 i = 0; i < numbers.length; i++) {
            if (isEvenNumber(numbers[i])) {
                count++;
            }
        }
        
        return count;
    }
    
    function isEvenNumber(uint256 _number) public view returns (bool) {
        return (_number % 2 == 0 ? true : false);
    }
}

While

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract While {
    uint256[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    function countEvenNumbers() public view returns (uint256) {
        uint256 count = 0;
        uint256 i = 0;
        
        while (i < numbers.length) {
            if (isEvenNumber(numbers[i])) {
                count++;
            }
            i++;
        }
        
        return count;
    }
    
    function isEvenNumber(uint256 _number) public view returns (bool) {
        return (_number % 2 == 0 ? true : false);
    }
}

Modifier

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.4;

contract Modifier {
    address owner;
    uint256 amountPerAddress = 5;
    
    constructor() {
        owner = msg.sender;
    }
    
    modifier onlyOwner {
        require(owner == msg.sender);
        _;
    }
    
    modifier maxAmount(uint256 _amount) {
        require(_amount < amountPerAddress);
        _;
    }
    
    function importantFunction() public onlyOwner view returns (string memory) {
        return "Hello you are owner!";
    }

    function updateAmountPerAddress(uint256 _amount) public onlyOwner {
        amountPerAddress = _amount;
    }

    function buySomething(uint256 _amount) public maxAmount(_amount) view returns (string memory) {
        return "Success!";
    }
}

Error

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

/// Not enough funds for transfer. Requested `requested`,
/// but only `available` available.
error NotEnoughFunds();

contract OtherContract {
    function wrongFunction() external {
        revert();
    }
}

contract ErrorControl {
    mapping(address => uint) balances;
    OtherContract public otherContract;

    constructor() {
        otherContract = new OtherContract();
    }

    function transferThrowError() public {
        revert();
        // throw;
    }
    
    function transferAssertError() public {
        assert(false); // true
        //.. ->> xx
        //.. ->> xx
    }
    
    function transferRevertError() public {
        revert NotEnoughFunds();
    }
    
    function requireRevertError() public {
        require(true, "revert error!!!!!");
    }

    function tryCatchError() public returns (string memory) {
        try otherContract.wrongFunction() {
        } catch {
            return "Something wrong!!";
        }
    }
}

Event - 事件

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Event {
    event MyPushLog(uint256 indexed);

    function debugMode(uint256 _message) public {
        emit MyPushLog(_message);
    }
}

前端測試鏈事件接收

import { ethers } from 'ethers'

const provider = new ethers.providers.JsonRpcProvider('使用 foundry anvil 啟動測試鏈')

const abi = ['event MyPushLog(uint256 indexed)']
const iface = new ethers.utils.Interface(abi)

const LogHash = ethers.utils.id('MyPushLog(uint256)')

const filter = {
  address: '替換為部署合約網址',
  topics: [LogHash],
}

provider.on(filter, async (result) => {
  console.log('Log in:', result, '\r\n')
  let events = iface.parseLog(result)
  console.log('indexed:', events.args[0])
})

Interface - 介面

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Counter {
    uint256 public count;
    
    function inc() external {
        count += 1;
    }
}

interface Counter {
    function count() external view returns (uint256);
    function inc() external;
}

contract Interface {
    function incCounter(address _counter) external {
        Counter(_counter).inc();
    }
    
    function getCount(address _counter) external view returns (uint256) {
        return Counter(_counter).count();
    }
}

作業:如何透過 modifier 讓外部合約無法操作 Counter 合約的 inc 功能。

抽象合約

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

abstract contract Feline {
    function utterance() public pure virtual returns (bytes32);
}

contract Cat is Feline {
    function utterance() public pure override returns (bytes32) {
        return "miaow";
    }
}

Receive

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Receive {

    event ReceiveLog(string);

    function buybool() public {
        payable(接收方地址).transfer(1 ether);
    }

    receive() external payable {
        emit ReceiveLog("[001]receive ether...");
    }

    fallback() external payable {}
}

Fallback

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Fallback {

    event FallbackCall(string);

    fallback() external payable {
        emit FallbackCall("call me fallback!");
    }
}

Virtual, Override

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Virtual {

    uint256 public counter = 0;

    function incCount() public virtual {
        counter++;
    }
}

contract Override is Virtual {
    function incCount() public override {
        counter += 2;
    }
}

Operator - 算術運算子

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Operator {
    uint x = 10;
    uint y = 5;

    function add() public view returns (uint256) {
        return x + y;
    }
    function sub() public view returns (uint256) {
        return x - y;
    }
    function mul() public view returns (uint256) {
        return x * y;
    }
    function div() public view returns (uint256) {
        return x / y;
    }
    function mod() public view returns (uint256) {
        return x % y;
    }
    function inc() public {
        x++;
    }
    function dec() public {
        y--;
    }
}

Operator - 關係運算子

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract RelationalOperator {
    function equal(uint256 left, uint256 right) public pure returns (bool) {
        return left == right;
    }
    
    function notEqual(uint256 left, uint256 right) public pure returns (bool) {
        return left != right;
    }
    
    function GT(uint256 left, uint256 right) public pure returns (bool) {
        return left > right;
    }
    
    function LT(uint256 left, uint256 right) public pure returns (bool) {
        return left < right;
    }
    
    function GTE(uint256 left, uint256 right) public pure returns (bool) {
        return left >= right;
    }
    
    function LTE(uint256 left, uint256 right) public pure returns (bool) {
        return left <= right;
    }
}

Storage, Memory, Calldata

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Storage {
    struct Todo {
        string title;
        bool completed;
    }

    // struct, array, mapping

    Todo[] public todos;

    function addTodo(string memory _title) public {
        todos.push(Todo({
            title: _title,
            completed: false
        }));
    }

    function updateTodoFromStorage(uint256 _index, string memory _title) public {
        _title = "eat breakfast";
        Todo storage todo = todos[0];
        todo.completed = true;
        todo.title = _title;
    }

    function fakeUpdateTodoFromMemory(uint256 _index) public view returns (Todo memory) {
        Todo memory todo = todos[_index];
        todo.completed = true;

        return todo;
    }

    function updateTodoFromCalldata(uint256 _index, string calldata _title) public {
        Todo storage todo = todos[0];
        todo.title = _title;
    }
}