Skip to content

Commit

Permalink
CCIP-4329 modify setChainRateLimiterConfig file for setting multiple …
Browse files Browse the repository at this point in the history
…rate limits (#15386)

* modify setChainRateLimiterConfig file for setting multiple rate limits

* Update gethwrappers

* [Bot] Update changeset file with jira issues

* snapshot fix

* fix wrappers after merge

* fix test that was broken in merge

* fix liquidityManager snapshot which is affected by token pool changes

* fix broken integration tests from removing critical setup function

* add array length check for setChainRateLimitConfigs

* formatting and snapshot fix

* Update gethwrappers

* simplify test setups

* Update gethwrappers

* update wrappers and snapshots which were broken in merge

* Update gethwrappers

* update wrappers and snapshot

* changeset

* snapshot update

* Delete contracts/.changeset/orange-buckets-live.md

* attempt fix changeset

* attempt changeset fix with update pnpm package

* re-add function that was removed early in PR to prevent any required tooling changes

* update liquidityManager snapshot because of changes to token pools

---------

Co-Authored-By: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>
  • Loading branch information
RensR and app-token-issuer-infra-releng[bot] committed Dec 10, 2024
1 parent 06914db commit dcfcc97
Show file tree
Hide file tree
Showing 12 changed files with 375 additions and 130 deletions.
5 changes: 5 additions & 0 deletions contracts/.changeset/small-countries-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/contracts': patch
---

Modify TokenPool.sol function setChainRateLimiterConfig to now accept an array of configs and set sequentially. Requested by front-end. PR issue CCIP-4329 #bugfix
231 changes: 117 additions & 114 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions contracts/gas-snapshots/liquiditymanager.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ LiquidityManager_addLiquidity:test_addLiquiditySuccess() (gas: 279154)
LiquidityManager_rebalanceLiquidity:test_InsufficientLiquidityReverts() (gas: 206745)
LiquidityManager_rebalanceLiquidity:test_InvalidRemoteChainReverts() (gas: 192319)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess() (gas: 9141768)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess_AlreadyFinalized() (gas: 9306597)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_MultiStageFinalization() (gas: 9301803)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_NativeRewrap() (gas: 9231693)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess_AlreadyFinalized() (gas: 9435588)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_MultiStageFinalization() (gas: 9430794)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_NativeRewrap() (gas: 9360684)
LiquidityManager_rebalanceLiquidity:test_rebalanceLiquiditySuccess() (gas: 382880)
LiquidityManager_receive:test_receive_success() (gas: 21182)
LiquidityManager_removeLiquidity:test_InsufficientLiquidityReverts() (gas: 184869)
Expand All @@ -19,7 +19,7 @@ LiquidityManager_setFinanceRole:test_OnlyOwnerReverts() (gas: 10987)
LiquidityManager_setFinanceRole:test_setFinanceRoleSuccess() (gas: 21836)
LiquidityManager_setLocalLiquidityContainer:test_OnlyOwnerReverts() (gas: 11052)
LiquidityManager_setLocalLiquidityContainer:test_ReverstWhen_CalledWithTheZeroAddress() (gas: 10643)
LiquidityManager_setLocalLiquidityContainer:test_setLocalLiquidityContainerSuccess() (gas: 3847225)
LiquidityManager_setLocalLiquidityContainer:test_setLocalLiquidityContainerSuccess() (gas: 3976172)
LiquidityManager_setMinimumLiquidity:test_OnlyOwnerReverts() (gas: 10925)
LiquidityManager_setMinimumLiquidity:test_setMinimumLiquiditySuccess() (gas: 36389)
LiquidityManager_withdrawERC20:test_withdrawERC20Reverts() (gas: 180359)
Expand Down
20 changes: 20 additions & 0 deletions contracts/src/v0.8/ccip/pools/TokenPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender {
error PoolAlreadyAdded(uint64 remoteChainSelector, bytes remotePoolAddress);
error InvalidRemotePoolForChain(uint64 remoteChainSelector, bytes remotePoolAddress);
error InvalidRemoteChainDecimals(bytes sourcePoolData);
error MismatchedArrayLengths();
error OverflowDetected(uint8 remoteDecimals, uint8 localDecimals, uint256 remoteAmount);
error InvalidDecimalArgs(uint8 expected, uint8 actual);

Expand Down Expand Up @@ -533,6 +534,25 @@ abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender {
return s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._currentTokenBucketState();
}

/// @notice Sets multiple chain rate limiter configs.
/// @param remoteChainSelectors The remote chain selector for which the rate limits apply.
/// @param outboundConfigs The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
/// @param inboundConfigs The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.
function setChainRateLimiterConfigs(
uint64[] calldata remoteChainSelectors,
RateLimiter.Config[] calldata outboundConfigs,
RateLimiter.Config[] calldata inboundConfigs
) external {
if (msg.sender != s_rateLimitAdmin && msg.sender != owner()) revert Unauthorized(msg.sender);
if (remoteChainSelectors.length != outboundConfigs.length || remoteChainSelectors.length != inboundConfigs.length) {
revert MismatchedArrayLengths();
}

for (uint256 i = 0; i < remoteChainSelectors.length; ++i) {
_setRateLimitConfig(remoteChainSelectors[i], outboundConfigs[i], inboundConfigs[i]);
}
}

/// @notice Sets the chain rate limiter config.
/// @param remoteChainSelector The remote chain selector for which the rate limits apply.
/// @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.24;

import {RateLimiter} from "../../../libraries/RateLimiter.sol";
import {TokenPool} from "../../../pools/TokenPool.sol";
import {TokenPoolSetup} from "./TokenPoolSetup.t.sol";

contract TokenPool_setChainRateLimiterConfigs is TokenPoolSetup {
uint64 internal s_remoteChainSelector;

function setUp() public virtual override {
TokenPoolSetup.setUp();

bytes[] memory remotePoolAddresses = new bytes[](1);
remotePoolAddresses[0] = abi.encode(address(2));

TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
s_remoteChainSelector = 123124;
chainUpdates[0] = TokenPool.ChainUpdate({
remoteChainSelector: s_remoteChainSelector,
remotePoolAddresses: remotePoolAddresses,
remoteTokenAddress: abi.encode(address(3)),
outboundRateLimiterConfig: _getOutboundRateLimiterConfig(),
inboundRateLimiterConfig: _getInboundRateLimiterConfig()
});
s_tokenPool.applyChainUpdates(new uint64[](0), chainUpdates);
}

function testFuzz_SetChainRateLimiterConfigs_Success(uint128 capacity, uint128 rate, uint32 newTime) public {
// Cap the lower bound to 4 so 4/2 is still >= 2
vm.assume(capacity >= 4);
// Cap the lower bound to 2 so 2/2 is still >= 1
rate = uint128(bound(rate, 2, capacity - 2));
// Bucket updates only work on increasing time
newTime = uint32(bound(newTime, block.timestamp + 1, type(uint32).max));
vm.warp(newTime);

uint256 oldOutboundTokens = s_tokenPool.getCurrentOutboundRateLimiterState(DEST_CHAIN_SELECTOR).tokens;
uint256 oldInboundTokens = s_tokenPool.getCurrentInboundRateLimiterState(DEST_CHAIN_SELECTOR).tokens;

RateLimiter.Config memory newOutboundConfig = RateLimiter.Config({isEnabled: true, capacity: capacity, rate: rate});
RateLimiter.Config memory newInboundConfig =
RateLimiter.Config({isEnabled: true, capacity: capacity / 2, rate: rate / 2});

uint64[] memory chainSelectors = new uint64[](1);
chainSelectors[0] = DEST_CHAIN_SELECTOR;

RateLimiter.Config[] memory newOutboundConfigs = new RateLimiter.Config[](1);
newOutboundConfigs[0] = newOutboundConfig;

RateLimiter.Config[] memory newInboundConfigs = new RateLimiter.Config[](1);
newInboundConfigs[0] = newInboundConfig;

vm.expectEmit();
emit RateLimiter.ConfigChanged(newOutboundConfig);
vm.expectEmit();
emit RateLimiter.ConfigChanged(newInboundConfig);
vm.expectEmit();
emit TokenPool.ChainConfigured(DEST_CHAIN_SELECTOR, newOutboundConfig, newInboundConfig);

s_tokenPool.setChainRateLimiterConfigs(chainSelectors, newOutboundConfigs, newInboundConfigs);

uint256 expectedTokens = RateLimiter._min(newOutboundConfig.capacity, oldOutboundTokens);

RateLimiter.TokenBucket memory bucket = s_tokenPool.getCurrentOutboundRateLimiterState(DEST_CHAIN_SELECTOR);
assertEq(bucket.capacity, newOutboundConfig.capacity);
assertEq(bucket.rate, newOutboundConfig.rate);
assertEq(bucket.tokens, expectedTokens);
assertEq(bucket.lastUpdated, newTime);

expectedTokens = RateLimiter._min(newInboundConfig.capacity, oldInboundTokens);

bucket = s_tokenPool.getCurrentInboundRateLimiterState(DEST_CHAIN_SELECTOR);
assertEq(bucket.capacity, newInboundConfig.capacity);
assertEq(bucket.rate, newInboundConfig.rate);
assertEq(bucket.tokens, expectedTokens);
assertEq(bucket.lastUpdated, newTime);
}

// Reverts

function test_OnlyOwnerOrRateLimitAdmin_Revert() public {
uint64[] memory chainSelectors = new uint64[](1);
chainSelectors[0] = DEST_CHAIN_SELECTOR;

RateLimiter.Config[] memory newOutboundConfigs = new RateLimiter.Config[](1);
newOutboundConfigs[0] = _getOutboundRateLimiterConfig();

RateLimiter.Config[] memory newInboundConfigs = new RateLimiter.Config[](1);
newInboundConfigs[0] = _getInboundRateLimiterConfig();

vm.startPrank(STRANGER);

vm.expectRevert(abi.encodeWithSelector(TokenPool.Unauthorized.selector, STRANGER));
s_tokenPool.setChainRateLimiterConfigs(chainSelectors, newOutboundConfigs, newInboundConfigs);
}

function test_NonExistentChain_Revert() public {
uint64 wrongChainSelector = 9084102894;

uint64[] memory chainSelectors = new uint64[](1);
chainSelectors[0] = wrongChainSelector;

RateLimiter.Config[] memory newOutboundConfigs = new RateLimiter.Config[](1);
RateLimiter.Config[] memory newInboundConfigs = new RateLimiter.Config[](1);

vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, wrongChainSelector));
s_tokenPool.setChainRateLimiterConfigs(chainSelectors, newOutboundConfigs, newInboundConfigs);
}

function test_MismatchedArrayLengths_Revert() public {
uint64[] memory chainSelectors = new uint64[](1);

RateLimiter.Config[] memory newOutboundConfigs = new RateLimiter.Config[](1);
RateLimiter.Config[] memory newInboundConfigs = new RateLimiter.Config[](2);

// test mismatched array lengths between rate limiters
vm.expectRevert(abi.encodeWithSelector(TokenPool.MismatchedArrayLengths.selector));
s_tokenPool.setChainRateLimiterConfigs(chainSelectors, newOutboundConfigs, newInboundConfigs);

newInboundConfigs = new RateLimiter.Config[](1);
chainSelectors = new uint64[](2);

// test mismatched array lengths between chain selectors and rate limiters
vm.expectRevert(abi.encodeWithSelector(TokenPool.MismatchedArrayLengths.selector));
s_tokenPool.setChainRateLimiterConfigs(chainSelectors, newOutboundConfigs, newInboundConfigs);
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion core/gethwrappers/ccip/generated/token_pool/token_pool.go

Large diffs are not rendered by default.

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion integration-tests/ccip-tests/contracts/contract_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,13 @@ func (w TokenPoolWrapper) ApplyChainUpdates(opts *bind.TransactOpts, update []to
}

func (w TokenPoolWrapper) SetChainRateLimiterConfig(opts *bind.TransactOpts, selector uint64, out token_pool.RateLimiterConfig, in token_pool.RateLimiterConfig) (*types.Transaction, error) {

if w.Latest != nil && w.Latest.PoolInterface != nil {
return w.Latest.PoolInterface.SetChainRateLimiterConfig(opts, selector, out, in)
selectors := []uint64{selector}
out := []token_pool.RateLimiterConfig{out}
in := []token_pool.RateLimiterConfig{in}

return w.Latest.PoolInterface.SetChainRateLimiterConfigs(opts, selectors, out, in)
}
if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
return w.V1_4_0.PoolInterface.SetChainRateLimiterConfig(opts, selector,
Expand Down

0 comments on commit dcfcc97

Please sign in to comment.