Skip to content

Commit 46a4bdc

Browse files
DhairyaSethiCheyenneAtapourmiguelmtzinf
authored
feat: Add compatibility for CCIP 1.5 Migration (#18)
* feat: enable remote rateLimitAdmin * chore: prettier * fix: remove unnecessary modifer * chore: reorder state variables * feat: upgrade remote pool * test: add tests after upgrading * feat: reserve storage space for future upgrades * diff: Update diff for UpgradeableBurnMintTokenPool * ci: Fix ci * ci: Fix ci * test: show init reverting after upgrade * fix: remove gap * fix: return to original test suite * test: simple tests showing upgrade * fix: add and correct comments * fix: comments to match parent contract * chore: prettier * fix: allow calls 1.2 on ramp during 1.5 migration by introducing legacyOnRamp * chore: update certora & compiler used to match forge * test: add fork base * wip: fork upgrade test * fix: onlyOnRamp condition * test: add testnet legacy pools * test: successful send with upgrade * test: add releaseOrMint tests * fix: legacyOnRamp -> proxyPool * feat: set proxy pool only once for dest chain * feat(tokenPools): disableInitializer on constructor, upd docs * fix: revert UpgradeableBurnMintTokenPoolOld from #16 (was accidentally merged) * chore: update diffs * chore: use negative conditional code style * docs: move base contract modification doc * Update contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/ForkBase.t.sol Co-authored-by: miguelmtz <[email protected]> * chore: update diffs * doc: for SendViaLegacyPool test * chore: reorder imports for consistency with code style * fix: rm immutability of pool proxy * test: rename for consistency * fix: use chain agnostic proxypool * fix: import on token pools to match chainlink style convention, upd diff * fix: test renaming to match style convention * chore: fix import order * chore: rm internal inline, typo * test: for 1_2OnRamp, refactor _messageToEvent * chore: rm unsued * doc: rm incorrect comment on proxy pool * test: fork test pre migration setup * test: expect events fork before migration * chore: revert name change in test * chore: upd comment * fix: rm disableInitializer as its handled by Initializable * chore: fix diff using diff algorithm patience * fix: add proxyPool whitelist to onlyOffRamp modifier * test: improve off ramp tests * chore: cleanup imports * test: dynamically fetch dest gas amt * fix: docs --------- Co-authored-by: CheyenneAtapour <[email protected]> Co-authored-by: miguelmtzinf <[email protected]> Co-authored-by: miguelmtz <[email protected]>
1 parent d27d468 commit 46a4bdc

18 files changed

+1372
-72
lines changed

.github/workflows/certora.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ jobs:
2020
with: { java-version: "11", java-package: jre }
2121

2222
- name: Install certora cli
23-
run: pip install certora-cli==7.6.3
23+
run: pip install certora-cli==7.17.2
2424

2525
- name: Install solc
2626
run: |
27-
wget https://github.com/ethereum/solidity/releases/download/v0.8.10/solc-static-linux
27+
wget https://github.com/ethereum/solidity/releases/download/v0.8.19/solc-static-linux
2828
chmod +x solc-static-linux
29-
sudo mv solc-static-linux /usr/local/bin/solc8.10
29+
sudo mv solc-static-linux /usr/local/bin/solc8.19
3030
3131
- name: Verify rule ${{ matrix.rule }}
3232
run: |

certora/confs/ccip.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"process": "emv",
1414
"prover_args": ["-depth 10","-mediumTimeout 700"],
1515
"smt_timeout": "600",
16-
"solc": "solc8.10",
16+
"solc": "solc8.19",
1717
"verify": "UpgradeableLockReleaseTokenPool:certora/specs/ccip.spec",
1818
"rule_sanity": "basic",
1919
"msg": "CCIP"

contracts/foundry.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ gas_price = 1
1616
block_timestamp = 1234567890
1717
block_number = 12345
1818

19+
[rpc_endpoints]
20+
sepolia = "https://sepolia.gateway.tenderly.co"
21+
arb_sepolia = "https://arbitrum-sepolia.gateway.tenderly.co"
22+
1923
[profile.ccip]
2024
solc_version = '0.8.19'
2125
src = 'src/v0.8/ccip'

contracts/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
pragma solidity ^0.8.0;
33

44
import {Initializable} from "solidity-utils/contracts/transparent-proxy/Initializable.sol";
5-
65
import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
76
import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
87

98
import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol";
109
import {UpgradeableBurnMintTokenPoolAbstract} from "./UpgradeableBurnMintTokenPoolAbstract.sol";
1110
import {RateLimiter} from "../../libraries/RateLimiter.sol";
12-
1311
import {IRouter} from "../../interfaces/IRouter.sol";
1412

1513
/// @title UpgradeableBurnMintTokenPool
@@ -19,6 +17,8 @@ import {IRouter} from "../../interfaces/IRouter.sol";
1917
/// - Implementation of Initializable to allow upgrades
2018
/// - Move of allowlist and router definition to initialization stage
2119
/// - Inclusion of rate limit admin who may configure rate limits in addition to owner
20+
/// - Modifications from inherited contract (see contract for more details):
21+
/// - UpgradeableTokenPool: Modify `onlyOnRamp` & `onlyOffRamp` modifier to accept transactions from ProxyPool
2222
contract UpgradeableBurnMintTokenPool is Initializable, UpgradeableBurnMintTokenPoolAbstract, ITypeAndVersion {
2323
error Unauthorized(address caller);
2424

@@ -45,8 +45,7 @@ contract UpgradeableBurnMintTokenPool is Initializable, UpgradeableBurnMintToken
4545
/// @param allowlist A set of addresses allowed to trigger lockOrBurn as original senders
4646
/// @param router The address of the router
4747
function initialize(address owner, address[] memory allowlist, address router) public virtual initializer {
48-
if (owner == address(0)) revert ZeroAddressNotAllowed();
49-
if (router == address(0)) revert ZeroAddressNotAllowed();
48+
if (owner == address(0) || router == address(0)) revert ZeroAddressNotAllowed();
5049
_transferOwnership(owner);
5150

5251
s_router = IRouter(router);

contracts/src/v0.8/ccip/pools/GHO/UpgradeableLockReleaseTokenPool.sol

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
pragma solidity ^0.8.0;
33

44
import {Initializable} from "solidity-utils/contracts/transparent-proxy/Initializable.sol";
5-
65
import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
76
import {ILiquidityContainer} from "../../../rebalancer/interfaces/ILiquidityContainer.sol";
87

@@ -11,7 +10,6 @@ import {RateLimiter} from "../../libraries/RateLimiter.sol";
1110

1211
import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
1312
import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
14-
1513
import {IRouter} from "../../interfaces/IRouter.sol";
1614

1715
/// @title UpgradeableLockReleaseTokenPool
@@ -21,6 +19,8 @@ import {IRouter} from "../../interfaces/IRouter.sol";
2119
/// - Implementation of Initializable to allow upgrades
2220
/// - Move of allowlist and router definition to initialization stage
2321
/// - Addition of a bridge limit to regulate the maximum amount of tokens that can be transferred out (burned/locked)
22+
/// - Modifications from inherited contract (see contract for more details):
23+
/// - UpgradeableTokenPool: Modify `onlyOnRamp` & `onlyOffRamp` modifier to accept transactions from ProxyPool
2424
contract UpgradeableLockReleaseTokenPool is Initializable, UpgradeableTokenPool, ILiquidityContainer, ITypeAndVersion {
2525
using SafeERC20 for IERC20;
2626

@@ -86,8 +86,7 @@ contract UpgradeableLockReleaseTokenPool is Initializable, UpgradeableTokenPool,
8686
address router,
8787
uint256 bridgeLimit
8888
) public virtual initializer {
89-
if (owner == address(0)) revert ZeroAddressNotAllowed();
90-
if (router == address(0)) revert ZeroAddressNotAllowed();
89+
if (owner == address(0) || router == address(0)) revert ZeroAddressNotAllowed();
9190
_transferOwnership(owner);
9291

9392
s_router = IRouter(router);

contracts/src/v0.8/ccip/pools/GHO/UpgradeableTokenPool.sol

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/tok
1212
import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
1313
import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
1414

15-
/// @notice Base abstract class with common functions for all token pools.
16-
/// A token pool serves as isolated place for holding tokens and token specific logic
17-
/// that may execute as tokens move across the bridge.
15+
/// @title UpgradeableTokenPool
16+
/// @author Aave Labs
17+
/// @notice Upgradeable version of Chainlink's CCIP TokenPool
18+
/// @dev Contract adaptations:
19+
/// - Setters & Getters for new ProxyPool (to support 1.5 CCIP migration on the existing 1.4 Pool)
20+
/// - Modify `onlyOnRamp` & `onlyOffRamp` modifier to accept transactions from ProxyPool
1821
abstract contract UpgradeableTokenPool is IPool, OwnerIsCreator, IERC165 {
1922
using EnumerableSet for EnumerableSet.AddressSet;
2023
using EnumerableSet for EnumerableSet.UintSet;
@@ -55,6 +58,12 @@ abstract contract UpgradeableTokenPool is IPool, OwnerIsCreator, IERC165 {
5558
RateLimiter.Config inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain
5659
}
5760

61+
/// @dev The storage slot for Proxy Pool address, act as an on ramp "wrapper" post ccip 1.5 migration.
62+
/// @dev This was added to continue support for 1.2 onRamp during 1.5 migration, and is stored
63+
/// this way to avoid storage collision.
64+
// bytes32(uint256(keccak256("ccip.pools.GHO.UpgradeableTokenPool.proxyPool")) - 1)
65+
bytes32 internal constant PROXY_POOL_SLOT = 0x75bb68f1b335d4dab6963140ecff58281174ef4362bb85a8593ab9379f24fae2;
66+
5867
/// @dev The bridgeable token that is managed by this pool.
5968
IERC20 internal immutable i_token;
6069
/// @dev The address of the arm proxy
@@ -250,15 +259,19 @@ abstract contract UpgradeableTokenPool is IPool, OwnerIsCreator, IERC165 {
250259
/// is a permissioned onRamp for the given chain on the Router.
251260
modifier onlyOnRamp(uint64 remoteChainSelector) {
252261
if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
253-
if (!(msg.sender == s_router.getOnRamp(remoteChainSelector))) revert CallerIsNotARampOnRouter(msg.sender);
262+
if (!(msg.sender == getProxyPool() || msg.sender == s_router.getOnRamp(remoteChainSelector))) {
263+
revert CallerIsNotARampOnRouter(msg.sender);
264+
}
254265
_;
255266
}
256267

257268
/// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
258269
/// is a permissioned offRamp for the given chain on the Router.
259270
modifier onlyOffRamp(uint64 remoteChainSelector) {
260271
if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
261-
if (!s_router.isOffRamp(remoteChainSelector, msg.sender)) revert CallerIsNotARampOnRouter(msg.sender);
272+
if (!(msg.sender == getProxyPool() || s_router.isOffRamp(remoteChainSelector, msg.sender))) {
273+
revert CallerIsNotARampOnRouter(msg.sender);
274+
}
262275
_;
263276
}
264277

@@ -317,4 +330,21 @@ abstract contract UpgradeableTokenPool is IPool, OwnerIsCreator, IERC165 {
317330
if (IARM(i_armProxy).isCursed()) revert BadARMSignal();
318331
_;
319332
}
333+
334+
/// @notice Getter for proxy pool address.
335+
/// @return proxyPool The proxy pool address.
336+
function getProxyPool() public view returns (address proxyPool) {
337+
assembly ("memory-safe") {
338+
proxyPool := shr(96, shl(96, sload(PROXY_POOL_SLOT)))
339+
}
340+
}
341+
342+
/// @notice Setter for proxy pool address, only callable by the DAO.
343+
/// @param proxyPool The address of the proxy pool.
344+
function setProxyPool(address proxyPool) external onlyOwner {
345+
if (proxyPool == address(0)) revert ZeroAddressNotAllowed();
346+
assembly ("memory-safe") {
347+
sstore(PROXY_POOL_SLOT, proxyPool)
348+
}
349+
}
320350
}

contracts/src/v0.8/ccip/pools/GHO/diffs/UpgradeableBurnMintTokenPoolAbstract_diff.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ index f5eb135186..e228732855 100644
77
// SPDX-License-Identifier: BUSL-1.1
88
-pragma solidity 0.8.19;
99
+pragma solidity ^0.8.0;
10-
10+
1111
-import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
1212
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
13-
13+
1414
-import {TokenPool} from "./TokenPool.sol";
1515
+import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol";
16-
16+
1717
-abstract contract BurnMintTokenPoolAbstract is TokenPool {
1818
+abstract contract UpgradeableBurnMintTokenPoolAbstract is UpgradeableTokenPool {
1919
/// @notice Contains the specific burn call for a pool.

contracts/src/v0.8/ccip/pools/GHO/diffs/UpgradeableBurnMintTokenPool_diff.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
```diff
22
diff --git a/src/v0.8/ccip/pools/BurnMintTokenPool.sol b/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol
3-
index 9af0f22f4c..a46ff915e5 100644
3+
index 9af0f22f4c..a5cecc0430 100644
44
--- a/src/v0.8/ccip/pools/BurnMintTokenPool.sol
55
+++ b/src/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol
66
@@ -1,28 +1,90 @@
77
// SPDX-License-Identifier: BUSL-1.1
88
-pragma solidity 0.8.19;
99
+pragma solidity ^0.8.0;
10-
10+
1111
-import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
1212
-import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
1313
+import {Initializable} from "solidity-utils/contracts/transparent-proxy/Initializable.sol";
14-
15-
-import {TokenPool} from "./TokenPool.sol";
16-
-import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol";
1714
+import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
1815
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
19-
+
16+
17+
-import {TokenPool} from "./TokenPool.sol";
18+
-import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol";
2019
+import {UpgradeableTokenPool} from "./UpgradeableTokenPool.sol";
2120
+import {UpgradeableBurnMintTokenPoolAbstract} from "./UpgradeableBurnMintTokenPoolAbstract.sol";
2221
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
23-
+
2422
+import {IRouter} from "../../interfaces/IRouter.sol";
2523
+
2624
+/// @title UpgradeableBurnMintTokenPool
@@ -29,17 +27,20 @@ index 9af0f22f4c..a46ff915e5 100644
2927
+/// @dev Contract adaptations:
3028
+/// - Implementation of Initializable to allow upgrades
3129
+/// - Move of allowlist and router definition to initialization stage
30+
+/// - Inclusion of rate limit admin who may configure rate limits in addition to owner
31+
+/// - Modifications from inherited contract (see contract for more details):
32+
+/// - UpgradeableTokenPool: Modify `onlyOnRamp` & `onlyOffRamp` modifier to accept transactions from ProxyPool
3233
+contract UpgradeableBurnMintTokenPool is Initializable, UpgradeableBurnMintTokenPoolAbstract, ITypeAndVersion {
3334
+ error Unauthorized(address caller);
34-
35+
3536
-/// @notice This pool mints and burns a 3rd-party token.
3637
-/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later.
3738
-/// It either accepts any address as originalSender, or only accepts whitelisted originalSender.
3839
-/// The only way to change whitelisting mode is to deploy a new pool.
3940
-/// If that is expected, please make sure the token's burner/minter roles are adjustable.
4041
-contract BurnMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion {
4142
string public constant override typeAndVersion = "BurnMintTokenPool 1.4.0";
42-
43+
4344
+ /// @notice The address of the rate limiter admin.
4445
+ /// @dev Can be address(0) if none is configured.
4546
+ address internal s_rateLimitAdmin;
@@ -57,7 +58,7 @@ index 9af0f22f4c..a46ff915e5 100644
5758
- ) TokenPool(token, allowlist, armProxy, router) {}
5859
+ bool allowlistEnabled
5960
+ ) UpgradeableTokenPool(IBurnMintERC20(token), armProxy, allowlistEnabled) {}
60-
61+
6162
- /// @inheritdoc BurnMintTokenPoolAbstract
6263
+ /// @dev Initializer
6364
+ /// @dev The address passed as `owner` must accept ownership after initialization.
@@ -66,8 +67,7 @@ index 9af0f22f4c..a46ff915e5 100644
6667
+ /// @param allowlist A set of addresses allowed to trigger lockOrBurn as original senders
6768
+ /// @param router The address of the router
6869
+ function initialize(address owner, address[] memory allowlist, address router) public virtual initializer {
69-
+ if (owner == address(0)) revert ZeroAddressNotAllowed();
70-
+ if (router == address(0)) revert ZeroAddressNotAllowed();
70+
+ if (owner == address(0) || router == address(0)) revert ZeroAddressNotAllowed();
7171
+ _transferOwnership(owner);
7272
+
7373
+ s_router = IRouter(router);
@@ -90,7 +90,7 @@ index 9af0f22f4c..a46ff915e5 100644
9090
+ return s_rateLimitAdmin;
9191
+ }
9292
+
93-
+ /// @notice Sets the rate limiter admin address.
93+
+ /// @notice Sets the chain rate limiter config.
9494
+ /// @dev Only callable by the owner or the rate limiter admin. NOTE: overwrites the normal
9595
+ /// onlyAdmin check in the base implementation to also allow the rate limiter admin.
9696
+ /// @param remoteChainSelector The remote chain selector for which the rate limits apply.

0 commit comments

Comments
 (0)