From 658740a3498955198dc0a542e6e69899f8a71620 Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:39:16 +0200 Subject: [PATCH 01/11] docs: Fix path in readme --- docs/soldoc/src/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/soldoc/src/README.md b/docs/soldoc/src/README.md index f23437fc..5667e3eb 100644 --- a/docs/soldoc/src/README.md +++ b/docs/soldoc/src/README.md @@ -5,7 +5,7 @@ This project implements a cross-chain token bridge system for the RLC token usin ## Diagrams and source code docs (soldocs): - [Diagrams](../../diagrams/) - - [Source code docs](../../soldoc/) + - [Source code docs](../../soldoc/src/SUMMARY.md) ## Architecture From 978e2c9b28444938dc25750cebe33dbc8076748f Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:44:41 +0200 Subject: [PATCH 02/11] feat: Restore implems deployment using CreateX --- script/lib/UUPSProxyDeployer.sol | 30 ++++++++++++---------- test/e2e/IexecLayerZeroBridgeScript.t.sol | 10 ++++++++ test/units/RLCCrosschainTokenScript.t.sol | 8 ++++++ test/units/RLCLiquidityUnifierScript.t.sol | 8 ++++++ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/script/lib/UUPSProxyDeployer.sol b/script/lib/UUPSProxyDeployer.sol index 15f268da..b6da3778 100644 --- a/script/lib/UUPSProxyDeployer.sol +++ b/script/lib/UUPSProxyDeployer.sol @@ -17,12 +17,12 @@ library UUPSProxyDeployer { Vm private constant vm = StdConstants.VM; /** - * Deploys a UUPS proxy contract and its implementation using the CreateX Factory + * Deploys a UUPS proxy contract and its implementation in create2 mode using CreateX Factory. * @param contractName The name of the contract to deploy (used to fetch creation code) * @param constructorData The constructor arguments for the implementation contract * @param initializeData The initialization data for the proxy contract * @param createXFactory The address of the CreateX factory - * @param salt The salt for deterministic deployment + * @param createxSalt The salt for deterministic deployment * @return The address of the deployed proxy */ function deployUUPSProxyWithCreateX( @@ -30,12 +30,12 @@ library UUPSProxyDeployer { bytes memory constructorData, bytes memory initializeData, address createXFactory, - bytes32 salt + bytes32 createxSalt ) internal returns (address) { - ICreateX createX = ICreateX(createXFactory); - address implementation = deployImplementation(contractName, constructorData, createX); - address proxy = createX.deployCreate2AndInit( - salt, + address implementation = + deployImplementationUsingCreateX(contractName, constructorData, createXFactory, createxSalt); + address proxy = ICreateX(createXFactory).deployCreate2AndInit( + createxSalt, abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(implementation, "")), // initCode initializeData, ICreateX.Values({constructorAmount: 0, initCallAmount: 0}) // values for CreateX @@ -45,18 +45,22 @@ library UUPSProxyDeployer { } /** - * Deploys the implementation contract using tradition `create`. + * Deploys the implementation contract in create2 mode using CreateX factory. * @param contractName The name of the contract to deploy (used to fetch creation code) * @param constructorData The constructor arguments for the implementation contract * @param createxFactory The address of the CreateX factory + * @param createxSalt The salt for deterministic deployment * @return The address of the deployed implementation contract */ - function deployImplementation(string memory contractName, bytes memory constructorData, ICreateX createxFactory) - internal - returns (address) - { + function deployImplementationUsingCreateX( + string memory contractName, + bytes memory constructorData, + address createxFactory, + bytes32 createxSalt + ) internal returns (address) { bytes memory creationCode = vm.getCode(contractName); - address implementation = createxFactory.deployCreate(abi.encodePacked(creationCode, constructorData)); + address implementation = + ICreateX(createxFactory).deployCreate2(createxSalt, abi.encodePacked(creationCode, constructorData)); console.log("Implementation deployed at:", implementation); return implementation; } diff --git a/test/e2e/IexecLayerZeroBridgeScript.t.sol b/test/e2e/IexecLayerZeroBridgeScript.t.sol index a9ae8026..a4a69be0 100644 --- a/test/e2e/IexecLayerZeroBridgeScript.t.sol +++ b/test/e2e/IexecLayerZeroBridgeScript.t.sol @@ -101,6 +101,16 @@ contract IexecLayerZeroBridgeScriptTest is Test { // TODO check that the proxy address is saved. } + function testFork_RevertWhen_TwoDeploymentsWithTheSameSalt() public { + deployer.deploy( + false, address(rlcCrosschainToken), params.lzEndpoint, admin, upgrader, pauser, params.createxFactory, salt + ); + vm.expectRevert(abi.encodeWithSignature("FailedContractCreation(address)", params.createxFactory)); + deployer.deploy( + false, address(rlcCrosschainToken), params.lzEndpoint, admin, upgrader, pauser, params.createxFactory, salt + ); + } + // TODO: add tests for the configuration script. function testFork_ConfigureContractCorrectly() public { diff --git a/test/units/RLCCrosschainTokenScript.t.sol b/test/units/RLCCrosschainTokenScript.t.sol index 1dd44490..9362a493 100644 --- a/test/units/RLCCrosschainTokenScript.t.sol +++ b/test/units/RLCCrosschainTokenScript.t.sol @@ -42,4 +42,12 @@ contract RLCCrosschainTokenTest is Test { // TODO check that the proxy address is saved. } + + // Makes sure create2 deployment is well implemented. + function test_RevertWhen_TwoDeploymentsWithTheSameSalt() public { + address random = makeAddr("random"); + deployer.deploy(name, symbol, admin, upgrader, createx, salt); + vm.expectRevert(abi.encodeWithSignature("FailedContractCreation(address)", createx)); + deployer.deploy("Foo", "BAR", random, random, createx, salt); + } } diff --git a/test/units/RLCLiquidityUnifierScript.t.sol b/test/units/RLCLiquidityUnifierScript.t.sol index d3161376..78f09b67 100644 --- a/test/units/RLCLiquidityUnifierScript.t.sol +++ b/test/units/RLCLiquidityUnifierScript.t.sol @@ -35,4 +35,12 @@ contract LiquidityUnifierTest is Test { rlcLiquidityUnifier.initialize(admin, upgrader); // TODO check that the proxy address is saved. } + + // Makes sure create2 deployment is well implemented. + function test_RevertWhen_TwoDeploymentsWithTheSameSalt() public { + address random = makeAddr("random"); + deployer.deploy(rlcToken, admin, upgrader, createx, salt); + vm.expectRevert(abi.encodeWithSignature("FailedContractCreation(address)", createx)); + deployer.deploy(rlcToken, random, random, createx, salt); + } } From a4270c511188e1266641cec8259f99513e0fa1ed Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:47:24 +0200 Subject: [PATCH 03/11] refactor: Rename function --- script/RLCCrosschainToken.s.sol | 4 +--- script/RLCLiquidityUnifier.s.sol | 2 +- script/bridges/layerZero/IexecLayerZeroBridge.s.sol | 2 +- script/lib/UUPSProxyDeployer.sol | 10 +++++----- test/units/utils/TestUtils.sol | 6 +++--- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/script/RLCCrosschainToken.s.sol b/script/RLCCrosschainToken.s.sol index 8c6b1724..07076e8f 100644 --- a/script/RLCCrosschainToken.s.sol +++ b/script/RLCCrosschainToken.s.sol @@ -58,8 +58,6 @@ contract Deploy is Script { ) public returns (address) { bytes memory initData = abi.encodeWithSelector(RLCCrosschainToken.initialize.selector, name, symbol, initialAdmin, initialUpgrader); - return UUPSProxyDeployer.deployUUPSProxyWithCreateX( - "RLCCrosschainToken", "", initData, createxFactory, createxSalt - ); + return UUPSProxyDeployer.deployUsingCreateX("RLCCrosschainToken", "", initData, createxFactory, createxSalt); } } diff --git a/script/RLCLiquidityUnifier.s.sol b/script/RLCLiquidityUnifier.s.sol index 45388a2a..bb5a6147 100644 --- a/script/RLCLiquidityUnifier.s.sol +++ b/script/RLCLiquidityUnifier.s.sol @@ -57,7 +57,7 @@ contract Deploy is Script { bytes memory constructorData = abi.encode(rlcToken); bytes memory initData = abi.encodeWithSelector(RLCLiquidityUnifier.initialize.selector, initialAdmin, initialUpgrader); - return UUPSProxyDeployer.deployUUPSProxyWithCreateX( + return UUPSProxyDeployer.deployUsingCreateX( "RLCLiquidityUnifier", constructorData, initData, createxFactory, createxSalt ); } diff --git a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol index 1d9a514d..d6541999 100644 --- a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol +++ b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol @@ -53,7 +53,7 @@ contract Deploy is Script { bytes memory initializeData = abi.encodeWithSelector( IexecLayerZeroBridge.initialize.selector, initialAdmin, initialUpgrader, initialPauser ); - return UUPSProxyDeployer.deployUUPSProxyWithCreateX( + return UUPSProxyDeployer.deployUsingCreateX( "IexecLayerZeroBridge", constructorData, initializeData, createxFactory, createxSalt ); } diff --git a/script/lib/UUPSProxyDeployer.sol b/script/lib/UUPSProxyDeployer.sol index b6da3778..9dfeb5b8 100644 --- a/script/lib/UUPSProxyDeployer.sol +++ b/script/lib/UUPSProxyDeployer.sol @@ -21,20 +21,20 @@ library UUPSProxyDeployer { * @param contractName The name of the contract to deploy (used to fetch creation code) * @param constructorData The constructor arguments for the implementation contract * @param initializeData The initialization data for the proxy contract - * @param createXFactory The address of the CreateX factory + * @param createxFactory The address of the CreateX factory * @param createxSalt The salt for deterministic deployment * @return The address of the deployed proxy */ - function deployUUPSProxyWithCreateX( + function deployUsingCreateX( string memory contractName, bytes memory constructorData, bytes memory initializeData, - address createXFactory, + address createxFactory, bytes32 createxSalt ) internal returns (address) { address implementation = - deployImplementationUsingCreateX(contractName, constructorData, createXFactory, createxSalt); - address proxy = ICreateX(createXFactory).deployCreate2AndInit( + deployImplementationUsingCreateX(contractName, constructorData, createxFactory, createxSalt); + address proxy = ICreateX(createxFactory).deployCreate2AndInit( createxSalt, abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(implementation, "")), // initCode initializeData, diff --git a/test/units/utils/TestUtils.sol b/test/units/utils/TestUtils.sol index 0450b5e4..88671f8b 100644 --- a/test/units/utils/TestUtils.sol +++ b/test/units/utils/TestUtils.sol @@ -45,7 +45,7 @@ library TestUtils { // Deploy Liquidity Unifier rlcLiquidityUnifier = RLCLiquidityUnifier( - UUPSProxyDeployer.deployUUPSProxyWithCreateX( + UUPSProxyDeployer.deployUsingCreateX( "RLCLiquidityUnifier", abi.encode(rlcToken), abi.encodeWithSelector(RLCLiquidityUnifier.initialize.selector, initialAdmin, initialUpgrader), @@ -56,7 +56,7 @@ library TestUtils { // Deploy IexecLayerZeroBridgeAdapter iexecLayerZeroBridgeChainA = IexecLayerZeroBridge( - UUPSProxyDeployer.deployUUPSProxyWithCreateX( + UUPSProxyDeployer.deployUsingCreateX( "IexecLayerZeroBridge", abi.encode(true, rlcLiquidityUnifier, lzEndpointSource), abi.encodeWithSelector( @@ -75,7 +75,7 @@ library TestUtils { ); // Deploy IexecLayerZeroBridge iexecLayerZeroBridgeChainB = IexecLayerZeroBridge( - UUPSProxyDeployer.deployUUPSProxyWithCreateX( + UUPSProxyDeployer.deployUsingCreateX( "IexecLayerZeroBridge", abi.encode(false, rlcCrosschainToken, lzEndpointDestination), abi.encodeWithSelector( From b8ff5c72ecdf4ec7ca5982e96846a58cb91acd69 Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:24:53 +0200 Subject: [PATCH 04/11] refactor: Move mock files to test folder --- script/bridges/layerZero/IexecLayerZeroBridge.s.sol | 7 +++++++ test/units/RLCLiquidityUnifierUpgrade.t.sol | 2 +- .../bridges/layerZero/IexecLayerZeroBridgeUpgrade.t.sol | 2 +- {src => test/units}/mocks/IexecLayerZeroBridgeV2Mock.sol | 2 +- {src => test/units}/mocks/RLCLiquidityUnifierV2Mock.sol | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) rename {src => test/units}/mocks/IexecLayerZeroBridgeV2Mock.sol (92%) rename {src => test/units}/mocks/RLCLiquidityUnifierV2Mock.sol (93%) diff --git a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol index d6541999..e58dfe37 100644 --- a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol +++ b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol @@ -59,6 +59,13 @@ contract Deploy is Script { } } +/** + * This script is used to configure the IexecLayerZeroBridge contract on both source + * and target chains. + * It sets required LayerZero bridge config: peer address and enforced options. + * It also grants the bridge the necessary roles in the RLCCrosschainToken contract + * or RLCLiquidityUnifier contract, depending on the configuration. + */ contract Configure is Script { using OptionsBuilder for bytes; diff --git a/test/units/RLCLiquidityUnifierUpgrade.t.sol b/test/units/RLCLiquidityUnifierUpgrade.t.sol index ffa3412d..20fba3db 100644 --- a/test/units/RLCLiquidityUnifierUpgrade.t.sol +++ b/test/units/RLCLiquidityUnifierUpgrade.t.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.22; import {TestHelperOz5} from "@layerzerolabs/test-devtools-evm-foundry/contracts/TestHelperOz5.sol"; -import {RLCLiquidityUnifierV2} from "../../src/mocks/RLCLiquidityUnifierV2Mock.sol"; import {RLCLiquidityUnifier} from "../../src/RLCLiquidityUnifier.sol"; import {TestUtils} from "./utils/TestUtils.sol"; import {UpgradeUtils} from "../../script/lib/UpgradeUtils.sol"; import {RLCMock} from "./mocks/RLCMock.sol"; +import {RLCLiquidityUnifierV2} from "./mocks/RLCLiquidityUnifierV2Mock.sol"; contract RLCLiquidityUnifierUpgradeTest is TestHelperOz5 { using TestUtils for *; diff --git a/test/units/bridges/layerZero/IexecLayerZeroBridgeUpgrade.t.sol b/test/units/bridges/layerZero/IexecLayerZeroBridgeUpgrade.t.sol index ceec7cac..b0fe7d43 100644 --- a/test/units/bridges/layerZero/IexecLayerZeroBridgeUpgrade.t.sol +++ b/test/units/bridges/layerZero/IexecLayerZeroBridgeUpgrade.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.22; import {TestHelperOz5} from "@layerzerolabs/test-devtools-evm-foundry/contracts/TestHelperOz5.sol"; -import {IexecLayerZeroBridgeV2} from "../../../../src/mocks/IexecLayerZeroBridgeV2Mock.sol"; +import {IexecLayerZeroBridgeV2} from "../../mocks/IexecLayerZeroBridgeV2Mock.sol"; import {TestUtils} from "./../../utils/TestUtils.sol"; import {UpgradeUtils} from "../../../../script/lib/UpgradeUtils.sol"; import {IexecLayerZeroBridge} from "../../../../src/bridges/layerZero/IexecLayerZeroBridge.sol"; diff --git a/src/mocks/IexecLayerZeroBridgeV2Mock.sol b/test/units/mocks/IexecLayerZeroBridgeV2Mock.sol similarity index 92% rename from src/mocks/IexecLayerZeroBridgeV2Mock.sol rename to test/units/mocks/IexecLayerZeroBridgeV2Mock.sol index 6ee77705..019d1f56 100644 --- a/src/mocks/IexecLayerZeroBridgeV2Mock.sol +++ b/test/units/mocks/IexecLayerZeroBridgeV2Mock.sol @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.22; -import {IexecLayerZeroBridge} from "../bridges/layerZero/IexecLayerZeroBridge.sol"; +import {IexecLayerZeroBridge} from "../../../src/bridges/layerZero/IexecLayerZeroBridge.sol"; /** * @title IexecLayerZeroBridgeV2 - V2 implementation with additional features diff --git a/src/mocks/RLCLiquidityUnifierV2Mock.sol b/test/units/mocks/RLCLiquidityUnifierV2Mock.sol similarity index 93% rename from src/mocks/RLCLiquidityUnifierV2Mock.sol rename to test/units/mocks/RLCLiquidityUnifierV2Mock.sol index 90644e20..2814bf5b 100644 --- a/src/mocks/RLCLiquidityUnifierV2Mock.sol +++ b/test/units/mocks/RLCLiquidityUnifierV2Mock.sol @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.22; -import {RLCLiquidityUnifier} from "../RLCLiquidityUnifier.sol"; +import {RLCLiquidityUnifier} from "../../../src/RLCLiquidityUnifier.sol"; /** * @title RLCLiquidityUnifierV2 - V2 implementation with additional features From 9dfe14f35fc03b3cffe361d7b5d2b7778ac388fb Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:39:19 +0200 Subject: [PATCH 05/11] feat: Add TODO --- script/RLCCrosschainToken.s.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/RLCCrosschainToken.s.sol b/script/RLCCrosschainToken.s.sol index 07076e8f..a3c84b4b 100644 --- a/script/RLCCrosschainToken.s.sol +++ b/script/RLCCrosschainToken.s.sol @@ -61,3 +61,5 @@ contract Deploy is Script { return UUPSProxyDeployer.deployUsingCreateX("RLCCrosschainToken", "", initData, createxFactory, createxSalt); } } + +// TODO add upgrade script. From 7b0edcaf10e80a77bbbeb5128abd76200b28c921 Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:48:42 +0200 Subject: [PATCH 06/11] chore: Clean Makefile --- Makefile | 56 ++++++++++--------------- README.md | 2 +- docs/soldoc/src/README.md | 2 +- script/SendFromArbitrumToEthereum.s.sol | 3 +- script/SendFromEthereumToArbitrum.s.sol | 3 +- 5 files changed, 25 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index 713cabb0..da032e5c 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ clean: forge clean # -# High-level deployment targets +# Deployment targets # deploy-on-anvil: @@ -78,13 +78,16 @@ deploy-all: # SOURCE_CHAIN, SOURCE_RPC, TARGET_CHAIN, TARGET_RPC @echo "⚠️ Run 'make configure-all' to configure bridges." @echo "⚠️ Please configure the bridges. Do not forget to authorize the RLCLiquidityUnifier and RLCCrosschainToken contracts on the bridges." -configure-all: # SOURCE_CHAIN, TARGET_CHAIN, SOURCE_RPC, TARGET_RPC - $(MAKE) configure-bridge SOURCE_CHAIN=$(SOURCE_CHAIN) TARGET_CHAIN=$(TARGET_CHAIN) RPC_URL=$(SOURCE_RPC) - $(MAKE) configure-bridge SOURCE_CHAIN=$(TARGET_CHAIN) TARGET_CHAIN=$(SOURCE_CHAIN) RPC_URL=$(TARGET_RPC) - @echo "Bridge configuration completed." +deploy-contract: # CONTRACT, CHAIN, RPC_URL + @echo "Deploying $(CONTRACT) on $(CHAIN)" + CHAIN=$(CHAIN) forge script script/$(CONTRACT).s.sol:Deploy \ + --rpc-url $(RPC_URL) \ + $$(if [ "$(CI)" = "true" ]; then echo "--private-key $(DEPLOYER_PRIVATE_KEY)"; else echo "--account $(ACCOUNT)"; fi) \ + --broadcast \ + -vvv # -# High-level upgrade targets +# Upgrade targets # upgrade-on-anvil: @@ -107,22 +110,6 @@ upgrade-all: # SOURCE_CHAIN, SOURCE_RPC, TARGET_CHAIN, TARGET_RPC $(MAKE) upgrade-contract CONTRACT=bridges/layerZero/IexecLayerZeroBridge CHAIN=$(SOURCE_CHAIN) RPC_URL=$(SOURCE_RPC) $(MAKE) upgrade-contract CONTRACT=bridges/layerZero/IexecLayerZeroBridge CHAIN=$(TARGET_CHAIN) RPC_URL=$(TARGET_RPC) -# -# Generic deployment targets -# - -deploy-contract: # CONTRACT, CHAIN, RPC_URL - @echo "Deploying $(CONTRACT) on $(CHAIN)" - CHAIN=$(CHAIN) forge script script/$(CONTRACT).s.sol:Deploy \ - --rpc-url $(RPC_URL) \ - $$(if [ "$(CI)" = "true" ]; then echo "--private-key $(DEPLOYER_PRIVATE_KEY)"; else echo "--account $(ACCOUNT)"; fi) \ - --broadcast \ - -vvv - -# -# Generic upgrade targets -# - upgrade-contract: # CONTRACT, CHAIN, RPC_URL @echo "Upgrading $(CONTRACT) on $(CHAIN)" CHAIN=$(CHAIN) forge script script/$(CONTRACT).s.sol:Upgrade \ @@ -132,9 +119,14 @@ upgrade-contract: # CONTRACT, CHAIN, RPC_URL -vvv # -# Generic configuration targets +# Configuration targets # +configure-all: # SOURCE_CHAIN, TARGET_CHAIN, SOURCE_RPC, TARGET_RPC + $(MAKE) configure-bridge SOURCE_CHAIN=$(SOURCE_CHAIN) TARGET_CHAIN=$(TARGET_CHAIN) RPC_URL=$(SOURCE_RPC) + $(MAKE) configure-bridge SOURCE_CHAIN=$(TARGET_CHAIN) TARGET_CHAIN=$(SOURCE_CHAIN) RPC_URL=$(TARGET_RPC) + @echo "Bridge configuration completed." + configure-bridge: # SOURCE_CHAIN, TARGET_CHAIN, RPC_URL @echo "Configuring LayerZero Bridge $(SOURCE_CHAIN) -> $(TARGET_CHAIN)" SOURCE_CHAIN=$(SOURCE_CHAIN) TARGET_CHAIN=$(TARGET_CHAIN) \ @@ -145,28 +137,19 @@ configure-bridge: # SOURCE_CHAIN, TARGET_CHAIN, RPC_URL -vvv # -# Individual upgrade targets -# - -upgrade-layerzero-bridge: # CHAIN, RPC_URL - $(MAKE) upgrade-contract CONTRACT=bridges/layerZero/IexecLayerZeroBridge CHAIN=$(CHAIN) RPC_URL=$(RPC_URL) - -# -# Bridge operations. -# - # Testnet bridge operations +# send-tokens-to-arbitrum-sepolia: @echo "Sending tokens cross-chain... from SEPOLIA to Arbitrum SEPOLIA" SOURCE_CHAIN=sepolia TARGET_CHAIN=arbitrum_sepolia \ - forge script script/SendFromEthereumToArbitrum.s.sol:SendTokensFromEthereumToArbitrum \ + forge script script/SendFromEthereumToArbitrum.s.sol:SendFromEthereumToArbitrum \ --rpc-url $(SEPOLIA_RPC_URL) \ --account $(ACCOUNT) \ --broadcast \ -vvv -send-tokens-to-sepolia: +send-tokens-to-ethereum-sepolia: @echo "Sending tokens cross-chain... from Arbitrum SEPOLIA to SEPOLIA" SOURCE_CHAIN=arbitrum_sepolia TARGET_CHAIN=sepolia \ forge script script/SendFromArbitrumToEthereum.s.sol:SendTokensFromArbitrumToEthereum \ @@ -175,7 +158,10 @@ send-tokens-to-sepolia: --broadcast \ -vvv +# # Mainnet bridge operations +# + send-tokens-to-arbitrum-mainnet: @echo "Sending tokens cross-chain... from ETHEREUM to Arbitrum MAINNET" SOURCE_CHAIN=ethereum TARGET_CHAIN=arbitrum \ diff --git a/README.md b/README.md index 3d2ed4b1..9e845fcc 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ This will: B. To send RLC tokens from Arbitrum Sepolia back to Ethereum Sepolia: ```bash -make send-tokens-to-sepolia +make send-tokens-to-ethereum-sepolia ``` This will: diff --git a/docs/soldoc/src/README.md b/docs/soldoc/src/README.md index 3d2ed4b1..9e845fcc 100644 --- a/docs/soldoc/src/README.md +++ b/docs/soldoc/src/README.md @@ -149,7 +149,7 @@ This will: B. To send RLC tokens from Arbitrum Sepolia back to Ethereum Sepolia: ```bash -make send-tokens-to-sepolia +make send-tokens-to-ethereum-sepolia ``` This will: diff --git a/script/SendFromArbitrumToEthereum.s.sol b/script/SendFromArbitrumToEthereum.s.sol index 6d7bea13..d3a04e4a 100644 --- a/script/SendFromArbitrumToEthereum.s.sol +++ b/script/SendFromArbitrumToEthereum.s.sol @@ -10,10 +10,9 @@ import {SendParam} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol"; import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; /** - * Script to send tokens from Arbitrum Mainnet to Ethereum Mainnet. + * Script to send tokens from Arbitrum Mainnet/Testnet to Ethereum Mainnet/Testnet. * This script demonstrates cross-chain token transfers using LayerZero bridge. */ -// TODO: fusion SendTokensFromArbitrumToEthereum and SendTokensFromEthereumToArbitrum into a single script with dynamic chain handling contract SendFromArbitrumToEthereum is Script { uint256 private constant TRANSFER_AMOUNT = 1 * 10 ** 9; // 1 RLC token with 9 decimals diff --git a/script/SendFromEthereumToArbitrum.s.sol b/script/SendFromEthereumToArbitrum.s.sol index f2026fd2..3f677ab0 100644 --- a/script/SendFromEthereumToArbitrum.s.sol +++ b/script/SendFromEthereumToArbitrum.s.sol @@ -10,10 +10,9 @@ import {SendParam} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol"; import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; /** - * Script to send tokens from Ethereum Mainnet to Arbitrum Mainnet. + * Script to send tokens from Ethereum Mainnet/Testnet to Arbitrum Mainnet/Testnet. * This script demonstrates cross-chain token transfers using LayerZero bridge. */ -// TODO: fusion SendTokensFromArbitrumToEthereum and SendTokensFromEthereumToArbitrum into a single script with dynamic chain handling contract SendFromEthereumToArbitrum is Script { uint256 private constant TRANSFER_AMOUNT = 1 * 10 ** 9; // 1 RLC token with 9 decimals /** From f563fcc4be80e125d97f42384e714d76623a681e Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:23:01 +0200 Subject: [PATCH 07/11] chore: Clean upgrade scripts --- Makefile | 14 +++++++------- README.md | 6 +++--- docs/soldoc/src/README.md | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index da032e5c..236052bb 100644 --- a/Makefile +++ b/Makefile @@ -90,23 +90,23 @@ deploy-contract: # CONTRACT, CHAIN, RPC_URL # Upgrade targets # -upgrade-on-anvil: - $(MAKE) upgrade-all \ +upgrade-bridge-on-anvil: + $(MAKE) upgrade-bridge \ SOURCE_CHAIN=sepolia SOURCE_RPC=$(ANVIL_SEPOLIA_RPC_URL) \ TARGET_CHAIN=arbitrum_sepolia TARGET_RPC=$(ANVIL_ARBITRUM_SEPOLIA_RPC_URL) -upgrade-on-mainnets: - $(MAKE) upgrade-all \ +upgrade-bridge-on-mainnets: + $(MAKE) upgrade-bridge \ SOURCE_CHAIN=ethereum SOURCE_RPC=$(ETHEREUM_RPC_URL) \ TARGET_CHAIN=arbitrum TARGET_RPC=$(ARBITRUM_RPC_URL) \ # TODO : RLCMultichain and RLCLiquidityUnifier upgrades -upgrade-on-testnets: - $(MAKE) upgrade-all \ +upgrade-bridge-on-testnets: + $(MAKE) upgrade-bridge \ SOURCE_CHAIN=sepolia SOURCE_RPC=$(SEPOLIA_RPC_URL) \ TARGET_CHAIN=arbitrum_sepolia TARGET_RPC=$(ARBITRUM_SEPOLIA_RPC_URL) \ -upgrade-all: # SOURCE_CHAIN, SOURCE_RPC, TARGET_CHAIN, TARGET_RPC +upgrade-bridge: # SOURCE_CHAIN, SOURCE_RPC, TARGET_CHAIN, TARGET_RPC $(MAKE) upgrade-contract CONTRACT=bridges/layerZero/IexecLayerZeroBridge CHAIN=$(SOURCE_CHAIN) RPC_URL=$(SOURCE_RPC) $(MAKE) upgrade-contract CONTRACT=bridges/layerZero/IexecLayerZeroBridge CHAIN=$(TARGET_CHAIN) RPC_URL=$(TARGET_RPC) diff --git a/README.md b/README.md index 9e845fcc..a56b1dc6 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ Test upgrades locally before deploying to live networks: ```bash # Test upgrade process on local forks -make upgrade-on-anvil +make upgrade-bridge-on-anvil ``` #### 2. Live Network Upgrades @@ -237,7 +237,7 @@ make upgrade-on-anvil Execute upgrades on live networks: ```bash -make upgrade-on-mainnets +make upgrade-bridge-on-mainnets ``` ### Upgrade Safety Features @@ -310,7 +310,7 @@ Contracts are automatically verified on block explorers during deployment: make deploy-on-mainnets # Upgrades and verifies contracts on mainnet -make upgrade-on-mainnets +make upgrade-bridge-on-mainnets ``` The verification is handled by Foundry's built-in `--verify` flag, which submits the source code and constructor arguments to the respective block explorers (Etherscan, Arbiscan, etc.). diff --git a/docs/soldoc/src/README.md b/docs/soldoc/src/README.md index 9e845fcc..a56b1dc6 100644 --- a/docs/soldoc/src/README.md +++ b/docs/soldoc/src/README.md @@ -229,7 +229,7 @@ Test upgrades locally before deploying to live networks: ```bash # Test upgrade process on local forks -make upgrade-on-anvil +make upgrade-bridge-on-anvil ``` #### 2. Live Network Upgrades @@ -237,7 +237,7 @@ make upgrade-on-anvil Execute upgrades on live networks: ```bash -make upgrade-on-mainnets +make upgrade-bridge-on-mainnets ``` ### Upgrade Safety Features @@ -310,7 +310,7 @@ Contracts are automatically verified on block explorers during deployment: make deploy-on-mainnets # Upgrades and verifies contracts on mainnet -make upgrade-on-mainnets +make upgrade-bridge-on-mainnets ``` The verification is handled by Foundry's built-in `--verify` flag, which submits the source code and constructor arguments to the respective block explorers (Etherscan, Arbiscan, etc.). From d5e8ca5ea938689d8b386948ac09539feab59d3d Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:23:16 +0200 Subject: [PATCH 08/11] chore: Clean upgrade scripts --- script/RLCCrosschainToken.s.sol | 6 +++++- script/RLCLiquidityUnifier.s.sol | 15 ++------------ .../layerZero/IexecLayerZeroBridge.s.sol | 20 ++----------------- 3 files changed, 9 insertions(+), 32 deletions(-) diff --git a/script/RLCCrosschainToken.s.sol b/script/RLCCrosschainToken.s.sol index a3c84b4b..4a2308e5 100644 --- a/script/RLCCrosschainToken.s.sol +++ b/script/RLCCrosschainToken.s.sol @@ -62,4 +62,8 @@ contract Deploy is Script { } } -// TODO add upgrade script. +contract Upgrade is Script { + function run() external pure { + revert('Not implemented!'); + } +} diff --git a/script/RLCLiquidityUnifier.s.sol b/script/RLCLiquidityUnifier.s.sol index bb5a6147..ad058f0e 100644 --- a/script/RLCLiquidityUnifier.s.sol +++ b/script/RLCLiquidityUnifier.s.sol @@ -64,18 +64,7 @@ contract Deploy is Script { } contract Upgrade is Script { - function run() external { - string memory chain = vm.envString("CHAIN"); - ConfigLib.CommonConfigParams memory commonParams = ConfigLib.readCommonConfig(chain); - - vm.startBroadcast(); - UpgradeUtils.UpgradeParams memory params = UpgradeUtils.UpgradeParams({ - proxyAddress: commonParams.rlcLiquidityUnifierAddress, - constructorData: abi.encode(commonParams.rlcToken), - contractName: "RLCLiquidityUnifierV2Mock.sol:RLCLiquidityUnifierV2", // Would be production contract in real deployment - newStateVariable: 1000000 * 10 ** 9 - }); - UpgradeUtils.executeUpgrade(params); - vm.stopBroadcast(); + function run() external pure { + revert('Not implemented!'); } } diff --git a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol index c1a856e2..3cc555b7 100644 --- a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol +++ b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol @@ -194,23 +194,7 @@ contract Configure is Script { * A script to upgrade the IexecLayerZeroBridge contract. */ contract Upgrade is Script { - function run() external { - string memory chain = vm.envString("CHAIN"); - ConfigLib.CommonConfigParams memory commonParams = ConfigLib.readCommonConfig(chain); - - // For testing purpose - uint256 newStateVariable = 1000000 * 10 ** 9; - address bridgeableToken = commonParams.approvalRequired - ? commonParams.rlcLiquidityUnifierAddress - : commonParams.rlcCrosschainTokenAddress; - vm.startBroadcast(); - UpgradeUtils.UpgradeParams memory params = UpgradeUtils.UpgradeParams({ - proxyAddress: commonParams.iexecLayerZeroBridgeAddress, - constructorData: abi.encode(commonParams.approvalRequired, bridgeableToken, commonParams.lzEndpoint), - contractName: "IexecLayerZeroBridgeV2Mock.sol:IexecLayerZeroBridgeV2", // Would be production contract in real deployment - newStateVariable: newStateVariable - }); - UpgradeUtils.executeUpgrade(params); - vm.stopBroadcast(); + function run() external pure { + revert('Not implemented!'); } } From fb3f7eec1e94cf89d1a4b20f5de1a6fbc0423913 Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:31:37 +0200 Subject: [PATCH 09/11] style: Format --- script/RLCCrosschainToken.s.sol | 2 +- script/RLCLiquidityUnifier.s.sol | 2 +- script/bridges/layerZero/IexecLayerZeroBridge.s.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/script/RLCCrosschainToken.s.sol b/script/RLCCrosschainToken.s.sol index 4a2308e5..dbc30659 100644 --- a/script/RLCCrosschainToken.s.sol +++ b/script/RLCCrosschainToken.s.sol @@ -64,6 +64,6 @@ contract Deploy is Script { contract Upgrade is Script { function run() external pure { - revert('Not implemented!'); + revert("Not implemented!"); } } diff --git a/script/RLCLiquidityUnifier.s.sol b/script/RLCLiquidityUnifier.s.sol index ad058f0e..dd0b6c8b 100644 --- a/script/RLCLiquidityUnifier.s.sol +++ b/script/RLCLiquidityUnifier.s.sol @@ -65,6 +65,6 @@ contract Deploy is Script { contract Upgrade is Script { function run() external pure { - revert('Not implemented!'); + revert("Not implemented!"); } } diff --git a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol index 3cc555b7..7d539a3f 100644 --- a/script/bridges/layerZero/IexecLayerZeroBridge.s.sol +++ b/script/bridges/layerZero/IexecLayerZeroBridge.s.sol @@ -195,6 +195,6 @@ contract Configure is Script { */ contract Upgrade is Script { function run() external pure { - revert('Not implemented!'); + revert("Not implemented!"); } } From cbe8d7fccd79d2a08e6873125a1baaf6d176dd76 Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 13 Oct 2025 15:12:35 +0200 Subject: [PATCH 10/11] chore: Restore comment --- script/SendFromArbitrumToEthereum.s.sol | 1 + script/SendFromEthereumToArbitrum.s.sol | 1 + 2 files changed, 2 insertions(+) diff --git a/script/SendFromArbitrumToEthereum.s.sol b/script/SendFromArbitrumToEthereum.s.sol index d3a04e4a..1039eb23 100644 --- a/script/SendFromArbitrumToEthereum.s.sol +++ b/script/SendFromArbitrumToEthereum.s.sol @@ -13,6 +13,7 @@ import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; * Script to send tokens from Arbitrum Mainnet/Testnet to Ethereum Mainnet/Testnet. * This script demonstrates cross-chain token transfers using LayerZero bridge. */ +// TODO merge SendFromArbitrumToEthereum and SendFromEthereumToArbitrum into a single script. contract SendFromArbitrumToEthereum is Script { uint256 private constant TRANSFER_AMOUNT = 1 * 10 ** 9; // 1 RLC token with 9 decimals diff --git a/script/SendFromEthereumToArbitrum.s.sol b/script/SendFromEthereumToArbitrum.s.sol index 3f677ab0..ac707272 100644 --- a/script/SendFromEthereumToArbitrum.s.sol +++ b/script/SendFromEthereumToArbitrum.s.sol @@ -13,6 +13,7 @@ import {MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; * Script to send tokens from Ethereum Mainnet/Testnet to Arbitrum Mainnet/Testnet. * This script demonstrates cross-chain token transfers using LayerZero bridge. */ +// TODO merge SendFromArbitrumToEthereum and SendFromEthereumToArbitrum into a single script. contract SendFromEthereumToArbitrum is Script { uint256 private constant TRANSFER_AMOUNT = 1 * 10 ** 9; // 1 RLC token with 9 decimals /** From 25a0813a9e43fc99478b7e25a81ad8fd355f4fb4 Mon Sep 17 00:00:00 2001 From: Zied <26070035+zguesmi@users.noreply.github.com> Date: Mon, 13 Oct 2025 15:15:46 +0200 Subject: [PATCH 11/11] fix: Fix script contract name --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 236052bb..47793fff 100644 --- a/Makefile +++ b/Makefile @@ -152,7 +152,7 @@ send-tokens-to-arbitrum-sepolia: send-tokens-to-ethereum-sepolia: @echo "Sending tokens cross-chain... from Arbitrum SEPOLIA to SEPOLIA" SOURCE_CHAIN=arbitrum_sepolia TARGET_CHAIN=sepolia \ - forge script script/SendFromArbitrumToEthereum.s.sol:SendTokensFromArbitrumToEthereum \ + forge script script/SendFromArbitrumToEthereum.s.sol:SendFromArbitrumToEthereum \ --rpc-url $(ARBITRUM_SEPOLIA_RPC_URL) \ --account $(ACCOUNT) \ --broadcast \