From 704ddd3ac213650db2c7a4ef757cb474d186f1b2 Mon Sep 17 00:00:00 2001 From: Matjaz Verbole Date: Tue, 2 Jan 2024 11:06:50 +0100 Subject: [PATCH] TransferFunds script enables sending of varying amounts of LSK tokens to different addresses --- script/TransferFunds.s.sol | 98 ++++++++++++++++++++++++++------ script/Utils.sol | 27 +++++++++ script/data/devnet/accounts.json | 22 +++++++ script/deployContracts.sh | 2 +- 4 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 script/data/devnet/accounts.json diff --git a/script/TransferFunds.s.sol b/script/TransferFunds.s.sol index fde3c856..64ef752b 100644 --- a/script/TransferFunds.s.sol +++ b/script/TransferFunds.s.sol @@ -29,8 +29,8 @@ interface IL1StandardBridge { } /// @title TransferFundsScript - L1 Lisk token transfer script -/// @notice This contract is used to transfer all deployer's L1 Lisk tokens to the L2 Claim contract via L1 Standard -/// Bridge. +/// @notice This contract is used to transfer all deployer's L1 Lisk tokens to a different addresses on L1 and L2 +/// networks. When sending tokens to the L2 network, the L1 Standard Bridge contract is used. contract TransferFundsScript is Script { /// @notice Utils contract which provides functions to read and write JSON files containing L1 and L2 addresses. Utils utils; @@ -39,15 +39,16 @@ contract TransferFundsScript is Script { utils = new Utils(); } - /// @notice This function transfers L1 Lisk tokens to the L2 Claim contract. - /// @dev This function first approves L1 Standard Bridge to transfer all deployer's L1 Lisk tokens and then calls - /// the depositERC20To function of the L1 Standard Bridge contract to transfer all deployer's L1 Lisk tokens to the - /// L2 Claim contract. + /// @notice This function transfers L1 Lisk tokens to a different addresses on L1 and L2 networks. + /// @dev This function first sends deployer's L1 Lisk tokens to all L1 addresses specified in the accounts.json + /// file. After it approves L1 Standard Bridge to transfer all remaining deployer's L1 Lisk tokens to the L2 + /// network. It does this in two steps. First it sends tokens to all L2 addresses specified in the + /// accounts.json file. After it transfers all remaining tokens to the L2 Claim contract. function run() public { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address l1StandardBridge = vm.envAddress("L1_STANDARD_BRIDGE_ADDR"); - console2.log("Simulation: Transferring Lisk tokens from L1 to L2 Claim contract..."); + console2.log("Simulation: Transferring Lisk tokens from L1 to a different addresses on L1 and L2 networks..."); // get L1LiskToken contract address Utils.L1AddressesConfig memory l1AddressesConfig = utils.readL1AddressesFile(); @@ -58,37 +59,100 @@ contract TransferFundsScript is Script { console2.log("Simulation: L2 Lisk token address: %s", l2AddressesConfig.L2LiskToken); console2.log("Simulation: L2 Claim contract address: %s", l2AddressesConfig.L2ClaimContract); + // get accounts to which L1 Lisk tokens will be transferred + Utils.Accounts memory accounts = utils.readAccountsFile(); + console2.log("Simulation: Number of L1 addresses: %s", accounts.l1Addresses.length); + for (uint256 i = 0; i < accounts.l1Addresses.length; i++) { + console2.log("Simulation: %d: %s", i + 1, accounts.l1Addresses[i].addr); + } + console2.log("Simulation: Number of L2 addresses: %s", accounts.l2Addresses.length); + for (uint256 i = 0; i < accounts.l2Addresses.length; i++) { + console2.log("Simulation: %d: %s", i + 1, accounts.l2Addresses[i].addr); + } + // get L1LiskToken and L1StandardBridge contracts instances L1LiskToken l1LiskToken = L1LiskToken(address(l1AddressesConfig.L1LiskToken)); IL1StandardBridge bridge = IL1StandardBridge(l1StandardBridge); + console2.log("Simulation: Sending L1 Lisk tokens to all L1 addresses..."); + + // send L1 Lisk tokens to all L1 addresses + for (uint256 i = 0; i < accounts.l1Addresses.length; i++) { + console2.log( + "Simulation: Sending %s L1 Lisk tokens to L1 address: %s", + accounts.l1Addresses[i].amount, + accounts.l1Addresses[i].addr + ); + vm.startBroadcast(deployerPrivateKey); + l1LiskToken.transfer(accounts.l1Addresses[i].addr, accounts.l1Addresses[i].amount); + vm.stopBroadcast(); + } + + for (uint256 i = 0; i < accounts.l1Addresses.length; i++) { + assert(l1LiskToken.balanceOf(accounts.l1Addresses[i].addr) == accounts.l1Addresses[i].amount); + } + + console2.log("Simulation: L1 Lisk tokens successfully sent to all L1 addresses!"); + + // balance of L1 Lisk tokens before sending them to L2 addresses + uint256 balanceBefore = l1LiskToken.balanceOf(vm.addr(deployerPrivateKey)); + console2.log( - "Simulation: Approving L1 Lisk tokens to be transfered by L1 Standard Bridge to the L2 Lisk token contract: %s", - l1LiskToken.balanceOf(vm.addr(deployerPrivateKey)) + "Simulation: Approving all remaining L1 Lisk tokens to be transfered by L1 Standard Bridge to the L2 network: %s", + balanceBefore ); vm.startBroadcast(deployerPrivateKey); - l1LiskToken.approve(address(bridge), l1LiskToken.balanceOf(vm.addr(deployerPrivateKey))); + l1LiskToken.approve(address(bridge), balanceBefore); vm.stopBroadcast(); - assert( - l1LiskToken.allowance(vm.addr(deployerPrivateKey), address(bridge)) - == l1LiskToken.balanceOf(vm.addr(deployerPrivateKey)) - ); + assert(l1LiskToken.allowance(vm.addr(deployerPrivateKey), address(bridge)) == balanceBefore); + + console2.log("Simulation: L1 Lisk tokens successfully approved to be transfered by L1 Standard Bridge!"); + + console2.log("Simulation: Sending L1 Lisk tokens to all L2 addresses..."); + + // send L1 Lisk tokens to all L2 addresses + for (uint256 i = 0; i < accounts.l2Addresses.length; i++) { + console2.log( + "Simulation: Sending %s L1 Lisk tokens to L2 address: %s", + accounts.l2Addresses[i].amount, + accounts.l2Addresses[i].addr + ); + vm.startBroadcast(deployerPrivateKey); + bridge.depositERC20To( + l1AddressesConfig.L1LiskToken, + l2AddressesConfig.L2LiskToken, + accounts.l2Addresses[i].addr, + accounts.l2Addresses[i].amount, + 1000000, + "" + ); + vm.stopBroadcast(); + } + + // total amount of tokens sent to L2 addresses + uint256 totalAmount = 0; + for (uint256 i = 0; i < accounts.l2Addresses.length; i++) { + totalAmount += accounts.l2Addresses[i].amount; + } + assert(l1LiskToken.balanceOf(vm.addr(deployerPrivateKey)) == balanceBefore - totalAmount); + + console2.log("Simulation: L1 Lisk tokens successfully sent to all L2 addresses!"); - console2.log("Simulation: Transferring all L1 Lisk tokens to the L2 Claim contract..."); + console2.log("Simulation: Transferring all remaining L1 Lisk tokens to the L2 Claim contract..."); vm.startBroadcast(deployerPrivateKey); bridge.depositERC20To( l1AddressesConfig.L1LiskToken, l2AddressesConfig.L2LiskToken, l2AddressesConfig.L2ClaimContract, - l1LiskToken.balanceOf(vm.addr(deployerPrivateKey)), + balanceBefore - totalAmount, 1000000, "" ); vm.stopBroadcast(); assert(l1LiskToken.balanceOf(vm.addr(deployerPrivateKey)) == 0); - assert(l1LiskToken.balanceOf(l1StandardBridge) == 200000000 * 10 ** 18); + assert(l1LiskToken.balanceOf(l1StandardBridge) == balanceBefore); console2.log("Simulation: L1 Lisk tokens successfully transferred to the L2 Claim contract!"); } diff --git a/script/Utils.sol b/script/Utils.sol index 20162a14..64732749 100644 --- a/script/Utils.sol +++ b/script/Utils.sol @@ -23,6 +23,23 @@ contract Utils is Script { address L2LiskToken; } + /// @notice This struct is used to read accounts from JSON file. These accounts are used to transfer L1 Lisk tokens + /// to them after all contracts are deployed. + struct Accounts { + /// @notice Array of L1 addresses and amounts of LSK tokens to be transferred to them. + FundedAccount[] l1Addresses; + /// @notice Array of L2 addresses and amounts of LSK tokens to be transferred to them. + FundedAccount[] l2Addresses; + } + + /// @notice This struct is used to read a single account from JSON file. + struct FundedAccount { + /// @notice Account address. + address addr; + /// @notice Amount of LSK tokens to be transferred to the account. + uint256 amount; + } + /// @notice This function reads L1 addresses from JSON file. /// @return L1AddressesConfig struct containing L1 addresses. function readL1AddressesFile() external view returns (L1AddressesConfig memory) { @@ -59,4 +76,14 @@ contract Utils is Script { string memory finalJson = vm.serializeAddress(json, "L2LiskToken", cfg.L2LiskToken); finalJson.write(string.concat("deployment/l2addresses.json")); } + + /// @notice This function reads accounts from JSON file. + /// @return Accounts struct containing accounts. + function readAccountsFile() external view returns (Accounts memory) { + string memory root = vm.projectRoot(); + string memory accountsPath = string.concat(root, "/script/data/devnet/accounts.json"); + string memory accountsJson = vm.readFile(accountsPath); + bytes memory accountsRaw = vm.parseJson(accountsJson); + return abi.decode(accountsRaw, (Accounts)); + } } diff --git a/script/data/devnet/accounts.json b/script/data/devnet/accounts.json new file mode 100644 index 00000000..b6154f19 --- /dev/null +++ b/script/data/devnet/accounts.json @@ -0,0 +1,22 @@ +{ + "l1Addresses": [ + { + "addr": "0xe708A1b91dDC44576731f7fEb4e193F48923Abba", + "amount": 2000000000000000000000 + }, + { + "addr": "0x1CA256b7a7883FFb046F39fC0602311B88C04AF9", + "amount": 4000000000000000000000 + } + ], + "l2Addresses": [ + { + "addr": "0x396df972a284ba7f5a8bec2d9b9ec2377a099215", + "amount": 3000000000000000000000 + }, + { + "addr": "0xf50c46F0b23a0e90409E7270568Dbb62522c28B9", + "amount": 5000000000000000000000 + } + ] +} \ No newline at end of file diff --git a/script/deployContracts.sh b/script/deployContracts.sh index fa793ed4..a7309596 100755 --- a/script/deployContracts.sh +++ b/script/deployContracts.sh @@ -43,6 +43,6 @@ forge script --rpc-url="$L2_RPC_URL" --broadcast --verify --etherscan-api-key="$ fi echo "Done." -echo "Transferring funds to L2Claim smart contract..." +echo "Transferring funds to L1 and L2 addresses and L2Claim smart contract..." forge script --rpc-url="$L1_RPC_URL" --broadcast -vvvv script/TransferFunds.s.sol:TransferFundsScript echo "Done."