# Data Structure 進階語法與資料結構教學程式碼共筆 ## Array ```solidity // 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 ```solidity // 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 ```solidity // 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 ```solidity // 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 ```solidity // 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 ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >= 0.8.4; contract Visibility { function coreFunction() [visibility] { // do something... } } ``` ## Visibility Function 02 ```solidity // 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 - 可變性 ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >= 0.8.4; contract StateMutability { function coreFunction() [visibility] [mutability] returns (bool) { return true; } } ``` ## Extends ```solidity // 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 ```solidity // 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 ```solidity // 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 ```solidity // 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 ```solidity // 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 - 事件 ```solidity // 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); } } ``` `前端測試鏈事件接收` ```javascript 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 - 介面 ```solidity // 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 功能。 `抽象合約` ```solidity // 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 ```solidity // 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 ```solidity! // 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 ```solidity! // 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 - 算術運算子 ```solidity // 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 - 關係運算子 ```solidity // 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 ```solidity! // 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; } } ```