Lisk Smart Contract
Foundry

Triển khai smart contract trên Lisk sử dụng Foundry

Lưu ý 1: Cài đặt lệnh curl trước khi bắt đầu

Lưu ý 2: Wallet deploy contract cần có balance trên Lisk Testnet

Cài đặt Foundry

  • Đối với MacOS hoặc Linux/Ubuntu

Run command:

curl -L https://foundry.paradigm.xyz | bash

Cài đặt thư viện mới nhất Foundry

foundryup
  • Đối với Windows

Lưu ý: Cài đặt Ubuntu WSL: https://documentation.ubuntu.com/wsl/latest/howto/install-ubuntu-wsl2/ (opens in a new tab)

Sau đó chạy lệnh tương tự như MacOS hoặc Linux/Ubuntu

Tạo project Foundry

forge init foundry_app && cd foundry_app

Tạo smart contract ERC20

  1. Cài đặt thư viện openzeppelin
forge install openzeppelin/openzeppelin-contracts
  1. Tạo file src/ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
 
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
 
contract MyToken is ERC20 {
    constructor() ERC20("MyToken", "MT") {
        _mint(msg.sender, 1000000 * (10 ** uint256(decimals())));
    }
}
  1. Compile smart contract ERC20
forge build
  1. Test smart contract ERC20
  • Tạo file test/ERC20.t.sol
/// test/ERC20.t.sol
 
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
 
import {Test, console2} from "forge-std/Test.sol";
import {MyToken} from "../src/ERC20.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
 
contract ERC20Test is Test {
    MyToken public token;
    address public owner;
    address public otherAccount;
    uint256 public constant INITIAL_SUPPLY = 1000000 * 10**18;
 
    function setUp() public {
        owner = makeAddr("owner");
        otherAccount = makeAddr("otherAccount");
        
        vm.startPrank(owner);
        token = new MyToken();
        vm.stopPrank();
    }
 
    function test_Deployment() public {
        assertEq(token.name(), "MyToken");
        assertEq(token.symbol(), "MTK");
        assertEq(token.totalSupply(), INITIAL_SUPPLY);
        assertEq(token.balanceOf(owner), INITIAL_SUPPLY);
    }
 
    function test_Transfers() public {
        uint256 transferAmount = 100 * 10**18;
 
        vm.prank(owner);
        token.transfer(otherAccount, transferAmount);
        
        assertEq(token.balanceOf(otherAccount), transferAmount);
        assertEq(token.balanceOf(owner), INITIAL_SUPPLY - transferAmount);
 
        vm.prank(otherAccount);
        vm.expectRevert(
            abi.encodeWithSelector(
                IERC20Errors.ERC20InsufficientBalance.selector,
                otherAccount,
                transferAmount,
                INITIAL_SUPPLY
            )
        );
        token.transfer(owner, INITIAL_SUPPLY);
    }
 
    function test_Allowances() public {
        uint256 transferAmount = 100 * 10**18;
 
        vm.prank(owner);
        token.approve(otherAccount, transferAmount);
 
        vm.prank(otherAccount);
        token.transferFrom(owner, otherAccount, transferAmount);
 
        assertEq(token.balanceOf(otherAccount), transferAmount);
 
        vm.prank(owner);
        token.approve(otherAccount, transferAmount - 1);
 
        vm.prank(otherAccount);
        vm.expectRevert(
            abi.encodeWithSelector(
                IERC20Errors.ERC20InsufficientAllowance.selector,
                otherAccount,
                transferAmount - 1,
                transferAmount
            )
        );
        token.transferFrom(owner, otherAccount, transferAmount);
    }
}
 
  • Chạy test
forge test
  • Kết quả
Ran 3 tests for test/ERC20.t.sol:ERC20Test
[PASS] test_Allowances() (gas: 78323)
[PASS] test_Deployment() (gas: 26513)
[PASS] test_Transfers() (gas: 48849)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 8.12ms (2.58ms CPU time)

Triển khai và verify smart contract ERC20

  • Chạy lệnh deploy
forge create --rpc-url https://rpc.sepolia-api.lisk.com \
--etherscan-api-key 123 \
--verify \
--verifier blockscout \
--verifier-url https://sepolia-blockscout.lisk.com/api \
--private-key <PRIVATE_KEY> \
src/ERC20.sol:MyToken
  • Kết quả
 [⠊] Compiling...
No files changed, compilation skipped
Deployer: 0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac
Deployed to: 0xeAB4eEBa1FF8504c124D031F6844AD98d07C318f
Transaction hash: 0x06ea4566108ba5376b636f6c04739a41991a24f795e38840a1a7f081b48a6005
Starting contract verification...
Waiting for blockscout to detect contract deployment...
Start verifying contract `0xeAB4eEBa1FF8504c124D031F6844AD98d07C318f` deployed on 4202
 
Submitting verification for [src/ERC20.sol:MyToken] 0xeAB4eEBa1FF8504c124D031F6844AD98d07C318f.
Submitted contract for verification:
	Response: `OK`
	GUID: `eab4eeba1ff8504c124d031f6844ad98d07c318f684efe50`
	URL: https://sepolia-blockscout.lisk.com/address/0xeab4eeba1ff8504c124d031f6844ad98d07c318f
Contract verification status:
Response: `OK`
Details: `Pass - Verified`
Contract successfully verified

Tương tác với smart contract

Read smart contract

  • Lấy balance của account
cast call <DEPLOYED_CONTRACT_ADDRESS> --rpc-url https://rpc.sepolia-api.lisk.com "balanceOf(address)" <YOUR_ACCOUNT_ADDRESS_HERE>
  • Kết quả
cast call 0xeAB4eEBa1FF8504c124D031F6844AD98d07C318f --rpc-url https://rpc.sepolia-api.lisk.com "balanceOf(address)" 0x783FC27915754512E72b5811599504eCa458E4C5
0x0000000000000000000000000000000000000000000000000000000000000000

Write smart contract

  • Transfer token
cast send <DEPLOYED_CONTRACT_ADDRESS> --rpc-url https://rpc.sepolia-api.lisk.com "transfer(address,uint256)" <RECIPIENT_ADDRESS_HERE> --private-key <SENDER_PRIVATE_KEY>
  • Kết quả
blockHash               0xea2fd5e5c30a13a2a685a9f80f0eb68489ff614572dcadfd5c7f975631d850c9
blockNumber             22347451
contractAddress         
cumulativeGasUsed       97764
effectiveGasPrice       254
from                    0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac
gasUsed                 51632
logs                    [{"address":"0xeAB4eEBa1FF8504c124D031F6844AD98d07C318f","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000f24ff3a9cf04c71dbc94d0b566f7a27b94566cac","0x000000000000000000000000783fc27915754512e72b5811599504eca458e4c5"],"data":"0x0000000000000000000000000000000000000000000000056bc75e2d63100000","blockHash":"0xea2fd5e5c30a13a2a685a9f80f0eb68489ff614572dcadfd5c7f975631d850c9","blockNumber":"0x154febb","transactionHash":"0x6a470418791599a1f63605e46ee19dacc1720e94ed4d627963a66c86226e00c2","transactionIndex":"0x1","logIndex":"0x0","removed":false}]
logsBloom               0x00000000000000000000002000000000000000000000000040000000000000000000000000000000000000000000000000000000000010000000000000000040000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000010000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800008000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000
root                    
status                  1 (success)
transactionHash         0x6a470418791599a1f63605e46ee19dacc1720e94ed4d627963a66c86226e00c2
transactionIndex        1
type                    2
blobGasPrice            
blobGasUsed             
authorizationList       
to                      0xeAB4eEBa1FF8504c124D031F6844AD98d07C318f
l1BaseFeeScalar             "0x2af8"
l1BlobBaseFee             "0x1"
l1BlobBaseFeeScalar             "0x109618"
l1Fee             "0x14d2733f"
l1GasPrice             "0x12eddcc"
l1GasUsed             "0x640"