33pragma solidity ^ 0.8.22 ;
44
55import {Script, console} from "forge-std/Script.sol " ;
6+ import {ConfigLib} from "./lib/ConfigLib.sol " ;
7+ import {IexecLayerZeroBridge} from "../src/bridges/layerZero/IexecLayerZeroBridge.sol " ;
8+ import {IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
69import {SendParam} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol " ;
710import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol " ;
8- import {IexecLayerZeroBridge} from "../src/bridges/layerZero/IexecLayerZeroBridge.sol " ;
9- import {ConfigLib} from "./lib/ConfigLib.sol " ;
1011
12+ /**
13+ * Script to send tokens from Arbitrum Mainnet to Ethereum Mainnet.
14+ * This script demonstrates cross-chain token transfers using LayerZero bridge.
15+ */
16+ // TODO: fusion SendTokensFromArbitrumToEthereum and SendTokensFromEthereumToArbitrum into a single script with dynamic chain handling
1117contract SendTokensFromArbitrumToEthereum is Script {
18+ uint256 private constant TRANSFER_AMOUNT = 10 * 10 ** 9 ; // 10 RLC tokens with 9 decimals
19+
1220 /**
1321 * @dev Converts an address to bytes32.
1422 * @param _addr The address to convert.
@@ -18,45 +26,59 @@ contract SendTokensFromArbitrumToEthereum is Script {
1826 return bytes32 (uint256 (uint160 (_addr)));
1927 }
2028
29+ /**
30+ * Main function to execute the cross-chain transfer.
31+ * Reads configuration and sends tokens from Arbitrum to Ethereum.
32+ */
2133 function run () external {
2234 string memory sourceChain = vm.envString ("SOURCE_CHAIN " );
2335 string memory targetChain = vm.envString ("TARGET_CHAIN " );
2436
2537 ConfigLib.CommonConfigParams memory sourceParams = ConfigLib.readCommonConfig (sourceChain);
2638 ConfigLib.CommonConfigParams memory targetParams = ConfigLib.readCommonConfig (targetChain);
2739
28- // Contract addresses
29- address iexecLayerZeroBridgeAddress = sourceParams.iexecLayerZeroBridgeAddress;
30-
31- // Transfer parameters
32- uint16 destinationChainId = uint16 (targetParams.lzChainId); // LayerZero chain ID for Ethereum Sepolia
33- address recipientAddress = vm.envAddress ("RECIPIENT_ADDRESS " );
34- console.log ("Recipient: %s " , recipientAddress);
40+ IexecLayerZeroBridge sourceBridge = IexecLayerZeroBridge (sourceParams.iexecLayerZeroBridgeAddress);
41+ IERC20 rlcToken = IERC20 (sourceParams.rlcCrosschainTokenAddress);
3542
36- uint256 amount = 5 * 10 ** 9 ; // RLC tokens (adjust the amount as needed)
43+ address sender = vm.envAddress ("RECIPIENT_ADDRESS " );
44+ address recipient = vm.envAddress ("RECIPIENT_ADDRESS " );
3745
38- // Send tokens cross-chain
39- IexecLayerZeroBridge iexecLayerZeroBridge = IexecLayerZeroBridge (iexecLayerZeroBridgeAddress );
40- console. log ( " Sending %s RLC to Ethereum Sepolia " , amount / 10 ** 9 );
46+ // Check sender's balance
47+ uint256 senderBalance = rlcToken. balanceOf (sender );
48+ require (senderBalance >= TRANSFER_AMOUNT, " Insufficient RLC balance " );
4149
50+ // Prepare send parameters
4251 SendParam memory sendParam = SendParam (
43- destinationChainId , // Destination endpoint ID.
44- addressToBytes32 (recipientAddress ), // Recipient address.
45- amount , // amount ( in local decimals, e.g., 5 RLC = 5 * 10 ** 9)
46- amount * 99 / 100 , // minAmount (allowing 1% slippage)
47- "" , // Extra options, not used in this case, already setup using ` setEnforcedOptions`
48- "" , // Composed message, not used in this case
49- "" // OFT command to be executed, unused in default OFT implementations.
52+ uint16 (targetParams.lzChainId) , // Destination endpoint ID
53+ addressToBytes32 (recipient ), // Recipient address
54+ TRANSFER_AMOUNT , // Amount to send in local decimals
55+ TRANSFER_AMOUNT * 99 / 100 , // Minimum amount to send (allowing 1% slippage)
56+ "" , // Extra options, already set via setEnforcedOptions
57+ "" , // Composed message for send() operation (unused)
58+ "" // OFT command to be executed ( unused in default OFT)
5059 );
5160
52- // Get the fee for the transfer
53- MessagingFee memory fee = iexecLayerZeroBridge.quoteSend (sendParam, false );
54- console.log ("Fee amount: " , fee.nativeFee);
61+ // Get quote for the transfer
62+ MessagingFee memory fee = sourceBridge.quoteSend (sendParam, false );
63+
64+ console.log ("=== Cross-Chain Transfer Details === " );
65+ console.log ("From: Arbitrum Mainnet " );
66+ console.log ("To: Ethereum Mainnet " );
67+ console.log ("Amount: %d RLC " , TRANSFER_AMOUNT / 10 ** 9 );
68+ console.log ("Fee: %d wei " , fee.nativeFee);
69+ console.log ("Sender: %s " , sender);
70+ console.log ("Recipient: %s " , recipient);
71+ console.log ("Sender Balance: %d RLC " , senderBalance / 10 ** 9 );
72+
5573 vm.startBroadcast ();
56- // Execute the cross-chain transfer
57- iexecLayerZeroBridge.send {value: fee.nativeFee}(sendParam, fee, msg .sender );
5874
59- console.log ("Cross-chain transfer from Arbitrum to Ethereum initiated! " );
75+ // Note: For crosschain tokens, no approval is needed as the bridge can burn directly
76+ console.log ("Initiating cross-chain transfer... " );
77+ sourceBridge.send {value: fee.nativeFee}(sendParam, fee, payable (sender));
78+
6079 vm.stopBroadcast ();
80+
81+ console.log ("Transfer initiated successfully! " );
82+ console.log ("Monitor the destination chain for token receipt. " );
6183 }
6284}
0 commit comments