Skip to content

Commit 21c35a5

Browse files
gfournierProLe-Caigneczguesmi
authored
feat : update crosschain scripts (#64)
Co-authored-by: Robin Le Caignec <72495599+Le-Caignec@users.noreply.github.com> Co-authored-by: Zied <26070035+zguesmi@users.noreply.github.com> Co-authored-by: Le-Caignec <robinlecaignec@yahoo.fr>
1 parent c539514 commit 21c35a5

File tree

5 files changed

+49
-36
lines changed

5 files changed

+49
-36
lines changed

.env.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ ANVIL_ARBITRUM_SEPOLIA_RPC_URL=http://localhost:8546
1212
# Account to be used for script execution.
1313
# Account name in Foundry keystore
1414
ACCOUNT=<your-account-name>
15+
RECIPIENT_ADDRESS=<recipient-address> # for cross-chain transfers scripts

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,17 @@ upgrade-layerzero-bridge: # CHAIN, RPC_URL
155155

156156
send-tokens-to-arbitrum-sepolia:
157157
@echo "Sending tokens cross-chain... from SEPOLIA to Arbitrum SEPOLIA"
158-
forge script script/SendEthereumToArbitrum.s.sol:SendTokensToArbitrumSepolia \
158+
SOURCE_CHAIN=sepolia TARGET_CHAIN=arbitrum_sepolia \
159+
forge script script/SendFromEthereumToArbitrum.s.sol:SendTokensFromEthereumToArbitrum \
159160
--rpc-url $(SEPOLIA_RPC_URL) \
160161
--account $(ACCOUNT) \
161162
--broadcast \
162163
-vvv
163164

164165
send-tokens-to-sepolia:
165166
@echo "Sending tokens cross-chain... from Arbitrum SEPOLIA to SEPOLIA"
166-
forge script script/SendArbitrumToEthereum.s.sol:SendTokensToSepolia \
167+
SOURCE_CHAIN=arbitrum_sepolia TARGET_CHAIN=sepolia \
168+
forge script script/SendFromArbitrumToEthereum.s.sol:SendTokensFromArbitrumToEthereum \
167169
--rpc-url $(ARBITRUM_SEPOLIA_RPC_URL) \
168170
--account $(ACCOUNT) \
169171
--broadcast \
Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import {Script, console} from "forge-std/Script.sol";
66
import {SendParam} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol";
77
import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
88
import {IexecLayerZeroBridge} from "../src/bridges/layerZero/IexecLayerZeroBridge.sol";
9-
109
import {ConfigLib} from "./lib/ConfigLib.sol";
1110

12-
contract SendTokensToSepolia is Script {
11+
contract SendTokensFromArbitrumToEthereum is Script {
1312
/**
1413
* @dev Converts an address to bytes32.
1514
* @param _addr The address to convert.
@@ -31,29 +30,23 @@ contract SendTokensToSepolia is Script {
3130

3231
// Transfer parameters
3332
uint16 destinationChainId = uint16(targetParams.lzChainId); // LayerZero chain ID for Ethereum Sepolia
34-
address recipientAddress = sourceParams.initialAdmin; // TODO read recipient address from env variables.
33+
address recipientAddress = vm.envAddress("RECIPIENT_ADDRESS");
3534
console.log("Recipient: %s", recipientAddress);
3635

37-
uint256 amount = 5 * 10 ** 18; // RLC tokens (adjust the amount as needed)
36+
uint256 amount = 5 * 10 ** 9; // RLC tokens (adjust the amount as needed)
3837

3938
// Send tokens cross-chain
4039
IexecLayerZeroBridge iexecLayerZeroBridge = IexecLayerZeroBridge(iexecLayerZeroBridgeAddress);
4140
console.log("Sending %s RLC to Ethereum Sepolia", amount / 10 ** 9);
4241

43-
// Estimate gas for the OFT endpoint
44-
// TODO extract in function and document
45-
bytes memory _extraOptions =
46-
abi.encodePacked(uint16(3), uint8(1), uint16(33), uint8(1), uint128(65000), uint128(0));
47-
48-
vm.startBroadcast();
4942
SendParam memory sendParam = SendParam(
50-
destinationChainId,
51-
addressToBytes32(recipientAddress),
52-
amount,
53-
amount * 9 / 10, // minAmount (allowing 10% slippage)
54-
_extraOptions,
55-
"",
56-
""
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.
5750
);
5851

5952
// Get the fee for the transfer
Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {SendParam} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol";
1010
import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
1111
import {ConfigLib} from "./lib/ConfigLib.sol";
1212

13-
contract SendTokensToArbitrumSepolia is Script {
13+
contract SendTokensFromEthereumToArbitrum is Script {
1414
/**
1515
* @dev Converts an address to bytes32.
1616
* @param _addr The address to convert.
@@ -29,36 +29,32 @@ contract SendTokensToArbitrumSepolia is Script {
2929

3030
// Contract addresses
3131
address iexecLayerZeroBridgeAddress = sourceParams.iexecLayerZeroBridgeAddress;
32-
address liquidityUnifierAddress = sourceParams.rlcLiquidityUnifierAddress;
33-
address rlcTokenAddress = sourceParams.rlcToken;
32+
address rlcMainnetTokenAddress = sourceParams.rlcToken;
3433

3534
// Transfer parameters
3635
uint16 destinationChainId = uint16(targetParams.lzChainId);
37-
address recipientAddress = targetParams.initialAdmin; // TODO read recipient address from env variables.
36+
address recipientAddress = vm.envAddress("RECIPIENT_ADDRESS");
3837
uint256 amount = 5 * 10 ** 9; // RLC tokens (adjust the amount as needed)
3938

4039
vm.startBroadcast();
4140
// First, approve the adapter to spend your tokens
42-
IERC20 rlcToken = IERC20(rlcTokenAddress);
43-
console.log("Approving RLCLiquidityUnifier contract to spend %s RLC", amount / 10 ** 9);
44-
rlcToken.approve(liquidityUnifierAddress, amount);
41+
IERC20 rlcToken = IERC20(rlcMainnetTokenAddress);
42+
console.log("Approving IexecLayerZeroBridge contract to spend %s RLC", amount / 10 ** 9);
43+
rlcToken.approve(iexecLayerZeroBridgeAddress, amount);
4544

4645
// Then, send tokens cross-chain
4746
IexecLayerZeroBridge adapter = IexecLayerZeroBridge(iexecLayerZeroBridgeAddress);
4847
console.log("Sending %s RLC to Arbitrum Sepolia", amount / 10 ** 9);
4948
console.log("Recipient: %s", recipientAddress);
5049

51-
// bytes memory _extraOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(65000, 0);
52-
bytes memory _extraOptions =
53-
abi.encodePacked(uint16(3), uint8(1), uint16(33), uint8(1), uint128(65000), uint128(0));
5450
SendParam memory sendParam = SendParam(
55-
destinationChainId, // You can also make this dynamic if needed
56-
addressToBytes32(recipientAddress),
57-
amount,
58-
amount * 9 / 10,
59-
_extraOptions,
60-
"",
61-
""
51+
destinationChainId, // Destination endpoint ID.
52+
addressToBytes32(recipientAddress), // Recipient address.
53+
amount, // Amount to send in local decimals.
54+
amount * 99 / 100, // Minimum amount to send in local decimals (allowing 1% slippage).
55+
"", // Extra options, not used in this case, already setup using `setEnforcedOptions`
56+
"", // Composed message for the send() operation, unused in this context.
57+
"" // OFT command to be executed, unused in default OFT implementations.
6258
);
6359

6460
MessagingFee memory fee = adapter.quoteSend(sendParam, false);

script/bridges/layerZero/IexecLayerZeroBridge.s.sol

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ pragma solidity ^0.8.22;
44

55
import {Script} from "forge-std/Script.sol";
66
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
7+
import {EnforcedOptionParam} from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol";
8+
import {OptionsBuilder} from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";
79
import {ConfigLib} from "./../../lib/ConfigLib.sol";
810
import {IexecLayerZeroBridge} from "../../../src/bridges/layerZero/IexecLayerZeroBridge.sol";
11+
import {RLCLiquidityUnifier} from "../../../src/RLCLiquidityUnifier.sol";
12+
import {RLCCrosschainToken} from "../../../src/RLCCrosschainToken.sol";
913
import {UUPSProxyDeployer} from "../../lib/UUPSProxyDeployer.sol";
1014
import {UpgradeUtils} from "../../lib/UpgradeUtils.sol";
1115

@@ -56,6 +60,8 @@ contract Deploy is Script {
5660
}
5761

5862
contract Configure is Script {
63+
using OptionsBuilder for bytes;
64+
5965
function run() external {
6066
string memory sourceChain = vm.envString("SOURCE_CHAIN");
6167
string memory targetChain = vm.envString("TARGET_CHAIN");
@@ -66,6 +72,21 @@ contract Configure is Script {
6672
sourceBridge.setPeer(
6773
targetParams.lzChainId, bytes32(uint256(uint160(targetParams.iexecLayerZeroBridgeAddress)))
6874
);
75+
EnforcedOptionParam[] memory enforcedOptions = new EnforcedOptionParam[](1);
76+
bytes memory _extraOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(70_000, 0); // 70_000 gas limit for the receiving executor and 0 for the executor's value
77+
enforcedOptions[0] = EnforcedOptionParam(targetParams.lzChainId, 2, _extraOptions);
78+
sourceBridge.setEnforcedOptions(enforcedOptions);
79+
// Authorize bridge in the relevant contract.
80+
if (sourceParams.approvalRequired) {
81+
RLCLiquidityUnifier rlcLiquidityUnifier = RLCLiquidityUnifier(sourceParams.rlcLiquidityUnifierAddress);
82+
bytes32 bridgeTokenRoleId = rlcLiquidityUnifier.TOKEN_BRIDGE_ROLE();
83+
rlcLiquidityUnifier.grantRole(bridgeTokenRoleId, address(sourceBridge));
84+
} else {
85+
RLCCrosschainToken rlcCrosschainToken = RLCCrosschainToken(sourceParams.rlcCrosschainTokenAddress);
86+
bytes32 bridgeTokenRoleId = rlcCrosschainToken.TOKEN_BRIDGE_ROLE();
87+
rlcCrosschainToken.grantRole(bridgeTokenRoleId, address(sourceBridge));
88+
}
89+
6990
vm.stopBroadcast();
7091
}
7192
}

0 commit comments

Comments
 (0)