diff --git a/evm/src/libraries/RateLimiter.sol b/evm/src/libraries/RateLimiter.sol index de0e191ba..cfcd6e6c7 100644 --- a/evm/src/libraries/RateLimiter.sol +++ b/evm/src/libraries/RateLimiter.sol @@ -143,6 +143,11 @@ abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { view returns (TrimmedAmount memory capacity) { + // If the rate limit duration is 0 then the rate limiter is skipped + if (rateLimitDuration == 0) { + return TrimmedAmount(type(uint64).max, rateLimitParams.currentCapacity.getDecimals()); + } + // The capacity and rate limit are expressed as trimmed amounts, i.e. // 64-bit unsigned integers. The following operations upcast the 64-bit // unsigned integers to 256-bit unsigned integers to avoid overflow. @@ -196,18 +201,21 @@ abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { } function _consumeOutboundAmount(TrimmedAmount memory amount) internal { + if (rateLimitDuration == 0) return; _consumeRateLimitAmount( amount, _getCurrentCapacity(_getOutboundLimitParams()), _getOutboundLimitParamsStorage() ); } function _backfillOutboundAmount(TrimmedAmount memory amount) internal { + if (rateLimitDuration == 0) return; _backfillRateLimitAmount( amount, _getCurrentCapacity(_getOutboundLimitParams()), _getOutboundLimitParamsStorage() ); } function _consumeInboundAmount(TrimmedAmount memory amount, uint16 chainId_) internal { + if (rateLimitDuration == 0) return; _consumeRateLimitAmount( amount, _getCurrentCapacity(_getInboundLimitParams(chainId_)), @@ -216,6 +224,7 @@ abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { } function _backfillInboundAmount(TrimmedAmount memory amount, uint16 chainId_) internal { + if (rateLimitDuration == 0) return; _backfillRateLimitAmount( amount, _getCurrentCapacity(_getInboundLimitParams(chainId_)), @@ -248,14 +257,18 @@ abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { view returns (bool) { - return _isAmountRateLimited(_getCurrentCapacity(_getOutboundLimitParams()), amount); + return rateLimitDuration != 0 + ? _isAmountRateLimited(_getCurrentCapacity(_getOutboundLimitParams()), amount) + : false; } function _isInboundAmountRateLimited( TrimmedAmount memory amount, uint16 chainId_ ) internal view returns (bool) { - return _isAmountRateLimited(_getCurrentCapacity(_getInboundLimitParams(chainId_)), amount); + return rateLimitDuration != 0 + ? _isAmountRateLimited(_getCurrentCapacity(_getInboundLimitParams(chainId_)), amount) + : false; } function _isAmountRateLimited( diff --git a/evm/test/NttManager.t.sol b/evm/test/NttManager.t.sol index a6209dbb6..9270baaf2 100644 --- a/evm/test/NttManager.t.sol +++ b/evm/test/NttManager.t.sol @@ -27,6 +27,7 @@ import "./mocks/MockNttManager.sol"; contract TestNttManager is Test, INttManagerEvents, IRateLimiterEvents { MockNttManagerContract nttManager; MockNttManagerContract nttManagerOther; + MockNttManagerContract nttManagerZeroRateLimiter; using TrimmedAmountLib for uint256; using TrimmedAmountLib for TrimmedAmount; @@ -71,6 +72,45 @@ contract TestNttManager is Test, INttManagerEvents, IRateLimiterEvents { assertEq(countSetBits(65535), 16); } + // === Deployments with rate limiter disabled + + function test_disabledRateLimiter() public { + DummyToken t = new DummyToken(); + NttManager implementation = + new MockNttManagerContract(address(t), INttManager.Mode.LOCKING, chainId, 0); + + nttManagerZeroRateLimiter = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerZeroRateLimiter.initialize(); + + address user_A = address(0x123); + address user_B = address(0x456); + + uint8 decimals = t.decimals(); + + nttManagerZeroRateLimiter.setPeer(chainId, toWormholeFormat(address(0x1)), 9); + + t.mintDummy(address(user_A), 5 * 10 ** decimals); + + vm.startPrank(user_A); + + t.approve(address(nttManagerZeroRateLimiter), 3 * 10 ** decimals); + + uint64 s1 = nttManagerZeroRateLimiter.transfer( + 1 * 10 ** decimals, chainId, toWormholeFormat(user_B) + ); + uint64 s2 = nttManagerZeroRateLimiter.transfer( + 1 * 10 ** decimals, chainId, toWormholeFormat(user_B) + ); + uint64 s3 = nttManagerZeroRateLimiter.transfer( + 1 * 10 ** decimals, chainId, toWormholeFormat(user_B) + ); + + assertEq(s1, 0); + assertEq(s2, 1); + assertEq(s3, 2); + } + // === ownership function test_owner() public {