From 52f810af3255672f8cbe2b51c39e6df103bbfeab Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 11 Apr 2024 13:09:57 -0700 Subject: [PATCH 1/2] Unilateral pause implementation * Added new structure with dynamic storage slots for the storage of it. * Getter for the struct. * Setter for setting each of the inbound and outbound calls * Added modifiers for functions that cannot be executed while paused and for functions that can ONLY be executed while paused. --- evm/src/NttManager/ManagerBase.sol | 53 ++++++++- evm/src/NttManager/NttManager.sol | 15 ++- evm/src/interfaces/IManagerBase.sol | 23 ++++ evm/test/IntegrationManual.t.sol | 21 +++- evm/test/IntegrationRelayer.t.sol | 66 ++++++++++- evm/test/IntegrationStandalone.t.sol | 37 ++++++ evm/test/NttManager.t.sol | 131 +++++++++++++++++++++- evm/test/RateLimit.t.sol | 4 + evm/test/Upgrades.t.sol | 10 ++ evm/test/libraries/TransceiverHelpers.sol | 8 ++ 10 files changed, 353 insertions(+), 15 deletions(-) diff --git a/evm/src/NttManager/ManagerBase.sol b/evm/src/NttManager/ManagerBase.sol index 127b88f03..fea546d7e 100644 --- a/evm/src/NttManager/ManagerBase.sol +++ b/evm/src/NttManager/ManagerBase.sol @@ -15,6 +15,7 @@ import "../interfaces/ITransceiver.sol"; import "../interfaces/IManagerBase.sol"; import "./TransceiverRegistry.sol"; +import "forge-std/console.sol"; // TODO - remove this - MAX abstract contract ManagerBase is IManagerBase, @@ -42,6 +43,27 @@ abstract contract ManagerBase is deployer = msg.sender; } + modifier inboundNotPaused(){ + if(_getUnilateralPauseStorage().inbound){ + revert InboundPaused(); + } + _; + } + + modifier outboundNotPaused(){ + if(_getUnilateralPauseStorage().outbound){ + revert OutboundPaused(); + } + _; + } + + modifier outboundWhenPaused(){ + if(_getUnilateralPauseStorage().outbound == false){ + revert NotPausedForUpdate(); + } + _; + } + function _migrate() internal virtual override { _checkThresholdInvariants(); _checkTransceiversInvariants(); @@ -57,8 +79,17 @@ abstract contract ManagerBase is bytes32 private constant THRESHOLD_SLOT = bytes32(uint256(keccak256("ntt.threshold")) - 1); + bytes32 private constant UNILATERAL_PAUSE_SLOT = bytes32(uint256(keccak256("ntt.unilateral_pause")) - 1); + // =============== Storage Getters/Setters ============================================== + function _getUnilateralPauseStorage() internal pure returns (UnilateralPause storage $) { + uint256 slot = uint256(UNILATERAL_PAUSE_SLOT); + assembly ("memory-safe") { + $.slot := slot + } + } + function _getThresholdStorage() private pure returns (_Threshold storage $) { uint256 slot = uint256(THRESHOLD_SLOT); assembly ("memory-safe") { @@ -273,6 +304,16 @@ abstract contract ManagerBase is return _getThresholdStorage().num; } + /// @inheritdoc IManagerBase + function getUnilateralPause() public view returns (UnilateralPause memory) { + UnilateralPause storage u = _getUnilateralPauseStorage(); + + return UnilateralPause({ + inbound: u.inbound, + outbound: u.outbound + }); + } + /// @inheritdoc IManagerBase function isMessageApproved(bytes32 digest) public view returns (bool) { uint8 threshold = getThreshold(); @@ -316,6 +357,14 @@ abstract contract ManagerBase is _unpause(); } + function setInboundPauseStatus(bool status) external onlyOwnerOrPauser(){ + _getUnilateralPauseStorage().inbound = status; + } + + function setOutboundPauseStatus(bool status) external onlyOwnerOrPauser(){ + _getUnilateralPauseStorage().outbound = status; + } + /// @notice Transfer ownership of the Manager contract and all Transceiver contracts to a new owner. function transferOwnership(address newOwner) public override onlyOwner { super.transferOwnership(newOwner); @@ -356,7 +405,7 @@ abstract contract ManagerBase is } /// @inheritdoc IManagerBase - function removeTransceiver(address transceiver) external onlyOwner { + function removeTransceiver(address transceiver) external onlyOwner outboundWhenPaused { _removeTransceiver(transceiver); _Threshold storage _threshold = _getThresholdStorage(); @@ -372,7 +421,7 @@ abstract contract ManagerBase is } /// @inheritdoc IManagerBase - function setThreshold(uint8 threshold) external onlyOwner { + function setThreshold(uint8 threshold) external onlyOwner outboundWhenPaused { if (threshold == 0) { revert ZeroThreshold(); } diff --git a/evm/src/NttManager/NttManager.sol b/evm/src/NttManager/NttManager.sol index 54e575e16..1fb2a7cb4 100644 --- a/evm/src/NttManager/NttManager.sol +++ b/evm/src/NttManager/NttManager.sol @@ -64,6 +64,8 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { __PausedOwnable_init(msg.sender, msg.sender); __ReentrancyGuard_init(); _setOutboundLimit(TrimmedAmountLib.max(tokenDecimals())); + _getUnilateralPauseStorage().inbound = true; + _getUnilateralPauseStorage().outbound = true; } function _initialize() internal virtual override { @@ -104,7 +106,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { bytes32 peerContract, uint8 decimals, uint256 inboundLimit - ) public onlyOwner { + ) public onlyOwner outboundWhenPaused { if (peerChainId == 0) { revert InvalidPeerChainIdZero(); } @@ -158,7 +160,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { uint256 amount, uint16 recipientChain, bytes32 recipient - ) external payable nonReentrant whenNotPaused returns (uint64) { + ) external payable nonReentrant whenNotPaused outboundNotPaused returns (uint64) { return _transferEntryPoint(amount, recipientChain, recipient, recipient, false, new bytes(1)); } @@ -171,7 +173,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { bytes32 refundAddress, bool shouldQueue, bytes memory transceiverInstructions - ) external payable nonReentrant whenNotPaused returns (uint64) { + ) external payable nonReentrant whenNotPaused outboundNotPaused returns (uint64) { return _transferEntryPoint( amount, recipientChain, recipient, refundAddress, shouldQueue, transceiverInstructions ); @@ -182,7 +184,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { uint16 sourceChainId, bytes32 sourceNttManagerAddress, TransceiverStructs.NttManagerMessage memory payload - ) external onlyTransceiver whenNotPaused { + ) external onlyTransceiver whenNotPaused inboundNotPaused{ _verifyPeer(sourceChainId, sourceNttManagerAddress); // Compute manager message digest and record transceiver attestation. @@ -198,7 +200,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { uint16 sourceChainId, bytes32 sourceNttManagerAddress, TransceiverStructs.NttManagerMessage memory message - ) public whenNotPaused { + ) public whenNotPaused inboundNotPaused { (bytes32 digest, bool alreadyExecuted) = _isMessageExecuted(sourceChainId, sourceNttManagerAddress, message); @@ -241,7 +243,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { } /// @inheritdoc INttManager - function completeInboundQueuedTransfer(bytes32 digest) external nonReentrant whenNotPaused { + function completeInboundQueuedTransfer(bytes32 digest) external nonReentrant whenNotPaused inboundNotPaused{ // find the message in the queue InboundQueuedTransfer memory queuedTransfer = getInboundQueuedTransfer(digest); if (queuedTransfer.txTimestamp == 0) { @@ -266,6 +268,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { payable nonReentrant whenNotPaused + outboundNotPaused returns (uint64) { // find the message in the queue diff --git a/evm/src/interfaces/IManagerBase.sol b/evm/src/interfaces/IManagerBase.sol index 66f4e13a7..a621c1c10 100644 --- a/evm/src/interfaces/IManagerBase.sol +++ b/evm/src/interfaces/IManagerBase.sol @@ -31,6 +31,12 @@ interface IManagerBase { uint8 num; } + /// @dev Structure for storing pause information for inbound and outbound transfers + struct UnilateralPause { + bool inbound; + bool outbound; + } + /// @notice Emitted when a message has been attested to. /// @dev Topic0 /// 0x35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e5. @@ -109,6 +115,19 @@ interface IManagerBase { /// @param chainId The target chain id error PeerNotRegistered(uint16 chainId); + /// @notice Error when the receiving message on inbound call when inbound calls are paused + /// @dev Selector 0xab6e758b + error InboundPaused(); + + /// @notice Error when sending a message when outbound transfers are paused + /// @dev Selector 0xe741d03c + error OutboundPaused(); + + /// @notice Error when trying to update sensitive values when the outbound is not paused + /// @dev Select 0x37291df0 + error NotPausedForUpdate(); + + /// @notice Fetch the delivery price for a given recipient chain transfer. /// @param recipientChain The chain ID of the transfer destination. /// @param transceiverInstructions The transceiver specific instructions for quoting and sending @@ -165,6 +184,10 @@ interface IManagerBase { /// it to be considered valid and acted upon. function getThreshold() external view returns (uint8); + /// @notice Returns the inbound and outbound pause information for the manager. + /// This is seperate to the general pause feature + function getUnilateralPause() external view returns (UnilateralPause memory); + /// @notice Returns a boolean indicating if the transceiver has attested to the message. function transceiverAttestedToMessage( bytes32 digest, diff --git a/evm/test/IntegrationManual.t.sol b/evm/test/IntegrationManual.t.sol index 56d762996..e330ac989 100644 --- a/evm/test/IntegrationManual.t.sol +++ b/evm/test/IntegrationManual.t.sol @@ -66,7 +66,7 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { address(new ERC1967Proxy(address(wormholeTransceiverChain1), "")) ); wormholeTransceiverChain1.initialize(); - + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1)); nttManagerChain1.setOutboundLimit(type(uint64).max); nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); @@ -108,6 +108,12 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { } function test_relayerTransceiverAuth() public { + + nttManagerChain1.setInboundPauseStatus(false); + nttManagerChain1.setOutboundPauseStatus(false); + nttManagerChain2.setInboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); + // Set up sensible WH transceiver peers _setTransceiverPeers( [wormholeTransceiverChain1, wormholeTransceiverChain2], @@ -143,7 +149,9 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { vm.chainId(chainId2); // Set bad manager peer (0x1) + nttManagerChain2.setOutboundPauseStatus(true); nttManagerChain2.setPeer(chainId1, toWormholeFormat(address(0x1)), 9, type(uint64).max); + nttManagerChain2.setOutboundPauseStatus(false); vm.startPrank(relayer); @@ -158,7 +166,9 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { ); vm.stopPrank(); + nttManagerChain2.setOutboundPauseStatus(true); _setManagerPeer(nttManagerChain2, nttManagerChain1, chainId1, 9, type(uint64).max); + nttManagerChain2.setOutboundPauseStatus(false); // Wrong caller - aka not relayer contract vm.prank(userD); @@ -215,6 +225,15 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { } function test_relayerWithInvalidWHTransceiver() public { + + require(nttManagerChain1.getUnilateralPause().inbound == true, "Inbound pause not true by default"); + require(nttManagerChain1.getUnilateralPause().outbound == true, "Outbound pause not true by default"); + + nttManagerChain1.setInboundPauseStatus(false); + nttManagerChain1.setOutboundPauseStatus(false); + nttManagerChain2.setInboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); + // Set up dodgy wormhole transceiver peers wormholeTransceiverChain2.setWormholePeer(chainId1, bytes32(uint256(uint160(address(0x1))))); wormholeTransceiverChain1.setWormholePeer( diff --git a/evm/test/IntegrationRelayer.t.sol b/evm/test/IntegrationRelayer.t.sol index 34e6b7ae5..97614f74b 100755 --- a/evm/test/IntegrationRelayer.t.sol +++ b/evm/test/IntegrationRelayer.t.sol @@ -98,6 +98,9 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole nttManagerChain1.setOutboundLimit(type(uint64).max); nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); nttManagerChain1.setThreshold(1); + + nttManagerChain1.setInboundPauseStatus(false); + nttManagerChain1.setOutboundPauseStatus(false); } // Setup the chain to relay to of the network @@ -145,8 +148,10 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2Other)); nttManagerChain2.setOutboundLimit(type(uint64).max); nttManagerChain2.setInboundLimit(type(uint64).max, chainId1); - nttManagerChain2.setThreshold(1); + + nttManagerChain2.setInboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); } function test_chainToChainReverts() public { @@ -158,9 +163,28 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole wormholeTransceiverChain2.setWormholePeer( chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); + + // Ensure that the enforcement for changing the peer is in place. + vm.expectRevert( + abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector) + ); nttManagerChain2.setPeer( chainId1, bytes32(uint256(uint160(address(nttManagerChain1)))), 9, type(uint64).max ); + + // Test that the threshold must be changed while in the paused state + vm.expectRevert( + abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector) + ); + nttManagerChain2.setThreshold(1); + + // Set the peer + nttManagerChain2.setOutboundPauseStatus(true); + nttManagerChain2.setPeer( + chainId1, bytes32(uint256(uint160(address(nttManagerChain1)))), 9, type(uint64).max + ); + nttManagerChain2.setOutboundPauseStatus(false); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); wormholeTransceiverChain2.setIsWormholeRelayingEnabled(chainId1, true); wormholeTransceiverChain2.setIsWormholeEvmChain(chainId1, true); @@ -171,9 +195,12 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole wormholeTransceiverChain1.setWormholePeer( chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2))))) ); + + nttManagerChain1.setOutboundPauseStatus(true); nttManagerChain1.setPeer( chainId2, bytes32(uint256(uint160(address(nttManagerChain2)))), 7, type(uint64).max ); + nttManagerChain1.setOutboundPauseStatus(false); // Enable general relaying on the chain to transfer for the funds. wormholeTransceiverChain1.setIsWormholeRelayingEnabled(chainId2, true); @@ -265,6 +292,18 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole instructions ); + // Test whether a random caller can set the inbound or outbound pause status + vm.expectRevert(abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, userA)); + nttManagerChain1.setOutboundPauseStatus(true); + vm.expectRevert(abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, userA)); + nttManagerChain1.setInboundPauseStatus(true); + + // Pause outbound transfers and see if this still succeeds + vm.stopPrank(); + nttManagerChain1.setOutboundPauseStatus(true); + vm.startPrank(userA); + + vm.expectRevert(abi.encodeWithSelector(IManagerBase.OutboundPaused.selector)); // Do the payment with slightly more gas than needed. This should result in a *payback* of 1 wei. nttManagerChain1.transfer{value: priceQuote1 + 1}( sendingAmount, @@ -275,6 +314,19 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole instructions ); + // Unpause then to do the transfer + vm.stopPrank(); + nttManagerChain1.setOutboundPauseStatus(false); + vm.startPrank(userA); + nttManagerChain1.transfer{value: priceQuote1 + 1}( + sendingAmount, + chainId2, + bytes32(uint256(uint160(userB))), + bytes32(uint256(uint160(userB))), + false, + instructions + ); + // Balance check on funds going in and out working as expected uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); @@ -319,18 +371,24 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole wormholeTransceiverChain2.setWormholePeer( chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); + + nttManagerChain2.setOutboundPauseStatus(true); nttManagerChain2.setPeer( chainId1, bytes32(uint256(uint160(address(nttManagerChain1)))), 9, type(uint64).max ); + nttManagerChain2.setOutboundPauseStatus(false); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); wormholeTransceiverChain2.setIsWormholeRelayingEnabled(chainId1, true); wormholeTransceiverChain2.setIsWormholeEvmChain(chainId1, true); // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here. vm.selectFork(sourceFork); + nttManagerChain1.setOutboundPauseStatus(true); nttManagerChain1.setPeer( chainId2, bytes32(uint256(uint160(address(nttManagerChain2)))), 7, type(uint64).max ); + nttManagerChain1.setOutboundPauseStatus(false); wormholeTransceiverChain1.setWormholePeer( chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2))))) ); @@ -476,9 +534,12 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole [wormholeTransceiverChain1, wormholeTransceiverChain1Other], [chainId1, chainId1] ); + + nttManagerChain2.setOutboundPauseStatus(true); nttManagerChain2.setPeer( chainId1, toWormholeFormat(address(nttManagerChain1)), 9, type(uint64).max ); + nttManagerChain2.setOutboundPauseStatus(false); // setup token DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); @@ -493,10 +554,11 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole [wormholeTransceiverChain2, wormholeTransceiverChain2Other], [chainId2, chainId2] ); + nttManagerChain1.setOutboundPauseStatus(true); nttManagerChain1.setPeer( chainId2, toWormholeFormat(address(nttManagerChain2)), 7, type(uint64).max ); - + nttManagerChain1.setOutboundPauseStatus(false); DummyToken token1 = DummyToken(nttManagerChain1.token()); uint8 decimals = token1.decimals(); diff --git a/evm/test/IntegrationStandalone.t.sol b/evm/test/IntegrationStandalone.t.sol index 3ac5c8c12..938ca4fba 100755 --- a/evm/test/IntegrationStandalone.t.sol +++ b/evm/test/IntegrationStandalone.t.sol @@ -146,6 +146,11 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { // Actually set it nttManagerChain1.setThreshold(1); nttManagerChain2.setThreshold(1); + + nttManagerChain1.setInboundPauseStatus(false); + nttManagerChain1.setOutboundPauseStatus(false); + nttManagerChain2.setInboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); } function test_chainToChainBase() public { @@ -331,7 +336,15 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { ); // Wrong chain receiving the signed VAA wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); + vm.chainId(chainId2); + + // Check if the inbound pauser works effectively + nttManagerChain2.setInboundPauseStatus(true); + vm.expectRevert(abi.encodeWithSelector(IManagerBase.InboundPaused.selector)); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); + nttManagerChain2.setInboundPauseStatus(false); + { uint256 supplyBefore = token2.totalSupply(); wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); @@ -378,6 +391,14 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { encodeTransceiverInstruction(true) ); + // Check that the outbound pause status checker works on queued transactions + vm.stopPrank(); + nttManagerChain2.setOutboundPauseStatus(true); + vm.expectRevert(abi.encodeWithSelector(IManagerBase.OutboundPaused.selector)); + nttManagerChain2.completeOutboundQueuedTransfer(0); + nttManagerChain2.setOutboundPauseStatus(false); + vm.startPrank(userC); + // Test timing on the queues vm.expectRevert( abi.encodeWithSelector( @@ -446,6 +467,14 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { Utils.fetchQueuedTransferDigestsFromLogs(vm.getRecordedLogs()); vm.warp(vm.getBlockTimestamp() + 100000); + + // Verify that the inbound paused modifier is functional for the inbound queue. + nttManagerChain1.setInboundPauseStatus(true); + vm.expectRevert(abi.encodeWithSelector(IManagerBase.InboundPaused.selector)); + nttManagerChain1.completeInboundQueuedTransfer(queuedDigests[0]); + nttManagerChain1.setInboundPauseStatus(false); + + // Complete the transfer and remove it from the queue. nttManagerChain1.completeInboundQueuedTransfer(queuedDigests[0]); // Double redeem @@ -514,9 +543,17 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2_2)); nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1_2)); + // Ensure that a threshold change comes alongside an upgrade pauser + vm.expectRevert(abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector)); + nttManagerChain1.setThreshold(2); + // Change the threshold from the setUp functions 1 to 2. + nttManagerChain1.setOutboundPauseStatus(true); + nttManagerChain2.setOutboundPauseStatus(true); nttManagerChain1.setThreshold(2); nttManagerChain2.setThreshold(2); + nttManagerChain1.setOutboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); // Setting up the transfer DummyToken token1 = DummyToken(nttManagerChain1.token()); diff --git a/evm/test/NttManager.t.sol b/evm/test/NttManager.t.sol index 4725d9710..b247d3a61 100644 --- a/evm/test/NttManager.t.sol +++ b/evm/test/NttManager.t.sol @@ -12,6 +12,7 @@ import "../src/interfaces/IRateLimiterEvents.sol"; import "../src/NttManager/TransceiverRegistry.sol"; import "../src/libraries/PausableUpgradeable.sol"; import "../src/libraries/TransceiverHelpers.sol"; +import "../src/libraries/PausableOwnable.sol"; import {Utils} from "./libraries/Utils.sol"; import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; @@ -70,6 +71,11 @@ contract TestNttManager is Test, IRateLimiterEvents { dummyTransceiver = new DummyTransceiver(address(nttManager)); nttManager.setTransceiver(address(dummyTransceiver)); + + nttManager.setOutboundPauseStatus(false); + nttManager.setInboundPauseStatus(false); + nttManagerOther.setInboundPauseStatus(false); + nttManagerOther.setOutboundPauseStatus(false); } // === pure unit tests @@ -93,6 +99,7 @@ contract TestNttManager is Test, IRateLimiterEvents { // === Deployments with rate limiter disabled function test_disabledRateLimiter() public { + DummyToken t = new DummyToken(); NttManager implementation = new MockNttManagerContract(address(t), IManagerBase.Mode.LOCKING, chainId, 0, true); @@ -104,14 +111,18 @@ contract TestNttManager is Test, IRateLimiterEvents { DummyTransceiver e = new DummyTransceiver(address(nttManagerZeroRateLimiter)); nttManagerZeroRateLimiter.setTransceiver(address(e)); + address user_A = address(0x123); address user_B = address(0x456); uint8 decimals = t.decimals(); + nttManagerZeroRateLimiter.setOutboundPauseStatus(true); nttManagerZeroRateLimiter.setPeer( chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max ); + nttManagerZeroRateLimiter.setOutboundPauseStatus(false); + nttManagerZeroRateLimiter.setInboundPauseStatus(false); t.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -136,14 +147,18 @@ contract TestNttManager is Test, IRateLimiterEvents { // Test incoming transfer completes successfully with rate limit disabled (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerZeroRateLimiter); + nttManagerZeroRateLimiter.setOutboundPauseStatus(true); nttManagerZeroRateLimiter.setThreshold(2); + // register nttManager peer bytes32 peer = toWormholeFormat(address(nttManager)); nttManagerZeroRateLimiter.setPeer( TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, type(uint64).max ); + nttManagerZeroRateLimiter.setOutboundPauseStatus(false); + TransceiverStructs.NttManagerMessage memory nttManagerMessage; bytes memory transceiverMessage; (nttManagerMessage, transceiverMessage) = TransceiverHelpersLib @@ -286,14 +301,17 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_disableReenableTransceiver() public { DummyTransceiver e = new DummyTransceiver(address(nttManager)); + nttManager.setOutboundPauseStatus(true); nttManager.setTransceiver(address(e)); nttManager.removeTransceiver(address(e)); nttManager.setTransceiver(address(e)); } function test_disableAllTransceiversFails() public { + nttManager.setOutboundPauseStatus(true); vm.expectRevert(abi.encodeWithSelector(IManagerBase.ZeroThreshold.selector)); nttManager.removeTransceiver(address(dummyTransceiver)); + nttManager.setOutboundPauseStatus(false); } function test_multipleTransceivers() public { @@ -337,8 +355,10 @@ contract TestNttManager is Test, IRateLimiterEvents { uint8 decimals = token.decimals(); + newNttManager.setOutboundPauseStatus(true); newNttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); newNttManager.setOutboundLimit(packTrimmedAmount(type(uint64).max, 8).untrim(decimals)); + newNttManager.setOutboundPauseStatus(false); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -368,7 +388,10 @@ contract TestNttManager is Test, IRateLimiterEvents { // since we register 1 in the setup DummyTransceiver e = new DummyTransceiver(address(nttManager)); nttManager.setTransceiver(address(e)); + + nttManager.setOutboundPauseStatus(true); nttManager.removeTransceiver(address(e)); + nttManager.setOutboundPauseStatus(false); // We should be able to register 64 transceivers total for (uint256 i = 0; i < 62; ++i) { @@ -390,7 +413,10 @@ contract TestNttManager is Test, IRateLimiterEvents { // since we register 1 in the setup DummyTransceiver e = new DummyTransceiver(address(nttManager)); nttManager.setTransceiver(address(e)); + + nttManager.setOutboundPauseStatus(true); nttManager.removeTransceiver(address(dummyTransceiver)); + nttManager.setOutboundPauseStatus(false); address user_A = address(0x123); address user_B = address(0x456); @@ -399,8 +425,10 @@ contract TestNttManager is Test, IRateLimiterEvents { uint8 decimals = token.decimals(); + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); nttManager.setOutboundLimit(packTrimmedAmount(type(uint64).max, 8).untrim(decimals)); + nttManager.setOutboundPauseStatus(false); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -435,7 +463,10 @@ contract TestNttManager is Test, IRateLimiterEvents { uint8 decimals = token.decimals(); + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); + nttManager.setOutboundPauseStatus(false); + nttManager.setOutboundLimit(0); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -499,6 +530,8 @@ contract TestNttManager is Test, IRateLimiterEvents { // == threshold function test_cantSetThresholdTooHigh() public { + nttManager.setOutboundPauseStatus(true); + // 1 transceiver set, so can't set threshold to 2 vm.expectRevert(abi.encodeWithSelector(IManagerBase.ThresholdTooHigh.selector, 2, 1)); nttManager.setThreshold(2); @@ -510,26 +543,31 @@ contract TestNttManager is Test, IRateLimiterEvents { nttManager.setTransceiver(address(e1)); nttManager.setTransceiver(address(e2)); + nttManager.setOutboundPauseStatus(true); nttManager.setThreshold(1); nttManager.setThreshold(2); nttManager.setThreshold(1); + nttManager.setOutboundPauseStatus(false); } function test_cantSetThresholdToZero() public { DummyTransceiver e = new DummyTransceiver(address(nttManager)); nttManager.setTransceiver(address(e)); + nttManager.setOutboundPauseStatus(true); vm.expectRevert(abi.encodeWithSelector(IManagerBase.ZeroThreshold.selector)); nttManager.setThreshold(0); } function test_onlyOwnerCanSetThreshold() public { + nttManager.setOutboundPauseStatus(true); + address notOwner = address(0x123); vm.startPrank(notOwner); - vm.expectRevert( abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, notOwner) ); + nttManager.setThreshold(1); } @@ -537,8 +575,8 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_peerRegistrationLimitsCanBeUpdated() public { bytes32 peer = toWormholeFormat(address(nttManager)); + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, 0); - IRateLimiter.RateLimitParams memory params = nttManager.getInboundLimitParams(TransceiverHelpersLib.SENDING_CHAIN_ID); assertEq(params.limit.getAmount(), 0); @@ -554,6 +592,7 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_onlyEnabledTransceiversCanAttest() public { (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.removeTransceiver(address(e1)); bytes32 peer = toWormholeFormat(address(nttManager)); nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, type(uint64).max); @@ -571,7 +610,9 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_onlyPeerNttManagerCanAttest() public { (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.setThreshold(2); + nttManagerOther.setOutboundPauseStatus(false); bytes32 peer = toWormholeFormat(address(nttManager)); @@ -592,11 +633,13 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_attestSimple() public { (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.setThreshold(2); // register nttManager peer bytes32 peer = toWormholeFormat(address(nttManager)); nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, type(uint64).max); + nttManagerOther.setOutboundPauseStatus(false); TransceiverStructs.NttManagerMessage memory nttManagerMessage; bytes memory transceiverMessage; @@ -615,11 +658,13 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_attestTwice() public { (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.setThreshold(2); // register nttManager peer bytes32 peer = toWormholeFormat(address(nttManager)); nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, type(uint64).max); + nttManagerOther.setOutboundPauseStatus(false); TransceiverStructs.NttManagerMessage memory nttManagerMessage; bytes memory transceiverMessage; @@ -643,11 +688,14 @@ contract TestNttManager is Test, IRateLimiterEvents { } function test_attestDisabled() public { - (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + + nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.setThreshold(2); bytes32 peer = toWormholeFormat(address(nttManager)); nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, type(uint64).max); + nttManagerOther.setOutboundPauseStatus(false); ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](1); transceivers[0] = e1; @@ -664,6 +712,7 @@ contract TestNttManager is Test, IRateLimiterEvents { transceivers ); + nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.removeTransceiver(address(e1)); bytes32 hash = @@ -683,8 +732,9 @@ contract TestNttManager is Test, IRateLimiterEvents { DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); - + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); + nttManager.setOutboundPauseStatus(false); nttManager.setOutboundLimit(packTrimmedAmount(type(uint64).max, 8).untrim(decimals)); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -725,7 +775,9 @@ contract TestNttManager is Test, IRateLimiterEvents { function test_transferWithAmountAndDecimalsThatCouldOverflow() public { // The source chain has 18 decimals trimmed to 8, and the peer has 6 decimals trimmed to 6 + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 6, type(uint64).max); + nttManager.setOutboundPauseStatus(false); address user_A = address(0x123); address user_B = address(0x456); @@ -825,12 +877,14 @@ contract TestNttManager is Test, IRateLimiterEvents { uint8 decimals = token.decimals(); + nttManager.setOutboundPauseStatus(true); nttManager.setPeer( TransceiverHelpersLib.SENDING_CHAIN_ID, toWormholeFormat(address(nttManagerOther)), 9, type(uint64).max ); + nttManager.setOutboundPauseStatus(false); nttManager.setOutboundLimit(0); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -969,7 +1023,11 @@ contract TestNttManager is Test, IRateLimiterEvents { uint256 maxAmount = 5 * 10 ** decimals; token.mintDummy(from, maxAmount); + + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); + nttManager.setOutboundPauseStatus(false); + nttManager.setOutboundLimit(packTrimmedAmount(type(uint64).max, 8).untrim(decimals)); nttManager.setInboundLimit( packTrimmedAmount(type(uint64).max, 8).untrim(decimals), @@ -1095,7 +1153,10 @@ contract TestNttManager is Test, IRateLimiterEvents { // register nttManager peer and transceiver bytes32 peer = toWormholeFormat(address(nttManager)); + newNttManager.setOutboundPauseStatus(true); newNttManager.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer, 9, type(uint64).max); + newNttManager.setOutboundPauseStatus(false); + newNttManager.setInboundPauseStatus(false); { DummyTransceiver e = new DummyTransceiver(address(newNttManager)); newNttManager.setTransceiver(address(e)); @@ -1120,7 +1181,10 @@ contract TestNttManager is Test, IRateLimiterEvents { // Check that we can receive a transfer (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(newNttManager); + + newNttManager.setOutboundPauseStatus(true); newNttManager.setThreshold(1); + newNttManager.setOutboundPauseStatus(false); bytes memory transceiverMessage; bytes memory tokenTransferMessage; @@ -1214,7 +1278,9 @@ contract TestNttManager is Test, IRateLimiterEvents { uint8 decimals = token.decimals(); + nttManager.setOutboundPauseStatus(true); nttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); + nttManager.setOutboundPauseStatus(false); nttManager.setOutboundLimit(packTrimmedAmount(type(uint64).max, 8).untrim(decimals)); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -1235,4 +1301,61 @@ contract TestNttManager is Test, IRateLimiterEvents { encodedInstructions ); } + + function test_setUnilateralPauseBase() public { + + // Both inbound and outbound pause should default to true on deployment + // IManagerBase.UnilateralPause memory initial_p = nttManager.getUnilateralPause(); + // require(initial_p.inbound == true, "Inital inbound pause value unset"); + // require(initial_p.outbound == true, "Inital outbound pause value unset"); + + nttManager.setInboundPauseStatus(true); + IManagerBase.UnilateralPause memory p_after_update1 = nttManager.getUnilateralPause(); + require(p_after_update1.inbound == true, "Inbound pause value unset after update"); + require(p_after_update1.outbound == false, "Outbound pause value not unset"); + + nttManager.setInboundPauseStatus(false); + IManagerBase.UnilateralPause memory p_after_update2 = nttManager.getUnilateralPause(); + require(p_after_update2.inbound == false, "Inbound pause value did not reset back to false"); + require(p_after_update2.outbound == false, "Outbound pause value not unset"); + + nttManager.setOutboundPauseStatus(true); + IManagerBase.UnilateralPause memory p_after_update3 = nttManager.getUnilateralPause(); + require(p_after_update3.inbound == false, "Inbound pause unexpectedly updated to true"); + require(p_after_update3.outbound == true, "Outbound pause value not set to true"); + + nttManager.setOutboundPauseStatus(false); + IManagerBase.UnilateralPause memory p_after_update4 = nttManager.getUnilateralPause(); + require(p_after_update4.inbound == false, "Inbound pause value changed unexpectedly"); + require(p_after_update4.outbound == false, "Outbound pause value did not reset back to false"); + } + + function test_setUnilateralPauseAuth() public { + + IManagerBase.UnilateralPause memory initial_p = nttManager.getUnilateralPause(); + require(initial_p.inbound == false, "Inital inbound pause value unset"); + require(initial_p.outbound == false, "Inital outbound pause value unset"); + + address user_B = address(0x456); + vm.startPrank(user_B); + + // Check if other can + vm.expectRevert( + abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, user_B) + ); + nttManager.setInboundPauseStatus(false); + + vm.expectRevert( + abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, user_B) + ); + nttManager.setOutboundPauseStatus(false); + + vm.stopPrank(); + nttManager.setInboundPauseStatus(true); + nttManager.setOutboundPauseStatus(true); + IManagerBase.UnilateralPause memory p_after_update1 = nttManager.getUnilateralPause(); + require(p_after_update1.inbound == true, "Inbound pause value unset after update"); + require(p_after_update1.outbound == true, "Outbound pause value unset after update"); + } + } diff --git a/evm/test/RateLimit.t.sol b/evm/test/RateLimit.t.sol index 159246e20..1ff92adfd 100644 --- a/evm/test/RateLimit.t.sol +++ b/evm/test/RateLimit.t.sol @@ -50,6 +50,10 @@ contract TestRateLimit is Test, IRateLimiterEvents { DummyTransceiver e = new DummyTransceiver(address(nttManager)); nttManager.setTransceiver(address(e)); + + nttManager.setInboundPauseStatus(false); + nttManager.setOutboundPauseStatus(false); + } function test_outboundRateLimit_setLimitSimple() public { diff --git a/evm/test/Upgrades.t.sol b/evm/test/Upgrades.t.sol index ceda71e7b..95c3c9bf6 100644 --- a/evm/test/Upgrades.t.sol +++ b/evm/test/Upgrades.t.sol @@ -139,6 +139,7 @@ contract TestUpgrades is Test, IRateLimiterEvents { nttManagerChain1.setThreshold(1); nttManagerChain2.setThreshold(1); vm.chainId(chainId1); + } function test_basicUpgradeNttManager() public { @@ -441,6 +442,11 @@ contract TestUpgrades is Test, IRateLimiterEvents { } function basicFunctionality() public { + + nttManagerChain1.setInboundPauseStatus(false); + nttManagerChain1.setOutboundPauseStatus(false); + nttManagerChain2.setInboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); vm.chainId(chainId1); // Setting up the transfer @@ -583,6 +589,10 @@ contract TestUpgrades is Test, IRateLimiterEvents { } vm.stopPrank(); + nttManagerChain1.setInboundPauseStatus(true); + nttManagerChain1.setOutboundPauseStatus(true); + nttManagerChain2.setInboundPauseStatus(true); + nttManagerChain2.setOutboundPauseStatus(true); } function encodeTransceiverInstruction(bool relayer_off) public view returns (bytes memory) { diff --git a/evm/test/libraries/TransceiverHelpers.sol b/evm/test/libraries/TransceiverHelpers.sol index 11a3551db..ee88b7623 100644 --- a/evm/test/libraries/TransceiverHelpers.sol +++ b/evm/test/libraries/TransceiverHelpers.sol @@ -19,11 +19,14 @@ library TransceiverHelpersLib { internal returns (DummyTransceiver, DummyTransceiver) { + nttManager.setOutboundPauseStatus(true); DummyTransceiver e1 = new DummyTransceiver(address(nttManager)); DummyTransceiver e2 = new DummyTransceiver(address(nttManager)); nttManager.setTransceiver(address(e1)); nttManager.setTransceiver(address(e2)); nttManager.setThreshold(2); + nttManager.setOutboundPauseStatus(false); + return (e1, e2); } @@ -98,9 +101,14 @@ library TransceiverHelpersLib { ) internal { DummyToken token = DummyToken(nttManager.token()); token.mintDummy(address(recipientNttManager), amount.untrim(token.decimals())); + + nttManager.setOutboundPauseStatus(true); + recipientNttManager.setOutboundPauseStatus(true); NttManagerHelpersLib.setConfigs( inboundLimit, nttManager, recipientNttManager, token.decimals() ); + nttManager.setOutboundPauseStatus(false); + recipientNttManager.setOutboundPauseStatus(false); } function buildTransceiverMessageWithNttManagerPayload( From 1d9dceff249a1d745cd46c030034574c937796f1 Mon Sep 17 00:00:00 2001 From: Maxwell Dulin Date: Thu, 11 Apr 2024 13:21:10 -0700 Subject: [PATCH 2/2] Forge fmt --- evm/src/NttManager/ManagerBase.sol | 28 +++++++++++++--------------- evm/src/NttManager/NttManager.sol | 13 +++++++++---- evm/src/interfaces/IManagerBase.sol | 7 +++---- evm/test/IntegrationManual.t.sol | 24 ++++++++++++++---------- evm/test/IntegrationRelayer.t.sol | 20 ++++++++++---------- evm/test/IntegrationStandalone.t.sol | 5 ++--- evm/test/NttManager.t.sol | 26 +++++++++----------------- evm/test/RateLimit.t.sol | 1 - evm/test/Upgrades.t.sol | 2 -- 9 files changed, 60 insertions(+), 66 deletions(-) diff --git a/evm/src/NttManager/ManagerBase.sol b/evm/src/NttManager/ManagerBase.sol index fea546d7e..46ed6b5b6 100644 --- a/evm/src/NttManager/ManagerBase.sol +++ b/evm/src/NttManager/ManagerBase.sol @@ -43,22 +43,22 @@ abstract contract ManagerBase is deployer = msg.sender; } - modifier inboundNotPaused(){ - if(_getUnilateralPauseStorage().inbound){ + modifier inboundNotPaused() { + if (_getUnilateralPauseStorage().inbound) { revert InboundPaused(); } _; } - modifier outboundNotPaused(){ - if(_getUnilateralPauseStorage().outbound){ + modifier outboundNotPaused() { + if (_getUnilateralPauseStorage().outbound) { revert OutboundPaused(); } _; } - modifier outboundWhenPaused(){ - if(_getUnilateralPauseStorage().outbound == false){ + modifier outboundWhenPaused() { + if (_getUnilateralPauseStorage().outbound == false) { revert NotPausedForUpdate(); } _; @@ -79,7 +79,8 @@ abstract contract ManagerBase is bytes32 private constant THRESHOLD_SLOT = bytes32(uint256(keccak256("ntt.threshold")) - 1); - bytes32 private constant UNILATERAL_PAUSE_SLOT = bytes32(uint256(keccak256("ntt.unilateral_pause")) - 1); + bytes32 private constant UNILATERAL_PAUSE_SLOT = + bytes32(uint256(keccak256("ntt.unilateral_pause")) - 1); // =============== Storage Getters/Setters ============================================== @@ -89,7 +90,7 @@ abstract contract ManagerBase is $.slot := slot } } - + function _getThresholdStorage() private pure returns (_Threshold storage $) { uint256 slot = uint256(THRESHOLD_SLOT); assembly ("memory-safe") { @@ -306,12 +307,9 @@ abstract contract ManagerBase is /// @inheritdoc IManagerBase function getUnilateralPause() public view returns (UnilateralPause memory) { - UnilateralPause storage u = _getUnilateralPauseStorage(); + UnilateralPause storage u = _getUnilateralPauseStorage(); - return UnilateralPause({ - inbound: u.inbound, - outbound: u.outbound - }); + return UnilateralPause({inbound: u.inbound, outbound: u.outbound}); } /// @inheritdoc IManagerBase @@ -357,11 +355,11 @@ abstract contract ManagerBase is _unpause(); } - function setInboundPauseStatus(bool status) external onlyOwnerOrPauser(){ + function setInboundPauseStatus(bool status) external onlyOwnerOrPauser { _getUnilateralPauseStorage().inbound = status; } - function setOutboundPauseStatus(bool status) external onlyOwnerOrPauser(){ + function setOutboundPauseStatus(bool status) external onlyOwnerOrPauser { _getUnilateralPauseStorage().outbound = status; } diff --git a/evm/src/NttManager/NttManager.sol b/evm/src/NttManager/NttManager.sol index 1fb2a7cb4..c0485eb05 100644 --- a/evm/src/NttManager/NttManager.sol +++ b/evm/src/NttManager/NttManager.sol @@ -64,8 +64,8 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { __PausedOwnable_init(msg.sender, msg.sender); __ReentrancyGuard_init(); _setOutboundLimit(TrimmedAmountLib.max(tokenDecimals())); - _getUnilateralPauseStorage().inbound = true; - _getUnilateralPauseStorage().outbound = true; + _getUnilateralPauseStorage().inbound = true; + _getUnilateralPauseStorage().outbound = true; } function _initialize() internal virtual override { @@ -184,7 +184,7 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { uint16 sourceChainId, bytes32 sourceNttManagerAddress, TransceiverStructs.NttManagerMessage memory payload - ) external onlyTransceiver whenNotPaused inboundNotPaused{ + ) external onlyTransceiver whenNotPaused inboundNotPaused { _verifyPeer(sourceChainId, sourceNttManagerAddress); // Compute manager message digest and record transceiver attestation. @@ -243,7 +243,12 @@ contract NttManager is INttManager, RateLimiter, ManagerBase { } /// @inheritdoc INttManager - function completeInboundQueuedTransfer(bytes32 digest) external nonReentrant whenNotPaused inboundNotPaused{ + function completeInboundQueuedTransfer(bytes32 digest) + external + nonReentrant + whenNotPaused + inboundNotPaused + { // find the message in the queue InboundQueuedTransfer memory queuedTransfer = getInboundQueuedTransfer(digest); if (queuedTransfer.txTimestamp == 0) { diff --git a/evm/src/interfaces/IManagerBase.sol b/evm/src/interfaces/IManagerBase.sol index a621c1c10..33b89155c 100644 --- a/evm/src/interfaces/IManagerBase.sol +++ b/evm/src/interfaces/IManagerBase.sol @@ -33,8 +33,8 @@ interface IManagerBase { /// @dev Structure for storing pause information for inbound and outbound transfers struct UnilateralPause { - bool inbound; - bool outbound; + bool inbound; + bool outbound; } /// @notice Emitted when a message has been attested to. @@ -127,7 +127,6 @@ interface IManagerBase { /// @dev Select 0x37291df0 error NotPausedForUpdate(); - /// @notice Fetch the delivery price for a given recipient chain transfer. /// @param recipientChain The chain ID of the transfer destination. /// @param transceiverInstructions The transceiver specific instructions for quoting and sending @@ -184,7 +183,7 @@ interface IManagerBase { /// it to be considered valid and acted upon. function getThreshold() external view returns (uint8); - /// @notice Returns the inbound and outbound pause information for the manager. + /// @notice Returns the inbound and outbound pause information for the manager. /// This is seperate to the general pause feature function getUnilateralPause() external view returns (UnilateralPause memory); diff --git a/evm/test/IntegrationManual.t.sol b/evm/test/IntegrationManual.t.sol index e330ac989..8bc77e512 100644 --- a/evm/test/IntegrationManual.t.sol +++ b/evm/test/IntegrationManual.t.sol @@ -66,7 +66,7 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { address(new ERC1967Proxy(address(wormholeTransceiverChain1), "")) ); wormholeTransceiverChain1.initialize(); - + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1)); nttManagerChain1.setOutboundLimit(type(uint64).max); nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); @@ -108,7 +108,6 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { } function test_relayerTransceiverAuth() public { - nttManagerChain1.setInboundPauseStatus(false); nttManagerChain1.setOutboundPauseStatus(false); nttManagerChain2.setInboundPauseStatus(false); @@ -149,9 +148,9 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { vm.chainId(chainId2); // Set bad manager peer (0x1) - nttManagerChain2.setOutboundPauseStatus(true); + nttManagerChain2.setOutboundPauseStatus(true); nttManagerChain2.setPeer(chainId1, toWormholeFormat(address(0x1)), 9, type(uint64).max); - nttManagerChain2.setOutboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); vm.startPrank(relayer); @@ -166,9 +165,9 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { ); vm.stopPrank(); - nttManagerChain2.setOutboundPauseStatus(true); + nttManagerChain2.setOutboundPauseStatus(true); _setManagerPeer(nttManagerChain2, nttManagerChain1, chainId1, 9, type(uint64).max); - nttManagerChain2.setOutboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); // Wrong caller - aka not relayer contract vm.prank(userD); @@ -225,9 +224,14 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { } function test_relayerWithInvalidWHTransceiver() public { - - require(nttManagerChain1.getUnilateralPause().inbound == true, "Inbound pause not true by default"); - require(nttManagerChain1.getUnilateralPause().outbound == true, "Outbound pause not true by default"); + require( + nttManagerChain1.getUnilateralPause().inbound == true, + "Inbound pause not true by default" + ); + require( + nttManagerChain1.getUnilateralPause().outbound == true, + "Outbound pause not true by default" + ); nttManagerChain1.setInboundPauseStatus(false); nttManagerChain1.setOutboundPauseStatus(false); @@ -258,7 +262,7 @@ contract TestRelayerEndToEndManual is IntegrationHelpers, IRateLimiterEvents { nttManagerChain1.transfer{ value: wormholeTransceiverChain1.quoteDeliveryPrice( chainId2, buildTransceiverInstruction(false) - ) + ) }( sendingAmount, chainId2, diff --git a/evm/test/IntegrationRelayer.t.sol b/evm/test/IntegrationRelayer.t.sol index 97614f74b..1b019059f 100755 --- a/evm/test/IntegrationRelayer.t.sol +++ b/evm/test/IntegrationRelayer.t.sol @@ -165,17 +165,13 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole ); // Ensure that the enforcement for changing the peer is in place. - vm.expectRevert( - abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector) - ); + vm.expectRevert(abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector)); nttManagerChain2.setPeer( chainId1, bytes32(uint256(uint160(address(nttManagerChain1)))), 9, type(uint64).max ); // Test that the threshold must be changed while in the paused state - vm.expectRevert( - abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector) - ); + vm.expectRevert(abi.encodeWithSelector(IManagerBase.NotPausedForUpdate.selector)); nttManagerChain2.setThreshold(1); // Set the peer @@ -293,9 +289,13 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole ); // Test whether a random caller can set the inbound or outbound pause status - vm.expectRevert(abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, userA)); + vm.expectRevert( + abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, userA) + ); nttManagerChain1.setOutboundPauseStatus(true); - vm.expectRevert(abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, userA)); + vm.expectRevert( + abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, userA) + ); nttManagerChain1.setInboundPauseStatus(true); // Pause outbound transfers and see if this still succeeds @@ -413,7 +413,7 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole nttManagerChain1.transfer{ value: wormholeTransceiverChain1.quoteDeliveryPrice( chainId2, buildTransceiverInstruction(false) - ) + ) }( sendingAmount, chainId2, @@ -467,7 +467,7 @@ contract TestEndToEndRelayer is IntegrationHelpers, IRateLimiterEvents, Wormhole nttManagerChain2.transfer{ value: wormholeTransceiverChain2.quoteDeliveryPrice( chainId1, buildTransceiverInstruction(false) - ) + ) }( sendingAmount, chainId1, diff --git a/evm/test/IntegrationStandalone.t.sol b/evm/test/IntegrationStandalone.t.sol index 938ca4fba..6261334b2 100755 --- a/evm/test/IntegrationStandalone.t.sol +++ b/evm/test/IntegrationStandalone.t.sol @@ -150,7 +150,7 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { nttManagerChain1.setInboundPauseStatus(false); nttManagerChain1.setOutboundPauseStatus(false); nttManagerChain2.setInboundPauseStatus(false); - nttManagerChain2.setOutboundPauseStatus(false); + nttManagerChain2.setOutboundPauseStatus(false); } function test_chainToChainBase() public { @@ -336,7 +336,6 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { ); // Wrong chain receiving the signed VAA wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); - vm.chainId(chainId2); // Check if the inbound pauser works effectively @@ -344,7 +343,7 @@ contract TestEndToEndBase is Test, IRateLimiterEvents { vm.expectRevert(abi.encodeWithSelector(IManagerBase.InboundPaused.selector)); wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); nttManagerChain2.setInboundPauseStatus(false); - + { uint256 supplyBefore = token2.totalSupply(); wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); diff --git a/evm/test/NttManager.t.sol b/evm/test/NttManager.t.sol index b247d3a61..61e9df7f6 100644 --- a/evm/test/NttManager.t.sol +++ b/evm/test/NttManager.t.sol @@ -99,7 +99,6 @@ contract TestNttManager is Test, IRateLimiterEvents { // === Deployments with rate limiter disabled function test_disabledRateLimiter() public { - DummyToken t = new DummyToken(); NttManager implementation = new MockNttManagerContract(address(t), IManagerBase.Mode.LOCKING, chainId, 0, true); @@ -111,7 +110,6 @@ contract TestNttManager is Test, IRateLimiterEvents { DummyTransceiver e = new DummyTransceiver(address(nttManagerZeroRateLimiter)); nttManagerZeroRateLimiter.setTransceiver(address(e)); - address user_A = address(0x123); address user_B = address(0x456); @@ -150,7 +148,6 @@ contract TestNttManager is Test, IRateLimiterEvents { nttManagerZeroRateLimiter.setOutboundPauseStatus(true); nttManagerZeroRateLimiter.setThreshold(2); - // register nttManager peer bytes32 peer = toWormholeFormat(address(nttManager)); nttManagerZeroRateLimiter.setPeer( @@ -358,7 +355,7 @@ contract TestNttManager is Test, IRateLimiterEvents { newNttManager.setOutboundPauseStatus(true); newNttManager.setPeer(chainId2, toWormholeFormat(address(0x1)), 9, type(uint64).max); newNttManager.setOutboundLimit(packTrimmedAmount(type(uint64).max, 8).untrim(decimals)); - newNttManager.setOutboundPauseStatus(false); + newNttManager.setOutboundPauseStatus(false); token.mintDummy(address(user_A), 5 * 10 ** decimals); @@ -688,7 +685,7 @@ contract TestNttManager is Test, IRateLimiterEvents { } function test_attestDisabled() public { - (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); nttManagerOther.setOutboundPauseStatus(true); nttManagerOther.setThreshold(2); @@ -1303,7 +1300,6 @@ contract TestNttManager is Test, IRateLimiterEvents { } function test_setUnilateralPauseBase() public { - // Both inbound and outbound pause should default to true on deployment // IManagerBase.UnilateralPause memory initial_p = nttManager.getUnilateralPause(); // require(initial_p.inbound == true, "Inital inbound pause value unset"); @@ -1327,11 +1323,12 @@ contract TestNttManager is Test, IRateLimiterEvents { nttManager.setOutboundPauseStatus(false); IManagerBase.UnilateralPause memory p_after_update4 = nttManager.getUnilateralPause(); require(p_after_update4.inbound == false, "Inbound pause value changed unexpectedly"); - require(p_after_update4.outbound == false, "Outbound pause value did not reset back to false"); - } + require( + p_after_update4.outbound == false, "Outbound pause value did not reset back to false" + ); + } function test_setUnilateralPauseAuth() public { - IManagerBase.UnilateralPause memory initial_p = nttManager.getUnilateralPause(); require(initial_p.inbound == false, "Inital inbound pause value unset"); require(initial_p.outbound == false, "Inital outbound pause value unset"); @@ -1339,15 +1336,11 @@ contract TestNttManager is Test, IRateLimiterEvents { address user_B = address(0x456); vm.startPrank(user_B); - // Check if other can - vm.expectRevert( - abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, user_B) - ); + // Check if other can + vm.expectRevert(abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, user_B)); nttManager.setInboundPauseStatus(false); - vm.expectRevert( - abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, user_B) - ); + vm.expectRevert(abi.encodeWithSelector(PausableUpgradeable.InvalidPauser.selector, user_B)); nttManager.setOutboundPauseStatus(false); vm.stopPrank(); @@ -1357,5 +1350,4 @@ contract TestNttManager is Test, IRateLimiterEvents { require(p_after_update1.inbound == true, "Inbound pause value unset after update"); require(p_after_update1.outbound == true, "Outbound pause value unset after update"); } - } diff --git a/evm/test/RateLimit.t.sol b/evm/test/RateLimit.t.sol index 1ff92adfd..e5b9ae667 100644 --- a/evm/test/RateLimit.t.sol +++ b/evm/test/RateLimit.t.sol @@ -53,7 +53,6 @@ contract TestRateLimit is Test, IRateLimiterEvents { nttManager.setInboundPauseStatus(false); nttManager.setOutboundPauseStatus(false); - } function test_outboundRateLimit_setLimitSimple() public { diff --git a/evm/test/Upgrades.t.sol b/evm/test/Upgrades.t.sol index 95c3c9bf6..88f3f7fb8 100644 --- a/evm/test/Upgrades.t.sol +++ b/evm/test/Upgrades.t.sol @@ -139,7 +139,6 @@ contract TestUpgrades is Test, IRateLimiterEvents { nttManagerChain1.setThreshold(1); nttManagerChain2.setThreshold(1); vm.chainId(chainId1); - } function test_basicUpgradeNttManager() public { @@ -442,7 +441,6 @@ contract TestUpgrades is Test, IRateLimiterEvents { } function basicFunctionality() public { - nttManagerChain1.setInboundPauseStatus(false); nttManagerChain1.setOutboundPauseStatus(false); nttManagerChain2.setInboundPauseStatus(false);