Aave explainer series - Chainlink CCIP and its Integration with Aave

Aave explainer series - Chainlink CCIP and its Integration with Aave

Aave explainer series - Chainlink CCIP and its Integration with Aave

Sep 11, 2024

Useful Links

This article was prepared for the Aave DAO as part of an explainer series published by LlamaRisk, which has been appointed as an Aave risk service provider. It offers an in-depth view of ChainLink's CCIP and its integration with Aave.

Executive summary

This article provides an in-depth analysis of Chainlink's Cross-Chain Interoperability Protocol (CCIP) and its integration with Aave, focusing on deploying Aave's decentralized stablecoin, GHO, across multiple blockchains. CCIP enables cross-chain operations through an architecture that involves both on-chain and off-chain components. Aave's integration with CCIP allows GHO to be bridged from Ethereum to other networks, starting with Arbitrum.

Key features of CCIP include Arbitrary Messaging, Token Transfer, and Programmable Token Transfer, facilitated by components such as Routers, TokenPools, and the Risk Management Network. The integration with Aave employs an adapted and customized version of the standard CCIP token transfer methods to maintain GHO's stability and ensure Aave DAO's control over the process. The system's architecture also introduces specific security measures, including rate and bridge limits, to mitigate risks associated with cross-chain transactions.

This article outlines the system architecture, technical implementation, and limitations of the current setup, providing insights into the ongoing evolution of GHO's cross-chain functionality.

CCIP System Architecture

Chainlink's Cross-Chain Interoperability Protocol (CCIP) is a solution designed to enable the transfer of data and tokens across multiple blockchain networks. CCIP provides an interface that allows users and decentralized applications (dApps) to perform cross-chain operations, such as arbitrary messaging, token transfers, and programmable token transfers. CCIP incorporates a set of Decentralized Oracle Networks (DON), including the Risk Management Network, a Committing DON, and an Executing DON. Each network of independent nodes provides secure and reliable data to smart contracts and performs different tasks to ensure the separation of concerns.

This infrastructure supports various applications, including DeFi, gaming, and traditional finance, enabling developers to create interoperable, cross-chain applications and improving the overall functionality and composability of the blockchain ecosystem. This article was written with CCIP v1.4 in mind. In Q4, CCIP will upgrade to v1.5, changing the architecture, features, and methodologies described.

CCIP has the following three core capabilities:

  • Arbitrary Messaging: CCIP allows sending arbitrary data (encoded as bytes) to receiving smart contracts on all CCIP supported networks. This functionality can trigger specific actions on other chains, such as minting tokens or NFTs, rebalancing indexes, or executing complex multi-chain tasks.

  • Token Transfer: CCIP enables the transfer of tokens directly to smart contracts or Externally Owned Accounts (EOAs) on different blockchains. This includes mechanisms like burn-and-mint and lock-and-mint to ensure secure and efficient transfers.

  • Programmable Token Transfer: This combines token transfer with arbitrary messaging, allowing users to transfer tokens and instructions for using them on the destination chain. For example, tokens can be sent to a lending protocol with instructions on using them as collateral for a loan.

The graph below shows a detailed flowchart of how the system works:

Source: Chainlink Documentation, August 22nd, 2024

CCIP is an interplay between on-chain and off-chain components designed to facilitate the seamless and secure transfer of data and tokens across multiple blockchain networks.

On-Chain Components

Router

The Router is a critical component in Chainlink's Cross-Chain Interoperability Protocol, serving as the primary interface for initiating and managing cross-chain transactions. It facilitates the secure and efficient transfer of data and tokens across different blockchain networks.

The Router forwards transaction details to the OnRamp contract on the source chain. This contract validates the transaction details, including checking message and gas limits, and keeps track of sequence numbers. The OnRamp contract then interacts with the TokenPool to lock or burn the specified amount of tokens on the source chain, ensuring that the tokens are accounted for and preventing double-spending. The TokenPool's use of the lock or burn mechanism depends on the token type (more on this in the TokenPool section).

The Router moves tokens directly for token transfers to the relevant token pool contract via transferFrom(). It also coordinates the process by routing the necessary information to the OnRamp contract, which performs the actual locking or burning of tokens on the source chain. The corresponding OffRamp contract on the destination chain is then instructed to unlock or mint the equivalent amount of tokens, with the mechanism used depending on the way the token is set up in CCIP.

After locking or burning the tokens, the OnRamp contract processes the instructions and prepares them for cross-chain execution. It emits an event monitored by the Committing Decentralized Oracle Network (DON), which bundles multiple transactions into a Merkle root and commits it to the CommitStore on the destination chain—more on DONs in the Decentralized Oracle Networks (DON) section.

Useful information about the Router can be obtained directly from the on-chain contract, such as the list of supported tokens or OnRamp and OffRamp contracts based on the chain selector:

The Router on Ethereum Mainnet is deployed at 0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D.

>>> Router.getSupportedTokens() 
[[0x72e364F2ABdC788b7E918bc238B21f109Cd634D7] 
[0xCA160D11087E03fd398d40f561cd4768825f4958] 
... 
[0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f]      # GHO Token Address 
... 
[0xc2e660C62F72c2ad35AcE6DB78a616215E2F2222]] 
  
>>> Router.getOnRamp(4949039107694359620) 
0x925228D7B82d883Dde340A55Fe8e6dA56244A22C 
    
>>> Router.isOffRamp(4949039107694359620, '0xeFC4a18af59398FF23bfe7325F2401aD44286F4d') 
'true'

In the upcoming CCIP v1.5 release, Router.getSupportedTokens() will be deprecated, and the TokenAdminRegistry contract can be used to retrieve this information instead.

An example of a transaction where a user interacts with the Router contract to send GHO to Arbitrum can be found here: Etherscan Transaction.

Source: Blocksec MetaSleuth

CommitStore

The CommitStore operates on a per-lane basis, where each lane represents a unidirectional connection between two blockchains. For example, a lane from Ethereum to Arbitrum differs from one from Arbitrum to Ethereum. Each lane has its own CommitStore to manage direction-specific transactions.

The CommitStore on the destination chain stores the Merkle root of the finalized message from the source chain. When transactions are initiated and processed, the Committing DON bundles them into a Merkle root and then stores them in the CommitStore on the destination chain.

After the Merkle root is stored, the Risk Management Network (RMN) must approve before the Executing DON can execute the transactions. The CommitStore checks if the RMN has blessed the Merkle root, ensuring all transactions are validated and anomaly-free. The Merkle root is a cryptographic commitment to a batch's transactions. Each transaction is hashed, and these hashes are paired and hashed together iteratively until a single root hash, the Merkle root, is generated. This root encapsulates the integrity of all included transactions. Validation involves the RMN verifying that the Merkle root corresponds correctly to the intended set of transactions, using Merkle proofs to check the integrity of individual transactions within the batch. This ensures that the batch is tamper-proof and that no unauthorized changes have been made to any transaction before the DON executes it.

Only after RMN approval can the Executing DON access the Merkle root from the CommitStore to execute the transactions on the destination chain. The Executing DON verifies the transactions against the blessed Merkle root and performs the necessary operations, such as unlocking or minting tokens.

OnRamp

The OnRamp contract handles the initial processing and validation of cross-chain transactions on the source blockchain. Each unidirectional lane, representing a connection between two blockchains, has a dedicated OnRamp contract.

The OnRamp contract validates the transaction by checking the message and gas limits and maintaining sequence numbers. This ensures that all transaction parameters are correct and meet the required standards. It then manages billing for the cross-chain transaction using the fee token specified in the message, with the fee being paid on the source chain.

In the case of token transfers, the OnRamp contract interacts with the TokenPool to lock or burn the specified amount of tokens on the source blockchain.

Once the tokens are locked or burned, the OnRamp contract emits an event monitored by the CommittingDON. The CommittingDON collects these events, bundles multiple transactions into a Merkle root, and commits this root to the CommitStore on the destination chain. This process ensures that the transactions are securely recorded and can be verified and executed on the destination blockchain.

Queried examples are based on the OnRamp contract for the lane to Arbitrum.

>>> OnRamp.currentRateLimiterState() 
5000000000000000000000000, 1722457655, true, 5000000000000000000000000, 1389000000000000000000 
# returns: max capacity, current timestamp, current capacity, refill rate 
  
>>> OnRamp.getPoolBySourceToken(0, '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f') 
'0x5756880B6a1EAba0175227bf02a7E87c1e02B28C' 
  
>>> OnRamp.currentRateLimiterState() 
5000000000000000000000000, 1722457655, true, 5000000000000000000000000, 1389000000000000000000 
# returns: max capacity, current timestamp, current capacity, refill rate 
  
>>> OnRamp.getPoolBySourceToken(0, '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f') 
'0x5756880B6a1EAba0175227bf02a7E87c1e02B28C'

OffRamp

The OffRamp contract finalizes cross-chain transactions on the destination blockchain. Each unidirectional lane between two blockchains has a dedicated OffRamp contract, ensuring secure and efficient transaction processing.

The OffRamp contract's primary function is verifying the validity of incoming messages. It does this by checking the proof the ExecutingDON provided against a committed and blessed Merkle root. This verification process ensures the transaction is authentic and approved by the Risk Management Network.

Once the transaction is validated, the OffRamp contract transmits the message to the Router on the destination blockchain. This step ensures that the transaction details are correctly routed and processed further. If the transaction includes a token transfer, the OffRamp contract interacts with the TokenPool to mint or unlock the assets to the receiver on the destination blockchain.

Queried examples are based on the OffRamp contract for the lane to Arbitrum.

>>> OnRamp.currentRateLimiterState() 
5000000000000000000000000, 1722457655, true, 5000000000000000000000000, 1389000000000000000000 
# returns: max capacity, current timestamp, current capacity, refill rate 
  
>>> OnRamp.getPoolByDestToken('0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f') 
'0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f'

TokenPool

The TokenPool manages the secure and efficient transfer of tokens across different blockchain networks. Each supported token has its own TokenPool on each chain, facilitating various mechanisms to handle token movements based on the token's characteristics and the use case.

The TokenPool supports four main mechanisms for handling token transfers, depending on the token type and use case:

  • Burn and Mint: This mechanism burns tokens on the source chain and mints an equivalent amount on the destination chain. For example, stablecoins like USDC, which can be natively minted on multiple blockchains, utilize this method to facilitate cross-chain transfers. This approach only works if USDC, for example, is integrated into CCIP.

  • Lock and Mint: This locks tokens on the source chain and mints a wrapped version on the destination chain. For instance, LINK tokens, which are only minted on Ethereum Mainnet and have a fixed supply, use the Lock and Mint mechanism. When transferring LINK from Ethereum to another chain, the tokens are locked on Ethereum, and a wrapped version is minted on the destination chain. Transferring 10 LINK from Ethereum Mainnet to Arbitrum involves locking 10 LINK in the TokenPool on Ethereum and minting 10 LINK in the TokenPool on Arbitrum. When transferring back, the LINK tokens on Arbitrum are burned, and the locked LINK tokens on Ethereum are unlocked.

  • Burn and Unlock: This burns tokens on the source chain and unlocks an equivalent amount on the destination chain. This is typically used when sending tokens back to their issuing chain, being the inverse of Lock and Mint.

  • Lock and Unlock: This locks tokens on the source chain and unlocks an equivalent amount on the destination chain without burning. For example, WETH uses this mechanism because it can be unwrapped into ETH. Burning WETH would remove ETH from circulation, so it is only locked and unlocked.

The TokenPool works closely with the OnRamp and OffRamp contracts. When a transaction involves token transfers, the OnRamp contract interacts with the TokenPool to lock or burn tokens on the source chain. Conversely, the OffRamp contract interacts with the TokenPool to unlock or mint tokens on the destination chain.

TokenPools have rate limits as a security measure, representing the maximum rate at which tokens can be transferred per lane. These limits help prevent abuse and ensure the secure handling of token transfers. The rate limits can be defined based on total daily tokens or other relevant metrics.

In this example transaction, the bridged GHO tokens are transferred and locked into the TokenPool contract of GHO.

Source: Blocksec MetaSleuth

Risk Management Network Contract

The on-chain Risk Management Network (RMN) contract is crucial for maintaining the security and integrity of cross-chain transactions. This contract oversees the validation and blessing of transactions and can pause the system if anomalies are detected.

Additionally, the RMN contract maintains a list of authorized, decentralized Risk Management nodes operated by independent entities. This decentralization is essential to avoid single points of failure and enhance system resilience.

These nodes validate the committed Merkle roots of transactions. They vote to bless or curse the transactions. When a transaction is initiated, the RMN contract requires a quorum of nodes to bless the committed Merkle root. Nodes independently reconstruct the Merkle tree and compare it with the one committed by the CommittingDON. If the roots match, nodes cast their votes to bless the root. When the cumulative weight of blessing votes exceeds a threshold, the root is marked as blessed, allowing the Executing DON to proceed with the transaction.

If a node detects an anomaly, it can vote to curse the system. The RMN Contract tracks these votes, and if their cumulative weight exceeds the threshold, the system is paused. This pause prevents further transactions until the issue is resolved, ensuring the system's security.

The RMN Contract also ensures that transactions achieve finality, meaning they cannot be reversed once confirmed. The separation of commitment and execution phases allows thorough checks and validations before transactions are executed on the destination chain.

CCIP Example Transaction

Let's take a look at a simple transaction where a user bridges GHO from Ethereum to Arbitrum, with the transactions viewable directly on the blockchain:

  1. The user initiates the cross-chain transaction through the Router. The amount of tokens the user wants to bridge is transferred to the GHO TokenPool on Ethereum, where the tokens are locked. Simultaneously, the CCIP fee (paid in wrapped ETH) is transferred to the EVM2EVMOnRamp contract. View transaction.

  2. The Committing and Executing DONs and the Risk Management Network validate the cross-chain transaction off-chain.

  3. GHO tokens are minted by the EVM2EVMOffRamp on Arbitrum and transferred to the user, completing the cross-chain transaction. View transaction.

Depending on various factors such as the type of transfer (arbitrary data, token transfers, or Programmable Token Transfer) or whether the receiver is a contract or EOA, the CCIP system performs different actions:

Source: Chainlink Documentation, August 22nd, 2024

Off-Chain Components

CCIP includes several off-chain components that work alongside the on-chain elements to ensure the smooth and secure execution of cross-chain transactions.

Decentralized Oracle Networks (DON)

In CCIP, Chainlink's Decentralized Oracle Networks (DONs) operate through two key phases: committing and executing. The commitment phase involves validating and bundling transactions into Merkle roots, while the execution phase processes these transactions on the destination chain.

These DONs run Chainlink OCR2, a protocol that functions in rounds where an observed data value is agreed upon. The output of this process is a report attested to by a quorum of participants. One participant transmits this report on-chain, but no single participant is responsible for communicating in every round. Instead, all participants attempt to do so round-robin until a transmission occurs.

In the context of CCIP, a lane consists of two OCR DON committees: the Committing DON and the Executing DON, which monitor transactions between a source and destination blockchain. This separation allows the Risk Management Network ample time to verify commitments before execution, enabling additional checks for abnormalities and enhancing overall security.

Committing DON

The CommittingDON is responsible for monitoring and validating cross-chain transactions before they are committed to the destination blockchain. When a transaction is initiated on the source blockchain, the CommittingDON monitors the OnRamp contract for relevant events, including details of the transactions that must be processed. Once it detects these events, it waits for transaction finality on the source chain to ensure the transactions are confirmed and irreversible.

After achieving finality, the CommittingDON bundles multiple transactions into a single Merkle root. This efficient bundling process helps maintain the integrity of the transaction data. The Merkle root is then signed by a quorum of oracle nodes within the CommittingDON, ensuring consensus and security. Finally, the signed Merkle root is written in the CommitStore contract on the destination blockchain and is awaiting further processing.

Executing DON

The ExecutingDON takes over once the Merkle root has been committed to the destination blockchain's CommitStore. It monitors the CommitStore for newly committed Merkle roots that the Risk Management Network has blessed. The ExecutingDON verifies that the transaction is part of the relayed Merkle root in the CommitStore contract, ensuring it has been validated and approved.

Upon verification, the ExecutingDON creates valid Merkle transaction proofs. These proofs are essential for confirming that the transactions are indeed part of the committed Merkle root. Once the proofs are generated, the ExecutingDON calls the OffRamp contract to execute the cross-chain transactions on the destination blockchain. This process includes transferring tokens or performing other specified actions based on the transaction details. The executing DON will attempt to execute a transaction on the destination chain; if it encounters a failure, it will repeatedly try again until it finally backs off, and the transaction becomes available for anyone to execute. If a transaction is valid but fails to execute, the end user, or anyone else, can execute the transaction on the end-users behalf.

Risk Management Nodes

Off-chain risk management nodes act as a secondary validation layer, ensuring that transactions processed by the CCIP system are secure and free from anomalies. These nodes operate in two main modes: blessing and cursing. The Risk Management Network (RMN) was developed by a separate team inside of Chainlink Labs in a programming language different from the committing DON but using a similar spec. This approach resembles N-version programming, which reduces the risk of bugs showing up in production, as the same bug would have to be separately implemented by two different teams in two different languages at two different times. This principle is used in high-availability environments like spacecraft and Ethereum L1 node software. There is also no overlap between the Node Operators in the RMN and the committing DON to further harden the security of CCIP.

  • Blessing: Each off-chain risk management node continuously checks the committed Merkle roots of messages stored in the CommitStore contract on each destination chain. The Committing DON is responsible for committing these Merkle roots. Off-chain nodes reconstruct the Merkle tree independently by fetching all source chain messages. They then compare their reconstructed Merkle root with the committed by the Committing DON. If the Merkle roots match, the node blesses the root by voting to approve it. A quorum of nodes must cast their blessing votes for the Merkle root to be officially blessed. Once the threshold is met, the Risk Management Contract on the destination chain labels the Merkle root as blessed, allowing the Executing DON to proceed with transaction execution.

  • Cursing: If a risk management node detects an anomaly, such as a mismatch between the committed Merkle root and its reconstructed version, it votes to curse the system. Similar to the blessing process, a quorum of cursing votes is required for the Risk Management Contract to label the CCIP system as cursed. When this happens, the system on the affected destination chain is paused, preventing further transactions. This pause remains until the detected issue is resolved and the system is deemed secure again. Common scenarios that lead to cursing include finality violations and execution safety violations.

CCIP Rate Limits

The CCIP architecture uses two rate limits as security measures. Each rate limit has a maximum capacity and a refill rate, which is the speed at which the maximum capacity is restored after consumption. The refill rate is managed entirely on-chain as the contract simply checks the time passed since the last token transfer to calculate the current limit. These rate limits are enforced on both the source and destination chains to provide an extra layer of security for token transfers.

Rate limits are governed by network administrators or the protocol's governance model. The Chainlink development team typically manages changes to the rate limits or through community governance proposals, depending on the protocol's structure and policies.

Token Pool Rate Limit

This rate limit is enforced on the TokenPool contract for each supported token on each lane. It limits the total amount of tokens transferable within a certain time.

The individual rate limit can be fetched directly from the TokenPool contract, for example, for the DPI token:

>>> TokenPool.getCurrentInboundRateLimiterState(4949039107694359620) 
2593000000000000000000, 1722781439, true, 2593000000000000000000, 180000000000000000 

>>> TokenPool.getCurrentOutboundRateLimiterState(4949039107694359620) 
2593000000000000000000, 1722781439, true, 2593000000000000000000, 180000000000000000

The returned values represent the current rate limit capacity, the timestamp when calling the function, whether the rate limit is turned on or off, the maximum rate limit capacity, and the refill rate.

Aggregate Rate Limit

In addition to the individual token pool rate limits, there is an overall rate limit for all supported tokens in a single lane, denominated in USD. For security reasons, this aggregate limit is set lower than the combined sum of all individual token pool limits.

The aggregated rate limits for a certain lane are stored in the OnRamp and OffRamp contracts. The current rate values can be fetched directly from the contracts using the currentRateLimiterState method:

>>> OnRamp.currentRateLimiterState() 
5000000000000000000000000, 1722457655, true, 5000000000000000000000000, 1389000000000000000000 
  
>>> OffRamp.currentRateLimiterState() 
5000000000000000000000000, 1722457655, true, 5000000000000000000000000, 1389000000000000000000

The returned values represent the current rate limit capacity, the timestamp when calling the function, whether the rate limit is turned on or off, the maximum rate limit capacity, and the refill rate.

CCIP Upgradability

Upgradability in the context of CCIP involves enhancing the system's operational scope, features, security, or reliability through two main methods:

  1. Smart Contract Configuration: These can be updated using exposed functions to adjust rate limits, supported tokens, or OnRamp contracts for different blockchains.

  2. Smart Contract Code: The source code of deployed contracts cannot be changed. Instead, new versions are deployed, and configurations can redirect calls to these latest versions. The Router contract is an exception and remains static to ensure the reliability and stability of the developers integrating it.

All on-chain configuration changes and upgrades to CCIP must go through a Role-based Access Control Timelock (RBACTimelock) contract.

Proposals can be made by a ManyChainMultiSig (MCMS) contract and must either:

  1. Undergo a review period enforced by the RBACTimelock, during which node operators can veto the proposal.

  2. Be explicitly approved by a quorum of independent signers, including multiple node operators, for urgent matters.

After passing the review without veto, updates become executable by anyone via a timelock worker.

CCIP Execution Latency

Chainlink's CCIP is designed to strongly emphasize security to reduce the risk of block reorganizations on the source blockchain. The total time it takes for a CCIP transaction to complete is primarily influenced by how long it takes to achieve finality on the originating blockchain. This finality time can vary significantly between blockchains. For instance, Ethereum typically takes about 15 minutes to finalize a block, whereas Avalanche can finalize transactions in roughly one second, leading to quicker overall transaction times for cross-chain transfers initiated from Avalanche.

Suppose the transaction fee paid on the source blockchain aligns with the expected execution cost on the destination chain. In that case, the message will be processed promptly after being validated by the Risk Management Network. However, if execution costs rise after the initial request, CCIP will incrementally adjust the gas price to ensure the transaction is eventually executed, which might cause delays.

Delays exceeding one hour are uncommon due to the implementation of Smart Execution. This mechanism aims to optimize execution within the Smart Execution time window. Should this window pass without successful execution due to network issues, users can manually execute the transaction using the CCIP Explorer. For further details on manual execution, consult the conceptual guide.

Integration with Aave

Aave leverages the CCIP system to enable GHO on different blockchains. Implementing GHO into CCIP does not follow the standard protocol but uses a modified custom version of the token pools.

GHO Stablecoin

GHO is described in the GHO documentation as:

GHO (pronounced "go") is a decentralized, overcollateralized stablecoin that is initially only minted from assets supplied to the Aave Protocol. GHO's value is programmatically aligned to the U.S. Dollar, which will be maintained through market efficiency.

As a decentralized stablecoin on the Ethereum Mainnet, GHO is minted by users. As with all borrowing on the Aave Protocol, a user must supply collateral (at a specific collateral ratio) to be able to mint GHO. Correspondingly, when a user repays a borrow position (or is liquidated), the GHO is returned to the Aave pool and burned. All the interest payments accrued by minters of GHO will go directly to the Aave DAO treasury, in contrast to the standard reserve factor collected when users borrow other assets, and the principal is burned.

Source: GHO docs

With the CCIP integration, GHO is now also available on Arbitrum, where it has a different behavior as it can also be supplied and borrowed from the Aave Pool.

Technical Implementation

NOTE: The expressions "TokenPool on Ethereum" and "GHO Reserve" are used interchangeably. However, it's important to distinguish between "Token Pool on Chain X" and "Facilitator," as they serve different roles in the cross-chain GHO architecture.

The CCIP TokenPool on chains other than Ethereum currently acts as a facilitator for GHO transfers:

GHO introduces the concept of Facilitators. A Facilitator can trustlessly mint and burn GHO tokens through various strategies. Different entities can implement these strategies and may employ varying approaches to integrate GHO (each entity is a facilitator). The Aave DAO assigns each Facilitator a Bucket with a specified Capacity, the upward limit of GHO that a specific Facilitator can mint. This limit is defined and can be changed by the Aave DAO. In the future, separate GHO facilitators may be deployed on different chains, with entities like Synthetix or facilitators dedicated to real-world assets (RWAs) potentially operating independently. This model allows multiple facilitators to exist on the same chain, each with distinct responsibilities, further diversifying GHO's cross-chain functionality.

Source: Gho Docs

For each blockchain network that supports GHO, there is a canonical version of the stablecoin. TokenPools help move GHO liquidity from Ethereum to other blockchains. Bridges, functioning as one type of facilitator, have a set credit limit that controls the amount of liquidity that can be transferred. This system adds a layer of checks on top of CCIP to ensure that the GHO reserve on Ethereum and the outstanding GHO on other chains are aligned. By tying the issuance process to Ethereum's reserves, this setup guarantees that all GHO tokens across different networks are fully backed, preserving the stablecoin's reliability and stability.

It's also worth noting that separate GHO facilitators may be deployed on different chains in the future. For example, entities like Synthetix could become independent GHO facilitators, or there could be a facilitator dedicated to real-world assets (RWAs) on Arbitrum. As this model evolves, a single chain may host multiple facilitators with different responsibilities. The TokenPool would then only be one of several facilitators on that chain.

Aave first integrated CCIP for their stablecoin GHO using the Arbitrum network. Aave plans a phased rollout by initially integrating on a single chain, observing and evaluating the implementation, and then refining the process based on the obtained insights.

Even though CCIP's smart contracts were fully compatible with GHO, modifications were made to ensure AAVE DAO retains control over the process.

All GHO-related audits are here: GitHub.

Contract deployments:

Supported Chains

Currently, only Arbitrum is supported. To check all currently supported chains, one can fetch a list of chain selectors of the allowed pools directly from the PoolToken contract on Ethereum using the getSupportedChains method. Chainlink lists all CCIP-supported networks: Supported Networks.

Additionally, the contract has an isSupportedChain method, which returns true or false based on the chain selector input used, indicating whether the chain is supported. This function will return true for all chain selectors fetched from getSupportedChains and false for all others.

>>> TokenPool.getSupportedChains() 
4949039107694359620             # chain selector of Arbitrum 
  
>>> TokenPool.getSupportedChains(4949039107694359620) 
'true' # returns true as Arbitrum is supported

Bridging Schemes for GHO

GHO combines "Lock and Mint" and "Burn and Mint" systems. The GHO tokens on non-issuing chains (all chains besides Ethereum) have a canonical version of the token and a Facilitator contract controlled by Aave Governance. The TokenPool on Ethereum, also known as the GHO Reserve, is the core contract where all GHO tokens are locked when they are bridged from Ethereum to other chains.

There are three types of bridging, described below. The third one is still being implemented and is not in use, as only Arbitrum has been integrated with CCIP.

1. Ethereum Mainnet to L2/Sidechain

When initially transferring GHO away from Ethereum Mainnet to any other L2 or Sidechain integrated into the CCIP system, the system uses the "Lock and Mint" mechanism. The to-be-bridged GHO tokens are locked in the GHO Reserve Contract on Ethereum Mainnet (source chain), meaning they are not withdrawn from circulation. The CCIP forwards the token bridging message to the Facilitator on the destination chain, and the rate limit controls are applied in parallel. If successful, a canonical version of GHO will be minted on the destination chain. The "Lock and Mint" mechanism always maintains a 1:1 lock-to-mint ratio, regardless of the price differences of GHO on the two chains.

For example, Alice bridges 100 GHO from Ethereum Mainnet to Arbitrum. Alice interacts with the CCIP Router contract. In the background, her 100 GHO are locked into the TokenPool on Ethereum. After the validation of the transaction, 100 tokens of a canonical version of GHO are minted into her wallet.

2. L2/Sidechain to Ethereum Mainnet

Bridging GHO from an L2/Sidechain back to Ethereum also uses the "Lock and Mint" mechanism, but this time, the tokens are burned and unlocked instead of locking and minting tokens. The canonical version of GHO is burned from the supply, and after the CCIP transaction is validated, GHO tokens are unlocked from the TokenPool.

For example, Alice bridges back her 50 GHO tokens to Ethereum Mainnet. She interacts with the CCIP Router contract on Arbitrum. In the background, her 50 GHO tokens on Arbitrum are burned, and after successful validation and execution of the transaction, 50 GHO tokens are unlocked from the TokenPool on Ethereum.

3. L2/Sidechain to L2/Sidechain

When bridging GHO between chains where neither is Ethereum, the system uses the "Burn and Mint" mechanism. GHO is burned on the source chain and minted on the destination chain.

For example, Alice decides to bridge her remaining 50 GHO from Arbitrum to Optimism (hypothetically assuming that Optimism is integrated into the CCIP system). Her 50 GHO tokens are burned in the TokenPool on Arbitrum, and 50 GHO tokens are freshly minted from the TokenPool on Optimism.

The entire bridging mechanism can be summarized as shown in the graph below:

Source: Aave Governance

Bridge and Rate Limits

The base CCIP system offers various security measures, such as the TokenPool rate limit and an aggregated USD rate limit, each with a maximum capacity and a refill rate. However, the GHO CCIP-System integration has modifications from the base case, which turn off these rate limitations (modifiable by Aave DAO). Instead, a bridgeLimit is introduced.

In addition to these limitations, cross-chain GHO is secured through the general CCIP systems of Committing, Executing, and Risk Management DONs.

Bridge Limit

The TokenPool has bridge limits, which can be directly read from the contract using the getBridgeLimit method. This value represents the maximum GHO tokens that can be bridged to other networks (currently only Arbitrum). The amount of GHO that has been bridged can be read from the contract using the getCurrentBridgedAmount method.

The bridge limit is updated whenever tokens are transferred to or from Arbitrum.

The current bridge limit and the currently bridged amount can be verified by calling both functions, getBridgeLimit and getCurrentBridgedAmount:

>>> TokenPool.getBridgeLimit() 
20000000000000000000000000             # 20,000,000 GHO Tokens 
  
>>> TokenPool.getCurrentBridgedAmount() 
4686124021957014087076087              # 4,686,124 GHO Tokens

The initial getBridgeLimit cap was set at 1,000,000 GHO. Subsequently, the cap was raised to 2,500,000 GHO, which was reached in about 90 minutes. Due to high demand, another cap increase was executed on August 6, following a discussion in the ARFC by Karpatkey on the Aave governance forum, proposing a new cap of 20,000,000 GHO.

Source: Dune Analytics

Along with the increase in the bridging cap, the proposal also raised the supply cap from 1,000,000 to 5,000,000 and the borrow cap from 900,000 to 4,500,000 GHO.

Rate Limit

In addition to the bridge limit, there are also rate limits. These limits apply to the OnRamp and OffRamp on different chains. This feature is implemented in the TokenPool but is not yet enabled; however, the Aave DAO can activate it in the future. This way, GHO transfers will not be stopped when the lane limit is reached.

>>> TokenPool.getCurrentInboundRateLimiterState() 
0, 1722772571, false, 0, 0 
  
>>> TokenPool.getCurrentOutboundRateLimiterState() 
0, 1722772715, false, 0, 0

The returned values are max capacity, the current timestamp, whether the rate limit is turned on or off, the current capacity, and the refill rate.

Upgradability and Access Control

The GHO-CCIP integration is designed with a robust upgradability mechanism to ensure the system can adapt to evolving requirements and improvements, which are implemented through upgradeable smart contracts.

This section only maps out the most crucial functions where the Aave DAO controls upgradability and other access controls.

GHO Token

Crosschain GHO utilizes an upgradeable version of the GHO token, allowing for necessary modifications while retaining the same functionality as the standard GHO token. Minor adaptations include shifting initializations from the constructor to an initialize function.

This approach ensures the contract can be upgraded with new features or improvements without redeployment or state loss, providing long-term maintainability and adaptability.

The changes introduced in the contracts ERC20.sol to UpgradeableERC20.sol and GhoToken.sol to UpgradeableGhoToken.sol implement an upgradeability mechanism using the initializer pattern, compatible with the proxy design pattern. This allows the contract's logic to be updated while preserving its state. Key modifications include:

  1. Initialization Functions: Introduction of _ERC20_init and initialize functions to set up contract state variables (name, symbol, etc.) instead of using constructors.

  2. Dynamic Computation of Immutable Variables: Removal of immutable variables like INITIAL_CHAIN_ID and INITIAL_DOMAIN_SEPARATOR, replaced with dynamic computations.

  3. Upgradeable Variables and Functions: Variables such as name, symbol, and mappings like _facilitators are now initialized through functions, making them upgradeable. Functions can also be modified or added in future versions.

A line-by-line code difference comparison can be found on GitHub.

TokenPools

Changing parameters on the TokenPool on Ethereum can only be done by the owner of the contract, the Aave Executor Lvl1.

>>> TokenPool.owner()           # Ethereum 
'0x5300A1a15135EA4dc7aD5a167152C01EFc9b192A' 
  
>>> TokenPool.owner()           # Arbitrum 
'0xFF1137243698CaA18EE364Cc966CF0e02A4e6327'

The most crucial owner-guarded functions in the TokenPools are the following:

  • setBridgeLimit: This function changes the limit of GHO tokens that can be bridged from Ethereum to other chains. It is currently set to 2,500,000 GHO tokens. The function can be changed by the owner or bridgeLimitAdmin. Currently, there is no bridgeLimitAdmin set (the owner can only set this). Therefore, only the owner can currently change the bridge limit. Note: The bridge limit only exists on the TokenPool on Ethereum.

  • setChainRateLimiterConfig: This function changes bucket capacity and rate limits parameters. Only the owner or the RateLimitAdmin can make these changes. Again, a RateLimitAdmin has not been set yet.

Billing (Transaction Fees for CCIP Usage)

CCIP involves two costs paid on the source chain: CCIP fees and gas costs. CCIP fees are paid in specific fee tokens to cover the gas costs associated with the transaction on the destination chain.

CCIP uses a flat-fee model as follows:

Source: CCIP Billing

LINK tokens are used to pay node operators to retrieve data for smart contracts and deposits placed by node operators as required by contract creators. The smallest denomination of LINK is called a Juel, and 1,000,000,000,000,000,000 (1e18) Juels are equal to 1 LINK. This is similar to Wei, which is the smallest denomination of ETH.

Source: Chainlink docs

Although GHO was technically implemented to support meta-transactions, anticipating the use of GHO as a payment currency for CCIP, it has yet to be used to pay fees. This integration is fully in the hands of the CCIP team.

Outlook and Analytics

On August 6, 2024, the GHO bridge limit was raised from 2.5 million to 20 million, as approved in this Aave governance proposal. Despite the increase, the GHO supply on Arbitrum initially dropped, likely due to prevailing market sentiment.

However, within about three weeks, the bridged amount of GHO surpassed the previous limit. As of September 4, 2024, the total bridged GHO on Arbitrum has risen to approximately 5.6 million tokens.

Source: Dune Analytics

Looking at the total amount of GHO deposited and withdrawn from the GHO TokenPool gives us a great visualization of demand for bridging GHO:

Source: Dune Analytics

To further bolster GHO's liquidity, Aave has launched a Long-Term Incentives Pilot Program (LTIPP) on Arbitrum, allocating 375,000 ARB tokens to incentivize GHO liquidity providers. These rewards aim to support GHO's peg and encourage liquidity providers to contribute to the Aave V3 pools on Arbitrum. Users deposit GHO into these pools, receiving aGHO tokens that yield returns and enhance demand for GHO across the network.

Now, let's take a closer look at the distribution of GHO on Arbitrum. The query below lists current GHO balances held by smart contracts and Externally Owned Accounts (EOAs). This breakdown offers insights into how GHO is allocated across different types of accounts on the network.

Source: Dune Analytics

On September 4, 2024, the largest holder of GHO tokens by far is the Aave V3 Pool (0xebe517846d0f36eced99c735cbf6131e1feb775d), holding approximately 5.1 million GHO out of the 5.6 million total GHO bridged. Users deposit GHO into this pool to supply liquidity for the Aave lending markets. In return, they receive aGHO, a yield-bearing token that reflects their deposits.

The second-largest GHO holder, with a balance of around 185,000, is the Balancer Vault at 0xba12222222228d8ba445958a75a0704d566bf2c8. Additionally, at fourth place, 18,600 GHO are deposited in a Uniswap V3 pool at 0xAe337136Cc2E383FDD59FCB0F24eDe7269ce7056, paired against USDC.

When looking at AMM liquidity for GHO swaps on Arbitrum, smaller swaps can be executed without any significant slippage, as shown below:

Source: LlamaSwap | September 4th, 2024

However, attempting to swap amounts greater than 200,000 GHO leads to substantial slippage, reflecting the limited liquidity available in AMMs as of this date.

Source: LlamaSwap, September 4th, 2024

Integration Challenges

Non-Rollback Problem and Bridge Limit

The non-rollback problem and bridge-limit issue in the cross-chain GHO architecture revolve around two key entities: the Aave DAO and the Chainlink CCIP infrastructure. Aave DAO acts as the "super-admin," managing permissions and configurations for the GHO token and cross-chain infrastructure. Chainlink CCIP handles cross-chain transactions by verifying user actions and controlling the minting or release of tokens on destination networks.

The introduction of the bridge limit by the AAVE DAO has opened up a set of possible edge cases when GHO goes to multiple chains, and individual bridge limits are set per chain. In that scenario, race conditions can occur where a user transfers GHO from one to another non-Ethereum chain, and upon arrival on the destination chain, the network capacity is insufficient to allow the GHO minting.

To address this, Aave Labs introduced a bridge limit on Ethereum identical to the Facilitator cap used across all chains, which ensures that the total amount of GHO tokens being bridged remains within a specified limit. While the bridge limit prevents user funds from getting locked, it raises an important question: does having a separate bridge limit increase flexibility? Some argue that it adds operational overhead without clear benefits. If GHO is always backed and safe, what is the actual risk or problem with allowing users to bridge larger amounts to new networks? This raises the question of whether the bridge limit truly solves a significant problem or if there are alternative, more efficient ways to address the risks involved without imposing such constraints.

Scenario Example

Let's assume the following scenario:

  • Bucket capacity on Arbitrum: 1,000 GHO

  • Bucket capacity on Optimism: 1,000 GHO

  • Both are filled.

Now, two actions happen almost simultaneously by two different actors:

  1. A user decides to bridge 500 GHO from Optimism to Arbitrum.

  2. AaveDAO executes a payload to reduce the bucket capacity of cross-chain GHO on Arbitrum to 500.

It is important to understand that the TokenPool on Optimism, used by the user to bridge GHO to Arbitrum, does not know that the bucket size on Arbitrum is being lowered.

Assume the payload is executed first, reducing the bucket capacity to 500. The GHO tokens on Optimism are burnt and should be minted on Arbitrum. However, due to the filled bucket capacity, there is no further capacity to mint.

CCIP has no mechanism to "roll back" transactions; as far as we know, no existing bridge has such a feature. Moreover, the concept of a rollback doesn't apply in the context of bridging since CCIP only operates once finality is reached on the source chain. Reversing finality to undo the transaction is not feasible. Therefore, these edge cases must be handled through business-level logic, as what a "rollback" entails can differ depending on the specific token or use case.

One potential approach, as suggested by bgdlabs, could be as follows:

  1. A user burns 500 GHO on Optimism.

  2. CCIP reviews the transaction.

  3. CCIP detects that the bucket capacity on Arbitrum is full, and no GHO can be minted there.

  4. The system re-mints the earlier burned amount of GHO to the user on Optimism.

Another feasible solution, if AAVE DAO wishes to maintain chain-specific bucket sizes, would be to implement an iouGHO system. Instead of directly transferring GHO, users would transfer an iouGHO that can be redeemed for canonical GHO when there is sufficient capacity. Users could transfer their iouGHO to another chain or back to Ethereum if capacity is unavailable.

This solution would keep AAVE DAO in full control, remove any dependency on Chainlink Labs for updates, and avoid the potential security risk of allowing CCIP to "re-mint" GHO without user action or intervention.

If no such mechanism is in place, funds could be temporarily stuck. The user would need to wait until the bucket has some capacity again to mint the GHO on Arbitrum.

This is a simple scenario. For instance, if both the bucket capacities of Arbitrum and Optimism are lowered, a user's GHO would be burned on Optimism, new GHO can't be minted on Arbitrum, and the rollback would be tricky as the GHO could not be re-minted on Optimism either due to the lowered capacity.

Aave's Temporary Solution

Aave aims to solve this problem by introducing a bridge limit, where the following statement always needs to hold:

The objective is to ensure that the previous case of user funds getting locked cannot happen. This is effectively achieved by introducing a strict procedure that is always to be respected. Whenever the minimum bucket size on any network with cross-chain GHO is raised, the bridge limit should be raised to that value.

However, this potentially leads to the following problem:

If the first rollout is for Arbitrum, and the capacity is incrementally increased to 20 million GHO, the bridge limit is also increased correspondingly, reaching 20 million. Now, if GHO is to be expanded to another chain, e.g., Optimism, starting with lower capacities and increasing them over time makes sense. However, as

needs to hold, the minimum capacity on Optimism would need to be 20 million.

Assuming successful GHO cross-chain expansion, with some chains having bucket sizes of 100 million GHO, maintaining such a high bridge limit across all new chains would not be feasible. This approach would expose GHO and Aave to significant risk. It is also worth noting that, as far as we know, GHO is the only stablecoin with chain-specific caps as a design goal. For example, USDC does not impose such limits—there isn't a cap of 5 million USDC on AVAX and 50 million on Arbitrum. Users can transfer 1 billion USDC to AVAX if it's fully backed, allowing the market to dictate where the greater demand for the stablecoin lies.

Future Solution

Aave Labs has stated:

The DAO and the CCIP team should consider having the ability to roll back operations for token transfers. We recommend that the CCIP team prioritize the support for this feature, allowing GHO to leverage it fully.

Source: Aave Governance (Response to bgdlabs statement on the [ARFC] GHO Cross-Chain Launch)

After further consultation with some people working on this problem, it was noted that the current design appears sufficient to support the rollout. No fundamental issues are introduced by setting the same bridge limit across all chains. While the original intention of having separate limits was to prevent excess GHO on chains with lower community demand, it's unclear whether this is a significant issue, nor that market forces wouldn't regulate it naturally.

According to Aave Labs, if demand, need, and incentives arise, a deployment to chains like Gnosis could occur when the DAO is ready. This wouldn't necessarily require any rework of the bridge limits. Therefore, this discussion about the bridge limit should be framed as an ongoing conversation rather than a fundamental blocker to expansion, with valid arguments on both sides.

Conclusion

The integration of Chainlink's CCIP with Aave's GHO stablecoin represents a significant step toward enabling cross-chain interoperability. By leveraging CCIP's infrastructure, Aave has successfully extended GHO's reach beyond Ethereum, starting with Arbitrum and potentially expanding to other networks.

However, while the integration has expanded GHO's cross-chain capabilities, challenges remain, particularly around managing bridge limits and the potential issue of user funds being temporarily stuck. Aave has implemented temporary solutions, such as the bridge limit and custom facilitators, which help mitigate these risks. However, ongoing discussions within the Aave DAO suggest that these limits may not be necessary and could even create operational overhead. Alternative solutions like the iouGHO system are also being explored to enhance flexibility without introducing significant risks.

Moving forward, a long-term resolution will require further collaboration between Aave and Chainlink, particularly in addressing the limitations of the current architecture and ensuring that GHO's cross-chain functionality is scalable, secure, and adaptable to market demands. This evolving collaboration will be key to addressing the outstanding challenges and refining GHO's expansion across multiple blockchains.

© 2023 Llama Risk. All rights reserved.