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
- Cài đặt thư viện openzeppelin
forge install openzeppelin/openzeppelin-contracts
- 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())));
}
}
- Compile smart contract ERC20
forge build
- 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"