Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9120dc5
feat: Implement IexecLayerZeroBridgeHarness and refactor deployment s…
Le-Caignec Jul 3, 2025
bf05f1b
feat: Add IexecLayerZeroBridgeHarness test suite for enhanced cross-c…
Le-Caignec Jul 4, 2025
9dc52a1
feat: Refactor deployment results and update test contracts for Layer…
Le-Caignec Jul 4, 2025
c79968a
feat: Update IexecLayerZeroBridge tests to use harness and remove obs…
Le-Caignec Jul 4, 2025
90c48cf
Merge branch 'main' into feature/add-unit-tests-for-_mint-function
Le-Caignec Jul 4, 2025
6ff1736
Merge branch 'main' into feature/add-unit-tests-for-_mint-function
Le-Caignec Jul 4, 2025
21f67b1
feat: Remove unused import from IexecLayerZeroBridge test file
Le-Caignec Jul 4, 2025
62f3ee5
feat: Add event emission expectations for CrosschainMint in IexecLaye…
Le-Caignec Jul 4, 2025
515c01b
Merge remote-tracking branch 'origin/main' into feature/add-unit-test…
Le-Caignec Jul 7, 2025
960acd0
refactor: Rename test functions for clarity on paused states
Le-Caignec Jul 7, 2025
6ee5934
refactor: Update token type from RLCMock to IERC20 for improved inter…
Le-Caignec Jul 7, 2025
218e43f
Merge branch 'main' into feature/add-unit-tests-for-_mint-function
Le-Caignec Jul 7, 2025
713fcfc
Merge remote-tracking branch 'origin/main' into feature/add-unit-test…
Le-Caignec Jul 8, 2025
21b37f0
fix: Correct parameter order in UUPSProxyDeployer deployment
Le-Caignec Jul 8, 2025
090d5a5
fix: Use dynamic contract name for IexecLayerZeroBridge deployment
Le-Caignec Jul 8, 2025
efd97f5
refactor: Simplify liquidity unifier and crosschain token deployment …
Le-Caignec Jul 8, 2025
7878f71
fix: Update Forge build command to include size analysis for source f…
Le-Caignec Jul 8, 2025
fd25e94
test ci
Le-Caignec Jul 8, 2025
cbffc8b
fix: Add environment file copy step after Forge build
Le-Caignec Jul 8, 2025
67f778a
Merge branch 'main' into feature/add-unit-tests-for-_mint-function
Le-Caignec Jul 8, 2025
d9cbc1d
Update test/units/bridges/layerZero/IexecLayerZeroBridge.t.sol
Le-Caignec Jul 8, 2025
34dbb20
Update test/units/bridges/layerZero/IexecLayerZeroBridge.t.sol
Le-Caignec Jul 8, 2025
49f461c
refactor: rename fuzz test for credit function to clarify address han…
Le-Caignec Jul 8, 2025
795cf82
fix: correct expected emit address in credit function test
Le-Caignec Jul 8, 2025
f3db488
refactor: comment out existing tests for send functionality and credi…
Le-Caignec Jul 8, 2025
c5836a9
refactor: update variable names for IexecLayerZeroBridge to improve c…
Le-Caignec Jul 8, 2025
c57974a
fix: uncomment
Le-Caignec Jul 9, 2025
f076db0
test: uncomment tests
Le-Caignec Jul 9, 2025
cda19cd
Update test/units/bridges/layerZero/IexecLayerZeroBridge.t.sol
zguesmi Jul 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/mocks/IexecLayerZeroBridgeHarness.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2025 IEXEC BLOCKCHAIN TECH <contact@iex.ec>
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.22;

import {IexecLayerZeroBridge} from "../bridges/layerZero/IexecLayerZeroBridge.sol";

contract IexecLayerZeroBridgeHarness is IexecLayerZeroBridge {
constructor(bool approvalRequired_, address bridgeableToken, address lzEndpoint)
IexecLayerZeroBridge(approvalRequired_, bridgeableToken, lzEndpoint)
{}

function exposed_debit(address from, uint256 amountLD, uint256 minAmountLD, uint32 dstEid)
external
returns (uint256 amountSentLD, uint256 amountReceivedLD)
{
return _debit(from, amountLD, minAmountLD, dstEid);
}

function exposed_credit(address to, uint256 amountLD, uint32 srcEid) external returns (uint256 amountReceivedLD) {
return _credit(to, amountLD, srcEid);
}
}
18 changes: 14 additions & 4 deletions test/units/RLCLiquidityUnifierUpgrade.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,27 @@ contract RLCLiquidityUnifierUpgradeTest is TestHelperOz5 {
address private upgrader = makeAddr("upgrader");

address public proxyAddress;
string private name = "iEx.ec Network Token";
string public symbol = "RLC";
uint256 public constant NEW_STATE_VARIABLE = 2;

function setUp() public virtual override {
super.setUp();
setUpEndpoints(2, LibraryType.UltraLightNode);
mockEndpoint = address(endpoints[1]);

(,, rlcToken,, rlcLiquidityUnifierV1) =
TestUtils.setupDeployment(name, symbol, mockEndpoint, mockEndpoint, admin, upgrader, pauser);
TestUtils.DeploymentResult memory deploymentResult = TestUtils.setupDeployment(
TestUtils.DeploymentParams({
iexecLayerZeroBridgeContractName: "IexecLayerZeroBridge",
lzEndpointSource: mockEndpoint,
lzEndpointDestination: mockEndpoint,
initialAdmin: admin,
initialUpgrader: upgrader,
initialPauser: pauser
})
);

rlcToken = deploymentResult.rlcToken;
rlcLiquidityUnifierV1 = deploymentResult.rlcLiquidityUnifier;

proxyAddress = address(rlcLiquidityUnifierV1);
}

Expand Down
20 changes: 16 additions & 4 deletions test/units/bridges/layerZero/IexecLayerZeroBridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ contract IexecLayerZeroBridgeTest is TestHelperOz5 {

uint256 private constant INITIAL_BALANCE = 100 * 10 ** 9; // 100 RLC tokens with 9 decimals
uint256 private constant TRANSFER_AMOUNT = 1 * 10 ** 9; // 1 RLC token with 9 decimals
string private name = "iEx.ec Network Token";
string private symbol = "RLC";

function setUp() public virtual override {
super.setUp();
Expand All @@ -51,8 +49,22 @@ contract IexecLayerZeroBridgeTest is TestHelperOz5 {
address lzEndpointSource = address(endpoints[SOURCE_EID]); // Source endpoint for Sepolia - Destination endpoint for Arbitrum Sepolia
address lzEndpointDestination = address(endpoints[DEST_EID]); // Source endpoint for Arbitrum Sepolia - Destination endpoint for Sepolia

(iexecLayerZeroBridgeEthereum, iexecLayerZeroBridgeChainX, rlcToken, rlcCrosschainToken, rlcLiquidityUnifier) =
TestUtils.setupDeployment(name, symbol, lzEndpointSource, lzEndpointDestination, admin, upgrader, pauser);
TestUtils.DeploymentResult memory deploymentResult2 = TestUtils.setupDeployment(
TestUtils.DeploymentParams({
iexecLayerZeroBridgeContractName: "IexecLayerZeroBridge",
lzEndpointSource: lzEndpointSource,
lzEndpointDestination: lzEndpointDestination,
initialAdmin: admin,
initialUpgrader: upgrader,
initialPauser: pauser
})
);

iexecLayerZeroBridgeEthereum = deploymentResult2.iexecLayerZeroBridgeChainA;
iexecLayerZeroBridgeChainX = deploymentResult2.iexecLayerZeroBridgeChainB;
rlcToken = deploymentResult2.rlcToken;
rlcCrosschainToken = deploymentResult2.rlcCrosschainToken;
rlcLiquidityUnifier = deploymentResult2.rlcLiquidityUnifier;

address iexecLayerZeroBridgeEthereumAddress = address(iexecLayerZeroBridgeEthereum);
address iexecLayerZeroBridgeChainXAddress = address(iexecLayerZeroBridgeChainX);
Expand Down
18 changes: 14 additions & 4 deletions test/units/bridges/layerZero/IexecLayerZeroBridgeUpgrade.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,27 @@ contract IexecLayerZeroBridgeUpgradeTest is TestHelperOz5 {
address public pauser = makeAddr("pauser");

address public proxyAddress;
string public name = "iEx.ec Network Token";
string public symbol = "RLC";
Comment on lines -25 to -26
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding those two string memory variables into our utils library caused a Stack too Deep issue. So the library needs to be refactored to use a struct and to improve storage management.

uint256 public constant NEW_STATE_VARIABLE = 2;

function setUp() public virtual override {
super.setUp();
setUpEndpoints(2, LibraryType.UltraLightNode);
mockEndpoint = address(endpoints[1]);

(, iexecLayerZeroBridgeV1,, rlcCrosschainToken,) =
TestUtils.setupDeployment(name, symbol, mockEndpoint, mockEndpoint, admin, upgrader, pauser);
TestUtils.DeploymentResult memory deploymentResult1 = TestUtils.setupDeployment(
TestUtils.DeploymentParams({
iexecLayerZeroBridgeContractName: "IexecLayerZeroBridge",
lzEndpointSource: mockEndpoint,
lzEndpointDestination: mockEndpoint,
initialAdmin: admin,
initialUpgrader: upgrader,
initialPauser: pauser
})
);

iexecLayerZeroBridgeV1 = deploymentResult1.iexecLayerZeroBridgeChainA;
rlcCrosschainToken = deploymentResult1.rlcCrosschainToken;

proxyAddress = address(iexecLayerZeroBridgeV1);
}

Expand Down
120 changes: 76 additions & 44 deletions test/units/utils/TestUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,58 @@ import {Deploy as RLCCrosschainTokenDeployScript} from "../../../script/RLCCross
library TestUtils {
using OptionsBuilder for bytes;

// TODO declare name and symbol inside the function.
function setupDeployment(
string memory name,
string memory symbol,
address lzEndpointSource,
address lzEndpointDestination,
address initialAdmin,
address initialUpgrader,
address initialPauser
)
internal
returns (
IexecLayerZeroBridge iexecLayerZeroBridgeChainA,
IexecLayerZeroBridge iexecLayerZeroBridgeChainB,
RLCMock rlcToken,
RLCCrosschainToken rlcCrosschainToken,
RLCLiquidityUnifier rlcLiquidityUnifier
)
{
address createXFactory = address(new CreateX());
// Struct to hold deployment parameters and reduce stack depth
struct DeploymentParams {
string iexecLayerZeroBridgeContractName;
address lzEndpointSource;
address lzEndpointDestination;
address initialAdmin;
address initialUpgrader;
address initialPauser;
}

// Deploy RLC token mock for L1
rlcToken = new RLCMock();
// Struct to hold deployment results
struct DeploymentResult {
IexecLayerZeroBridge iexecLayerZeroBridgeChainA;
IexecLayerZeroBridge iexecLayerZeroBridgeChainB;
RLCMock rlcToken;
RLCCrosschainToken rlcCrosschainToken;
RLCLiquidityUnifier rlcLiquidityUnifier;
}

// salt for createX
function setupDeployment(DeploymentParams memory params) public returns (DeploymentResult memory result) {
string memory name = "iEx.ec Network Token";
string memory symbol = "RLC";
address createXFactory = address(new CreateX());
bytes32 salt = keccak256("salt");

// Deploy RLC token mock for L1
result.rlcToken = new RLCMock();

// Deploy Liquidity Unifier
rlcLiquidityUnifier = RLCLiquidityUnifier(
result.rlcLiquidityUnifier =
_deployLiquidityUnifier(result.rlcToken, params.initialAdmin, params.initialUpgrader, createXFactory, salt);

// Deploy IexecLayerZeroBridge for Chain A
result.iexecLayerZeroBridgeChainA =
_deployBridge(params, true, address(result.rlcLiquidityUnifier), createXFactory, salt);

// Deploy RLC Crosschain token and Bridge for Chain B
result.rlcCrosschainToken =
_deployCrosschainToken(name, symbol, params.initialAdmin, params.initialUpgrader, createXFactory, salt);

result.iexecLayerZeroBridgeChainB =
_deployBridge(params, false, address(result.rlcCrosschainToken), createXFactory, salt);
}

function _deployLiquidityUnifier(
RLCMock rlcToken,
address initialAdmin,
address initialUpgrader,
address createXFactory,
bytes32 salt
) private returns (RLCLiquidityUnifier) {
return RLCLiquidityUnifier(
UUPSProxyDeployer.deployUUPSProxyWithCreateX(
"RLCLiquidityUnifier",
abi.encode(rlcToken),
Expand All @@ -53,39 +76,48 @@ library TestUtils {
salt
)
);
}

// Deploy IexecLayerZeroBridgeAdapter
iexecLayerZeroBridgeChainA = IexecLayerZeroBridge(
function _deployBridge(
DeploymentParams memory params,
bool approvalRequired,
address bridgeableToken,
address createXFactory,
bytes32 salt
) private returns (IexecLayerZeroBridge) {
return IexecLayerZeroBridge(
UUPSProxyDeployer.deployUUPSProxyWithCreateX(
"IexecLayerZeroBridge",
abi.encode(true, rlcLiquidityUnifier, lzEndpointSource),
params.iexecLayerZeroBridgeContractName,
abi.encode(
approvalRequired,
bridgeableToken,
approvalRequired ? params.lzEndpointSource : params.lzEndpointDestination
),
abi.encodeWithSelector(
IexecLayerZeroBridge.initialize.selector, initialAdmin, initialUpgrader, initialPauser
IexecLayerZeroBridge.initialize.selector,
params.initialAdmin,
params.initialUpgrader,
params.initialPauser
),
createXFactory,
salt
)
);
}

// Deploy RLC Crosschain token (for L2)
rlcCrosschainToken = RLCCrosschainToken(
function _deployCrosschainToken(
string memory name,
string memory symbol,
address initialAdmin,
address initialUpgrader,
address createXFactory,
bytes32 salt
) private returns (RLCCrosschainToken) {
return RLCCrosschainToken(
new RLCCrosschainTokenDeployScript().deploy(
name, symbol, initialAdmin, initialUpgrader, createXFactory, salt
)
);
// Deploy IexecLayerZeroBridge
iexecLayerZeroBridgeChainB = IexecLayerZeroBridge(
UUPSProxyDeployer.deployUUPSProxyWithCreateX(
"IexecLayerZeroBridge",
abi.encode(false, rlcCrosschainToken, lzEndpointDestination),
abi.encodeWithSelector(
IexecLayerZeroBridge.initialize.selector, initialAdmin, initialUpgrader, initialPauser
),
createXFactory,
salt
)
);
// TODO: see if it's possible to authorize the bridge here.
}

/**
Expand Down