From b1443cc46439a06c0a1af00d865302bafad2992d Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Thu, 23 May 2024 17:44:17 +0200 Subject: [PATCH 1/4] fix: Add code diffs between custom token pools and standard implementation --- .../diffs/BurnMintTokenPoolAbstract_diff.md | 21 ++ .../pools/diffs/BurnMintTokenPool_diff.md | 87 ++++++++ .../pools/diffs/LockReleaseTokenPool_diff.md | 201 ++++++++++++++++++ .../v0.8/ccip/pools/diffs/TokenPool_diff.md | 51 +++++ 4 files changed, 360 insertions(+) create mode 100644 contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md create mode 100644 contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md create mode 100644 contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md create mode 100644 contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md diff --git a/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md b/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md new file mode 100644 index 0000000000..ab584e1849 --- /dev/null +++ b/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md @@ -0,0 +1,21 @@ +```diff +diff --git a/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol b/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPoolAbstract.sol +index f5eb135186..651965e40b 100644 +--- a/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol ++++ b/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPoolAbstract.sol +@@ -1,11 +1,11 @@ + // SPDX-License-Identifier: BUSL-1.1 +-pragma solidity 0.8.19; ++pragma solidity ^0.8.0; + + import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; + +-import {TokenPool} from "./TokenPool.sol"; ++import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; + +-abstract contract BurnMintTokenPoolAbstract is TokenPool { ++abstract contract UpgradeableBurnMintTokenPoolAbstract is UpgradeableTokenPool { + /// @notice Contains the specific burn call for a pool. + /// @dev overriding this method allows us to create pools with different burn signatures + /// without duplicating the underlying logic. +``` diff --git a/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md b/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md new file mode 100644 index 0000000000..3fdf2d83da --- /dev/null +++ b/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md @@ -0,0 +1,87 @@ +```diff +diff --git a/src/v0.8/ccip/pools/BurnMintTokenPool.sol b/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPool.sol +index 9af0f22f4c..f07f8c3a28 100644 +--- a/src/v0.8/ccip/pools/BurnMintTokenPool.sol ++++ b/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPool.sol +@@ -1,29 +1,66 @@ + // SPDX-License-Identifier: BUSL-1.1 +-pragma solidity 0.8.19; ++pragma solidity ^0.8.0; + + import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; + import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; + +-import {TokenPool} from "./TokenPool.sol"; +-import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol"; ++import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; ++import {UpgradeableBurnMintTokenPoolAbstract} from "./UpgradeableBurnMintTokenPoolAbstract.sol"; + +-/// @notice This pool mints and burns a 3rd-party token. +-/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later. +-/// It either accepts any address as originalSender, or only accepts whitelisted originalSender. +-/// The only way to change whitelisting mode is to deploy a new pool. +-/// If that is expected, please make sure the token's burner/minter roles are adjustable. +-contract BurnMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion { ++import {IRouter} from "../interfaces/IRouter.sol"; ++import {VersionedInitializable} from "./VersionedInitializable.sol"; ++ ++/// @title UpgradeableBurnMintTokenPool ++/// @author Aave Labs ++/// @notice Upgradeable version of Chainlink's CCIP BurnMintTokenPool ++/// @dev Contract adaptations: ++/// - Implementation of VersionedInitializable to allow upgrades ++/// - Move of allowlist and router definition to initialization stage ++contract UpgradeableBurnMintTokenPool is VersionedInitializable, UpgradeableBurnMintTokenPoolAbstract, ITypeAndVersion { + string public constant override typeAndVersion = "BurnMintTokenPool 1.4.0"; + ++ /// @dev Constructor ++ /// @param token The bridgeable token that is managed by this pool. ++ /// @param armProxy The address of the arm proxy ++ /// @param allowlistEnabled True if pool is set to access-controlled mode, false otherwise + constructor( +- IBurnMintERC20 token, +- address[] memory allowlist, ++ address token, + address armProxy, +- address router +- ) TokenPool(token, allowlist, armProxy, router) {} ++ bool allowlistEnabled ++ ) UpgradeableTokenPool(IBurnMintERC20(token), armProxy, allowlistEnabled) {} + +- /// @inheritdoc BurnMintTokenPoolAbstract ++ /// @dev Initializer ++ /// @dev The address passed as `owner` must accept ownership after initialization. ++ /// @dev The `allowlist` is only effective if pool is set to access-controlled mode ++ /// @param owner The address of the owner ++ /// @param allowlist A set of addresses allowed to trigger lockOrBurn as original senders ++ /// @param router The address of the router ++ function initialize(address owner, address[] memory allowlist, address router) public virtual initializer { ++ if (owner == address(0)) revert ZeroAddressNotAllowed(); ++ if (router == address(0)) revert ZeroAddressNotAllowed(); ++ _transferOwnership(owner); ++ ++ s_router = IRouter(router); ++ ++ // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas. ++ if (i_allowlistEnabled) { ++ _applyAllowListUpdates(new address[](0), allowlist); ++ } ++ } ++ ++ /// @inheritdoc UpgradeableBurnMintTokenPoolAbstract + function _burn(uint256 amount) internal virtual override { + IBurnMintERC20(address(i_token)).burn(amount); + } ++ ++ /// @notice Returns the revision number ++ /// @return The revision number ++ function REVISION() public pure virtual returns (uint256) { ++ return 1; ++ } ++ ++ /// @inheritdoc VersionedInitializable ++ function getRevision() internal pure virtual override returns (uint256) { ++ return REVISION(); ++ } + } +``` diff --git a/contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md b/contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md new file mode 100644 index 0000000000..3a81233289 --- /dev/null +++ b/contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md @@ -0,0 +1,201 @@ +```diff +diff --git a/src/v0.8/ccip/pools/LockReleaseTokenPool.sol b/src/v0.8/ccip/pools/UpgradeableLockReleaseTokenPool.sol +index 1a17fa0398..7ca3d5f389 100644 +--- a/src/v0.8/ccip/pools/LockReleaseTokenPool.sol ++++ b/src/v0.8/ccip/pools/UpgradeableLockReleaseTokenPool.sol +@@ -1,26 +1,41 @@ + // SPDX-License-Identifier: BUSL-1.1 +-pragma solidity 0.8.19; ++pragma solidity ^0.8.0; + + import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; + import {ILiquidityContainer} from "../../rebalancer/interfaces/ILiquidityContainer.sol"; + +-import {TokenPool} from "./TokenPool.sol"; ++import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; + import {RateLimiter} from "../libraries/RateLimiter.sol"; + + import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; + import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; + +-/// @notice Token pool used for tokens on their native chain. This uses a lock and release mechanism. +-/// Because of lock/unlock requiring liquidity, this pool contract also has function to add and remove +-/// liquidity. This allows for proper bookkeeping for both user and liquidity provider balances. +-/// @dev One token per LockReleaseTokenPool. +-contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion { ++import {IRouter} from "../interfaces/IRouter.sol"; ++import {VersionedInitializable} from "./VersionedInitializable.sol"; ++ ++/// @title UpgradeableLockReleaseTokenPool ++/// @author Aave Labs ++/// @notice Upgradeable version of Chainlink's CCIP LockReleaseTokenPool ++/// @dev Contract adaptations: ++/// - Implementation of VersionedInitializable to allow upgrades ++/// - Move of allowlist and router definition to initialization stage ++/// - Addition of a bridge limit to regulate the maximum amount of tokens that can be transferred out (burned/locked) ++contract UpgradeableLockReleaseTokenPool is ++ VersionedInitializable, ++ UpgradeableTokenPool, ++ ILiquidityContainer, ++ ITypeAndVersion ++{ + using SafeERC20 for IERC20; + + error InsufficientLiquidity(); + error LiquidityNotAccepted(); + error Unauthorized(address caller); + ++ error BridgeLimitExceeded(uint256 bridgeLimit); ++ error NotEnoughBridgedAmount(); ++ event BridgeLimitUpdated(uint256 oldBridgeLimit, uint256 newBridgeLimit); ++ + string public constant override typeAndVersion = "LockReleaseTokenPool 1.4.0"; + + /// @dev The unique lock release pool flag to signal through EIP 165. +@@ -37,16 +52,55 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion + /// @dev Can be address(0) if none is configured. + address internal s_rateLimitAdmin; + ++ /// @notice Maximum amount of tokens that can be bridged to other chains ++ uint256 private s_bridgeLimit; ++ /// @notice Amount of tokens bridged (transferred out) ++ /// @dev Must always be equal to or below the bridge limit ++ uint256 private s_currentBridged; ++ /// @notice The address of the bridge limit admin. ++ /// @dev Can be address(0) if none is configured. ++ address internal s_bridgeLimitAdmin; ++ ++ /// @dev Constructor ++ /// @param token The bridgeable token that is managed by this pool. ++ /// @param armProxy The address of the arm proxy ++ /// @param allowlistEnabled True if pool is set to access-controlled mode, false otherwise ++ /// @param acceptLiquidity True if the pool accepts liquidity, false otherwise + constructor( +- IERC20 token, +- address[] memory allowlist, ++ address token, + address armProxy, +- bool acceptLiquidity, +- address router +- ) TokenPool(token, allowlist, armProxy, router) { ++ bool allowlistEnabled, ++ bool acceptLiquidity ++ ) UpgradeableTokenPool(IERC20(token), armProxy, allowlistEnabled) { + i_acceptLiquidity = acceptLiquidity; + } + ++ /// @dev Initializer ++ /// @dev The address passed as `owner` must accept ownership after initialization. ++ /// @dev The `allowlist` is only effective if pool is set to access-controlled mode ++ /// @param owner The address of the owner ++ /// @param allowlist A set of addresses allowed to trigger lockOrBurn as original senders ++ /// @param router The address of the router ++ /// @param bridgeLimit The maximum amount of tokens that can be bridged to other chains ++ function initialize( ++ address owner, ++ address[] memory allowlist, ++ address router, ++ uint256 bridgeLimit ++ ) public virtual initializer { ++ if (owner == address(0)) revert ZeroAddressNotAllowed(); ++ if (router == address(0)) revert ZeroAddressNotAllowed(); ++ _transferOwnership(owner); ++ ++ s_router = IRouter(router); ++ ++ // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas. ++ if (i_allowlistEnabled) { ++ _applyAllowListUpdates(new address[](0), allowlist); ++ } ++ s_bridgeLimit = bridgeLimit; ++ } ++ + /// @notice Locks the token in the pool + /// @param amount Amount to lock + /// @dev The whenHealthy check is important to ensure that even if a ramp is compromised +@@ -66,6 +120,9 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion + whenHealthy + returns (bytes memory) + { ++ // Increase bridged amount because tokens are leaving the source chain ++ if ((s_currentBridged += amount) > s_bridgeLimit) revert BridgeLimitExceeded(s_bridgeLimit); ++ + _consumeOutboundRateLimit(remoteChainSelector, amount); + emit Locked(msg.sender, amount); + return ""; +@@ -83,6 +140,11 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion + uint64 remoteChainSelector, + bytes memory + ) external virtual override onlyOffRamp(remoteChainSelector) whenHealthy { ++ // This should never occur. Amount should never exceed the current bridged amount ++ if (amount > s_currentBridged) revert NotEnoughBridgedAmount(); ++ // Reduce bridged amount because tokens are back to source chain ++ s_currentBridged -= amount; ++ + _consumeInboundRateLimit(remoteChainSelector, amount); + getToken().safeTransfer(receiver, amount); + emit Released(msg.sender, receiver, amount); +@@ -120,11 +182,46 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion + s_rateLimitAdmin = rateLimitAdmin; + } + ++ /// @notice Sets the bridge limit, the maximum amount of tokens that can be bridged out ++ /// @dev Only callable by the owner or the bridge limit admin. ++ /// @dev Bridge limit changes should be carefully managed, specially when reducing below the current bridged amount ++ /// @param newBridgeLimit The new bridge limit ++ function setBridgeLimit(uint256 newBridgeLimit) external { ++ if (msg.sender != s_bridgeLimitAdmin && msg.sender != owner()) revert Unauthorized(msg.sender); ++ uint256 oldBridgeLimit = s_bridgeLimit; ++ s_bridgeLimit = newBridgeLimit; ++ emit BridgeLimitUpdated(oldBridgeLimit, newBridgeLimit); ++ } ++ ++ /// @notice Sets the bridge limit admin address. ++ /// @dev Only callable by the owner. ++ /// @param bridgeLimitAdmin The new bridge limit admin address. ++ function setBridgeLimitAdmin(address bridgeLimitAdmin) external onlyOwner { ++ s_bridgeLimitAdmin = bridgeLimitAdmin; ++ } ++ ++ /// @notice Gets the bridge limit ++ /// @return The maximum amount of tokens that can be transferred out to other chains ++ function getBridgeLimit() external view virtual returns (uint256) { ++ return s_bridgeLimit; ++ } ++ ++ /// @notice Gets the current bridged amount to other chains ++ /// @return The amount of tokens transferred out to other chains ++ function getCurrentBridgedAmount() external view virtual returns (uint256) { ++ return s_currentBridged; ++ } ++ + /// @notice Gets the rate limiter admin address. + function getRateLimitAdmin() external view returns (address) { + return s_rateLimitAdmin; + } + ++ /// @notice Gets the bridge limiter admin address. ++ function getBridgeLimitAdmin() external view returns (address) { ++ return s_bridgeLimitAdmin; ++ } ++ + /// @notice Checks if the pool can accept liquidity. + /// @return true if the pool can accept liquidity, false otherwise. + function canAcceptLiquidity() external view returns (bool) { +@@ -166,4 +263,15 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion + + _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig); + } ++ ++ /// @notice Returns the revision number ++ /// @return The revision number ++ function REVISION() public pure virtual returns (uint256) { ++ return 1; ++ } ++ ++ /// @inheritdoc VersionedInitializable ++ function getRevision() internal pure virtual override returns (uint256) { ++ return REVISION(); ++ } + } +``` diff --git a/contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md b/contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md new file mode 100644 index 0000000000..4029fe88bd --- /dev/null +++ b/contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md @@ -0,0 +1,51 @@ +```diff +diff --git a/src/v0.8/ccip/pools/TokenPool.sol b/src/v0.8/ccip/pools/UpgradeableTokenPool.sol +index b3571bb449..fcd8948098 100644 +--- a/src/v0.8/ccip/pools/TokenPool.sol ++++ b/src/v0.8/ccip/pools/UpgradeableTokenPool.sol +@@ -1,5 +1,5 @@ + // SPDX-License-Identifier: BUSL-1.1 +-pragma solidity 0.8.19; ++pragma solidity ^0.8.0; + + import {IPool} from "../interfaces/pools/IPool.sol"; + import {IARM} from "../interfaces/IARM.sol"; +@@ -15,7 +15,7 @@ import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts + /// @notice Base abstract class with common functions for all token pools. + /// A token pool serves as isolated place for holding tokens and token specific logic + /// that may execute as tokens move across the bridge. +-abstract contract TokenPool is IPool, OwnerIsCreator, IERC165 { ++abstract contract UpgradeableTokenPool is IPool, OwnerIsCreator, IERC165 { + using EnumerableSet for EnumerableSet.AddressSet; + using EnumerableSet for EnumerableSet.UintSet; + using RateLimiter for RateLimiter.TokenBucket; +@@ -74,23 +74,17 @@ abstract contract TokenPool is IPool, OwnerIsCreator, IERC165 { + EnumerableSet.UintSet internal s_remoteChainSelectors; + /// @dev Outbound rate limits. Corresponds to the inbound rate limit for the pool + /// on the remote chain. +- mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) internal s_outboundRateLimits; ++ mapping(uint64 => RateLimiter.TokenBucket) internal s_outboundRateLimits; + /// @dev Inbound rate limits. This allows per destination chain + /// token issuer specified rate limiting (e.g. issuers may trust chains to varying + /// degrees and prefer different limits) +- mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) internal s_inboundRateLimits; ++ mapping(uint64 => RateLimiter.TokenBucket) internal s_inboundRateLimits; + +- constructor(IERC20 token, address[] memory allowlist, address armProxy, address router) { +- if (address(token) == address(0) || router == address(0)) revert ZeroAddressNotAllowed(); ++ constructor(IERC20 token, address armProxy, bool allowlistEnabled) { ++ if (address(token) == address(0)) revert ZeroAddressNotAllowed(); + i_token = token; + i_armProxy = armProxy; +- s_router = IRouter(router); +- +- // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas. +- i_allowlistEnabled = allowlist.length > 0; +- if (i_allowlistEnabled) { +- _applyAllowListUpdates(new address[](0), allowlist); +- } ++ i_allowlistEnabled = allowlistEnabled; + } + + /// @notice Get ARM proxy address +``` From ffea18d05d2b0630c03e32f1d178f7ad0eadc7c9 Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Thu, 23 May 2024 18:21:30 +0200 Subject: [PATCH 2/4] fix: Directory restructure --- README.md | 5 + .../UpgradeableBurnMintTokenPool.sol | 6 +- .../UpgradeableBurnMintTokenPoolAbstract.sol | 2 +- .../UpgradeableLockReleaseTokenPool.sol | 12 +- .../pools/{ => GHO}/UpgradeableTokenPool.sol | 16 +- .../{ => GHO}/VersionedInitializable.sol | 0 .../diffs/BurnMintTokenPoolAbstract_diff.md | 6 +- .../{ => GHO}/diffs/BurnMintTokenPool_diff.md | 10 +- .../diffs/LockReleaseTokenPool_diff.md | 24 +- .../pools/{ => GHO}/diffs/TokenPool_diff.md | 6 +- contracts/src/v0.8/ccip/test/BaseTest.t.sol | 7 +- .../v0.8/ccip/test/mocks/MockUpgradeable.sol | 2 +- .../test/pools/GHO/GHOTokenPoolEthereum.t.sol | 4 +- .../GHO/GHOTokenPoolEthereumBridgeLimit.t.sol | 41 ++- ...okenPoolEthereumBridgeLimitInvariant.t.sol | 313 ++++++++++++++++++ ...GHOTokenPoolEthereumBridgeLimitSetup.t.sol | 26 +- .../pools/GHO/GHOTokenPoolEthereumE2E.t.sol | 6 +- .../pools/GHO/GHOTokenPoolEthereumSetup.t.sol | 4 +- .../test/pools/GHO/GHOTokenPoolRemote.t.sol | 4 +- .../pools/GHO/GHOTokenPoolRemoteE2E.t.sol | 6 +- .../pools/GHO/GHOTokenPoolRemoteSetup.t.sol | 4 +- 21 files changed, 431 insertions(+), 73 deletions(-) rename contracts/src/v0.8/ccip/pools/{ => GHO}/UpgradeableBurnMintTokenPool.sol (92%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/UpgradeableBurnMintTokenPoolAbstract.sol (95%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/UpgradeableLockReleaseTokenPool.sol (95%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/UpgradeableTokenPool.sol (95%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/VersionedInitializable.sol (100%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/diffs/BurnMintTokenPoolAbstract_diff.md (99%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/diffs/BurnMintTokenPool_diff.md (99%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/diffs/LockReleaseTokenPool_diff.md (99%) rename contracts/src/v0.8/ccip/pools/{ => GHO}/diffs/TokenPool_diff.md (99%) create mode 100644 contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitInvariant.t.sol diff --git a/README.md b/README.md index eff798d46b..2e90af3864 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +> Forked repository of CCIP contracts ([version 2.8.0 release](https://github.com/smartcontractkit/ccip/tree/v2.8.0-ccip1.4.0-release)) includes modifications for developing custom TokenPool contracts tailored for the GHO cross-chain strategy. All relevant code and tests are located in the [GHO pools directory](./contracts/v0.8/ccip/pools/GHO). +

@@ -232,9 +234,11 @@ flowchart RL github.com/smartcontractkit/chainlink/core/scripts --> github.com/smartcontractkit/chainlink/v2 ``` + The `integration-tests` and `core/scripts` modules import the root module using a relative replace in their `go.mod` files, so dependency changes in the root `go.mod` often require changes in those modules as well. After making a change, `go mod tidy` can be run on all three modules using: + ``` make gomodtidy ``` @@ -254,6 +258,7 @@ pnpm i ```bash pnpm test ``` + NOTE: Chainlink is currently in the process of migrating to Foundry and contains both Foundry and Hardhat tests in some versions. More information can be found here: [Chainlink Foundry Documentation](https://github.com/smartcontractkit/chainlink/blob/develop/contracts/foundry.md). Any 't.sol' files associated with Foundry tests, contained within the src directories will be ignored by Hardhat. diff --git a/contracts/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol similarity index 92% rename from contracts/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPool.sol rename to contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol index f07f8c3a28..cc0f24af39 100644 --- a/contracts/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; -import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol"; import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; import {UpgradeableBurnMintTokenPoolAbstract} from "./UpgradeableBurnMintTokenPoolAbstract.sol"; -import {IRouter} from "../interfaces/IRouter.sol"; +import {IRouter} from "../../interfaces/IRouter.sol"; import {VersionedInitializable} from "./VersionedInitializable.sol"; /// @title UpgradeableBurnMintTokenPool diff --git a/contracts/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPoolAbstract.sol b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPoolAbstract.sol similarity index 95% rename from contracts/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPoolAbstract.sol rename to contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPoolAbstract.sol index 651965e40b..e228732855 100644 --- a/contracts/src/v0.8/ccip/pools/UpgradeableBurnMintTokenPoolAbstract.sol +++ b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPoolAbstract.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; +import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol"; import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; diff --git a/contracts/src/v0.8/ccip/pools/UpgradeableLockReleaseTokenPool.sol b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableLockReleaseTokenPool.sol similarity index 95% rename from contracts/src/v0.8/ccip/pools/UpgradeableLockReleaseTokenPool.sol rename to contracts/src/v0.8/ccip/pools/GHO/UpgradeableLockReleaseTokenPool.sol index 7ca3d5f389..0fac98c708 100644 --- a/contracts/src/v0.8/ccip/pools/UpgradeableLockReleaseTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableLockReleaseTokenPool.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; -import {ILiquidityContainer} from "../../rebalancer/interfaces/ILiquidityContainer.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {ILiquidityContainer} from "../../../rebalancer/interfaces/ILiquidityContainer.sol"; import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; -import {RateLimiter} from "../libraries/RateLimiter.sol"; +import {RateLimiter} from "../../libraries/RateLimiter.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; -import {IRouter} from "../interfaces/IRouter.sol"; +import {IRouter} from "../../interfaces/IRouter.sol"; import {VersionedInitializable} from "./VersionedInitializable.sol"; /// @title UpgradeableLockReleaseTokenPool diff --git a/contracts/src/v0.8/ccip/pools/UpgradeableTokenPool.sol b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableTokenPool.sol similarity index 95% rename from contracts/src/v0.8/ccip/pools/UpgradeableTokenPool.sol rename to contracts/src/v0.8/ccip/pools/GHO/UpgradeableTokenPool.sol index fcd8948098..ee359ac1f8 100644 --- a/contracts/src/v0.8/ccip/pools/UpgradeableTokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/GHO/UpgradeableTokenPool.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {IPool} from "../interfaces/pools/IPool.sol"; -import {IARM} from "../interfaces/IARM.sol"; -import {IRouter} from "../interfaces/IRouter.sol"; +import {IPool} from "../../interfaces/pools/IPool.sol"; +import {IARM} from "../../interfaces/IARM.sol"; +import {IRouter} from "../../interfaces/IRouter.sol"; -import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol"; -import {RateLimiter} from "../libraries/RateLimiter.sol"; +import {OwnerIsCreator} from "../../../shared/access/OwnerIsCreator.sol"; +import {RateLimiter} from "../../libraries/RateLimiter.sol"; -import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; -import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; /// @notice Base abstract class with common functions for all token pools. /// A token pool serves as isolated place for holding tokens and token specific logic diff --git a/contracts/src/v0.8/ccip/pools/VersionedInitializable.sol b/contracts/src/v0.8/ccip/pools/GHO/VersionedInitializable.sol similarity index 100% rename from contracts/src/v0.8/ccip/pools/VersionedInitializable.sol rename to contracts/src/v0.8/ccip/pools/GHO/VersionedInitializable.sol diff --git a/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md b/contracts/src/v0.8/ccip/pools/GHO/diffs/BurnMintTokenPoolAbstract_diff.md similarity index 99% rename from contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md rename to contracts/src/v0.8/ccip/pools/GHO/diffs/BurnMintTokenPoolAbstract_diff.md index ab584e1849..11c20c0a6d 100644 --- a/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPoolAbstract_diff.md +++ b/contracts/src/v0.8/ccip/pools/GHO/diffs/BurnMintTokenPoolAbstract_diff.md @@ -7,12 +7,12 @@ index f5eb135186..651965e40b 100644 // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.19; +pragma solidity ^0.8.0; - + import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; - + -import {TokenPool} from "./TokenPool.sol"; +import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; - + -abstract contract BurnMintTokenPoolAbstract is TokenPool { +abstract contract UpgradeableBurnMintTokenPoolAbstract is UpgradeableTokenPool { /// @notice Contains the specific burn call for a pool. diff --git a/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md b/contracts/src/v0.8/ccip/pools/GHO/diffs/BurnMintTokenPool_diff.md similarity index 99% rename from contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md rename to contracts/src/v0.8/ccip/pools/GHO/diffs/BurnMintTokenPool_diff.md index 3fdf2d83da..1dfabb1e60 100644 --- a/contracts/src/v0.8/ccip/pools/diffs/BurnMintTokenPool_diff.md +++ b/contracts/src/v0.8/ccip/pools/GHO/diffs/BurnMintTokenPool_diff.md @@ -7,15 +7,15 @@ index 9af0f22f4c..f07f8c3a28 100644 // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.19; +pragma solidity ^0.8.0; - + import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; - + -import {TokenPool} from "./TokenPool.sol"; -import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol"; +import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; +import {UpgradeableBurnMintTokenPoolAbstract} from "./UpgradeableBurnMintTokenPoolAbstract.sol"; - + -/// @notice This pool mints and burns a 3rd-party token. -/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later. -/// It either accepts any address as originalSender, or only accepts whitelisted originalSender. @@ -33,7 +33,7 @@ index 9af0f22f4c..f07f8c3a28 100644 +/// - Move of allowlist and router definition to initialization stage +contract UpgradeableBurnMintTokenPool is VersionedInitializable, UpgradeableBurnMintTokenPoolAbstract, ITypeAndVersion { string public constant override typeAndVersion = "BurnMintTokenPool 1.4.0"; - + + /// @dev Constructor + /// @param token The bridgeable token that is managed by this pool. + /// @param armProxy The address of the arm proxy @@ -47,7 +47,7 @@ index 9af0f22f4c..f07f8c3a28 100644 - ) TokenPool(token, allowlist, armProxy, router) {} + bool allowlistEnabled + ) UpgradeableTokenPool(IBurnMintERC20(token), armProxy, allowlistEnabled) {} - + - /// @inheritdoc BurnMintTokenPoolAbstract + /// @dev Initializer + /// @dev The address passed as `owner` must accept ownership after initialization. diff --git a/contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md b/contracts/src/v0.8/ccip/pools/GHO/diffs/LockReleaseTokenPool_diff.md similarity index 99% rename from contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md rename to contracts/src/v0.8/ccip/pools/GHO/diffs/LockReleaseTokenPool_diff.md index 3a81233289..ac5d7bf30e 100644 --- a/contracts/src/v0.8/ccip/pools/diffs/LockReleaseTokenPool_diff.md +++ b/contracts/src/v0.8/ccip/pools/GHO/diffs/LockReleaseTokenPool_diff.md @@ -7,17 +7,17 @@ index 1a17fa0398..7ca3d5f389 100644 // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.19; +pragma solidity ^0.8.0; - + import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; import {ILiquidityContainer} from "../../rebalancer/interfaces/ILiquidityContainer.sol"; - + -import {TokenPool} from "./TokenPool.sol"; +import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; - + import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; - + -/// @notice Token pool used for tokens on their native chain. This uses a lock and release mechanism. -/// Because of lock/unlock requiring liquidity, this pool contract also has function to add and remove -/// liquidity. This allows for proper bookkeeping for both user and liquidity provider balances. @@ -40,22 +40,22 @@ index 1a17fa0398..7ca3d5f389 100644 + ITypeAndVersion +{ using SafeERC20 for IERC20; - + error InsufficientLiquidity(); error LiquidityNotAccepted(); error Unauthorized(address caller); - + + error BridgeLimitExceeded(uint256 bridgeLimit); + error NotEnoughBridgedAmount(); + event BridgeLimitUpdated(uint256 oldBridgeLimit, uint256 newBridgeLimit); + string public constant override typeAndVersion = "LockReleaseTokenPool 1.4.0"; - + /// @dev The unique lock release pool flag to signal through EIP 165. @@ -37,16 +52,55 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion /// @dev Can be address(0) if none is configured. address internal s_rateLimitAdmin; - + + /// @notice Maximum amount of tokens that can be bridged to other chains + uint256 private s_bridgeLimit; + /// @notice Amount of tokens bridged (transferred out) @@ -83,7 +83,7 @@ index 1a17fa0398..7ca3d5f389 100644 + ) UpgradeableTokenPool(IERC20(token), armProxy, allowlistEnabled) { i_acceptLiquidity = acceptLiquidity; } - + + /// @dev Initializer + /// @dev The address passed as `owner` must accept ownership after initialization. + /// @dev The `allowlist` is only effective if pool is set to access-controlled mode @@ -138,7 +138,7 @@ index 1a17fa0398..7ca3d5f389 100644 @@ -120,11 +182,46 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion s_rateLimitAdmin = rateLimitAdmin; } - + + /// @notice Sets the bridge limit, the maximum amount of tokens that can be bridged out + /// @dev Only callable by the owner or the bridge limit admin. + /// @dev Bridge limit changes should be carefully managed, specially when reducing below the current bridged amount @@ -173,7 +173,7 @@ index 1a17fa0398..7ca3d5f389 100644 function getRateLimitAdmin() external view returns (address) { return s_rateLimitAdmin; } - + + /// @notice Gets the bridge limiter admin address. + function getBridgeLimitAdmin() external view returns (address) { + return s_bridgeLimitAdmin; @@ -183,7 +183,7 @@ index 1a17fa0398..7ca3d5f389 100644 /// @return true if the pool can accept liquidity, false otherwise. function canAcceptLiquidity() external view returns (bool) { @@ -166,4 +263,15 @@ contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion - + _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig); } + diff --git a/contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md b/contracts/src/v0.8/ccip/pools/GHO/diffs/TokenPool_diff.md similarity index 99% rename from contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md rename to contracts/src/v0.8/ccip/pools/GHO/diffs/TokenPool_diff.md index 4029fe88bd..6ff8893172 100644 --- a/contracts/src/v0.8/ccip/pools/diffs/TokenPool_diff.md +++ b/contracts/src/v0.8/ccip/pools/GHO/diffs/TokenPool_diff.md @@ -7,7 +7,7 @@ index b3571bb449..fcd8948098 100644 // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.19; +pragma solidity ^0.8.0; - + import {IPool} from "../interfaces/pools/IPool.sol"; import {IARM} from "../interfaces/IARM.sol"; @@ -15,7 +15,7 @@ import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts @@ -30,7 +30,7 @@ index b3571bb449..fcd8948098 100644 /// degrees and prefer different limits) - mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) internal s_inboundRateLimits; + mapping(uint64 => RateLimiter.TokenBucket) internal s_inboundRateLimits; - + - constructor(IERC20 token, address[] memory allowlist, address armProxy, address router) { - if (address(token) == address(0) || router == address(0)) revert ZeroAddressNotAllowed(); + constructor(IERC20 token, address armProxy, bool allowlistEnabled) { @@ -46,6 +46,6 @@ index b3571bb449..fcd8948098 100644 - } + i_allowlistEnabled = allowlistEnabled; } - + /// @notice Get ARM proxy address ``` diff --git a/contracts/src/v0.8/ccip/test/BaseTest.t.sol b/contracts/src/v0.8/ccip/test/BaseTest.t.sol index e12746a802..f645a6e612 100644 --- a/contracts/src/v0.8/ccip/test/BaseTest.t.sol +++ b/contracts/src/v0.8/ccip/test/BaseTest.t.sol @@ -2,12 +2,15 @@ pragma solidity 0.8.19; import {Test, stdError} from "forge-std/Test.sol"; +import {StdInvariant} from "forge-std/StdInvariant.sol"; +import {StdCheats} from "forge-std/StdCheats.sol"; +import {StdUtils} from "forge-std/StdUtils.sol"; import {MockARM} from "./mocks/MockARM.sol"; import {StructFactory} from "./StructFactory.sol"; import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent-proxy/TransparentUpgradeableProxy.sol"; -import {UpgradeableLockReleaseTokenPool} from "../pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableBurnMintTokenPool} from "../pools/UpgradeableBurnMintTokenPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableBurnMintTokenPool} from "../pools/GHO/UpgradeableBurnMintTokenPool.sol"; import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol"; contract BaseTest is Test, StructFactory { diff --git a/contracts/src/v0.8/ccip/test/mocks/MockUpgradeable.sol b/contracts/src/v0.8/ccip/test/mocks/MockUpgradeable.sol index e613768e6c..bd80dee812 100644 --- a/contracts/src/v0.8/ccip/test/mocks/MockUpgradeable.sol +++ b/contracts/src/v0.8/ccip/test/mocks/MockUpgradeable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {VersionedInitializable} from "../../pools/VersionedInitializable.sol"; +import {VersionedInitializable} from "../../pools/GHO/VersionedInitializable.sol"; /** * @dev Mock contract to test upgrades, not to be used in production. diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereum.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereum.t.sol index 6ab3e47ecd..8eacd4232e 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereum.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereum.t.sol @@ -8,8 +8,8 @@ import {stdError} from "forge-std/Test.sol"; import {MockUpgradeable} from "../../mocks/MockUpgradeable.sol"; import {IPool} from "../../../interfaces/pools/IPool.sol"; import {LockReleaseTokenPool} from "../../../pools/LockReleaseTokenPool.sol"; -import {UpgradeableLockReleaseTokenPool} from "../../../pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {EVM2EVMOffRamp} from "../../../offRamp/EVM2EVMOffRamp.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol"; diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimit.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimit.t.sol index 83eae99a71..6bf367d5a1 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimit.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimit.t.sol @@ -746,10 +746,8 @@ contract GHOTokenPoolEthereumBridgeLimitTripleScenario is GHOTokenPoolEthereumBr /// @dev All remote liquidity is on one chain or the other function testLiquidityUnbalanced() public { - uint256 amount; - // Bridge all out to Arbitrum - amount = _getMaxToBridgeOut(0); + uint256 amount = _getMaxToBridgeOut(0); deal(tokens[0], USER, amount); _bridgeGho(0, 1, USER, amount); @@ -810,4 +808,41 @@ contract GHOTokenPoolEthereumBridgeLimitTripleScenario is GHOTokenPoolEthereumBr _updateBucketCapacity(1, 10); _moveGhoDestination(0, 1, USER, 10); } + + /// @dev Test showcasing a user locked due to a bridge limit reduction below current bridged amount + function testUserLockedBridgeLimitReductionBelowLevel() public { + // Bridge all out to Arbitrum + uint256 amount = _getMaxToBridgeOut(0); + deal(tokens[0], USER, amount); + _bridgeGho(0, 1, USER, amount); + + // Reduce bridge limit below current bridged amount + uint256 newBridgeLimit = amount / 2; + _updateBridgeLimit(newBridgeLimit); + _updateBucketCapacity(1, newBridgeLimit); + // _updateBucketCapacity(2, newBridgeLimit); + + // assertEq(_getMaxToBridgeIn(2), newBridgeLimit); + + // Reverts + _bridgeGho(1, 2, USER, amount); + } + + /// @dev Test showcasing a user locked due to a bridge limit reduction below current bridged amount + function testUserLockedBridgeLimitReductionBelowLevel2() public { + // Bridge all out to Arbitrum + uint256 amount = _getMaxToBridgeOut(0); + deal(tokens[0], USER, amount); + _bridgeGho(0, 1, USER, amount); + + // Reduce bridge limit below current bridged amount + uint256 newBridgeLimit = amount / 2; + _updateBridgeLimit(newBridgeLimit); + _updateBucketCapacity(2, newBridgeLimit); + + // assertEq(_getMaxToBridgeIn(2), newBridgeLimit); + + // Reverts + _bridgeGho(1, 2, USER, amount); + } } diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitInvariant.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitInvariant.t.sol new file mode 100644 index 0000000000..300b2caf21 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitInvariant.t.sol @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +import {GhoToken} from "@aave/gho-core/gho/GhoToken.sol"; + +import {IPool} from "../../../interfaces/pools/IPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; +import {RateLimiter} from "../../../libraries/RateLimiter.sol"; + +import {StdInvariant} from "forge-std/StdInvariant.sol"; +import {BaseTest} from "../../BaseTest.t.sol"; + +import {console2} from "forge-std/console2.sol"; + +contract GHOTokenPoolHandler is BaseTest { + address internal ARM_PROXY = makeAddr("ARM_PROXY"); + address internal ROUTER = makeAddr("ROUTER"); + address internal RAMP = makeAddr("RAMP"); + address internal AAVE_DAO = makeAddr("AAVE_DAO"); + address internal PROXY_ADMIN = makeAddr("PROXY_ADMIN"); + address internal USER = makeAddr("USER"); + + uint256 public immutable INITIAL_BRIDGE_LIMIT = 100e6 * 1e18; + + uint256[] public chainsList; + mapping(uint256 => address) public pools; // chainId => bridgeTokenPool + mapping(uint256 => address) public tokens; // chainId => ghoToken + mapping(uint256 => uint256) public bucketCapacities; // chainId => bucketCapacities + mapping(uint256 => uint256) public bucketLevels; // chainId => bucketLevels + mapping(uint256 => uint256) public liquidity; // chainId => liquidity + uint256 public remoteLiquidity; + uint256 public bridged; + bool public capacityBelowLevelUpdate; + + constructor() { + // Ethereum with id 0 + chainsList.push(0); + tokens[0] = address(new GhoToken(AAVE_DAO)); + pools[0] = _deployUpgradeableLockReleaseTokenPool( + tokens[0], + ARM_PROXY, + ROUTER, + OWNER, + INITIAL_BRIDGE_LIMIT, + PROXY_ADMIN + ); + + // Mock calls for bridging + vm.mockCall(ROUTER, abi.encodeWithSelector(bytes4(keccak256("getOnRamp(uint64)"))), abi.encode(RAMP)); + vm.mockCall(ROUTER, abi.encodeWithSelector(bytes4(keccak256("isOffRamp(uint64,address)"))), abi.encode(true)); + vm.mockCall(ARM_PROXY, abi.encodeWithSelector(bytes4(keccak256("isCursed()"))), abi.encode(false)); + + // Arbitrum + _addBridge(1, INITIAL_BRIDGE_LIMIT); + _enableLane(0, 1); + + // Avalanche + _addBridge(2, INITIAL_BRIDGE_LIMIT); + _enableLane(0, 2); + _enableLane(1, 2); + } + + /// forge-config: ccip.fuzz.runs = 500 + function bridgeGho(uint256 fromChain, uint256 toChain, uint256 amount) public { + fromChain = bound(fromChain, 0, 2); + toChain = bound(toChain, 0, 2); + vm.assume(fromChain != toChain); + uint256 maxBalance = GhoToken(tokens[fromChain]).balanceOf(address(this)); + uint256 maxToBridge = _getMaxToBridgeOut(fromChain); + uint256 maxAmount = maxBalance > maxToBridge ? maxToBridge : maxBalance; + amount = bound(amount, 0, maxAmount); + + console2.log("bridgeGho", fromChain, toChain, amount); + console2.log("bridgeLimit", UpgradeableLockReleaseTokenPool(pools[0]).getBridgeLimit()); + console2.log("currentBridged", UpgradeableLockReleaseTokenPool(pools[0]).getBridgeLimit()); + if (!_isEthereumChain(fromChain)) { + console2.log("bucket from", fromChain, _getCapacity(fromChain), _getLevel(fromChain)); + } + if (!_isEthereumChain(toChain)) { + console2.log("bucket to", toChain, _getCapacity(toChain), _getLevel(toChain)); + } + + if (amount > 0) { + _bridgeGho(fromChain, toChain, address(this), amount); + } + } + + /// forge-config: ccip.fuzz.runs = 500 + function updateBucketCapacity(uint256 chain, uint128 newCapacity) public { + chain = bound(chain, 1, 2); + uint256 otherChain = (chain % 2) + 1; + vm.assume(newCapacity >= bridged); + + uint256 oldCapacity = bucketCapacities[chain]; + + console2.log("updateBucketCapacity", chain, oldCapacity, newCapacity); + if (newCapacity < bucketLevels[chain]) { + capacityBelowLevelUpdate = true; + } else { + capacityBelowLevelUpdate = false; + } + + if (newCapacity > oldCapacity) { + // Increase + _updateBucketCapacity(chain, newCapacity); + // keep bridge limit as the minimum bucket capacity + if (newCapacity < bucketCapacities[otherChain]) { + _updateBridgeLimit(newCapacity); + } + } else { + // Reduction + // keep bridge limit as the minimum bucket capacity + if (newCapacity < bucketCapacities[otherChain]) { + _updateBridgeLimit(newCapacity); + } + _updateBucketCapacity(chain, newCapacity); + } + } + + function _enableLane(uint256 fromId, uint256 toId) internal { + // from + UpgradeableTokenPool.ChainUpdate[] memory chainUpdate = new UpgradeableTokenPool.ChainUpdate[](1); + RateLimiter.Config memory emptyRateConfig = RateLimiter.Config(false, 0, 0); + chainUpdate[0] = UpgradeableTokenPool.ChainUpdate({ + remoteChainSelector: uint64(toId), + allowed: true, + outboundRateLimiterConfig: emptyRateConfig, + inboundRateLimiterConfig: emptyRateConfig + }); + + vm.startPrank(OWNER); + UpgradeableTokenPool(pools[fromId]).applyChainUpdates(chainUpdate); + + // to + chainUpdate[0].remoteChainSelector = uint64(fromId); + UpgradeableTokenPool(pools[toId]).applyChainUpdates(chainUpdate); + vm.stopPrank(); + } + + function _addBridge(uint256 chainId, uint256 bucketCapacity) internal { + require(tokens[chainId] == address(0), "BRIDGE_ALREADY_EXISTS"); + + chainsList.push(chainId); + + // GHO Token + GhoToken ghoToken = new GhoToken(AAVE_DAO); + tokens[chainId] = address(ghoToken); + + // UpgradeableTokenPool + address bridgeTokenPool = _deployUpgradeableBurnMintTokenPool( + address(ghoToken), + ARM_PROXY, + ROUTER, + OWNER, + PROXY_ADMIN + ); + pools[chainId] = bridgeTokenPool; + + // Facilitator + bucketCapacities[chainId] = bucketCapacity; + vm.stopPrank(); + vm.startPrank(AAVE_DAO); + ghoToken.grantRole(ghoToken.FACILITATOR_MANAGER_ROLE(), AAVE_DAO); + ghoToken.addFacilitator(bridgeTokenPool, "UpgradeableTokenPool", uint128(bucketCapacity)); + vm.stopPrank(); + } + + function _updateBridgeLimit(uint256 newBridgeLimit) internal { + vm.stopPrank(); + vm.startPrank(OWNER); + UpgradeableLockReleaseTokenPool(pools[0]).setBridgeLimit(newBridgeLimit); + vm.stopPrank(); + } + + function _updateBucketCapacity(uint256 chainId, uint256 newBucketCapacity) internal { + bucketCapacities[chainId] = newBucketCapacity; + vm.stopPrank(); + vm.startPrank(AAVE_DAO); + GhoToken(tokens[chainId]).grantRole(GhoToken(tokens[chainId]).BUCKET_MANAGER_ROLE(), AAVE_DAO); + GhoToken(tokens[chainId]).setFacilitatorBucketCapacity(pools[chainId], uint128(newBucketCapacity)); + vm.stopPrank(); + } + + function _getCapacity(uint256 chain) internal view returns (uint256) { + require(!_isEthereumChain(chain), "No bucket on Ethereum"); + (uint256 capacity, ) = GhoToken(tokens[chain]).getFacilitatorBucket(pools[chain]); + return capacity; + } + + function _getLevel(uint256 chain) internal view returns (uint256) { + require(!_isEthereumChain(chain), "No bucket on Ethereum"); + (, uint256 level) = GhoToken(tokens[chain]).getFacilitatorBucket(pools[chain]); + return level; + } + + function _getMaxToBridgeOut(uint256 fromChain) internal view returns (uint256) { + if (_isEthereumChain(fromChain)) { + UpgradeableLockReleaseTokenPool ethTokenPool = UpgradeableLockReleaseTokenPool(pools[0]); + uint256 bridgeLimit = ethTokenPool.getBridgeLimit(); + uint256 currentBridged = ethTokenPool.getCurrentBridgedAmount(); + return currentBridged > bridgeLimit ? 0 : bridgeLimit - currentBridged; + } else { + (, uint256 level) = GhoToken(tokens[fromChain]).getFacilitatorBucket(pools[fromChain]); + return level; + } + } + + function _bridgeGho(uint256 fromChain, uint256 toChain, address user, uint256 amount) internal { + _moveGhoOrigin(fromChain, toChain, user, amount); + _moveGhoDestination(fromChain, toChain, user, amount); + } + + function _moveGhoOrigin(uint256 fromChain, uint256 toChain, address user, uint256 amount) internal { + // Simulate CCIP pull of funds + vm.startPrank(user); + GhoToken(tokens[fromChain]).transfer(pools[fromChain], amount); + + vm.startPrank(RAMP); + IPool(pools[fromChain]).lockOrBurn(user, bytes(""), amount, uint64(toChain), bytes("")); + + if (_isEthereumChain(fromChain)) { + // Lock + bridged += amount; + } else { + // Burn + bucketLevels[fromChain] -= amount; + liquidity[fromChain] -= amount; + remoteLiquidity -= amount; + } + } + + function _moveGhoDestination(uint256 fromChain, uint256 toChain, address user, uint256 amount) internal { + vm.startPrank(RAMP); + IPool(pools[toChain]).releaseOrMint(bytes(""), user, amount, uint64(fromChain), bytes("")); + + if (_isEthereumChain(toChain)) { + // Release + bridged -= amount; + } else { + // Mint + bucketLevels[toChain] += amount; + liquidity[toChain] += amount; + remoteLiquidity += amount; + } + } + + function _isEthereumChain(uint256 chainId) internal pure returns (bool) { + return chainId == 0; + } + + function getChainsList() public view returns (uint256[] memory) { + return chainsList; + } +} + +contract GHOTokenPoolEthereumBridgeLimitInvariant is BaseTest { + GHOTokenPoolHandler handler; + + function setUp() public override { + super.setUp(); + + handler = new GHOTokenPoolHandler(); + handler.getChainsList(); + deal(handler.tokens(0), address(handler), handler.INITIAL_BRIDGE_LIMIT()); + + targetContract(address(handler)); + } + + /// forge-config: ccip.invariant.fail-on-revert = true + /// forge-config: ccip.invariant.runs = 2000 + /// forge-config: ccip.invariant.depth = 50 + function invariant_bridgeLimit() public { + // Check bridged + assertEq(UpgradeableLockReleaseTokenPool(handler.pools(0)).getCurrentBridgedAmount(), handler.bridged()); + + // Check levels and buckets + uint256 sumLevels; + uint256 chainId; + uint256 capacity; + uint256 level; + uint256[] memory chainsListLocal = handler.getChainsList(); + for (uint i = 1; i < chainsListLocal.length; i++) { + // not counting Ethereum -{0} + chainId = chainsListLocal[i]; + (capacity, level) = GhoToken(handler.tokens(chainId)).getFacilitatorBucket(handler.pools(chainId)); + + // Aggregate levels + sumLevels += level; + + assertEq(capacity, handler.bucketCapacities(chainId), "wrong bucket capacity"); + assertEq(level, handler.bucketLevels(chainId), "wrong bucket level"); + + assertGe( + capacity, + UpgradeableLockReleaseTokenPool(handler.pools(0)).getBridgeLimit(), + "capacity must be equal to bridgeLimit" + ); + + // This invariant only holds if there were no bridge limit reductions below the current bridged amount + if (!handler.capacityBelowLevelUpdate()) { + assertLe( + level, + UpgradeableLockReleaseTokenPool(handler.pools(0)).getBridgeLimit(), + "level cannot be higher than bridgeLimit" + ); + } + } + // Check bridged is equal to sum of levels + assertEq(UpgradeableLockReleaseTokenPool(handler.pools(0)).getCurrentBridgedAmount(), sumLevels, "wrong bridged"); + assertEq(handler.remoteLiquidity(), sumLevels, "wrong bridged"); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitSetup.t.sol index 16cea99aeb..5e9b5f147a 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumBridgeLimitSetup.t.sol @@ -5,11 +5,12 @@ import {GhoToken} from "@aave/gho-core/gho/GhoToken.sol"; import {BaseTest} from "../../BaseTest.t.sol"; import {IPool} from "../../../interfaces/pools/IPool.sol"; -import {UpgradeableLockReleaseTokenPool} from "../../../pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableBurnMintTokenPool} from "../../../pools/UpgradeableBurnMintTokenPool.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; +import {console2} from "forge-std/console2.sol"; contract GHOTokenPoolEthereumBridgeLimitSetup is BaseTest { address internal ARM_PROXY = makeAddr("ARM_PROXY"); address internal ROUTER = makeAddr("ROUTER"); @@ -18,18 +19,19 @@ contract GHOTokenPoolEthereumBridgeLimitSetup is BaseTest { address internal PROXY_ADMIN = makeAddr("PROXY_ADMIN"); address internal USER = makeAddr("USER"); - uint256 internal INITIAL_BRIDGE_LIMIT = 100e6 * 1e18; + uint256 public immutable INITIAL_BRIDGE_LIMIT = 100e6 * 1e18; - uint256[] internal chainsList; - mapping(uint256 => address) internal pools; // chainId => bridgeTokenPool - mapping(uint256 => address) internal tokens; // chainId => ghoToken - mapping(uint256 => uint256) internal bucketCapacities; // chainId => bucketCapacities - mapping(uint256 => uint256) internal bucketLevels; // chainId => bucketLevels - mapping(uint256 => uint256) internal liquidity; // chainId => liquidity - uint256 internal remoteLiquidity; - uint256 internal bridged; + uint256[] public chainsList; + mapping(uint256 => address) public pools; // chainId => bridgeTokenPool + mapping(uint256 => address) public tokens; // chainId => ghoToken + mapping(uint256 => uint256) public bucketCapacities; // chainId => bucketCapacities + mapping(uint256 => uint256) public bucketLevels; // chainId => bucketLevels + mapping(uint256 => uint256) public liquidity; // chainId => liquidity + uint256 public remoteLiquidity; + uint256 public bridged; function setUp() public virtual override { + console2.log("ENTRA"); // Ethereum with id 0 chainsList.push(0); tokens[0] = address(new GhoToken(AAVE_DAO)); diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumE2E.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumE2E.t.sol index 82e236618b..52ef9f5d6d 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumE2E.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumE2E.t.sol @@ -9,9 +9,9 @@ import "../../commitStore/CommitStore.t.sol"; import "../../onRamp/EVM2EVMOnRampSetup.t.sol"; import "../../offRamp/EVM2EVMOffRampSetup.t.sol"; import {IBurnMintERC20} from "../../../../shared/token/ERC20/IBurnMintERC20.sol"; -import {UpgradeableLockReleaseTokenPool} from "../../../pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableBurnMintTokenPool} from "../../../pools/UpgradeableBurnMintTokenPool.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {IPool} from "../../../interfaces/pools/IPool.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; import {E2E} from "../End2End.t.sol"; diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumSetup.t.sol index 89d27aaf9f..44038b9eb4 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolEthereumSetup.t.sol @@ -7,8 +7,8 @@ import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent- import {stdError} from "forge-std/Test.sol"; import {BaseTest} from "../../BaseTest.t.sol"; import {IPool} from "../../../interfaces/pools/IPool.sol"; -import {UpgradeableLockReleaseTokenPool} from "../../../pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {EVM2EVMOnRamp} from "../../../onRamp/EVM2EVMOnRamp.sol"; import {EVM2EVMOffRamp} from "../../../offRamp/EVM2EVMOffRamp.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemote.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemote.t.sol index 3e2696bbf9..b1027365c2 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemote.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemote.t.sol @@ -6,11 +6,11 @@ import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent- import {stdError} from "forge-std/Test.sol"; import {MockUpgradeable} from "../../mocks/MockUpgradeable.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {EVM2EVMOnRamp} from "../../../onRamp/EVM2EVMOnRamp.sol"; import {EVM2EVMOffRamp} from "../../../offRamp/EVM2EVMOffRamp.sol"; import {BurnMintTokenPool} from "../../../pools/BurnMintTokenPool.sol"; -import {UpgradeableBurnMintTokenPool} from "../../../pools/UpgradeableBurnMintTokenPool.sol"; +import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; import {GHOTokenPoolRemoteSetup} from "./GHOTokenPoolRemoteSetup.t.sol"; diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteE2E.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteE2E.t.sol index 62d6f5235b..ccad39ce6c 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteE2E.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteE2E.t.sol @@ -9,9 +9,9 @@ import "../../commitStore/CommitStore.t.sol"; import "../../onRamp/EVM2EVMOnRampSetup.t.sol"; import "../../offRamp/EVM2EVMOffRampSetup.t.sol"; import {IBurnMintERC20} from "../../../../shared/token/ERC20/IBurnMintERC20.sol"; -import {UpgradeableLockReleaseTokenPool} from "../../../pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableBurnMintTokenPool} from "../../../pools/UpgradeableBurnMintTokenPool.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol"; +import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {IPool} from "../../../interfaces/pools/IPool.sol"; import {RateLimiter} from "../../../libraries/RateLimiter.sol"; import {E2E} from "../End2End.t.sol"; diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteSetup.t.sol index 529715aaf2..402ca41b17 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/GHOTokenPoolRemoteSetup.t.sol @@ -5,10 +5,10 @@ import {GhoToken} from "@aave/gho-core/gho/GhoToken.sol"; import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent-proxy/TransparentUpgradeableProxy.sol"; import {stdError} from "forge-std/Test.sol"; -import {UpgradeableTokenPool} from "../../../pools/UpgradeableTokenPool.sol"; +import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol"; import {Router} from "../../../Router.sol"; import {BurnMintERC677} from "../../../../shared/token/ERC677/BurnMintERC677.sol"; -import {UpgradeableBurnMintTokenPool} from "../../../pools/UpgradeableBurnMintTokenPool.sol"; +import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol"; import {RouterSetup} from "../../router/RouterSetup.t.sol"; contract GHOTokenPoolRemoteSetup is RouterSetup { From bf5ae088cbbf18bb5524c5a9ee5473b7a1527cfc Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Thu, 23 May 2024 18:25:25 +0200 Subject: [PATCH 3/4] fix: Fix README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e90af3864..db9ffe5360 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -> Forked repository of CCIP contracts ([version 2.8.0 release](https://github.com/smartcontractkit/ccip/tree/v2.8.0-ccip1.4.0-release)) includes modifications for developing custom TokenPool contracts tailored for the GHO cross-chain strategy. All relevant code and tests are located in the [GHO pools directory](./contracts/v0.8/ccip/pools/GHO). +> ❗️ Forked repository of CCIP contracts ([version 2.8.0 release](https://github.com/smartcontractkit/ccip/tree/v2.8.0-ccip1.4.0-release)) that includes modifications for developing custom TokenPool contracts tailored for the [GHO cross-chain strategy](https://governance.aave.com/t/arfc-gho-cross-chain-launch/17616). All relevant code and tests are located in the [GHO pools directory](./contracts/v0.8/ccip/pools/GHO).

From e2eac9f5a5ce3b609e4b47021b48c38ebf7d8d5a Mon Sep 17 00:00:00 2001 From: miguelmtzinf Date: Thu, 23 May 2024 18:29:15 +0200 Subject: [PATCH 4/4] fix: Remove unneccesary files --- contracts/src/v0.8/ccip/script.s.sol | 83 ---------------------------- 1 file changed, 83 deletions(-) delete mode 100644 contracts/src/v0.8/ccip/script.s.sol diff --git a/contracts/src/v0.8/ccip/script.s.sol b/contracts/src/v0.8/ccip/script.s.sol deleted file mode 100644 index 95ef0c509b..0000000000 --- a/contracts/src/v0.8/ccip/script.s.sol +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; - -import {Script, console2} from 'forge-std/Script.sol'; -import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent-proxy/TransparentUpgradeableProxy.sol"; -import {UpgradeableLockReleaseTokenPool} from "./pools/UpgradeableLockReleaseTokenPool.sol"; -import {UpgradeableBurnMintTokenPool} from "./pools/UpgradeableBurnMintTokenPool.sol"; -import {UpgradeableTokenPool} from "./pools/UpgradeableTokenPool.sol"; - - -contract DeployLockReleaseTokenPool is Script { - // ETH SEPOLIA - 11155111 - address GHO_TOKEN = 0xc4bF5CbDaBE595361438F8c6a187bDc330539c60; - address PROXY_ADMIN = 0xfA0e305E0f46AB04f00ae6b5f4560d61a2183E00; - address ARM_PROXY = 0xba3f6251de62dED61Ff98590cB2fDf6871FbB991; - address ROUTER = 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59; - address TOKEN_POOL_OWNER = 0xa4b184737418B3014b3B1b1f0bE6700Bd9640FfE; - - // ARB SEPOLIA - 421614 - // address GHO_TOKEN = 0xb13Cfa6f8B2Eed2C37fB00fF0c1A59807C585810; - // address PROXY_ADMIN = 0xfA0e305E0f46AB04f00ae6b5f4560d61a2183E00; - // address ARM_PROXY = 0x9527E2d01A3064ef6b50c1Da1C0cC523803BCFF2; - // address ROUTER = 0x2a9C5afB0d0e4BAb2BCdaE109EC4b0c4Be15a165; - // address TOKEN_POOL_OWNER = 0xa4b184737418B3014b3B1b1f0bE6700Bd9640FfE; - - // BASE SEPOLIA - 84532 - // address GHO_TOKEN = 0x7CFa3f3d1cded0Da930881c609D4Dbf0012c14Bb; - // address PROXY_ADMIN = 0xfA0e305E0f46AB04f00ae6b5f4560d61a2183E00; - // address ARM_PROXY = 0x99360767a4705f68CcCb9533195B761648d6d807; - // address ROUTER = 0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93; - // address TOKEN_POOL_OWNER = 0xa4b184737418B3014b3B1b1f0bE6700Bd9640FfE; - - // FUJI - 43113 - // address GHO_TOKEN = 0x9c04928Cc678776eC1C1C0E46ecC03a5F47A7723; - // address PROXY_ADMIN = 0xfA0e305E0f46AB04f00ae6b5f4560d61a2183E00; - // address ARM_PROXY = 0xAc8CFc3762a979628334a0E4C1026244498E821b; - // address ROUTER = 0xF694E193200268f9a4868e4Aa017A0118C9a8177; - // address TOKEN_POOL_OWNER = 0xa4b184737418B3014b3B1b1f0bE6700Bd9640FfE; - - function run() external { - console2.log('Block Number: ', block.number); - vm.startBroadcast(); - - UpgradeableLockReleaseTokenPool tokenPoolImpl = new UpgradeableLockReleaseTokenPool(GHO_TOKEN, ARM_PROXY, false, true); - // Imple init - address[] memory emptyArray = new address[](0); - tokenPoolImpl.initialize(TOKEN_POOL_OWNER, emptyArray, ROUTER, 10e18); - // proxy deploy and init - bytes memory tokenPoolInitParams = abi.encodeWithSignature( - "initialize(address,address[],address,uint256)", - TOKEN_POOL_OWNER, - emptyArray, - ROUTER, - 10e18 - ); - TransparentUpgradeableProxy tokenPoolProxy = new TransparentUpgradeableProxy( - address(tokenPoolImpl), - PROXY_ADMIN, - tokenPoolInitParams - ); - - vm.stopBroadcast(); - // Manage ownership - // UpgradeableLockReleaseTokenPool(address(tokenPoolProxy)).acceptOwnership(); - - } -} - -contract Accept is Script { - - function run() external { - console2.log('Block Number: ', block.number); - vm.startBroadcast(); - - console2.log(UpgradeableLockReleaseTokenPool(0x50A715d63bDcd5455a3308932a624263d170Dd74).getBridgeLimit()); - - // Manage ownership - UpgradeableLockReleaseTokenPool(0x50A715d63bDcd5455a3308932a624263d170Dd74).acceptOwnership(); - vm.stopBroadcast(); - - } -} -