Skip to content

Conversation

@efecarranza
Copy link
Contributor

@efecarranza efecarranza commented Jun 3, 2025

Changelog

Add CCIP Bridge for Aave to transfer GHO from mainnet to pre-defined networks.
Add fork tests.
Add unit tests.

@efecarranza efecarranza marked this pull request as ready for review June 7, 2025 10:40
@efecarranza efecarranza changed the title [DRAFT] CCIP Bridge CCIP Bridge Jun 7, 2025
vm.selectFork(mainnetFork);
uint128 limit = mainnetBridge.getRateLimit(ARBITRUM_CHAIN_SELECTOR);

vm.assume(amount > limit && amount < 1e32); // made top limit to prevent arithmetic overflow

Choose a reason for hiding this comment

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

Might be better to use bound here in case of running with very high fuzz runs, to avoid vm.assume rejecting too many inputs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point!


bridge = new AaveGhoCcipBridge(address(mockRouter), address(mockGho), collector, admin);

vm.startPrank(alice);

Choose a reason for hiding this comment

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

small nit: No need to start and stop prank, can just use vm.prank(alice)

@efecarranza
Copy link
Contributor Author

@CheyenneAtapour updated! thanks

Choose a reason for hiding this comment

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

empty

Choose a reason for hiding this comment

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

is this contract provided by chainlink? wondering if makes sense to move this file and Client lib into a dedicated chainlink folder, under the ccip one

*
* -- Permissions
* The contract implements AccessControl for permissioned functions.
* The DEFAULT_ADMIN will always be the respective network's Short Executor (Governance).
Copy link

@miguelmtzinf miguelmtzinf Jul 14, 2025

Choose a reason for hiding this comment

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

level 1 instead of short

* @title AaveGhoCcipBridge
* @author TokenLogic
* @notice It provides bridging capabilities for the GHO token across networks.
*

Choose a reason for hiding this comment

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

I d move the spec to a README file

Comment on lines 80 to 85
/**
* @param router The address of the Chainlink CCIP router
* @param gho The address of the GHO token
* @param collector The address of collector on same chain
* @param executor The address of the contract executor
*/

Choose a reason for hiding this comment

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

Suggested change
/**
* @param router The address of the Chainlink CCIP router
* @param gho The address of the GHO token
* @param collector The address of collector on same chain
* @param executor The address of the contract executor
*/
/**
* @dev Constructor
* @param router The address of the Chainlink CCIP router
* @param gho The address of the GHO token
* @param collector The address of the Aave Collector
* @param initialAdmin The address of the initial admin
*/

Choose a reason for hiding this comment

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

(and the last param in the constructor should change to match ofc)

address public immutable COLLECTOR;

/// @inheritdoc IAaveGhoCcipBridge
address public immutable EXECUTOR;

Choose a reason for hiding this comment

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

I d remove this and use a role for whoCanRescue or just the default admin role.
It's confusing having 2 access control systems in the same contract: access control and dedicated executor access control for rescue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what would you return in whoCanRescue() for the address? didn't understand that part.
something like:

whoCanRescue() {
if (hasRole(DEFAULT_ADMIN, msg.sender) return msg.sender

?

Copy link

@miguelmtzinf miguelmtzinf Jul 25, 2025

Choose a reason for hiding this comment

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

it seems you gotta use RescuableACL instead and add proper ACL checks to _checkRescueGuardian. We can use DEFAULT_ADMIN or an ad-hoc role, no strong opinion

uint128 limit = _getRateLimit(chainSelector);
if (amount > limit) {
revert RateLimitExceeded(limit);
}

Choose a reason for hiding this comment

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

not checking for bridge limit on Ethereum. Both things (rate limit and bridge limit) will be checked later when executing the transfer on CCIP side, so we can remove both checks if we wanna rely on them

Copy link
Contributor Author

Choose a reason for hiding this comment

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

didn't understand the first part of not checking for bridge limit on Ethereum.

Copy link

@miguelmtzinf miguelmtzinf Jul 25, 2025

Choose a reason for hiding this comment

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

a bit of literature about GHO CCIP and bridge limit: https://www.llamarisk.com/research/explainer-series-ccip
I d suggest to remove rate limit check and keep this simple

Copy link
Contributor

@brotherlymite brotherlymite Aug 5, 2025

Choose a reason for hiding this comment

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

agree on this, we validate the rateLimit on TokenPool contract already so cleaner to remove from here

if (feeToken == address(0)) {
if (msg.value < fee) revert InsufficientFee();
} else {
IERC20(feeToken).transferFrom(msg.sender, address(this), fee);
Copy link

@miguelmtzinf miguelmtzinf Jul 14, 2025

Choose a reason for hiding this comment

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

why we do 2 transfers of GHO instead of 1. Separately, pls use safeTransfer

Choose a reason for hiding this comment

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

ah, was assuming we only work with GHO as fee token if not ETH.

* @param feeToken The address of the fee token (use address(0) for fee in native token)
* @return message EVM2AnyMessage to transfer GHO cross-chain
*/
function _buildCCIPMessage(uint64 chainSelector, uint256 amount, uint256 gasLimit, address feeToken)

Choose a reason for hiding this comment

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

do we wanna put any restriction on feeToken?
also, what happens if the token is not supported by CCIP. Cannot recall where it d fail

Copy link
Contributor Author

Choose a reason for hiding this comment

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

}

/// @inheritdoc IAaveGhoCcipBridge
function setDestinationChain(uint64 chainSelector, address bridge) external onlyRole(DEFAULT_ADMIN_ROLE) {

Choose a reason for hiding this comment

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

what is the permissions hierarchy / model? Everything is under default admin role...
is just that we wanna have multiple admins?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

to me, these set functions should only be done via governance, which would be the admin.
for bridging, i'd allow a guardian (bridger role) to call that so it can be assigned to an allowed party like the aave finance committee

function removeDestinationChain(uint64 chainSelector) external onlyRole(DEFAULT_ADMIN_ROLE) {
delete destinations[chainSelector];

emit DestinationChainRemoved(chainSelector);

Choose a reason for hiding this comment

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

feels that this can be replaced with emit DestinationChainSet(chainSelector, address(0));

revert UnknownSourceDestination();
}

_ccipReceive(message);

Choose a reason for hiding this comment

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

i don't think an internal method is needed here, only used once

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's overriding the CCIPReceiver.sol abstract contract

}

/// @inheritdoc IAaveGhoCcipBridge
function processMessage(Client.Any2EVMMessage calldata message) external onlySelf {

Choose a reason for hiding this comment

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

why this cannot be internal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

try/catch on solidity only works for external methods

try this.processMessage(message) {}
catch (bytes memory err) {
failedMessages[message.messageId] = true;
failedTokenTransfers[message.messageId] = message;

Choose a reason for hiding this comment

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

we got feedback from Chainlink saying that it's not needed to store the entire msg, can you revisit that please?

Choose a reason for hiding this comment

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

reference: #347 (comment)

@github-actions
Copy link
Contributor

🌈 Test Results zksync
Compiling 112 files with Solc 0.8.24
Solc 0.8.24 finished in 5.77s
Compiler run successful!

Compiling 112 files with zksolc and solc 0.8.24
zksolc and solc 0.8.24 finished in 75.65s
Compiler run successful with warnings:
Warning
Warning: You are using 'create'/'create2' in an assembly block, probably by providing bytecode and expecting an EVM-like behavior.
EraVM does not use bytecode for contract deployment. Instead, it refers to contracts using their bytecode hashes.
In order to deploy a contract, please use the `new` operator in Solidity instead of raw 'create'/'create2' in assembly.
In Solidity v0.6 and older, it can be a false-positive warning if there is 'create(' or 'create2(' in comments within assembly.
Learn more about CREATE/CREATE2 EraVM limitations at https: //docs.zksync.io/zksync-protocol/differences/evm-instructions#create-create2

You may disable this warning with:
    1. `suppressedWarnings = ["assemblycreate"]` in standard JSON.
    2. `--suppress-warnings assemblycreate` in the CLI.
    --> lib/forge-std/src/StdCheats.sol: 506:19
     |
 506 |             addr := create(0, add(bytecode, 0x20), mload(bytecode))
     |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Warning
Warning: You are using 'create'/'create2' in an assembly block, probably by providing bytecode and expecting an EVM-like behavior.
EraVM does not use bytecode for contract deployment. Instead, it refers to contracts using their bytecode hashes.
In order to deploy a contract, please use the `new` operator in Solidity instead of raw 'create'/'create2' in assembly.
In Solidity v0.6 and older, it can be a false-positive warning if there is 'create(' or 'create2(' in comments within assembly.
Learn more about CREATE/CREATE2 EraVM limitations at https: //docs.zksync.io/zksync-protocol/differences/evm-instructions#create-create2

You may disable this warning with:
    1. `suppressedWarnings = ["assemblycreate"]` in standard JSON.
    2. `--suppress-warnings assemblycreate` in the CLI.
    --> lib/forge-std/src/StdCheats.sol: 516:19
     |
 516 |             addr := create(0, add(bytecode, 0x20), mload(bytecode))
     |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Warning
Warning: You are using 'create'/'create2' in an assembly block, probably by providing bytecode and expecting an EVM-like behavior.
EraVM does not use bytecode for contract deployment. Instead, it refers to contracts using their bytecode hashes.
In order to deploy a contract, please use the `new` operator in Solidity instead of raw 'create'/'create2' in assembly.
In Solidity v0.6 and older, it can be a false-positive warning if there is 'create(' or 'create2(' in comments within assembly.
Learn more about CREATE/CREATE2 EraVM limitations at https: //docs.zksync.io/zksync-protocol/differences/evm-instructions#create-create2

You may disable this warning with:
    1. `suppressedWarnings = ["assemblycreate"]` in standard JSON.
    2. `--suppress-warnings assemblycreate` in the CLI.
    --> lib/forge-std/src/StdCheats.sol: 527:19
     |
 527 |             addr := create(val, add(bytecode, 0x20), mload(bytecode))
     |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Warning
Warning: You are using 'create'/'create2' in an assembly block, probably by providing bytecode and expecting an EVM-like behavior.
EraVM does not use bytecode for contract deployment. Instead, it refers to contracts using their bytecode hashes.
In order to deploy a contract, please use the `new` operator in Solidity instead of raw 'create'/'create2' in assembly.
In Solidity v0.6 and older, it can be a false-positive warning if there is 'create(' or 'create2(' in comments within assembly.
Learn more about CREATE/CREATE2 EraVM limitations at https: //docs.zksync.io/zksync-protocol/differences/evm-instructions#create-create2

You may disable this warning with:
    1. `suppressedWarnings = ["assemblycreate"]` in standard JSON.
    2. `--suppress-warnings assemblycreate` in the CLI.
    --> lib/forge-std/src/StdCheats.sol: 537:19
     |
 537 |             addr := create(val, add(bytecode, 0x20), mload(bytecode))
     |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

2025-07-15T11:16:15.223187Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:15.545376Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:25.596472Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:38.343733Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:38.569581Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:38.794992Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:39.533608Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:39.999165Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:40.876242Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:41.298624Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:42.092081Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:42.883777Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:43.998173Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:44.591459Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:45.016863Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:46.099285Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:46.329908Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:46.548705Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:47.244779Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:47.652491Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:48.696039Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:49.156614Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:49.965556Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:50.792467Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:51.869054Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:52.889680Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:53.319453Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:54.387245Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:54.613006Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:54.830968Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:55.516719Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:55.934435Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:56.776886Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:57.218561Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:58.004324Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:58.772804Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:16:59.793902Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:00.612968Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:01.021085Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:02.088797Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:02.317293Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:02.534171Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:03.219525Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:03.628833Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:04.508910Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:04.940945Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:05.758674Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:06.533441Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:07.615410Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:08.448997Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:08.846594Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:09.866524Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:10.088807Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:10.298448Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:10.974269Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:11.375495Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:12.229737Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:12.761253Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:13.543134Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:14.357244Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:15.394381Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:16.272582Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2
2025-07-15T11:17:16.703328Z ERROR foundry_zksync_core::vm::inspect: reverting initiator tx nonce for CALL address=0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38 from=3 to=2 deploy_nonce=2

Ran 1 test for zksync/tests/ProtocolV3TestBase.t.sol:ProtocolV3TestBaseTest
[PASS] test_helpers() (gas: 86657142)
Logs:
  0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4
  0x493257fD37EDB34451f62EDf8D2a0C418852bA4C
  0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91
  0x703b52F2b28fEbcB60E1372858AF5b18849FE867
  0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E
  E2E: Collateral USDC, TestAsset USDC
  SUPPLY: USDC, Amount: 100021569651
  SUPPLY: USDC, Amount: 1000215696
  WITHDRAW: USDC, Amount: 500107848
  WITHDRAW: USDC, Amount: 500107848
  BORROW: USDC, Amount 1000215696
  REPAY: USDC, Amount: 1000215696
  E2E: Collateral USDC, TestAsset USDT
  SUPPLY: USDC, Amount: 100021569651
  SUPPLY: USDT, Amount: 999072570
  WITHDRAW: USDT, Amount: 499536285
  WITHDRAW: USDT, Amount: 499536284
  BORROW: USDT, Amount 999072570
  REPAY: USDT, Amount: 999072570
  E2E: Collateral USDC, TestAsset WETH
  SUPPLY: USDC, Amount: 100021569651
  SUPPLY: WETH, Amount: 247815794951065425
  WITHDRAW: WETH, Amount: 123907897475532712
  WITHDRAW: WETH, Amount: 123907897475532714
  BORROW: WETH, Amount 247815794951065425
  REPAY: WETH, Amount: 247815794951065425
  E2E: Collateral USDC, TestAsset wstETH
  SUPPLY: USDC, Amount: 100021569651
  SUPPLY: wstETH, Amount: 208779402016001902
  WITHDRAW: wstETH, Amount: 104389701008000951
  WITHDRAW: wstETH, Amount: 104389701008000952
  BORROW: wstETH, Amount 208779402016001902
  REPAY: wstETH, Amount: 208779402016001902
  E2E: Collateral USDC, TestAsset ZK
  SUPPLY: USDC, Amount: 100021569651
  SUPPLY: ZK, Amount: 3854761082871773878172
  WITHDRAW: ZK, Amount: 1927380541435886939086
  WITHDRAW: ZK, Amount: 1927380541435886939085
  BORROW: ZK, Amount 3854761082871773878172
  REPAY: ZK, Amount: 3854761082871773878172

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 63.11s (61.23s CPU time)

Ran 1 test suite in 63.12s (63.11s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

@github-actions
Copy link
Contributor

github-actions bot commented Jul 15, 2025

♻️ Forge Gas Snapshots

Seems like you are not measuring gas of any operations yet. 🤔
Consider adding some snapshot tests to measure regressions & improvements.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 15, 2025

Forge Build Sizes

🔕 Unchanged
Contract Runtime Size (B) Initcode Size (B) Runtime Margin (B) Initcode Margin (B)
AaveArbEthERC20Bridge 4,965 5,532 19,611 43,620
AaveGhoCcipBridge 18,244 19,937 6,332 29,215
AaveGovernanceV2 85 160 24,491 48,992
AaveOpEthERC20Bridge 4,215 4,782 20,361 44,370
AavePolEthERC20Bridge 5,540 6,107 19,036 43,045
AavePolEthPlasmaBridge 4,801 5,368 19,775 43,784
AaveSwapper 7,867 8,571 16,709 40,581
AaveV2Avalanche 85 160 24,491 48,992
AaveV2AvalancheAssets 85 160 24,491 48,992
AaveV2ConfigEngine 4,830 5,719 19,746 43,433
AaveV2Ethereum 85 160 24,491 48,992
AaveV2EthereumAMM 85 160 24,491 48,992
AaveV2EthereumAMMAssets 85 160 24,491 48,992
AaveV2EthereumAssets 85 160 24,491 48,992
AaveV2EthereumRatesUpdate 2,431 2,730 22,145 46,422
AaveV2Polygon 85 160 24,491 48,992
AaveV2PolygonAssets 85 160 24,491 48,992
AaveV3Arbitrum 85 160 24,491 48,992
AaveV3ArbitrumAssets 85 160 24,491 48,992
AaveV3ArbitrumEModes 85 160 24,491 48,992
AaveV3ArbitrumExternalLibraries 85 160 24,491 48,992
AaveV3Avalanche 85 160 24,491 48,992
AaveV3AvalancheAssets 85 160 24,491 48,992
AaveV3AvalancheCollateralUpdate 8,472 8,899 16,104 40,253
AaveV3AvalancheCollateralUpdateCorrectBonus 8,472 8,899 16,104 40,253
AaveV3AvalancheCollateralUpdateNoChange 8,598 9,025 15,978 40,127
AaveV3AvalancheCollateralUpdateWrongBonus 8,472 8,899 16,104 40,253
AaveV3AvalancheEModeCategoryUpdateEdgeBonus 8,272 8,699 16,304 40,453
AaveV3AvalancheEModeCategoryUpdateNoChange 8,495 8,922 16,081 40,230
AaveV3AvalancheEModes 85 160 24,491 48,992
AaveV3AvalancheExternalLibraries 85 160 24,491 48,992
AaveV3BNB 85 160 24,491 48,992
AaveV3BNBAssets 85 160 24,491 48,992
AaveV3BNBEModes 85 160 24,491 48,992
AaveV3BNBExternalLibraries 85 160 24,491 48,992
AaveV3Base 85 160 24,491 48,992
AaveV3BaseAssets 85 160 24,491 48,992
AaveV3BaseEModes 85 160 24,491 48,992
AaveV3BaseExternalLibraries 85 160 24,491 48,992
AaveV3Celo 85 160 24,491 48,992
AaveV3CeloAssets 85 160 24,491 48,992
AaveV3CeloEModes 85 160 24,491 48,992
AaveV3CeloExternalLibraries 85 160 24,491 48,992
AaveV3Ethereum 85 160 24,491 48,992
AaveV3EthereumAssetEModeUpdate 8,267 8,694 16,309 40,458
AaveV3EthereumAssets 85 160 24,491 48,992
AaveV3EthereumEModes 85 160 24,491 48,992
AaveV3EthereumEtherFi 85 160 24,491 48,992
AaveV3EthereumEtherFiAssets 85 160 24,491 48,992
AaveV3EthereumEtherFiEModes 85 160 24,491 48,992
AaveV3EthereumEtherFiExternalLibraries 85 160 24,491 48,992
AaveV3EthereumExternalLibraries 85 160 24,491 48,992
AaveV3EthereumLido 85 160 24,491 48,992
AaveV3EthereumLidoAssets 85 160 24,491 48,992
AaveV3EthereumLidoEModes 85 160 24,491 48,992
AaveV3EthereumLidoExternalLibraries 85 160 24,491 48,992
AaveV3EthereumMockCapUpdate 8,389 8,816 16,187 40,336
AaveV3Fantom 85 160 24,491 48,992
AaveV3FantomAssets 85 160 24,491 48,992
AaveV3Gnosis 85 160 24,491 48,992
AaveV3GnosisAssets 85 160 24,491 48,992
AaveV3GnosisEModes 85 160 24,491 48,992
AaveV3GnosisExternalLibraries 85 160 24,491 48,992
AaveV3InkWhitelabel 85 160 24,491 48,992
AaveV3InkWhitelabelAssets 85 160 24,491 48,992
AaveV3InkWhitelabelEModes 85 160 24,491 48,992
AaveV3InkWhitelabelExternalLibraries 85 160 24,491 48,992
AaveV3Linea 85 160 24,491 48,992
AaveV3LineaAssets 85 160 24,491 48,992
AaveV3LineaEModes 85 160 24,491 48,992
AaveV3LineaExternalLibraries 85 160 24,491 48,992
AaveV3Mantle 85 160 24,491 48,992
AaveV3MantleAssets 85 160 24,491 48,992
AaveV3MantleEModes 85 160 24,491 48,992
AaveV3MantleExternalLibraries 85 160 24,491 48,992
AaveV3Metis 85 160 24,491 48,992
AaveV3MetisAssets 85 160 24,491 48,992
AaveV3MetisEModes 85 160 24,491 48,992
AaveV3MetisExternalLibraries 85 160 24,491 48,992
AaveV3Optimism 85 160 24,491 48,992
AaveV3OptimismAssets 85 160 24,491 48,992
AaveV3OptimismEModes 85 160 24,491 48,992
AaveV3OptimismExternalLibraries 85 160 24,491 48,992
AaveV3OptimismMockRatesUpdate 8,716 9,143 15,860 40,009
AaveV3Plasma 85 160 24,491 48,992
AaveV3PlasmaAssets 85 160 24,491 48,992
AaveV3PlasmaEModes 85 160 24,491 48,992
AaveV3PlasmaExternalLibraries 85 160 24,491 48,992
AaveV3Polygon 85 160 24,491 48,992
AaveV3PolygonAssets 85 160 24,491 48,992
AaveV3PolygonBorrowUpdate 8,469 8,896 16,107 40,256
AaveV3PolygonBorrowUpdateNoChange 8,598 9,025 15,978 40,127
AaveV3PolygonEModeCategoryUpdate 8,272 8,699 16,304 40,453
AaveV3PolygonEModes 85 160 24,491 48,992
AaveV3PolygonExternalLibraries 85 160 24,491 48,992
AaveV3PolygonPriceFeedUpdate 8,298 8,725 16,278 40,427
AaveV3Scroll 85 160 24,491 48,992
AaveV3ScrollAssets 85 160 24,491 48,992
AaveV3ScrollEModes 85 160 24,491 48,992
AaveV3ScrollExternalLibraries 85 160 24,491 48,992
AaveV3Soneium 85 160 24,491 48,992
AaveV3SoneiumAssets 85 160 24,491 48,992
AaveV3SoneiumEModes 85 160 24,491 48,992
AaveV3SoneiumExternalLibraries 85 160 24,491 48,992
AaveV3Sonic 85 160 24,491 48,992
AaveV3SonicAssets 85 160 24,491 48,992
AaveV3SonicEModes 85 160 24,491 48,992
AaveV3SonicExternalLibraries 85 160 24,491 48,992
AaveV3ZkSync 85 160 24,491 48,992
AaveV3ZkSyncAssets 85 160 24,491 48,992
AaveV3ZkSyncEModes 85 160 24,491 48,992
AaveV3ZkSyncExternalLibraries 85 160 24,491 48,992
Address 85 160 24,491 48,992
ArbSysMock 1,234 1,262 23,342 47,890
CallWithExactGas 85 160 24,491 48,992
CapsPlusRiskSteward 4,384 5,056 20,192 44,096
CapsPlusRiskStewardErrors 831 908 23,745 48,244
ChainHelpers 85 160 24,491 48,992
ChainIds 85 160 24,491 48,992
ChainlinkEthereum 85 160 24,491 48,992
Client 271 348 24,305 48,804
CollectorUtils 85 160 24,491 48,992
ConfiguratorInputTypes (lib/aave-address-book/lib/aave-v3-origin/src/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol) 85 160 24,491 48,992
ConfiguratorInputTypes (lib/aave-address-book/src/AaveV2.sol) 85 160 24,491 48,992
Constants 1,561 1,589 23,015 47,563
Create2Utils 240 316 24,336 48,836
Create2UtilsZkSync 223 299 24,353 48,853
DataTypes (lib/aave-address-book/lib/aave-v3-origin/src/contracts/protocol/libraries/types/DataTypes.sol) 85 160 24,491 48,992
DataTypes (lib/aave-address-book/src/AaveV2.sol) 85 160 24,491 48,992
DefaultReserveInterestRateStrategy 5,508 6,678 19,068 42,474
DeployV2EngineAvaLib 85 160 24,491 48,992
DeployV2EngineEthAMMLib 85 160 24,491 48,992
DeployV2EngineEthLib 85 160 24,491 48,992
DeployV2EnginePolLib 85 160 24,491 48,992
DeployV2RatesFactoryAvaLib 85 160 24,491 48,992
DeployV2RatesFactoryEthAMMLib 85 160 24,491 48,992
DeployV2RatesFactoryEthLib 85 160 24,491 48,992
DeployV2RatesFactoryLib 85 160 24,491 48,992
DeployV2RatesFactoryPolLib 85 160 24,491 48,992
ERC165Checker 85 160 24,491 48,992
ERC20Mock 3,913 4,869 20,663 44,283
EngineFlags 85 160 24,491 48,992
Errors (lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Errors.sol) 85 160 24,491 48,992
Errors (lib/aave-address-book/lib/aave-v3-origin/src/contracts/protocol/libraries/helpers/Errors.sol) 85 160 24,491 48,992
Errors (lib/aave-address-book/src/AaveV2.sol) 8,323 8,400 16,253 40,752
Errors (lib/aave-address-book/src/governance-v3/Errors.sol) 10,003 10,080 14,573 39,072
FreezingSteward 1,295 1,731 23,281 47,421
GhoArbitrum 85 160 24,491 48,992
GovV3Helpers 3,851 3,928 20,725 45,224
GovV3StorageHelpers 85 160 24,491 48,992
GovernanceV3Arbitrum 85 160 24,491 48,992
GovernanceV3Avalanche 85 160 24,491 48,992
GovernanceV3BNB 85 160 24,491 48,992
GovernanceV3Base 85 160 24,491 48,992
GovernanceV3Celo 85 160 24,491 48,992
GovernanceV3Ethereum 85 160 24,491 48,992
GovernanceV3Gnosis 85 160 24,491 48,992
GovernanceV3Ink 85 160 24,491 48,992
GovernanceV3InkWhitelabel 85 160 24,491 48,992
GovernanceV3Linea 85 160 24,491 48,992
GovernanceV3Mantle 85 160 24,491 48,992
GovernanceV3Metis 85 160 24,491 48,992
GovernanceV3Optimism 85 160 24,491 48,992
GovernanceV3Plasma 85 160 24,491 48,992
GovernanceV3Polygon 85 160 24,491 48,992
GovernanceV3PolygonZkEvm 85 160 24,491 48,992
GovernanceV3Scroll 85 160 24,491 48,992
GovernanceV3Soneium 85 160 24,491 48,992
GovernanceV3Sonic 85 160 24,491 48,992
GovernanceV3ZkSync 85 160 24,491 48,992
IpfsUtils 85 160 24,491 48,992
Math 85 160 24,491 48,992
MiscAvalanche 85 160 24,491 48,992
MiscEthereum 85 160 24,491 48,992
MiscPolygon 85 160 24,491 48,992
MockAggregator 431 709 24,145 48,443
MockCCIPRouter 8,611 8,639 15,965 40,513
MyPayload (tests/swaps/DepositV2SwapPayloadTest.t.sol) 1,529 1,617 23,047 47,535
MyPayload (tests/swaps/DepositV3SwapPayloadTest.t.sol) 1,529 1,617 23,047 47,535
Ownable (lib/aave-address-book/lib/aave-v3-origin/src/contracts/dependencies/openzeppelin/contracts/Ownable.sol) 1,457 1,665 23,119 47,487
Panic 85 160 24,491 48,992
PayloadWithEmit 150 176 24,426 48,976
PayloadsControllerUtils 85 160 24,491 48,992
PercentageMath (lib/aave-address-book/lib/aave-v3-origin/src/contracts/protocol/libraries/math/PercentageMath.sol) 85 160 24,491 48,992
PercentageMath (src/dependencies/PercentageMath.sol) 85 160 24,491 48,992
ProxyHelpers (lib/aave-address-book/lib/aave-v3-origin/src/../tests/utils/ProxyHelpers.sol) 85 160 24,491 48,992
ProxyHelpers (lib/aave-address-book/lib/aave-v3-origin/tests/utils/ProxyHelpers.sol) 85 160 24,491 48,992
Register 2,758 18,453 21,818 30,699
ReserveConfiguration 274 351 24,302 48,801
SafeCast 85 160 24,491 48,992
SafeERC20 85 160 24,491 48,992
SafeMath 85 160 24,491 48,992
SignedMath 85 160 24,491 48,992
StorageHelpers 85 160 24,491 48,992
Strings (lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Strings.sol) 85 160 24,491 48,992
Strings (lib/aave-address-book/lib/aave-v3-origin/src/contracts/dependencies/openzeppelin/contracts/Strings.sol) 85 160 24,491 48,992
TestNetChainIds 85 160 24,491 48,992
V2RateStrategyFactory 13,226 13,525 11,350 35,627
WadRayMath (lib/aave-address-book/lib/aave-v3-origin/src/contracts/protocol/libraries/math/WadRayMath.sol) 85 160 24,491 48,992
WadRayMath (src/dependencies/WadRayMath.sol) 85 160 24,491 48,992

/**
* @title AaveGhoCcipBridge
* @author TokenLogic
* @notice It provides bridging capabilities for the GHO token across networks.

Choose a reason for hiding this comment

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

Remove the word 'It' from the beginning

Suggested change
* @notice It provides bridging capabilities for the GHO token across networks.
* @notice Provides bridging capabilities for the GHO token across networks.

) external view returns (Client.EVMTokenAmount[] memory);

/**
* @dev Returns the bridge rate limit for a given chain.

Choose a reason for hiding this comment

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

Suggested change
* @dev Returns the bridge rate limit for a given chain.
* @notice Returns the bridge rate limit for a given chain.

uint256 fee = IRouterClient(ROUTER).getFee(chainSelector, message);

if (feeToken == address(0)) {
if (msg.value < fee) revert InsufficientFee();

Choose a reason for hiding this comment

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

should we refund the user ETH if they supply excess fee?

Copy link
Contributor Author

@efecarranza efecarranza Sep 3, 2025

Choose a reason for hiding this comment

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

@CheyenneAtapour I replaced the payback in order to simplify the logic. The extra ETH can be withdrawn by the Rescuable functions and i don't really envision ETH being used much to be honest.
The caller is always going to be governance, I'm also thinking of moving this back to Ownable.

What do you think? @miguelmtzinf

Choose a reason for hiding this comment

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

sounds good. However, if the purpose of the contract is to be pre-funded always, we can remove this logic of pulling funds from sender and the payable (we should add a receive instead)

revert UnsupportedChain();
}

uint128 limit = _getRateLimit(chainSelector);
Copy link

@miguelmtzinf miguelmtzinf Sep 4, 2025

Choose a reason for hiding this comment

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

we are not checking bridgeLimit on ETH token pool. We can either check both things or none of them (this is for better devx, as it d revert anyway)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@miguelmtzinf i have updated to check the current remaining limit (bridge - bridgedAmount), as it's most likely going to be an unreachable statement as the rateLimit is never going to be greater than the bridgeLimit itself.

}

/// @inheritdoc CCIPReceiver
function ccipReceive(Client.Any2EVMMessage calldata message) external override onlyRouter {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

On processMessage() we are checking if message.sender is the bridge configured.

@efecarranza
Copy link
Contributor Author

@miguelmtzinf @CheyenneAtapour @brotherlymite i have updated the PR. thank you

Comment on lines 24 to 26
* @dev The fee token must be pre-funded for the bridge message to be sent. When doing a governance
* proposal ensure funds are present on this contract beforehand (GHO/LINK) or transfer funds from the
* treasury as part of the proposal.

Choose a reason for hiding this comment

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

Suggested change
* @dev The fee token must be pre-funded for the bridge message to be sent. When doing a governance
* proposal ensure funds are present on this contract beforehand (GHO/LINK) or transfer funds from the
* treasury as part of the proposal.
* @dev The fees required for bridge messages must be available in advance. For governance proposals, ensure
* this contract is pre-funded with the necessary tokens (GHO/LINK), or include a transfer from the treasury
* as part of the proposal.

address public immutable COLLECTOR;

/// @inheritdoc IAaveGhoCcipBridge
mapping(uint64 chainSelector => RemoteChainConfig remoteConfig) public destinations;

Choose a reason for hiding this comment

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

Suggested change
mapping(uint64 chainSelector => RemoteChainConfig remoteConfig) public destinations;
mapping(uint64 chainSelector => RemoteChainConfig) public destinations;

just because this was added in 0.8.18 and may bring a bit of friction for integrations

Choose a reason for hiding this comment

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

same with the rest


/// https://etherscan.io/address/0x06179f7C1be40863405f374E7f5F8806c728660A
/// @dev Upgradeable contract so address unlikely to change
address public constant MAINNET_TOKEN_POOL = 0x06179f7C1be40863405f374E7f5F8806c728660A;

Choose a reason for hiding this comment

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

we must fetch this from the router

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this isn't available in the router, didn't know where to fetch it from

Choose a reason for hiding this comment

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

router.getOnRamp(destionationChainSelector).getPoolBySourceToken(destionationChainSelector, GHO_TOKEN)

* @param messageId The ID of the cross-chain message
* @param destinationChainSelector The selector of the destination chain
* @param from The address of sender on source chain
* @param amount The total amount of GHO transfered

Choose a reason for hiding this comment

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

Suggested change
* @param amount The total amount of GHO transfered
* @param amount The total amount of GHO transferred

Comment on lines 9 to 11
import {RescuableBase, IRescuableBase} from 'solidity-utils/contracts/utils/RescuableBase.sol';

import {Client} from 'src/dependencies/chainlink/libraries/Client.sol';

Choose a reason for hiding this comment

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

Suggested change
import {RescuableBase, IRescuableBase} from 'solidity-utils/contracts/utils/RescuableBase.sol';
import {Client} from 'src/dependencies/chainlink/libraries/Client.sol';
import {RescuableBase, IRescuableBase} from 'solidity-utils/contracts/utils/RescuableBase.sol';
import {Client} from 'src/dependencies/chainlink/libraries/Client.sol';


/// @dev Map containing failed token transfer amounts for a message
mapping(bytes32 messageId => Client.EVMTokenAmount[] destTokenAmounts)
private _failedTokenTransfers;

Choose a reason for hiding this comment

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

Suggested change
private _failedTokenTransfers;
internal _failedTokenTransfers;

internal is fine, same with _failedMessages

uint256 fee = IRouterClient(ROUTER).getFee(chainSelector, message);

if (feeToken == address(0)) {
if (msg.value < fee) revert InsufficientFee();

Choose a reason for hiding this comment

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

sounds good. However, if the purpose of the contract is to be pre-funded always, we can remove this logic of pulling funds from sender and the payable (we should add a receive instead)

// Only applicable to Mainnet
// Should be unreachable as it's unlikely to be lower than the rate limit
if (block.chainid == 1) {
uint256 bridgeLimit = ITokenPool(MAINNET_TOKEN_POOL).getBridgeLimit() -

Choose a reason for hiding this comment

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

Suggested change
uint256 bridgeLimit = ITokenPool(MAINNET_TOKEN_POOL).getBridgeLimit() -
uint256 availableToBridge = ITokenPool(MAINNET_TOKEN_POOL).getBridgeLimit() -

}

// Only applicable to Mainnet
// Should be unreachable as it's unlikely to be lower than the rate limit

Choose a reason for hiding this comment

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

this is wrong, because the rate limit gets replenished based on the velocity (token per second), and bridge limit does not.

*/
function destinations(
uint64 chainSelector
) external view returns (bytes memory, bytes memory, uint32);

Choose a reason for hiding this comment

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

weird that we are exposing 3 bytes when we have our own struct for this (RemoteChainConfig) here, and exposing a CCIP struct (Client.EVMTokenAmount[]) on getInvalidMessage. From the integration pov i think it d be better to use our own struct for getInvalidMessage so it's easy to consume.

transferOwnership(initialOwner);
}

/// @dev Default receive function so the contract can be sent Ether

Choose a reason for hiding this comment

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

Suggested change
/// @dev Default receive function so the contract can be sent Ether
/// @dev Default receive function enabling the contract to accept native tokens

address public immutable COLLECTOR;

/// @dev Map containing destination chain's configuration
mapping(uint64 => RemoteChainConfig) internal destinations;

Choose a reason for hiding this comment

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

Suggested change
mapping(uint64 => RemoteChainConfig) internal destinations;
mapping(uint64 => RemoteChainConfig) internal _destinations;

gasLimit: gasLimit
});

emit DestinationChainSet(chainSelector, destination, gasLimit);
Copy link

@miguelmtzinf miguelmtzinf Sep 16, 2025

Choose a reason for hiding this comment

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

not emitting extraArgs here.

extraArgs: remoteConfig.extraArgsOverride.length > 0
? remoteConfig.extraArgsOverride
: Client._argsToBytes(
Client.GenericExtraArgs({gasLimit: remoteConfig.gasLimit, allowOutOfOrderExecution: true})

Choose a reason for hiding this comment

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

so how gasLimit would work here? it will always use the configured value and never the default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it will use the configured, I ran tests with chainlink and not using the default for EVM chains would save > 100,000 gas.

Copy link
Contributor Author

@efecarranza efecarranza Sep 16, 2025

Choose a reason for hiding this comment

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


### Destination Addresses

The destination chain address must be provided as bytes. For EVM chains, convert the address to bytes with `abi.encode(address)`, where address if an EVM address. For Solana/Aptos, `abi.encode(bytes32)` where bytes32 is the Aptos/Solana address.

Choose a reason for hiding this comment

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

We can remove this paragraph, favoring the one below

/**
* Struct representing a destination chain
* @return extraArgsOverride Any extra arguments to pass with message to the destination chain
* @return bridge The bytes representation of an address (EVM or non-EVM)

Choose a reason for hiding this comment

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

this should be destination and should be the first return

/// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165.
/// the contract is called. If not, only tokens are transferred.
/// @return success A boolean value indicating whether the ccip message was received without errors.
/// @return retBytes A bytes array containing return data form CCIP receiver.

Choose a reason for hiding this comment

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

Suggested change
/// @return retBytes A bytes array containing return data form CCIP receiver.
/// @return retBytes A bytes array containing return data from CCIP receiver.


/// @param destinationChainSelector The destination chainSelector.
/// @param message The cross-chain CCIP message including data and/or tokens.
/// @return fee returns execution fee for the message.

Choose a reason for hiding this comment

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

Suggested change
/// @return fee returns execution fee for the message.
/// @return fee returns execution fee for the message

Looks like the sentence is meant to be continued below

Choose a reason for hiding this comment

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

Ah, sry, this is a chainlink dep. So all good!

/// @param destinationChainSelector The destination chain ID.
/// @param message The cross-chain CCIP message including data and/or tokens.
/// @return messageId The message ID.
/// @dev Note if msg.value is larger than the required fee (from getFee) we accept.

Choose a reason for hiding this comment

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

Suggested change
/// @dev Note if msg.value is larger than the required fee (from getFee) we accept.
/// @dev Note if msg.value is larger than the required fee (from getFee) we accept

Same, sentence continued in next line

Copy link

@CheyenneAtapour CheyenneAtapour left a comment

Choose a reason for hiding this comment

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

Looks good to us

-Aave Labs

@brotherlymite brotherlymite merged commit 2f8cbf0 into bgd-labs:main Oct 14, 2025
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants