Skip to content

Commit

Permalink
feat: Upgrade Remote Pool to include RateLimitAdmin (#16)
Browse files Browse the repository at this point in the history
* 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

---------

Co-authored-by: miguelmtzinf <miguelmtz.mail@gmail.com>
  • Loading branch information
CheyenneAtapour and miguelmtzinf authored Oct 15, 2024
1 parent d27d468 commit c020802
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {Initializable} from "solidity-utils/contracts/transparent-proxy/Initializable.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";

/// @title UpgradeableBurnMintTokenPoolOld
/// @author Aave Labs
/// @notice Upgradeable version of Chainlink's CCIP BurnMintTokenPool
/// @dev Contract adaptations:
/// - Implementation of Initializable to allow upgrades
/// - Move of allowlist and router definition to initialization stage
contract UpgradeableBurnMintTokenPoolOld is Initializable, 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(
address token,
address armProxy,
bool allowlistEnabled
) UpgradeableTokenPool(IBurnMintERC20(token), armProxy, allowlistEnabled) {}

/// @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);
}
}
31 changes: 31 additions & 0 deletions contracts/src/v0.8/ccip/test/pools/GHO/GhoBaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {IBurnMintERC20} from "../../../../shared/token/ERC20/IBurnMintERC20.sol"
import {IPool} from "../../../interfaces/pools/IPool.sol";
import {UpgradeableLockReleaseTokenPool} from "../../../pools/GHO/UpgradeableLockReleaseTokenPool.sol";
import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol";
import {UpgradeableBurnMintTokenPoolOld} from "../../../pools/GHO/UpgradeableBurnMintTokenPoolOld.sol";
import {UpgradeableTokenPool} from "../../../pools/GHO/UpgradeableTokenPool.sol";
import {RateLimiter} from "../../../libraries/RateLimiter.sol";
import {BaseTest} from "../../BaseTest.t.sol";
Expand Down Expand Up @@ -65,6 +66,36 @@ abstract contract GhoBaseTest is BaseTest {
return address(tokenPoolProxy);
}

function _deployUpgradeableBurnMintTokenPoolOld(
address ghoToken,
address arm,
address router,
address owner,
address proxyAdmin
) internal returns (address) {
// Deploy BurnMintTokenPool for GHO token on source chain
UpgradeableBurnMintTokenPoolOld tokenPoolImpl = new UpgradeableBurnMintTokenPoolOld(ghoToken, arm, false);
// proxy deploy and init
address[] memory emptyArray = new address[](0);
bytes memory tokenPoolInitParams = abi.encodeWithSignature(
"initialize(address,address[],address)",
owner,
emptyArray,
router
);
TransparentUpgradeableProxy tokenPoolProxy = new TransparentUpgradeableProxy(
address(tokenPoolImpl),
proxyAdmin,
tokenPoolInitParams
);
// Manage ownership
changePrank(owner);
UpgradeableBurnMintTokenPoolOld(address(tokenPoolProxy)).acceptOwnership();
vm.stopPrank();

return address(tokenPoolProxy);
}

function _deployUpgradeableLockReleaseTokenPool(
address ghoToken,
address arm,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent-proxy/TransparentUpgradeableProxy.sol";

import {UpgradeableBurnMintTokenPool} from "../../../pools/GHO/UpgradeableBurnMintTokenPool.sol";
import {GhoTokenPoolRemoteSetup} from "./GhoTokenPoolRemoteSetup.t.sol";

contract GhoTokenPoolRemoteUpgrade is GhoTokenPoolRemoteSetup {
// Unable to call setRateLimitAdmin() before upgrade
function testSetRateLimitAdminRevertsBeforeUpgrade() public {
s_pool = UpgradeableBurnMintTokenPool(
_deployUpgradeableBurnMintTokenPoolOld(
address(s_burnMintERC677),
address(s_mockARM),
address(s_sourceRouter),
AAVE_DAO,
PROXY_ADMIN
)
);
vm.prank(AAVE_DAO);
vm.expectRevert();
s_pool.setRateLimitAdmin(AAVE_DAO);
}

// Able to call setRateLimitAdmin() after upgrade
function testUpgradeAndSetRateLimitAdmin() public {
// Assume existing remote pool as is deployed
s_pool = UpgradeableBurnMintTokenPool(
_deployUpgradeableBurnMintTokenPoolOld(
address(s_burnMintERC677),
address(s_mockARM),
address(s_sourceRouter),
AAVE_DAO,
PROXY_ADMIN
)
);

// Deploy new implementation
UpgradeableBurnMintTokenPool tokenPoolImpl = new UpgradeableBurnMintTokenPool(
address(s_burnMintERC677),
address(s_mockARM),
false
);
// Do the upgrade
vm.prank(PROXY_ADMIN);
TransparentUpgradeableProxy(payable(address(s_pool))).upgradeTo(address(tokenPoolImpl));

// Set rate limit admin now works
vm.prank(AAVE_DAO);
s_pool.setRateLimitAdmin(OWNER);
assertEq(OWNER, s_pool.getRateLimitAdmin());
}

// Unable to call initialize() on proxy after upgrade
function testInitializeRevertsAfterUpgrade() public {
s_pool = UpgradeableBurnMintTokenPool(
_deployUpgradeableBurnMintTokenPoolOld(
address(s_burnMintERC677),
address(s_mockARM),
address(s_sourceRouter),
AAVE_DAO,
PROXY_ADMIN
)
);

// Deploy new implementation
UpgradeableBurnMintTokenPool tokenPoolImpl = new UpgradeableBurnMintTokenPool(
address(s_burnMintERC677),
address(s_mockARM),
false
);
// Do the upgrade
vm.prank(PROXY_ADMIN);
TransparentUpgradeableProxy(payable(address(s_pool))).upgradeTo(address(tokenPoolImpl));

vm.startPrank(OWNER);
vm.expectRevert("Initializable: contract is already initialized");
s_pool.initialize(OWNER, new address[](0), address(s_sourceRouter));
}
}

0 comments on commit c020802

Please sign in to comment.