From bf4c93db43383c219ed0efb14d66261f16f8ba55 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sat, 24 Feb 2024 21:18:00 -0500 Subject: [PATCH] The great renaming (#191) * endpoint -> transceiver * Manager -> NttManager * sibling -> peer * evm: fix 4byte prefixes after rename --- evm/src/Endpoint.sol | 142 ----- evm/src/EndpointRegistry.sol | 270 --------- evm/src/{Manager.sol => NttManager.sol} | 312 +++++----- evm/src/Transceiver.sol | 142 +++++ evm/src/TransceiverRegistry.sol | 279 +++++++++ ...leEndpoint.sol => WormholeTransceiver.sol} | 232 ++++---- evm/src/interfaces/IEndpoint.sol | 29 - evm/src/interfaces/IManagerStandalone.sol | 18 - .../{IManager.sol => INttManager.sol} | 54 +- ...anagerEvents.sol => INttManagerEvents.sol} | 46 +- evm/src/interfaces/INttManagerStandalone.sol | 18 + evm/src/interfaces/IRateLimiter.sol | 6 +- evm/src/interfaces/ITransceiver.sol | 29 + ...eEndpoint.sol => IWormholeTransceiver.sol} | 18 +- evm/src/libraries/RateLimiter.sol | 8 +- ...ointHelpers.sol => TransceiverHelpers.sol} | 0 ...ointStructs.sol => TransceiverStructs.sol} | 280 ++++----- evm/test/EndpointStructs.t.sol | 110 ---- evm/test/IntegrationRelayer.t.sol | 383 ++++++------ evm/test/IntegrationStandalone.t.sol | 329 ++++++----- evm/test/Manager.t.sol | 539 ----------------- evm/test/NttManager.t.sol | 546 ++++++++++++++++++ evm/test/Ownership.t.sol | 36 +- evm/test/RateLimit.t.sol | 263 +++++---- evm/test/TransceiverStructs.t.sol | 116 ++++ evm/test/Upgrades.t.sol | 357 ++++++------ ...tReceiver.sol => ITransceiverReceiver.sol} | 2 +- evm/test/libraries/EndpointHelpers.sol | 118 ---- ...nagerHelpers.sol => NttManagerHelpers.sol} | 12 +- evm/test/libraries/TransceiverHelpers.sol | 126 ++++ evm/test/mocks/DummyEndpoint.sol | 51 -- evm/test/mocks/DummyToken.sol | 6 +- evm/test/mocks/DummyTransceiver.sol | 51 ++ .../{MockManager.sol => MockNttManager.sol} | 24 +- ...MockEndpoints.sol => MockTransceivers.sol} | 38 +- .../ntt-messages/src/endpoints/wormhole.rs | 8 - solana/modules/ntt-messages/src/lib.rs | 6 +- .../src/{manager.rs => ntt_manager.rs} | 16 +- .../src/{endpoint.rs => transceiver.rs} | 136 ++--- .../src/{endpoints => transceivers}/mod.rs | 0 .../ntt-messages/src/transceivers/wormhole.rs | 8 + .../src/config.rs | 10 +- .../src/endpoints/accounts/mod.rs | 1 - .../src/endpoints/accounts/sibling.rs | 13 - .../src/error.rs | 16 +- .../src/instructions/admin.rs | 54 +- .../src/instructions/initialize.rs | 4 +- .../src/instructions/redeem.rs | 46 +- .../src/instructions/transfer.rs | 26 +- .../example-native-token-transfers/src/lib.rs | 30 +- .../src/messages.rs | 10 +- .../src/peer.rs | 14 + .../src/queue/outbox.rs | 8 +- .../src/registered_endpoint.rs | 13 - .../src/registered_transceiver.rs | 13 + .../src/sibling.rs | 14 - .../src/transceivers/accounts/mod.rs | 1 + .../src/transceivers/accounts/peer.rs | 13 + .../src/{endpoints => transceivers}/mod.rs | 0 .../wormhole/instructions/admin.rs | 24 +- .../wormhole/instructions/mod.rs | 0 .../wormhole/instructions/receive_message.rs | 37 +- .../wormhole/instructions/release_outbound.rs | 49 +- .../wormhole/mod.rs | 0 .../tests/cancel_flow.rs | 53 +- .../tests/common/setup.rs | 32 +- .../tests/sdk/accounts.rs | 42 +- .../tests/sdk/instructions/admin.rs | 26 +- .../tests/sdk/instructions/redeem.rs | 12 +- .../tests/sdk/instructions/transfer.rs | 6 +- .../tests/sdk/mod.rs | 2 +- .../sdk/{endpoints => transceivers}/mod.rs | 0 .../wormhole/instructions/admin.rs | 16 +- .../wormhole/instructions/mod.rs | 0 .../wormhole/instructions/receive_message.rs | 6 +- .../wormhole/instructions/release_outbound.rs | 4 +- .../wormhole/mod.rs | 0 .../tests/transfer.rs | 29 +- solana/tests/example-native-token-transfer.ts | 36 +- solana/ts/sdk/index.ts | 124 ++-- solana/ts/sdk/payloads/common.ts | 62 +- solana/ts/sdk/payloads/wormhole.ts | 4 +- 82 files changed, 3052 insertions(+), 2962 deletions(-) delete mode 100644 evm/src/Endpoint.sol delete mode 100644 evm/src/EndpointRegistry.sol rename evm/src/{Manager.sol => NttManager.sol} (67%) create mode 100644 evm/src/Transceiver.sol create mode 100644 evm/src/TransceiverRegistry.sol rename evm/src/{WormholeEndpoint.sol => WormholeTransceiver.sol} (57%) delete mode 100644 evm/src/interfaces/IEndpoint.sol delete mode 100644 evm/src/interfaces/IManagerStandalone.sol rename evm/src/interfaces/{IManager.sol => INttManager.sol} (74%) rename evm/src/interfaces/{IManagerEvents.sol => INttManagerEvents.sol} (56%) create mode 100644 evm/src/interfaces/INttManagerStandalone.sol create mode 100644 evm/src/interfaces/ITransceiver.sol rename evm/src/interfaces/{IWormholeEndpoint.sol => IWormholeTransceiver.sol} (69%) rename evm/src/libraries/{EndpointHelpers.sol => TransceiverHelpers.sol} (100%) rename evm/src/libraries/{EndpointStructs.sol => TransceiverStructs.sol} (50%) delete mode 100644 evm/test/EndpointStructs.t.sol delete mode 100644 evm/test/Manager.t.sol create mode 100644 evm/test/NttManager.t.sol create mode 100644 evm/test/TransceiverStructs.t.sol rename evm/test/interfaces/{IEndpointReceiver.sol => ITransceiverReceiver.sol} (80%) delete mode 100644 evm/test/libraries/EndpointHelpers.sol rename evm/test/libraries/{ManagerHelpers.sol => NttManagerHelpers.sol} (50%) create mode 100644 evm/test/libraries/TransceiverHelpers.sol delete mode 100644 evm/test/mocks/DummyEndpoint.sol create mode 100644 evm/test/mocks/DummyTransceiver.sol rename evm/test/mocks/{MockManager.sol => MockNttManager.sol} (75%) rename evm/test/mocks/{MockEndpoints.sol => MockTransceivers.sol} (72%) delete mode 100644 solana/modules/ntt-messages/src/endpoints/wormhole.rs rename solana/modules/ntt-messages/src/{manager.rs => ntt_manager.rs} (82%) rename solana/modules/ntt-messages/src/{endpoint.rs => transceiver.rs} (55%) rename solana/modules/ntt-messages/src/{endpoints => transceivers}/mod.rs (100%) create mode 100644 solana/modules/ntt-messages/src/transceivers/wormhole.rs delete mode 100644 solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs delete mode 100644 solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs create mode 100644 solana/programs/example-native-token-transfers/src/peer.rs delete mode 100644 solana/programs/example-native-token-transfers/src/registered_endpoint.rs create mode 100644 solana/programs/example-native-token-transfers/src/registered_transceiver.rs delete mode 100644 solana/programs/example-native-token-transfers/src/sibling.rs create mode 100644 solana/programs/example-native-token-transfers/src/transceivers/accounts/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/transceivers/accounts/peer.rs rename solana/programs/example-native-token-transfers/src/{endpoints => transceivers}/mod.rs (100%) rename solana/programs/example-native-token-transfers/src/{endpoints => transceivers}/wormhole/instructions/admin.rs (51%) rename solana/programs/example-native-token-transfers/src/{endpoints => transceivers}/wormhole/instructions/mod.rs (100%) rename solana/programs/example-native-token-transfers/src/{endpoints => transceivers}/wormhole/instructions/receive_message.rs (53%) rename solana/programs/example-native-token-transfers/src/{endpoints => transceivers}/wormhole/instructions/release_outbound.rs (71%) rename solana/programs/example-native-token-transfers/src/{endpoints => transceivers}/wormhole/mod.rs (100%) rename solana/programs/example-native-token-transfers/tests/sdk/{endpoints => transceivers}/mod.rs (100%) rename solana/programs/example-native-token-transfers/tests/sdk/{endpoints => transceivers}/wormhole/instructions/admin.rs (70%) rename solana/programs/example-native-token-transfers/tests/sdk/{endpoints => transceivers}/wormhole/instructions/mod.rs (100%) rename solana/programs/example-native-token-transfers/tests/sdk/{endpoints => transceivers}/wormhole/instructions/receive_message.rs (86%) rename solana/programs/example-native-token-transfers/tests/sdk/{endpoints => transceivers}/wormhole/instructions/release_outbound.rs (90%) rename solana/programs/example-native-token-transfers/tests/sdk/{endpoints => transceivers}/wormhole/mod.rs (100%) diff --git a/evm/src/Endpoint.sol b/evm/src/Endpoint.sol deleted file mode 100644 index e665a0a7e..000000000 --- a/evm/src/Endpoint.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; - -import "./libraries/EndpointStructs.sol"; -import "./libraries/PausableOwnable.sol"; -import "./interfaces/IManager.sol"; -import "./interfaces/IEndpoint.sol"; -import "./libraries/external/ReentrancyGuardUpgradeable.sol"; -import "./libraries/Implementation.sol"; -import "wormhole-solidity-sdk/Utils.sol"; - -abstract contract Endpoint is - IEndpoint, - PausableOwnable, - ReentrancyGuardUpgradeable, - Implementation -{ - /// @dev updating bridgeManager requires a new Endpoint deployment. - /// Projects should implement their own governance to remove the old Endpoint contract address and then add the new one. - address public immutable manager; - address public immutable managerToken; - - constructor(address _manager) { - manager = _manager; - managerToken = IManager(manager).token(); - } - - /// =============== MODIFIERS =============================================== - - modifier onlyManager() { - if (msg.sender != manager) { - revert CallerNotManager(msg.sender); - } - _; - } - - /// =============== ADMIN =============================================== - - function _initialize() internal virtual override { - __ReentrancyGuard_init(); - // owner of the endpoint is set to the owner of the manager - __PausedOwnable_init(msg.sender, getManagerOwner()); - } - - /// @dev transfer the ownership of the endpoint to a new address - /// the manager should be able to update endpoint ownership. - function transferEndpointOwnership(address newOwner) external onlyManager { - _transferOwnership(newOwner); - } - - /// @dev pause the endpoint. - function _pauseEndpoint() internal { - _pause(); - } - - function upgrade(address newImplementation) external onlyOwner { - _upgrade(newImplementation); - } - - function _migrate() internal virtual override {} - - /// @dev This method checks that the the referecnes to the manager and its corresponding function are correct - /// When new immutable variables are added, this function should be updated. - function _checkImmutables() internal view override { - assert(this.manager() == manager); - assert(this.managerToken() == managerToken); - } - - /// =============== GETTERS & SETTERS =============================================== - - function getManagerOwner() public view returns (address) { - return IOwnableUpgradeable(manager).owner(); - } - - function getManagerToken() public view virtual returns (address) { - return managerToken; - } - - /// =============== TRANSCEIVING LOGIC =============================================== - /** - * @dev send a message to another chain. - * @param recipientChain The chain id of the recipient. - * @param instruction An additional Instruction provided by the Endpoint to be - * executed on the recipient chain. - * @param managerMessage A message to be sent to the manager on the recipient chain. - */ - function sendMessage( - uint16 recipientChain, - EndpointStructs.EndpointInstruction memory instruction, - bytes memory managerMessage, - bytes32 recipientManagerAddress - ) external payable nonReentrant onlyManager { - _sendMessage( - recipientChain, - msg.value, - msg.sender, - recipientManagerAddress, - instruction, - managerMessage - ); - } - - function _sendMessage( - uint16 recipientChain, - uint256 deliveryPayment, - address caller, - bytes32 recipientManagerAddress, - EndpointStructs.EndpointInstruction memory endpointInstruction, - bytes memory managerMessage - ) internal virtual; - - // @dev This method is called by the BridgeManager contract to send a cross-chain message. - // Forwards the VAA payload to the endpoint manager contract. - // @param sourceChainId The chain id of the sender. - // @param sourceManagerAddress The address of the sender's manager contract. - // @param payload The VAA payload. - function _deliverToManager( - uint16 sourceChainId, - bytes32 sourceManagerAddress, - bytes32 recipientManagerAddress, - EndpointStructs.ManagerMessage memory payload - ) internal virtual { - if (recipientManagerAddress != toWormholeFormat(manager)) { - revert UnexpectedRecipientManagerAddress( - toWormholeFormat(manager), recipientManagerAddress - ); - } - IManager(manager).attestationReceived(sourceChainId, sourceManagerAddress, payload); - } - - function quoteDeliveryPrice( - uint16 targetChain, - EndpointStructs.EndpointInstruction memory instruction - ) external view returns (uint256) { - return _quoteDeliveryPrice(targetChain, instruction); - } - - function _quoteDeliveryPrice( - uint16 targetChain, - EndpointStructs.EndpointInstruction memory endpointInstruction - ) internal view virtual returns (uint256); -} diff --git a/evm/src/EndpointRegistry.sol b/evm/src/EndpointRegistry.sol deleted file mode 100644 index 66edaeaf4..000000000 --- a/evm/src/EndpointRegistry.sol +++ /dev/null @@ -1,270 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; - -/// @dev This contract is responsible for handling the registration of Endpoints. -abstract contract EndpointRegistry { - constructor() { - _checkEndpointsInvariants(); - } - - /// @dev Information about registered endpoints. - struct EndpointInfo { - // whether this endpoint is registered - bool registered; - // whether this endpoint is enabled - bool enabled; - uint8 index; - } - - /// @dev Bitmap encoding the enabled endpoints. - /// invariant: forall (i: uint8), enabledEndpointBitmap & i == 1 <=> endpointInfos[i].enabled - struct _EnabledEndpointBitmap { - uint64 bitmap; - } - - /// @dev Total number of registered endpoints. This number can only increase. - /// invariant: numRegisteredEndpoints <= MAX_ENDPOINTS - /// invariant: forall (i: uint8), - /// i < numRegisteredEndpoints <=> exists (a: address), endpointInfos[a].index == i - struct _NumEndpoints { - uint8 registered; - uint8 enabled; - } - - uint8 constant MAX_ENDPOINTS = 64; - - error CallerNotEndpoint(address caller); - error InvalidEndpointZeroAddress(); - error DisabledEndpoint(address endpoint); - error TooManyEndpoints(); - error NonRegisteredEndpoint(address endpoint); - error EndpointAlreadyEnabled(address endpoint); - - event EndpointAdded(address endpoint); - event EndpointRemoved(address endpoint); - - modifier onlyEndpoint() { - if (!_getEndpointInfosStorage()[msg.sender].enabled) { - revert CallerNotEndpoint(msg.sender); - } - _; - } - - /// =============== STORAGE =============================================== - - bytes32 private constant ENDPOINT_INFOS_SLOT = - bytes32(uint256(keccak256("ntt.endpointInfos")) - 1); - - bytes32 private constant ENDPOINT_BITMAP_SLOT = - bytes32(uint256(keccak256("ntt.endpointBitmap")) - 1); - - bytes32 private constant ENABLED_ENDPOINTS_SLOT = - bytes32(uint256(keccak256("ntt.enabledEndpoints")) - 1); - - bytes32 private constant REGISTERED_ENDPOINTS_SLOT = - bytes32(uint256(keccak256("ntt.registeredEndpoints")) - 1); - - bytes32 private constant NUM_REGISTERED_ENDPOINTS_SLOT = - bytes32(uint256(keccak256("ntt.numRegisteredEndpoints")) - 1); - - function _getEndpointInfosStorage() - internal - pure - returns (mapping(address => EndpointInfo) storage $) - { - uint256 slot = uint256(ENDPOINT_INFOS_SLOT); - assembly ("memory-safe") { - $.slot := slot - } - } - - function _getEnabledEndpointsStorage() internal pure returns (address[] storage $) { - uint256 slot = uint256(ENABLED_ENDPOINTS_SLOT); - assembly ("memory-safe") { - $.slot := slot - } - } - - function _getEndpointBitmapStorage() private pure returns (_EnabledEndpointBitmap storage $) { - uint256 slot = uint256(ENDPOINT_BITMAP_SLOT); - assembly ("memory-safe") { - $.slot := slot - } - } - - function _getRegisteredEndpointsStorage() internal pure returns (address[] storage $) { - uint256 slot = uint256(REGISTERED_ENDPOINTS_SLOT); - assembly ("memory-safe") { - $.slot := slot - } - } - - function _getNumEndpointsStorage() internal pure returns (_NumEndpoints storage $) { - uint256 slot = uint256(NUM_REGISTERED_ENDPOINTS_SLOT); - assembly ("memory-safe") { - $.slot := slot - } - } - - /// =============== GETTERS/SETTERS ======================================== - - function _setEndpoint(address endpoint) internal returns (uint8 index) { - mapping(address => EndpointInfo) storage endpointInfos = _getEndpointInfosStorage(); - _EnabledEndpointBitmap storage _enabledEndpointBitmap = _getEndpointBitmapStorage(); - address[] storage _enabledEndpoints = _getEnabledEndpointsStorage(); - - _NumEndpoints storage _numEndpoints = _getNumEndpointsStorage(); - - if (endpoint == address(0)) { - revert InvalidEndpointZeroAddress(); - } - - if (_numEndpoints.registered >= MAX_ENDPOINTS) { - revert TooManyEndpoints(); - } - - if (endpointInfos[endpoint].registered) { - endpointInfos[endpoint].enabled = true; - } else { - endpointInfos[endpoint] = - EndpointInfo({registered: true, enabled: true, index: _numEndpoints.registered}); - _numEndpoints.registered++; - _getRegisteredEndpointsStorage().push(endpoint); - } - - _enabledEndpoints.push(endpoint); - _numEndpoints.enabled++; - - uint64 updatedEnabledEndpointBitmap = - _enabledEndpointBitmap.bitmap | uint64(1 << endpointInfos[endpoint].index); - // ensure that this actually changed the bitmap - if (updatedEnabledEndpointBitmap == _enabledEndpointBitmap.bitmap) { - revert EndpointAlreadyEnabled(endpoint); - } - _enabledEndpointBitmap.bitmap = updatedEnabledEndpointBitmap; - - emit EndpointAdded(endpoint); - - _checkEndpointsInvariants(); - - return endpointInfos[endpoint].index; - } - - function _removeEndpoint(address endpoint) internal { - mapping(address => EndpointInfo) storage endpointInfos = _getEndpointInfosStorage(); - _EnabledEndpointBitmap storage _enabledEndpointBitmap = _getEndpointBitmapStorage(); - address[] storage _enabledEndpoints = _getEnabledEndpointsStorage(); - - if (endpoint == address(0)) { - revert InvalidEndpointZeroAddress(); - } - - if (!endpointInfos[endpoint].registered) { - revert NonRegisteredEndpoint(endpoint); - } - - if (!endpointInfos[endpoint].enabled) { - revert DisabledEndpoint(endpoint); - } - - endpointInfos[endpoint].enabled = false; - _getNumEndpointsStorage().enabled--; - - uint64 updatedEnabledEndpointBitmap = - _enabledEndpointBitmap.bitmap & uint64(~(1 << endpointInfos[endpoint].index)); - // ensure that this actually changed the bitmap - assert(updatedEnabledEndpointBitmap < _enabledEndpointBitmap.bitmap); - _enabledEndpointBitmap.bitmap = updatedEnabledEndpointBitmap; - - bool removed = false; - - uint256 numEnabledEndpoints = _enabledEndpoints.length; - for (uint256 i = 0; i < numEnabledEndpoints; i++) { - if (_enabledEndpoints[i] == endpoint) { - _enabledEndpoints[i] = _enabledEndpoints[numEnabledEndpoints - 1]; - _enabledEndpoints.pop(); - removed = true; - break; - } - } - assert(removed); - - emit EndpointRemoved(endpoint); - - _checkEndpointsInvariants(); - // we call the invariant check on the endpoint here as well, since - // the above check only iterates through the enabled endpoints. - _checkEndpointInvariants(endpoint); - } - - function _getEnabledEndpointsBitmap() internal view virtual returns (uint64 bitmap) { - return _getEndpointBitmapStorage().bitmap; - } - - /// @notice Returns the Endpoint contracts that have been registered via governance. - function getEndpoints() external pure returns (address[] memory result) { - result = _getEnabledEndpointsStorage(); - } - - /// ============== INVARIANTS ============================================= - - /// @dev Check that the endpoint manager is in a valid state. - /// Checking these invariants is somewhat costly, but we only need to do it - /// when modifying the endpoints, which happens infrequently. - function _checkEndpointsInvariants() internal view { - _NumEndpoints storage _numEndpoints = _getNumEndpointsStorage(); - address[] storage _enabledEndpoints = _getEnabledEndpointsStorage(); - - uint256 numEndpointsEnabled = _numEndpoints.enabled; - assert(numEndpointsEnabled == _enabledEndpoints.length); - - for (uint256 i = 0; i < numEndpointsEnabled; i++) { - _checkEndpointInvariants(_enabledEndpoints[i]); - } - - // invariant: each endpoint is only enabled once - for (uint256 i = 0; i < numEndpointsEnabled; i++) { - for (uint256 j = i + 1; j < numEndpointsEnabled; j++) { - assert(_enabledEndpoints[i] != _enabledEndpoints[j]); - } - } - - // invariant: numRegisteredEndpoints <= MAX_ENDPOINTS - assert(_numEndpoints.registered <= MAX_ENDPOINTS); - } - - // @dev Check that the endpoint is in a valid state. - function _checkEndpointInvariants(address endpoint) private view { - mapping(address => EndpointInfo) storage endpointInfos = _getEndpointInfosStorage(); - _EnabledEndpointBitmap storage _enabledEndpointBitmap = _getEndpointBitmapStorage(); - _NumEndpoints storage _numEndpoints = _getNumEndpointsStorage(); - address[] storage _enabledEndpoints = _getEnabledEndpointsStorage(); - - EndpointInfo memory endpointInfo = endpointInfos[endpoint]; - - // if an endpoint is not registered, it should not be enabled - assert(endpointInfo.registered || (!endpointInfo.enabled && endpointInfo.index == 0)); - - bool endpointInEnabledBitmap = - (_enabledEndpointBitmap.bitmap & uint64(1 << endpointInfo.index)) != 0; - bool endpointEnabled = endpointInfo.enabled; - - bool endpointInEnabledEndpoints = false; - - for (uint256 i = 0; i < _numEndpoints.enabled; i++) { - if (_enabledEndpoints[i] == endpoint) { - endpointInEnabledEndpoints = true; - break; - } - } - - // invariant: endpointInfos[endpoint].enabled - // <=> enabledEndpointBitmap & (1 << endpointInfos[endpoint].index) != 0 - assert(endpointInEnabledBitmap == endpointEnabled); - - // invariant: endpointInfos[endpoint].enabled <=> endpoint in _enabledEndpoints - assert(endpointInEnabledEndpoints == endpointEnabled); - - assert(endpointInfo.index < _numEndpoints.registered); - } -} diff --git a/evm/src/Manager.sol b/evm/src/NttManager.sol similarity index 67% rename from evm/src/Manager.sol rename to evm/src/NttManager.sol index 64c8ab5f3..a17717f2d 100644 --- a/evm/src/Manager.sol +++ b/evm/src/NttManager.sol @@ -10,22 +10,22 @@ import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; import "./libraries/external/OwnableUpgradeable.sol"; import "./libraries/external/ReentrancyGuardUpgradeable.sol"; -import "./libraries/EndpointStructs.sol"; -import "./libraries/EndpointHelpers.sol"; +import "./libraries/TransceiverStructs.sol"; +import "./libraries/TransceiverHelpers.sol"; import "./libraries/RateLimiter.sol"; -import "./interfaces/IManager.sol"; -import "./interfaces/IManagerEvents.sol"; +import "./interfaces/INttManager.sol"; +import "./interfaces/INttManagerEvents.sol"; import "./interfaces/INTTToken.sol"; -import "./interfaces/IEndpoint.sol"; -import "./EndpointRegistry.sol"; +import "./interfaces/ITransceiver.sol"; +import "./TransceiverRegistry.sol"; import "./NttNormalizer.sol"; import "./libraries/PausableOwnable.sol"; import "./libraries/Implementation.sol"; -contract Manager is - IManager, - IManagerEvents, - EndpointRegistry, +contract NttManager is + INttManager, + INttManagerEvents, + TransceiverRegistry, RateLimiter, NttNormalizer, ReentrancyGuardUpgradeable, @@ -36,9 +36,9 @@ contract Manager is using SafeERC20 for IERC20; error RefundFailed(uint256 refundAmount); - error CannotRenounceManagerOwnership(address owner); + error CannotRenounceNttManagerOwnership(address owner); error UnexpectedOwner(address expectedOwner, address owner); - error EndpointAlreadyAttestedToMessage(bytes32 managerMessageHash); + error TransceiverAlreadyAttestedToMessage(bytes32 nttManagerMessageHash); address public immutable token; address immutable deployer; @@ -55,8 +55,8 @@ contract Manager is struct AttestationInfo { // whether this message has been executed bool executed; - // bitmap of endpoints that have attested to this message (NOTE: might contain disabled endpoints) - uint64 attestedEndpoints; + // bitmap of transceivers that have attested to this message (NOTE: might contain disabled transceivers) + uint64 attestedTransceivers; } struct _Sequence { @@ -75,7 +75,7 @@ contract Manager is bytes32 private constant MESSAGE_SEQUENCE_SLOT = bytes32(uint256(keccak256("ntt.messageSequence")) - 1); - bytes32 private constant SIBLINGS_SLOT = bytes32(uint256(keccak256("ntt.siblings")) - 1); + bytes32 private constant PEERS_SLOT = bytes32(uint256(keccak256("ntt.peers")) - 1); bytes32 private constant THRESHOLD_SLOT = bytes32(uint256(keccak256("ntt.threshold")) - 1); @@ -106,8 +106,8 @@ contract Manager is } } - function _getSiblingsStorage() internal pure returns (mapping(uint16 => bytes32) storage $) { - uint256 slot = uint256(SIBLINGS_SLOT); + function _getPeersStorage() internal pure returns (mapping(uint16 => bytes32) storage $) { + uint256 slot = uint256(PEERS_SLOT); assembly ("memory-safe") { $.slot := slot } @@ -131,47 +131,47 @@ contract Manager is return uint8(mode); } - /// @notice Returns the number of Endpoints that must attest to a msgId for + /// @notice Returns the number of Transceivers that must attest to a msgId for /// it to be considered valid and acted upon. function getThreshold() public view returns (uint8) { return _getThresholdStorage().num; } - function setEndpoint(address endpoint) external onlyOwner { - _setEndpoint(endpoint); + function setTransceiver(address transceiver) external onlyOwner { + _setTransceiver(transceiver); _Threshold storage _threshold = _getThresholdStorage(); // We do not automatically increase the threshold here. // Automatically increasing the threshold can result in a scenario // where in-flight messages can't be redeemed. - // For example: Assume there is 1 Endpoint and the threshold is 1. - // If we were to add a new Endpoint, the threshold would increase to 2. + // For example: Assume there is 1 Transceiver and the threshold is 1. + // If we were to add a new Transceiver, the threshold would increase to 2. // However, all messages that are either in-flight or that are sent on - // a source chain that does not yet have 2 Endpoints will only have been - // sent from a single endpoint, so they would never be able to get + // a source chain that does not yet have 2 Transceivers will only have been + // sent from a single transceiver, so they would never be able to get // redeemed. // Instead, we leave it up to the owner to manually update the threshold - // after some period of time, ideally once all chains have the new Endpoint + // after some period of time, ideally once all chains have the new Transceiver // and transfers that were sent via the old configuration are all complete. // However if the threshold is 0 (the initial case) we do increment to 1. if (_threshold.num == 0) { _threshold.num = 1; } - emit EndpointAdded(endpoint, _getNumEndpointsStorage().enabled, _threshold.num); + emit TransceiverAdded(transceiver, _getNumTransceiversStorage().enabled, _threshold.num); } - function removeEndpoint(address endpoint) external onlyOwner { - _removeEndpoint(endpoint); + function removeTransceiver(address transceiver) external onlyOwner { + _removeTransceiver(transceiver); _Threshold storage _threshold = _getThresholdStorage(); - uint8 numEnabledEndpoints = _getNumEndpointsStorage().enabled; + uint8 numEnabledTransceivers = _getNumTransceiversStorage().enabled; - if (numEnabledEndpoints < _threshold.num) { - _threshold.num = numEnabledEndpoints; + if (numEnabledTransceivers < _threshold.num) { + _threshold.num = numEnabledTransceivers; } - emit EndpointRemoved(endpoint, _threshold.num); + emit TransceiverRemoved(transceiver, _threshold.num); } constructor( @@ -188,7 +188,7 @@ contract Manager is deployer = msg.sender; } - function __Manager_init() internal onlyInitializing { + function __NttManager_init() internal onlyInitializing { // check if the owner is the deployer of this contract if (msg.sender != deployer) { revert UnexpectedOwner(deployer, msg.sender); @@ -198,14 +198,14 @@ contract Manager is } function _initialize() internal virtual override { - __Manager_init(); + __NttManager_init(); _checkThresholdInvariants(); - _checkEndpointsInvariants(); + _checkTransceiversInvariants(); } function _migrate() internal virtual override { _checkThresholdInvariants(); - _checkEndpointsInvariants(); + _checkTransceiversInvariants(); } /// =============== ADMIN =============================================== @@ -213,59 +213,59 @@ contract Manager is _upgrade(newImplementation); } - /// @dev Transfer ownership of the Manager contract and all Endpoint contracts to a new owner. + /// @dev Transfer ownership of the NttManager contract and all Transceiver contracts to a new owner. function transferOwnership(address newOwner) public override onlyOwner { super.transferOwnership(newOwner); - // loop through all the registered endpoints and set the new owner of each endpoint to the newOwner - address[] storage _registeredEndpoints = _getRegisteredEndpointsStorage(); - _checkRegisteredEndpointsInvariants(); + // loop through all the registered transceivers and set the new owner of each transceiver to the newOwner + address[] storage _registeredTransceivers = _getRegisteredTransceiversStorage(); + _checkRegisteredTransceiversInvariants(); - for (uint256 i = 0; i < _registeredEndpoints.length; i++) { - IEndpoint(_registeredEndpoints[i]).transferEndpointOwnership(newOwner); + for (uint256 i = 0; i < _registeredTransceivers.length; i++) { + ITransceiver(_registeredTransceivers[i]).transferTransceiverOwnership(newOwner); } } - /// @dev This method should return an array of delivery prices corresponding to each endpoint. + /// @dev This method should return an array of delivery prices corresponding to each transceiver. function quoteDeliveryPrice( uint16 recipientChain, - EndpointStructs.EndpointInstruction[] memory endpointInstructions, - address[] memory enabledEndpoints + TransceiverStructs.TransceiverInstruction[] memory transceiverInstructions, + address[] memory enabledTransceivers ) public view returns (uint256[] memory, uint256) { - uint256 numEnabledEndpoints = enabledEndpoints.length; - mapping(address => EndpointInfo) storage endpointInfos = _getEndpointInfosStorage(); + uint256 numEnabledTransceivers = enabledTransceivers.length; + mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage(); - uint256[] memory priceQuotes = new uint256[](numEnabledEndpoints); + uint256[] memory priceQuotes = new uint256[](numEnabledTransceivers); uint256 totalPriceQuote = 0; - for (uint256 i = 0; i < numEnabledEndpoints; i++) { - address endpointAddr = enabledEndpoints[i]; - uint8 registeredEndpointIndex = endpointInfos[endpointAddr].index; - uint256 endpointPriceQuote = IEndpoint(endpointAddr).quoteDeliveryPrice( - recipientChain, endpointInstructions[registeredEndpointIndex] + for (uint256 i = 0; i < numEnabledTransceivers; i++) { + address transceiverAddr = enabledTransceivers[i]; + uint8 registeredTransceiverIndex = transceiverInfos[transceiverAddr].index; + uint256 transceiverPriceQuote = ITransceiver(transceiverAddr).quoteDeliveryPrice( + recipientChain, transceiverInstructions[registeredTransceiverIndex] ); - priceQuotes[i] = endpointPriceQuote; - totalPriceQuote += endpointPriceQuote; + priceQuotes[i] = transceiverPriceQuote; + totalPriceQuote += transceiverPriceQuote; } return (priceQuotes, totalPriceQuote); } - function _sendMessageToEndpoints( + function _sendMessageToTransceivers( uint16 recipientChain, uint256[] memory priceQuotes, - EndpointStructs.EndpointInstruction[] memory endpointInstructions, - address[] memory enabledEndpoints, - bytes memory managerMessage + TransceiverStructs.TransceiverInstruction[] memory transceiverInstructions, + address[] memory enabledTransceivers, + bytes memory nttManagerMessage ) internal { - uint256 numEnabledEndpoints = enabledEndpoints.length; - mapping(address => EndpointInfo) storage endpointInfos = _getEndpointInfosStorage(); - // call into endpoint contracts to send the message - for (uint256 i = 0; i < numEnabledEndpoints; i++) { - address endpointAddr = enabledEndpoints[i]; - // send it to the recipient manager based on the chain - IEndpoint(endpointAddr).sendMessage{value: priceQuotes[i]}( + uint256 numEnabledTransceivers = enabledTransceivers.length; + mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage(); + // call into transceiver contracts to send the message + for (uint256 i = 0; i < numEnabledTransceivers; i++) { + address transceiverAddr = enabledTransceivers[i]; + // send it to the recipient nttManager based on the chain + ITransceiver(transceiverAddr).sendMessage{value: priceQuotes[i]}( recipientChain, - endpointInstructions[endpointInfos[endpointAddr].index], - managerMessage, - getSibling(recipientChain) + transceiverInstructions[transceiverInfos[transceiverAddr].index], + nttManagerMessage, + getPeer(recipientChain) ); } } @@ -275,30 +275,33 @@ contract Manager is return messageAttestations(digest) >= threshold && threshold > 0; } - function _setEndpointAttestedToMessage(bytes32 digest, uint8 index) internal { - _getMessageAttestationsStorage()[digest].attestedEndpoints |= uint64(1 << index); + function _setTransceiverAttestedToMessage(bytes32 digest, uint8 index) internal { + _getMessageAttestationsStorage()[digest].attestedTransceivers |= uint64(1 << index); } - function _setEndpointAttestedToMessage(bytes32 digest, address endpoint) internal { - _setEndpointAttestedToMessage(digest, _getEndpointInfosStorage()[endpoint].index); + function _setTransceiverAttestedToMessage(bytes32 digest, address transceiver) internal { + _setTransceiverAttestedToMessage(digest, _getTransceiverInfosStorage()[transceiver].index); - emit MessageAttestedTo(digest, endpoint, _getEndpointInfosStorage()[endpoint].index); + emit MessageAttestedTo( + digest, transceiver, _getTransceiverInfosStorage()[transceiver].index + ); } /* - * @dev pause the Endpoint. + * @dev pause the Transceiver. */ function pause() public onlyOwnerOrPauser { _pause(); } - /// @dev Returns the bitmap of attestations from enabled endpoints for a given message. + /// @dev Returns the bitmap of attestations from enabled transceivers for a given message. function _getMessageAttestations(bytes32 digest) internal view returns (uint64) { - uint64 enabledEndpointBitmap = _getEnabledEndpointsBitmap(); - return _getMessageAttestationsStorage()[digest].attestedEndpoints & enabledEndpointBitmap; + uint64 enabledTransceiverBitmap = _getEnabledTransceiversBitmap(); + return + _getMessageAttestationsStorage()[digest].attestedTransceivers & enabledTransceiverBitmap; } - function _getEnabledEndpointAttestedToMessage( + function _getEnabledTransceiverAttestedToMessage( bytes32 digest, uint8 index ) internal view returns (bool) { @@ -341,7 +344,7 @@ contract Manager is queuedTransfer.recipientChain, queuedTransfer.recipient, queuedTransfer.sender, - queuedTransfer.endpointInstructions + queuedTransfer.transceiverInstructions ); } @@ -375,7 +378,7 @@ contract Manager is return normalizedAmount; } - /// @dev Simple quality of life transfer method that doesn't deal with queuing or passing endpoint instructions. + /// @dev Simple quality of life transfer method that doesn't deal with queuing or passing transceiver instructions. function transfer( uint256 amount, uint16 recipientChain, @@ -386,16 +389,16 @@ contract Manager is /// @notice Called by the user to send the token cross-chain. /// This function will either lock or burn the sender's tokens. - /// Finally, this function will call into the Endpoint contracts to send a message with the incrementing sequence number and the token transfer payload. + /// Finally, this function will call into the Transceiver contracts to send a message with the incrementing sequence number and the token transfer payload. function transfer( uint256 amount, uint16 recipientChain, bytes32 recipient, bool shouldQueue, - bytes memory endpointInstructions + bytes memory transceiverInstructions ) external payable nonReentrant whenNotPaused returns (uint64) { return _transferEntryPoint( - amount, recipientChain, recipient, shouldQueue, endpointInstructions + amount, recipientChain, recipient, shouldQueue, transceiverInstructions ); } @@ -404,7 +407,7 @@ contract Manager is uint16 recipientChain, bytes32 recipient, bool shouldQueue, - bytes memory endpointInstructions + bytes memory transceiverInstructions ) internal returns (uint64) { if (amount == 0) { revert ZeroAmount(); @@ -488,7 +491,7 @@ contract Manager is recipientChain, recipient, msg.sender, - endpointInstructions + transceiverInstructions ); // refund price quote back to sender @@ -506,7 +509,12 @@ contract Manager is _backfillInboundAmount(normalizedAmount, recipientChain); return _transfer( - sequence, normalizedAmount, recipientChain, recipient, msg.sender, endpointInstructions + sequence, + normalizedAmount, + recipientChain, + recipient, + msg.sender, + transceiverInstructions ); } @@ -516,16 +524,16 @@ contract Manager is uint16 recipientChain, bytes32 recipient, address sender, - bytes memory endpointInstructions + bytes memory transceiverInstructions ) internal returns (uint64 msgSequence) { - // cache enabled endpoints to avoid multiple storage reads - address[] memory enabledEndpoints = _getEnabledEndpointsStorage(); + // cache enabled transceivers to avoid multiple storage reads + address[] memory enabledTransceivers = _getEnabledTransceiversStorage(); - EndpointStructs.EndpointInstruction[] memory instructions = - EndpointStructs.parseEndpointInstructions(endpointInstructions, enabledEndpoints.length); + TransceiverStructs.TransceiverInstruction[] memory instructions = TransceiverStructs + .parseTransceiverInstructions(transceiverInstructions, enabledTransceivers.length); (uint256[] memory priceQuotes, uint256 totalPriceQuote) = - quoteDeliveryPrice(recipientChain, instructions, enabledEndpoints); + quoteDeliveryPrice(recipientChain, instructions, enabledTransceivers); { // check up front that msg.value will cover the delivery price if (msg.value < totalPriceQuote) { @@ -542,20 +550,20 @@ contract Manager is // push it on the stack again to avoid a stack too deep error uint64 seq = sequence; - EndpointStructs.NativeTokenTransfer memory ntt = EndpointStructs.NativeTokenTransfer( + TransceiverStructs.NativeTokenTransfer memory ntt = TransceiverStructs.NativeTokenTransfer( amount, toWormholeFormat(token), recipient, recipientChain ); - // construct the ManagerMessage payload - bytes memory encodedManagerPayload = EndpointStructs.encodeManagerMessage( - EndpointStructs.ManagerMessage( - seq, toWormholeFormat(sender), EndpointStructs.encodeNativeTokenTransfer(ntt) + // construct the NttManagerMessage payload + bytes memory encodedNttManagerPayload = TransceiverStructs.encodeNttManagerMessage( + TransceiverStructs.NttManagerMessage( + seq, toWormholeFormat(sender), TransceiverStructs.encodeNativeTokenTransfer(ntt) ) ); // send the message - _sendMessageToEndpoints( - recipientChain, priceQuotes, instructions, enabledEndpoints, encodedManagerPayload + _sendMessageToTransceivers( + recipientChain, priceQuotes, instructions, enabledTransceivers, encodedNttManagerPayload ); emit TransferSent(recipient, _nttDenormalize(amount), recipientChain, seq); @@ -564,10 +572,10 @@ contract Manager is return sequence; } - /// @dev Verify that the sibling address saved for `sourceChainId` matches the `siblingAddress`. - function _verifySibling(uint16 sourceChainId, bytes32 siblingAddress) internal view { - if (getSibling(sourceChainId) != siblingAddress) { - revert InvalidSibling(sourceChainId, siblingAddress); + /// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`. + function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view { + if (getPeer(sourceChainId) != peerAddress) { + revert InvalidPeer(sourceChainId, peerAddress); } } @@ -586,16 +594,16 @@ contract Manager is } /// @dev Called after a message has been sufficiently verified to execute the command in the message. - /// This function will decode the payload as an ManagerMessage to extract the sequence, msgType, and other parameters. + /// This function will decode the payload as an NttManagerMessage to extract the sequence, msgType, and other parameters. function executeMsg( uint16 sourceChainId, - bytes32 sourceManagerAddress, - EndpointStructs.ManagerMessage memory message + bytes32 sourceNttManagerAddress, + TransceiverStructs.NttManagerMessage memory message ) public { // verify chain has not forked checkFork(evmChainId); - bytes32 digest = EndpointStructs.managerMessageDigest(sourceChainId, message); + bytes32 digest = TransceiverStructs.nttManagerMessageDigest(sourceChainId, message); if (!isMessageApproved(digest)) { revert MessageNotApproved(digest); @@ -603,15 +611,15 @@ contract Manager is bool msgAlreadyExecuted = _replayProtect(digest); if (msgAlreadyExecuted) { - // end execution early to mitigate the possibility of race conditions from endpoints - // attempting to deliver the same message when (threshold < number of endpoint messages) + // end execution early to mitigate the possibility of race conditions from transceivers + // attempting to deliver the same message when (threshold < number of transceiver messages) // notify client (off-chain process) so they don't attempt redundant msg delivery - emit MessageAlreadyExecuted(sourceManagerAddress, digest); + emit MessageAlreadyExecuted(sourceNttManagerAddress, digest); return; } - EndpointStructs.NativeTokenTransfer memory nativeTokenTransfer = - EndpointStructs.parseNativeTokenTransfer(message.payload); + TransceiverStructs.NativeTokenTransfer memory nativeTokenTransfer = + TransceiverStructs.parseNativeTokenTransfer(message.payload); // verify that the destination chain is valid if (nativeTokenTransfer.toChain != chainId) { @@ -706,64 +714,66 @@ contract Manager is return _getMessageAttestationsStorage()[digest].executed; } - function getSibling(uint16 chainId_) public view returns (bytes32) { - return _getSiblingsStorage()[chainId_]; + function getPeer(uint16 chainId_) public view returns (bytes32) { + return _getPeersStorage()[chainId_]; } - /// @notice this sets the corresponding sibling. - /// @dev The manager that executes the message sets the source manager as the sibling. - function setSibling(uint16 siblingChainId, bytes32 siblingContract) public onlyOwner { - if (siblingChainId == 0) { - revert InvalidSiblingChainIdZero(); + /// @notice this sets the corresponding peer. + /// @dev The nttManager that executes the message sets the source nttManager as the peer. + function setPeer(uint16 peerChainId, bytes32 peerContract) public onlyOwner { + if (peerChainId == 0) { + revert InvalidPeerChainIdZero(); } - if (siblingContract == bytes32(0)) { - revert InvalidSiblingZeroAddress(); + if (peerContract == bytes32(0)) { + revert InvalidPeerZeroAddress(); } - bytes32 oldSiblingContract = _getSiblingsStorage()[siblingChainId]; + bytes32 oldPeerContract = _getPeersStorage()[peerChainId]; - _getSiblingsStorage()[siblingChainId] = siblingContract; + _getPeersStorage()[peerChainId] = peerContract; - emit SiblingUpdated(siblingChainId, oldSiblingContract, siblingContract); + emit PeerUpdated(peerChainId, oldPeerContract, peerContract); } - function endpointAttestedToMessage(bytes32 digest, uint8 index) public view returns (bool) { - return _getMessageAttestationsStorage()[digest].attestedEndpoints & uint64(1 << index) == 1; + function transceiverAttestedToMessage(bytes32 digest, uint8 index) public view returns (bool) { + return + _getMessageAttestationsStorage()[digest].attestedTransceivers & uint64(1 << index) == 1; } function attestationReceived( uint16 sourceChainId, - bytes32 sourceManagerAddress, - EndpointStructs.ManagerMessage memory payload - ) external onlyEndpoint { - _verifySibling(sourceChainId, sourceManagerAddress); + bytes32 sourceNttManagerAddress, + TransceiverStructs.NttManagerMessage memory payload + ) external onlyTransceiver { + _verifyPeer(sourceChainId, sourceNttManagerAddress); - bytes32 managerMessageHash = EndpointStructs.managerMessageDigest(sourceChainId, payload); + bytes32 nttManagerMessageHash = + TransceiverStructs.nttManagerMessageDigest(sourceChainId, payload); - // set the attested flag for this endpoint. + // set the attested flag for this transceiver. // NOTE: Attestation is idempotent (bitwise or 1), but we revert // anyway to ensure that the client does not continue to initiate calls - // to receive the same message through the same endpoint. + // to receive the same message through the same transceiver. if ( - endpointAttestedToMessage( - managerMessageHash, _getEndpointInfosStorage()[msg.sender].index + transceiverAttestedToMessage( + nttManagerMessageHash, _getTransceiverInfosStorage()[msg.sender].index ) ) { - revert EndpointAlreadyAttestedToMessage(managerMessageHash); + revert TransceiverAlreadyAttestedToMessage(nttManagerMessageHash); } - _setEndpointAttestedToMessage(managerMessageHash, msg.sender); + _setTransceiverAttestedToMessage(nttManagerMessageHash, msg.sender); - if (isMessageApproved(managerMessageHash)) { - executeMsg(sourceChainId, sourceManagerAddress, payload); + if (isMessageApproved(nttManagerMessageHash)) { + executeMsg(sourceChainId, sourceNttManagerAddress, payload); } } - // @dev Count the number of attestations from enabled endpoints for a given message. + // @dev Count the number of attestations from enabled transceivers for a given message. function messageAttestations(bytes32 digest) public view returns (uint8 count) { return countSetBits(_getMessageAttestations(digest)); } - function tokenDecimals() public view override(IManager, RateLimiter) returns (uint8) { + function tokenDecimals() public view override(INttManager, RateLimiter) returns (uint8) { return tokenDecimals_; } @@ -777,24 +787,24 @@ contract Manager is assert(this.rateLimitDuration() == rateLimitDuration); } - function _checkRegisteredEndpointsInvariants() internal view { - if (_getRegisteredEndpointsStorage().length != _getNumEndpointsStorage().registered) { - revert RetrievedIncorrectRegisteredEndpoints( - _getRegisteredEndpointsStorage().length, _getNumEndpointsStorage().registered + function _checkRegisteredTransceiversInvariants() internal view { + if (_getRegisteredTransceiversStorage().length != _getNumTransceiversStorage().registered) { + revert RetrievedIncorrectRegisteredTransceivers( + _getRegisteredTransceiversStorage().length, _getNumTransceiversStorage().registered ); } } function _checkThresholdInvariants() internal view { uint8 threshold = _getThresholdStorage().num; - _NumEndpoints memory numEndpoints = _getNumEndpointsStorage(); + _NumTransceivers memory numTransceivers = _getNumTransceiversStorage(); - // invariant: threshold <= enabledEndpoints.length - if (threshold > numEndpoints.enabled) { - revert ThresholdTooHigh(threshold, numEndpoints.enabled); + // invariant: threshold <= enabledTransceivers.length + if (threshold > numTransceivers.enabled) { + revert ThresholdTooHigh(threshold, numTransceivers.enabled); } - if (numEndpoints.registered > 0) { + if (numTransceivers.registered > 0) { if (threshold == 0) { revert ZeroThreshold(); } diff --git a/evm/src/Transceiver.sol b/evm/src/Transceiver.sol new file mode 100644 index 000000000..79706bd1b --- /dev/null +++ b/evm/src/Transceiver.sol @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +import "./libraries/TransceiverStructs.sol"; +import "./libraries/PausableOwnable.sol"; +import "./interfaces/INttManager.sol"; +import "./interfaces/ITransceiver.sol"; +import "./libraries/external/ReentrancyGuardUpgradeable.sol"; +import "./libraries/Implementation.sol"; +import "wormhole-solidity-sdk/Utils.sol"; + +abstract contract Transceiver is + ITransceiver, + PausableOwnable, + ReentrancyGuardUpgradeable, + Implementation +{ + /// @dev updating bridgeNttManager requires a new Transceiver deployment. + /// Projects should implement their own governance to remove the old Transceiver contract address and then add the new one. + address public immutable nttManager; + address public immutable nttManagerToken; + + constructor(address _nttManager) { + nttManager = _nttManager; + nttManagerToken = INttManager(nttManager).token(); + } + + /// =============== MODIFIERS =============================================== + + modifier onlyNttManager() { + if (msg.sender != nttManager) { + revert CallerNotNttManager(msg.sender); + } + _; + } + + /// =============== ADMIN =============================================== + + function _initialize() internal virtual override { + __ReentrancyGuard_init(); + // owner of the transceiver is set to the owner of the nttManager + __PausedOwnable_init(msg.sender, getNttManagerOwner()); + } + + /// @dev transfer the ownership of the transceiver to a new address + /// the nttManager should be able to update transceiver ownership. + function transferTransceiverOwnership(address newOwner) external onlyNttManager { + _transferOwnership(newOwner); + } + + /// @dev pause the transceiver. + function _pauseTransceiver() internal { + _pause(); + } + + function upgrade(address newImplementation) external onlyOwner { + _upgrade(newImplementation); + } + + function _migrate() internal virtual override {} + + /// @dev This method checks that the the referecnes to the nttManager and its corresponding function are correct + /// When new immutable variables are added, this function should be updated. + function _checkImmutables() internal view override { + assert(this.nttManager() == nttManager); + assert(this.nttManagerToken() == nttManagerToken); + } + + /// =============== GETTERS & SETTERS =============================================== + + function getNttManagerOwner() public view returns (address) { + return IOwnableUpgradeable(nttManager).owner(); + } + + function getNttManagerToken() public view virtual returns (address) { + return nttManagerToken; + } + + /// =============== TRANSCEIVING LOGIC =============================================== + /** + * @dev send a message to another chain. + * @param recipientChain The chain id of the recipient. + * @param instruction An additional Instruction provided by the Transceiver to be + * executed on the recipient chain. + * @param nttManagerMessage A message to be sent to the nttManager on the recipient chain. + */ + function sendMessage( + uint16 recipientChain, + TransceiverStructs.TransceiverInstruction memory instruction, + bytes memory nttManagerMessage, + bytes32 recipientNttManagerAddress + ) external payable nonReentrant onlyNttManager { + _sendMessage( + recipientChain, + msg.value, + msg.sender, + recipientNttManagerAddress, + instruction, + nttManagerMessage + ); + } + + function _sendMessage( + uint16 recipientChain, + uint256 deliveryPayment, + address caller, + bytes32 recipientNttManagerAddress, + TransceiverStructs.TransceiverInstruction memory transceiverInstruction, + bytes memory nttManagerMessage + ) internal virtual; + + // @dev This method is called by the BridgeNttManager contract to send a cross-chain message. + // Forwards the VAA payload to the transceiver nttManager contract. + // @param sourceChainId The chain id of the sender. + // @param sourceNttManagerAddress The address of the sender's nttManager contract. + // @param payload The VAA payload. + function _deliverToNttManager( + uint16 sourceChainId, + bytes32 sourceNttManagerAddress, + bytes32 recipientNttManagerAddress, + TransceiverStructs.NttManagerMessage memory payload + ) internal virtual { + if (recipientNttManagerAddress != toWormholeFormat(nttManager)) { + revert UnexpectedRecipientNttManagerAddress( + toWormholeFormat(nttManager), recipientNttManagerAddress + ); + } + INttManager(nttManager).attestationReceived(sourceChainId, sourceNttManagerAddress, payload); + } + + function quoteDeliveryPrice( + uint16 targetChain, + TransceiverStructs.TransceiverInstruction memory instruction + ) external view returns (uint256) { + return _quoteDeliveryPrice(targetChain, instruction); + } + + function _quoteDeliveryPrice( + uint16 targetChain, + TransceiverStructs.TransceiverInstruction memory transceiverInstruction + ) internal view virtual returns (uint256); +} diff --git a/evm/src/TransceiverRegistry.sol b/evm/src/TransceiverRegistry.sol new file mode 100644 index 000000000..e7e35e56b --- /dev/null +++ b/evm/src/TransceiverRegistry.sol @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +/// @dev This contract is responsible for handling the registration of Transceivers. +abstract contract TransceiverRegistry { + constructor() { + _checkTransceiversInvariants(); + } + + /// @dev Information about registered transceivers. + struct TransceiverInfo { + // whether this transceiver is registered + bool registered; + // whether this transceiver is enabled + bool enabled; + uint8 index; + } + + /// @dev Bitmap encoding the enabled transceivers. + /// invariant: forall (i: uint8), enabledTransceiverBitmap & i == 1 <=> transceiverInfos[i].enabled + struct _EnabledTransceiverBitmap { + uint64 bitmap; + } + + /// @dev Total number of registered transceivers. This number can only increase. + /// invariant: numRegisteredTransceivers <= MAX_TRANSCEIVERS + /// invariant: forall (i: uint8), + /// i < numRegisteredTransceivers <=> exists (a: address), transceiverInfos[a].index == i + struct _NumTransceivers { + uint8 registered; + uint8 enabled; + } + + uint8 constant MAX_TRANSCEIVERS = 64; + + error CallerNotTransceiver(address caller); + error InvalidTransceiverZeroAddress(); + error DisabledTransceiver(address transceiver); + error TooManyTransceivers(); + error NonRegisteredTransceiver(address transceiver); + error TransceiverAlreadyEnabled(address transceiver); + + event TransceiverAdded(address transceiver); + event TransceiverRemoved(address transceiver); + + modifier onlyTransceiver() { + if (!_getTransceiverInfosStorage()[msg.sender].enabled) { + revert CallerNotTransceiver(msg.sender); + } + _; + } + + /// =============== STORAGE =============================================== + + bytes32 private constant TRANSCEIVER_INFOS_SLOT = + bytes32(uint256(keccak256("ntt.transceiverInfos")) - 1); + + bytes32 private constant TRANSCEIVER_BITMAP_SLOT = + bytes32(uint256(keccak256("ntt.transceiverBitmap")) - 1); + + bytes32 private constant ENABLED_TRANSCEIVERS_SLOT = + bytes32(uint256(keccak256("ntt.enabledTransceivers")) - 1); + + bytes32 private constant REGISTERED_TRANSCEIVERS_SLOT = + bytes32(uint256(keccak256("ntt.registeredTransceivers")) - 1); + + bytes32 private constant NUM_REGISTERED_TRANSCEIVERS_SLOT = + bytes32(uint256(keccak256("ntt.numRegisteredTransceivers")) - 1); + + function _getTransceiverInfosStorage() + internal + pure + returns (mapping(address => TransceiverInfo) storage $) + { + uint256 slot = uint256(TRANSCEIVER_INFOS_SLOT); + assembly ("memory-safe") { + $.slot := slot + } + } + + function _getEnabledTransceiversStorage() internal pure returns (address[] storage $) { + uint256 slot = uint256(ENABLED_TRANSCEIVERS_SLOT); + assembly ("memory-safe") { + $.slot := slot + } + } + + function _getTransceiverBitmapStorage() + private + pure + returns (_EnabledTransceiverBitmap storage $) + { + uint256 slot = uint256(TRANSCEIVER_BITMAP_SLOT); + assembly ("memory-safe") { + $.slot := slot + } + } + + function _getRegisteredTransceiversStorage() internal pure returns (address[] storage $) { + uint256 slot = uint256(REGISTERED_TRANSCEIVERS_SLOT); + assembly ("memory-safe") { + $.slot := slot + } + } + + function _getNumTransceiversStorage() internal pure returns (_NumTransceivers storage $) { + uint256 slot = uint256(NUM_REGISTERED_TRANSCEIVERS_SLOT); + assembly ("memory-safe") { + $.slot := slot + } + } + + /// =============== GETTERS/SETTERS ======================================== + + function _setTransceiver(address transceiver) internal returns (uint8 index) { + mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage(); + _EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage(); + address[] storage _enabledTransceivers = _getEnabledTransceiversStorage(); + + _NumTransceivers storage _numTransceivers = _getNumTransceiversStorage(); + + if (transceiver == address(0)) { + revert InvalidTransceiverZeroAddress(); + } + + if (_numTransceivers.registered >= MAX_TRANSCEIVERS) { + revert TooManyTransceivers(); + } + + if (transceiverInfos[transceiver].registered) { + transceiverInfos[transceiver].enabled = true; + } else { + transceiverInfos[transceiver] = TransceiverInfo({ + registered: true, + enabled: true, + index: _numTransceivers.registered + }); + _numTransceivers.registered++; + _getRegisteredTransceiversStorage().push(transceiver); + } + + _enabledTransceivers.push(transceiver); + _numTransceivers.enabled++; + + uint64 updatedEnabledTransceiverBitmap = + _enabledTransceiverBitmap.bitmap | uint64(1 << transceiverInfos[transceiver].index); + // ensure that this actually changed the bitmap + if (updatedEnabledTransceiverBitmap == _enabledTransceiverBitmap.bitmap) { + revert TransceiverAlreadyEnabled(transceiver); + } + _enabledTransceiverBitmap.bitmap = updatedEnabledTransceiverBitmap; + + emit TransceiverAdded(transceiver); + + _checkTransceiversInvariants(); + + return transceiverInfos[transceiver].index; + } + + function _removeTransceiver(address transceiver) internal { + mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage(); + _EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage(); + address[] storage _enabledTransceivers = _getEnabledTransceiversStorage(); + + if (transceiver == address(0)) { + revert InvalidTransceiverZeroAddress(); + } + + if (!transceiverInfos[transceiver].registered) { + revert NonRegisteredTransceiver(transceiver); + } + + if (!transceiverInfos[transceiver].enabled) { + revert DisabledTransceiver(transceiver); + } + + transceiverInfos[transceiver].enabled = false; + _getNumTransceiversStorage().enabled--; + + uint64 updatedEnabledTransceiverBitmap = + _enabledTransceiverBitmap.bitmap & uint64(~(1 << transceiverInfos[transceiver].index)); + // ensure that this actually changed the bitmap + assert(updatedEnabledTransceiverBitmap < _enabledTransceiverBitmap.bitmap); + _enabledTransceiverBitmap.bitmap = updatedEnabledTransceiverBitmap; + + bool removed = false; + + uint256 numEnabledTransceivers = _enabledTransceivers.length; + for (uint256 i = 0; i < numEnabledTransceivers; i++) { + if (_enabledTransceivers[i] == transceiver) { + _enabledTransceivers[i] = _enabledTransceivers[numEnabledTransceivers - 1]; + _enabledTransceivers.pop(); + removed = true; + break; + } + } + assert(removed); + + emit TransceiverRemoved(transceiver); + + _checkTransceiversInvariants(); + // we call the invariant check on the transceiver here as well, since + // the above check only iterates through the enabled transceivers. + _checkTransceiverInvariants(transceiver); + } + + function _getEnabledTransceiversBitmap() internal view virtual returns (uint64 bitmap) { + return _getTransceiverBitmapStorage().bitmap; + } + + /// @notice Returns the Transceiver contracts that have been registered via governance. + function getTransceivers() external pure returns (address[] memory result) { + result = _getEnabledTransceiversStorage(); + } + + /// ============== INVARIANTS ============================================= + + /// @dev Check that the transceiver nttManager is in a valid state. + /// Checking these invariants is somewhat costly, but we only need to do it + /// when modifying the transceivers, which happens infrequently. + function _checkTransceiversInvariants() internal view { + _NumTransceivers storage _numTransceivers = _getNumTransceiversStorage(); + address[] storage _enabledTransceivers = _getEnabledTransceiversStorage(); + + uint256 numTransceiversEnabled = _numTransceivers.enabled; + assert(numTransceiversEnabled == _enabledTransceivers.length); + + for (uint256 i = 0; i < numTransceiversEnabled; i++) { + _checkTransceiverInvariants(_enabledTransceivers[i]); + } + + // invariant: each transceiver is only enabled once + for (uint256 i = 0; i < numTransceiversEnabled; i++) { + for (uint256 j = i + 1; j < numTransceiversEnabled; j++) { + assert(_enabledTransceivers[i] != _enabledTransceivers[j]); + } + } + + // invariant: numRegisteredTransceivers <= MAX_TRANSCEIVERS + assert(_numTransceivers.registered <= MAX_TRANSCEIVERS); + } + + // @dev Check that the transceiver is in a valid state. + function _checkTransceiverInvariants(address transceiver) private view { + mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage(); + _EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage(); + _NumTransceivers storage _numTransceivers = _getNumTransceiversStorage(); + address[] storage _enabledTransceivers = _getEnabledTransceiversStorage(); + + TransceiverInfo memory transceiverInfo = transceiverInfos[transceiver]; + + // if an transceiver is not registered, it should not be enabled + assert( + transceiverInfo.registered || (!transceiverInfo.enabled && transceiverInfo.index == 0) + ); + + bool transceiverInEnabledBitmap = + (_enabledTransceiverBitmap.bitmap & uint64(1 << transceiverInfo.index)) != 0; + bool transceiverEnabled = transceiverInfo.enabled; + + bool transceiverInEnabledTransceivers = false; + + for (uint256 i = 0; i < _numTransceivers.enabled; i++) { + if (_enabledTransceivers[i] == transceiver) { + transceiverInEnabledTransceivers = true; + break; + } + } + + // invariant: transceiverInfos[transceiver].enabled + // <=> enabledTransceiverBitmap & (1 << transceiverInfos[transceiver].index) != 0 + assert(transceiverInEnabledBitmap == transceiverEnabled); + + // invariant: transceiverInfos[transceiver].enabled <=> transceiver in _enabledTransceivers + assert(transceiverInEnabledTransceivers == transceiverEnabled); + + assert(transceiverInfo.index < _numTransceivers.registered); + } +} diff --git a/evm/src/WormholeEndpoint.sol b/evm/src/WormholeTransceiver.sol similarity index 57% rename from evm/src/WormholeEndpoint.sol rename to evm/src/WormholeTransceiver.sol index 4660e7933..0e18d692f 100644 --- a/evm/src/WormholeEndpoint.sol +++ b/evm/src/WormholeTransceiver.sol @@ -5,58 +5,58 @@ import "wormhole-solidity-sdk/WormholeRelayerSDK.sol"; import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; -import "./libraries/EndpointHelpers.sol"; -import "./libraries/EndpointStructs.sol"; -import "./interfaces/IWormholeEndpoint.sol"; +import "./libraries/TransceiverHelpers.sol"; +import "./libraries/TransceiverStructs.sol"; +import "./interfaces/IWormholeTransceiver.sol"; import "./interfaces/ISpecialRelayer.sol"; -import "./interfaces/IManager.sol"; -import "./Endpoint.sol"; +import "./interfaces/INttManager.sol"; +import "./Transceiver.sol"; -contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { +contract WormholeTransceiver is Transceiver, IWormholeTransceiver, IWormholeReceiver { using BytesParsing for bytes; uint256 public constant GAS_LIMIT = 500000; uint8 public immutable consistencyLevel; - /// @dev Prefix for all EndpointMessage payloads + /// @dev Prefix for all TransceiverMessage payloads /// This is 0x99'E''W''H' - /// @notice Magic string (constant value set by messaging provider) that idenfies the payload as an endpoint-emitted payload. - /// Note that this is not a security critical field. It's meant to be used by messaging providers to identify which messages are Endpoint-related. - bytes4 constant WH_ENDPOINT_PAYLOAD_PREFIX = 0x9945FF10; + /// @notice Magic string (constant value set by messaging provider) that idenfies the payload as an transceiver-emitted payload. + /// Note that this is not a security critical field. It's meant to be used by messaging providers to identify which messages are Transceiver-related. + bytes4 constant WH_TRANSCEIVER_PAYLOAD_PREFIX = 0x9945FF10; - /// @dev Prefix for all Wormhole endpoint initialisation payloads - /// This is bytes4(keccak256("WormholeEndpointInit")) - bytes4 constant WH_ENDPOINT_INIT_PREFIX = 0xc83e3d2e; + /// @dev Prefix for all Wormhole transceiver initialisation payloads + /// This is bytes4(keccak256("WormholeTransceiverInit")) + bytes4 constant WH_TRANSCEIVER_INIT_PREFIX = 0x9c23bd3b; - /// @dev Prefix for all Wormhole sibling registration payloads - /// This is bytes4(keccak256("WormholeSiblingRegistration")) - bytes4 constant WH_SIBLING_REGISTRATION_PREFIX = 0xd0d292f1; + /// @dev Prefix for all Wormhole peer registration payloads + /// This is bytes4(keccak256("WormholePeerRegistration")) + bytes4 constant WH_PEER_REGISTRATION_PREFIX = 0x18fc67c2; IWormhole public immutable wormhole; IWormholeRelayer public immutable wormholeRelayer; ISpecialRelayer public immutable specialRelayer; - uint256 public immutable wormholeEndpoint_evmChainId; + uint256 public immutable wormholeTransceiver_evmChainId; - struct WormholeEndpointInstruction { + struct WormholeTransceiverInstruction { bool shouldSkipRelayerSend; } /// =============== STORAGE =============================================== bytes32 private constant WORMHOLE_CONSUMED_VAAS_SLOT = - bytes32(uint256(keccak256("whEndpoint.consumedVAAs")) - 1); + bytes32(uint256(keccak256("whTransceiver.consumedVAAs")) - 1); - bytes32 private constant WORMHOLE_SIBLINGS_SLOT = - bytes32(uint256(keccak256("whEndpoint.siblings")) - 1); + bytes32 private constant WORMHOLE_PEERS_SLOT = + bytes32(uint256(keccak256("whTransceiver.peers")) - 1); bytes32 private constant WORMHOLE_RELAYING_ENABLED_CHAINS_SLOT = - bytes32(uint256(keccak256("whEndpoint.relayingEnabledChains")) - 1); + bytes32(uint256(keccak256("whTransceiver.relayingEnabledChains")) - 1); bytes32 private constant SPECIAL_RELAYING_ENABLED_CHAINS_SLOT = - bytes32(uint256(keccak256("whEndpoint.specialRelayingEnabledChains")) - 1); + bytes32(uint256(keccak256("whTransceiver.specialRelayingEnabledChains")) - 1); bytes32 private constant WORMHOLE_EVM_CHAIN_IDS = - bytes32(uint256(keccak256("whEndpoint.evmChainIds")) - 1); + bytes32(uint256(keccak256("whTransceiver.evmChainIds")) - 1); /// =============== GETTERS/SETTERS ======================================== @@ -71,12 +71,12 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { } } - function _getWormholeSiblingsStorage() + function _getWormholePeersStorage() internal pure returns (mapping(uint16 => bytes32) storage $) { - uint256 slot = uint256(WORMHOLE_SIBLINGS_SLOT); + uint256 slot = uint256(WORMHOLE_PEERS_SLOT); assembly ("memory-safe") { $.slot := slot } @@ -123,33 +123,33 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { } constructor( - address manager, + address nttManager, address wormholeCoreBridge, address wormholeRelayerAddr, address specialRelayerAddr, uint8 _consistencyLevel - ) Endpoint(manager) { + ) Transceiver(nttManager) { wormhole = IWormhole(wormholeCoreBridge); wormholeRelayer = IWormholeRelayer(wormholeRelayerAddr); specialRelayer = ISpecialRelayer(specialRelayerAddr); - wormholeEndpoint_evmChainId = block.chainid; + wormholeTransceiver_evmChainId = block.chainid; consistencyLevel = _consistencyLevel; } function _initialize() internal override { super._initialize(); - _initializeEndpoint(); + _initializeTransceiver(); } - function _initializeEndpoint() internal { - EndpointStructs.EndpointInit memory init = EndpointStructs.EndpointInit({ - endpointIdentifier: WH_ENDPOINT_INIT_PREFIX, - managerAddress: toWormholeFormat(manager), - managerMode: IManager(manager).getMode(), - tokenAddress: toWormholeFormat(managerToken), - tokenDecimals: IManager(manager).tokenDecimals() + function _initializeTransceiver() internal { + TransceiverStructs.TransceiverInit memory init = TransceiverStructs.TransceiverInit({ + transceiverIdentifier: WH_TRANSCEIVER_INIT_PREFIX, + nttManagerAddress: toWormholeFormat(nttManager), + nttManagerMode: INttManager(nttManager).getMode(), + tokenAddress: toWormholeFormat(nttManagerToken), + tokenDecimals: INttManager(nttManager).tokenDecimals() }); - wormhole.publishMessage(0, EndpointStructs.encodeEndpointInit(init), consistencyLevel); + wormhole.publishMessage(0, TransceiverStructs.encodeTransceiverInit(init), consistencyLevel); } function _checkInvalidRelayingConfig(uint16 chainId) internal view returns (bool) { @@ -162,11 +162,11 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { function _quoteDeliveryPrice( uint16 targetChain, - EndpointStructs.EndpointInstruction memory instruction + TransceiverStructs.TransceiverInstruction memory instruction ) internal view override returns (uint256 nativePriceQuote) { // Check the special instruction up front to see if we should skip sending via a relayer - WormholeEndpointInstruction memory weIns = - parseWormholeEndpointInstruction(instruction.payload); + WormholeTransceiverInstruction memory weIns = + parseWormholeTransceiverInstruction(instruction.payload); if (weIns.shouldSkipRelayerSend) { return 0; } @@ -179,7 +179,7 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { (uint256 cost,) = wormholeRelayer.quoteEVMDeliveryPrice(targetChain, 0, GAS_LIMIT); return cost; } else if (isSpecialRelayingEnabled(targetChain)) { - uint256 cost = specialRelayer.quoteDeliveryPrice(getManagerToken(), targetChain, 0); + uint256 cost = specialRelayer.quoteDeliveryPrice(getNttManagerToken(), targetChain, 0); return cost; } else { return 0; @@ -190,42 +190,43 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { uint16 recipientChain, uint256 deliveryPayment, address caller, - bytes32 recipientManagerAddress, - EndpointStructs.EndpointInstruction memory instruction, - bytes memory managerMessage + bytes32 recipientNttManagerAddress, + TransceiverStructs.TransceiverInstruction memory instruction, + bytes memory nttManagerMessage ) internal override { ( - EndpointStructs.EndpointMessage memory endpointMessage, - bytes memory encodedEndpointPayload - ) = EndpointStructs.buildAndEncodeEndpointMessage( - WH_ENDPOINT_PAYLOAD_PREFIX, + TransceiverStructs.TransceiverMessage memory transceiverMessage, + bytes memory encodedTransceiverPayload + ) = TransceiverStructs.buildAndEncodeTransceiverMessage( + WH_TRANSCEIVER_PAYLOAD_PREFIX, toWormholeFormat(caller), - recipientManagerAddress, - managerMessage, + recipientNttManagerAddress, + nttManagerMessage, new bytes(0) ); - WormholeEndpointInstruction memory weIns = - parseWormholeEndpointInstruction(instruction.payload); + WormholeTransceiverInstruction memory weIns = + parseWormholeTransceiverInstruction(instruction.payload); if (!weIns.shouldSkipRelayerSend && _shouldRelayViaStandardRelaying(recipientChain)) { wormholeRelayer.sendPayloadToEvm{value: deliveryPayment}( recipientChain, - fromWormholeFormat(getWormholeSibling(recipientChain)), - encodedEndpointPayload, + fromWormholeFormat(getWormholePeer(recipientChain)), + encodedTransceiverPayload, 0, GAS_LIMIT ); } else if (!weIns.shouldSkipRelayerSend && isSpecialRelayingEnabled(recipientChain)) { - uint64 sequence = wormhole.publishMessage(0, encodedEndpointPayload, consistencyLevel); + uint64 sequence = + wormhole.publishMessage(0, encodedTransceiverPayload, consistencyLevel); specialRelayer.requestDelivery{value: deliveryPayment}( - getManagerToken(), recipientChain, 0, sequence + getNttManagerToken(), recipientChain, 0, sequence ); } else { - wormhole.publishMessage(0, encodedEndpointPayload, consistencyLevel); + wormhole.publishMessage(0, encodedTransceiverPayload, consistencyLevel); } - emit SendEndpointMessage(recipientChain, endpointMessage); + emit SendTransceiverMessage(recipientChain, transceiverMessage); } function receiveWormholeMessages( @@ -235,12 +236,12 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { uint16 sourceChain, bytes32 deliveryHash ) external payable onlyRelayer { - if (getWormholeSibling(sourceChain) != sourceAddress) { - revert InvalidWormholeSibling(sourceChain, sourceAddress); + if (getWormholePeer(sourceChain) != sourceAddress) { + revert InvalidWormholePeer(sourceChain, sourceAddress); } // VAA replay protection - // Note that this VAA is for the AR delivery, not for the raw message emitted by the source chain Endpoint contract. + // Note that this VAA is for the AR delivery, not for the raw message emitted by the source chain Transceiver contract. // The VAAs received by this entrypoint are different than the VAA received by the receiveMessage entrypoint. if (isVAAConsumed(deliveryHash)) { revert TransferAlreadyCompleted(deliveryHash); @@ -255,38 +256,38 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { // emit `ReceivedRelayedMessage` event emit ReceivedRelayedMessage(deliveryHash, sourceChain, sourceAddress); - // parse the encoded Endpoint payload - EndpointStructs.EndpointMessage memory parsedEndpointMessage; - EndpointStructs.ManagerMessage memory parsedManagerMessage; - (parsedEndpointMessage, parsedManagerMessage) = - EndpointStructs.parseEndpointAndManagerMessage(WH_ENDPOINT_PAYLOAD_PREFIX, payload); + // parse the encoded Transceiver payload + TransceiverStructs.TransceiverMessage memory parsedTransceiverMessage; + TransceiverStructs.NttManagerMessage memory parsedNttManagerMessage; + (parsedTransceiverMessage, parsedNttManagerMessage) = TransceiverStructs + .parseTransceiverAndNttManagerMessage(WH_TRANSCEIVER_PAYLOAD_PREFIX, payload); - _deliverToManager( + _deliverToNttManager( sourceChain, - parsedEndpointMessage.sourceManagerAddress, - parsedEndpointMessage.recipientManagerAddress, - parsedManagerMessage + parsedTransceiverMessage.sourceNttManagerAddress, + parsedTransceiverMessage.recipientNttManagerAddress, + parsedNttManagerMessage ); } /// @notice Receive an attested message from the verification layer - /// This function should verify the encodedVm and then deliver the attestation to the endpoint manager contract. + /// This function should verify the encodedVm and then deliver the attestation to the transceiver nttManager contract. function receiveMessage(bytes memory encodedMessage) external { uint16 sourceChainId; bytes memory payload; (sourceChainId, payload) = _verifyMessage(encodedMessage); - // parse the encoded Endpoint payload - EndpointStructs.EndpointMessage memory parsedEndpointMessage; - EndpointStructs.ManagerMessage memory parsedManagerMessage; - (parsedEndpointMessage, parsedManagerMessage) = - EndpointStructs.parseEndpointAndManagerMessage(WH_ENDPOINT_PAYLOAD_PREFIX, payload); + // parse the encoded Transceiver payload + TransceiverStructs.TransceiverMessage memory parsedTransceiverMessage; + TransceiverStructs.NttManagerMessage memory parsedNttManagerMessage; + (parsedTransceiverMessage, parsedNttManagerMessage) = TransceiverStructs + .parseTransceiverAndNttManagerMessage(WH_TRANSCEIVER_PAYLOAD_PREFIX, payload); - _deliverToManager( + _deliverToNttManager( sourceChainId, - parsedEndpointMessage.sourceManagerAddress, - parsedEndpointMessage.recipientManagerAddress, - parsedManagerMessage + parsedTransceiverMessage.sourceNttManagerAddress, + parsedTransceiverMessage.recipientNttManagerAddress, + parsedNttManagerMessage ); } @@ -300,9 +301,9 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { revert InvalidVaa(reason); } - // ensure that the message came from a registered sibling contract + // ensure that the message came from a registered peer contract if (!_verifyBridgeVM(vm)) { - revert InvalidWormholeSibling(vm.emitterChainId, vm.emitterAddress); + revert InvalidWormholePeer(vm.emitterChainId, vm.emitterAddress); } // save the VAA hash in storage to protect against replay attacks. @@ -318,8 +319,8 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { } function _verifyBridgeVM(IWormhole.VM memory vm) internal view returns (bool) { - checkFork(wormholeEndpoint_evmChainId); - return getWormholeSibling(vm.emitterChainId) == vm.emitterAddress; + checkFork(wormholeTransceiver_evmChainId); + return getWormholePeer(vm.emitterChainId) == vm.emitterAddress; } function isVAAConsumed(bytes32 hash) public view returns (bool) { @@ -330,51 +331,48 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { _getWormholeConsumedVAAsStorage()[hash] = true; } - /// @notice Get the corresponding Endpoint contract on other chains that have been registered via governance. - /// This design should be extendable to other chains, so each Endpoint would be potentially concerned with Endpoints on multiple other chains - /// Note that siblings are registered under wormhole chainID values - function getWormholeSibling(uint16 chainId) public view returns (bytes32) { - return _getWormholeSiblingsStorage()[chainId]; + /// @notice Get the corresponding Transceiver contract on other chains that have been registered via governance. + /// This design should be extendable to other chains, so each Transceiver would be potentially concerned with Transceivers on multiple other chains + /// Note that peers are registered under wormhole chainID values + function getWormholePeer(uint16 chainId) public view returns (bytes32) { + return _getWormholePeersStorage()[chainId]; } - function setWormholeSibling( - uint16 siblingChainId, - bytes32 siblingContract - ) external onlyOwner { - _setWormholeSibling(siblingChainId, siblingContract); + function setWormholePeer(uint16 peerChainId, bytes32 peerContract) external onlyOwner { + _setWormholePeer(peerChainId, peerContract); } - function _setWormholeSibling(uint16 chainId, bytes32 siblingContract) internal { + function _setWormholePeer(uint16 chainId, bytes32 peerContract) internal { if (chainId == 0) { revert InvalidWormholeChainIdZero(); } - if (siblingContract == bytes32(0)) { - revert InvalidWormholeSiblingZeroAddress(); + if (peerContract == bytes32(0)) { + revert InvalidWormholePeerZeroAddress(); } - bytes32 oldSiblingContract = _getWormholeSiblingsStorage()[chainId]; + bytes32 oldPeerContract = _getWormholePeersStorage()[chainId]; - // We don't want to allow updating a sibling since this adds complexity in the accountant - // If the owner makes a mistake with sibling registration they should deploy a new Wormhole - // endpoint and register this new endpoint with the Manager - if (oldSiblingContract != bytes32(0)) { - revert SiblingAlreadySet(chainId, oldSiblingContract); + // We don't want to allow updating a peer since this adds complexity in the accountant + // If the owner makes a mistake with peer registration they should deploy a new Wormhole + // transceiver and register this new transceiver with the NttManager + if (oldPeerContract != bytes32(0)) { + revert PeerAlreadySet(chainId, oldPeerContract); } - _getWormholeSiblingsStorage()[chainId] = siblingContract; + _getWormholePeersStorage()[chainId] = peerContract; - // Publish a message for this endpoint registration - EndpointStructs.EndpointRegistration memory registration = EndpointStructs - .EndpointRegistration({ - endpointIdentifier: WH_SIBLING_REGISTRATION_PREFIX, - endpointChainId: chainId, - endpointAddress: siblingContract + // Publish a message for this transceiver registration + TransceiverStructs.TransceiverRegistration memory registration = TransceiverStructs + .TransceiverRegistration({ + transceiverIdentifier: WH_PEER_REGISTRATION_PREFIX, + transceiverChainId: chainId, + transceiverAddress: peerContract }); wormhole.publishMessage( - 0, EndpointStructs.encodeEndpointRegistration(registration), consistencyLevel + 0, TransceiverStructs.encodeTransceiverRegistration(registration), consistencyLevel ); - emit SetWormholeSibling(chainId, siblingContract); + emit SetWormholePeer(chainId, peerContract); } function isWormholeRelayingEnabled(uint16 chainId) public view returns (bool) { @@ -424,12 +422,12 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { emit SetIsWormholeEvmChain(chainId); } - function parseWormholeEndpointInstruction(bytes memory encoded) + function parseWormholeTransceiverInstruction(bytes memory encoded) public pure - returns (WormholeEndpointInstruction memory instruction) + returns (WormholeTransceiverInstruction memory instruction) { - // If the user doesn't pass in any endpoint instructions then the default is false + // If the user doesn't pass in any transceiver instructions then the default is false if (encoded.length == 0) { instruction.shouldSkipRelayerSend = false; return instruction; @@ -440,7 +438,7 @@ contract WormholeEndpoint is Endpoint, IWormholeEndpoint, IWormholeReceiver { encoded.checkLength(offset); } - function encodeWormholeEndpointInstruction(WormholeEndpointInstruction memory instruction) + function encodeWormholeTransceiverInstruction(WormholeTransceiverInstruction memory instruction) public pure returns (bytes memory) diff --git a/evm/src/interfaces/IEndpoint.sol b/evm/src/interfaces/IEndpoint.sol deleted file mode 100644 index 3efc3eca0..000000000 --- a/evm/src/interfaces/IEndpoint.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; - -import "../libraries/EndpointStructs.sol"; - -interface IEndpoint { - error CallerNotManager(address caller); - error CannotRenounceEndpointOwnership(address currentOwner); - error CannotTransferEndpointOwnership(address currentOwner, address newOwner); - error UnexpectedRecipientManagerAddress( - bytes32 recipientManagerAddress, bytes32 expectedRecipientManagerAddress - ); - - function quoteDeliveryPrice( - uint16 recipientChain, - EndpointStructs.EndpointInstruction memory instruction - ) external view returns (uint256); - - function sendMessage( - uint16 recipientChain, - EndpointStructs.EndpointInstruction memory instruction, - bytes memory managerMessage, - bytes32 recipientManagerAddress - ) external payable; - - function upgrade(address newImplementation) external; - - function transferEndpointOwnership(address newOwner) external; -} diff --git a/evm/src/interfaces/IManagerStandalone.sol b/evm/src/interfaces/IManagerStandalone.sol deleted file mode 100644 index e6c76f22f..000000000 --- a/evm/src/interfaces/IManagerStandalone.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; - -import "../libraries/EndpointStructs.sol"; - -interface IManagerStandalone { - error ZeroThreshold(); - error ThresholdTooHigh(uint256 threshold, uint256 endpoints); - error RetrievedIncorrectRegisteredEndpoints(uint256 retrieved, uint256 registered); - - function attestationReceived( - uint16 sourceChainId, - bytes32 sourceManagerAddress, - EndpointStructs.ManagerMessage memory payload - ) external; - - function upgrade(address newImplementation) external; -} diff --git a/evm/src/interfaces/IManager.sol b/evm/src/interfaces/INttManager.sol similarity index 74% rename from evm/src/interfaces/IManager.sol rename to evm/src/interfaces/INttManager.sol index fe2cdef7b..d055c3515 100644 --- a/evm/src/interfaces/IManager.sol +++ b/evm/src/interfaces/INttManager.sol @@ -2,9 +2,9 @@ pragma solidity >=0.8.8 <0.9.0; import "../libraries/NormalizedAmount.sol"; -import "../libraries/EndpointStructs.sol"; +import "../libraries/TransceiverStructs.sol"; -interface IManager { +interface INttManager { /// @notice payment for a transfer is too low. /// @param requiredPayment The required payment. /// @param providedPayment The provided payment. @@ -26,23 +26,23 @@ interface IManager { /// @param mode The mode. error InvalidMode(uint8 mode); - /// @notice the sibling for the chain does not match the configuration. + /// @notice the peer for the chain does not match the configuration. /// @param chainId ChainId of the source chain. - /// @param siblingAddress Address of the sibling manager contract. - error InvalidSibling(uint16 chainId, bytes32 siblingAddress); - error InvalidSiblingChainIdZero(); + /// @param peerAddress Address of the peer nttManager contract. + error InvalidPeer(uint16 chainId, bytes32 peerAddress); + error InvalidPeerChainIdZero(); - /// @notice Sibling cannot be the zero address. - error InvalidSiblingZeroAddress(); + /// @notice Peer cannot be the zero address. + error InvalidPeerZeroAddress(); /// @notice The number of thresholds should not be zero. error ZeroThreshold(); - /// @notice The threshold for endpoint attestations is too high. + /// @notice The threshold for transceiver attestations is too high. /// @param threshold The threshold. - /// @param endpoints The number of endpoints. - error ThresholdTooHigh(uint256 threshold, uint256 endpoints); - error RetrievedIncorrectRegisteredEndpoints(uint256 retrieved, uint256 registered); + /// @param transceivers The number of transceivers. + error ThresholdTooHigh(uint256 threshold, uint256 transceivers); + error RetrievedIncorrectRegisteredTransceivers(uint256 retrieved, uint256 registered); // @notice transfer a given amount to a recipient on a given chain. // @dev transfers are queued if the outbound limit is hit @@ -61,12 +61,12 @@ interface IManager { bytes memory encodedInstructions ) external payable returns (uint64 msgId); - function getSibling(uint16 chainId_) external view returns (bytes32); + function getPeer(uint16 chainId_) external view returns (bytes32); - function setSibling(uint16 siblingChainId, bytes32 siblingContract) external; + function setPeer(uint16 peerChainId, bytes32 peerContract) external; /// @notice Check if a message has been approved. The message should have at least - /// the minimum threshold of attestations fron distinct endpoints. + /// the minimum threshold of attestations fron distinct transceivers. /// /// @param digest The digest of the message. /// @return Whether the message has been approved. @@ -100,45 +100,45 @@ interface IManager { // @notice Fetch the delivery price for a given recipient chain transfer. // @param recipientChain The chain to transfer to. - // @param endpointInstructions An additional instruction the endpoint can forward to + // @param transceiverInstructions An additional instruction the transceiver can forward to // the recipient chain. - // @param enabledEndpoints The endpoints that are enabled for the transfer. - // @return The delivery prices associated with each endpoint, and the sum + // @param enabledTransceivers The transceivers that are enabled for the transfer. + // @return The delivery prices associated with each transceiver, and the sum // of these prices. function quoteDeliveryPrice( uint16 recipientChain, - EndpointStructs.EndpointInstruction[] memory endpointInstructions, - address[] memory enabledEndpoints + TransceiverStructs.TransceiverInstruction[] memory transceiverInstructions, + address[] memory enabledTransceivers ) external view returns (uint256[] memory, uint256); function nextMessageSequence() external view returns (uint64); function token() external view returns (address); - /// @notice Called by an Endpoint contract to deliver a verified attestation. + /// @notice Called by an Transceiver contract to deliver a verified attestation. /// @dev This function enforces attestation threshold and replay logic for messages. /// Once all validations are complete, this function calls _executeMsg to execute /// the command specified by the message. /// @param sourceChainId The chain id of the sender. - /// @param sourceManagerAddress The address of the sender's manager contract. + /// @param sourceNttManagerAddress The address of the sender's nttManager contract. /// @param payload The VAA payload. function attestationReceived( uint16 sourceChainId, - bytes32 sourceManagerAddress, - EndpointStructs.ManagerMessage memory payload + bytes32 sourceNttManagerAddress, + TransceiverStructs.NttManagerMessage memory payload ) external; - /// @notice upgrade to a new manager implementation. + /// @notice upgrade to a new nttManager implementation. /// @dev This is upgraded via a proxy. /// /// @param newImplementation The address of the new implementation. function upgrade(address newImplementation) external; - /// @notice Returns the mode (locking or burning) of the Manager. + /// @notice Returns the mode (locking or burning) of the NttManager. /// @return mode A uint8 corresponding to the mode function getMode() external view returns (uint8); - /// @notice Returns the number of decimals of the token managed by the Manager. + /// @notice Returns the number of decimals of the token managed by the NttManager. /// @return decimals The number of decimals of the token. function tokenDecimals() external view returns (uint8); } diff --git a/evm/src/interfaces/IManagerEvents.sol b/evm/src/interfaces/INttManagerEvents.sol similarity index 56% rename from evm/src/interfaces/IManagerEvents.sol rename to evm/src/interfaces/INttManagerEvents.sol index 343bd4ccf..0bcabc2ab 100644 --- a/evm/src/interfaces/IManagerEvents.sol +++ b/evm/src/interfaces/INttManagerEvents.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.8 <0.9.0; import "../libraries/NormalizedAmount.sol"; -interface IManagerEvents { - /// @notice Emitted when a message is sent from the manager. +interface INttManagerEvents { + /// @notice Emitted when a message is sent from the nttManager. /// @dev Topic0 /// 0x71ec1d4b53baa86365b6523ea136c9fe0f72c36c721e7e28e9efac2c23b39d98. /// @param recipient The recipient of the message. @@ -15,53 +15,51 @@ interface IManagerEvents { bytes32 recipient, uint256 amount, uint16 recipientChain, uint64 msgSequence ); - /// @notice Emitted when the sibling contract is updated. + /// @notice Emitted when the peer contract is updated. /// @dev Topic0 /// 0x51b8437a7e22240c473f4cbdb4ed3a4f4bf5a9e7b3c511d7cfe0197325735700. - /// @param chainId_ The chain ID of the sibling contract. - /// @param oldSiblingContract The old sibling contract address. - /// @param siblingContract The new sibling contract address. - event SiblingUpdated( - uint16 indexed chainId_, bytes32 oldSiblingContract, bytes32 siblingContract - ); + /// @param chainId_ The chain ID of the peer contract. + /// @param oldPeerContract The old peer contract address. + /// @param peerContract The new peer contract address. + event PeerUpdated(uint16 indexed chainId_, bytes32 oldPeerContract, bytes32 peerContract); /// @notice Emitted when a message has been attested to. /// @dev Topic0 /// 0x35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e5. /// @param digest The digest of the message. - /// @param endpoint The address of the endpoint. - /// @param index The index of the endpoint in the bitmap. - event MessageAttestedTo(bytes32 digest, address endpoint, uint8 index); + /// @param transceiver The address of the transceiver. + /// @param index The index of the transceiver in the bitmap. + event MessageAttestedTo(bytes32 digest, address transceiver, uint8 index); - /// @notice Emmitted when the threshold required endpoints is changed. + /// @notice Emmitted when the threshold required transceivers is changed. /// @dev Topic0 /// 0x2a855b929b9a53c6fb5b5ed248b27e502b709c088e036a5aa17620c8fc5085a9. /// @param oldThreshold The old threshold. /// @param threshold The new threshold. event ThresholdChanged(uint8 oldThreshold, uint8 threshold); - /// @notice Emitted when an endpoint is removed from the manager. + /// @notice Emitted when an transceiver is removed from the nttManager. /// @dev Topic0 /// 0xc6289e62021fd0421276d06677862d6b328d9764cdd4490ca5ac78b173f25883. - /// @param endpoint The address of the endpoint. - /// @param endpointsNum The current number of endpoints. - /// @param threshold The current threshold of endpoints. - event EndpointAdded(address endpoint, uint256 endpointsNum, uint8 threshold); + /// @param transceiver The address of the transceiver. + /// @param transceiversNum The current number of transceivers. + /// @param threshold The current threshold of transceivers. + event TransceiverAdded(address transceiver, uint256 transceiversNum, uint8 threshold); - /// @notice Emitted when an endpoint is removed from the manager. + /// @notice Emitted when an transceiver is removed from the nttManager. /// @dev Topic0 /// 0x638e631f34d9501a3ff0295873b29f50d0207b5400bf0e48b9b34719e6b1a39e. - /// @param endpoint The address of the endpoint. - /// @param threshold The current threshold of endpoints. - event EndpointRemoved(address endpoint, uint8 threshold); + /// @param transceiver The address of the transceiver. + /// @param threshold The current threshold of transceivers. + event TransceiverRemoved(address transceiver, uint8 threshold); /// @notice Emitted when a message has already been executed to /// notify client of against retries. /// @dev Topic0 /// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2. - /// @param sourceManager The address of the source manager. + /// @param sourceNttManager The address of the source nttManager. /// @param msgHash The keccak-256 hash of the message. - event MessageAlreadyExecuted(bytes32 indexed sourceManager, bytes32 indexed msgHash); + event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash); /// @notice Emitted when a transfer has been redeemed /// (either minted or unlocked on the recipient chain). diff --git a/evm/src/interfaces/INttManagerStandalone.sol b/evm/src/interfaces/INttManagerStandalone.sol new file mode 100644 index 000000000..7f5da281f --- /dev/null +++ b/evm/src/interfaces/INttManagerStandalone.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +import "../libraries/TransceiverStructs.sol"; + +interface INttManagerStandalone { + error ZeroThreshold(); + error ThresholdTooHigh(uint256 threshold, uint256 transceivers); + error RetrievedIncorrectRegisteredTransceivers(uint256 retrieved, uint256 registered); + + function attestationReceived( + uint16 sourceChainId, + bytes32 sourceNttManagerAddress, + TransceiverStructs.NttManagerMessage memory payload + ) external; + + function upgrade(address newImplementation) external; +} diff --git a/evm/src/interfaces/IRateLimiter.sol b/evm/src/interfaces/IRateLimiter.sol index 2674d4232..0aacdbb16 100644 --- a/evm/src/interfaces/IRateLimiter.sol +++ b/evm/src/interfaces/IRateLimiter.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.8 <0.9.0; import "../libraries/NormalizedAmount.sol"; -import "../libraries/EndpointStructs.sol"; +import "../libraries/TransceiverStructs.sol"; interface IRateLimiter { /// @notice Not enough capacity to send the transfer. @@ -58,14 +58,14 @@ interface IRateLimiter { /// - txTimestamp: the timestamp of the transfer. /// - recipientChain: the chain of the recipient. /// - sender: the sender of the transfer. - /// - endpointInstructions: additional instructions to be forwarded to the recipient chain. + /// - transceiverInstructions: additional instructions to be forwarded to the recipient chain. struct OutboundQueuedTransfer { bytes32 recipient; NormalizedAmount amount; uint64 txTimestamp; uint16 recipientChain; address sender; - bytes endpointInstructions; + bytes transceiverInstructions; } /// @notice Parameters for an inbound queued transfer. diff --git a/evm/src/interfaces/ITransceiver.sol b/evm/src/interfaces/ITransceiver.sol new file mode 100644 index 000000000..a6ed8435d --- /dev/null +++ b/evm/src/interfaces/ITransceiver.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +import "../libraries/TransceiverStructs.sol"; + +interface ITransceiver { + error CallerNotNttManager(address caller); + error CannotRenounceTransceiverOwnership(address currentOwner); + error CannotTransferTransceiverOwnership(address currentOwner, address newOwner); + error UnexpectedRecipientNttManagerAddress( + bytes32 recipientNttManagerAddress, bytes32 expectedRecipientNttManagerAddress + ); + + function quoteDeliveryPrice( + uint16 recipientChain, + TransceiverStructs.TransceiverInstruction memory instruction + ) external view returns (uint256); + + function sendMessage( + uint16 recipientChain, + TransceiverStructs.TransceiverInstruction memory instruction, + bytes memory nttManagerMessage, + bytes32 recipientNttManagerAddress + ) external payable; + + function upgrade(address newImplementation) external; + + function transferTransceiverOwnership(address newOwner) external; +} diff --git a/evm/src/interfaces/IWormholeEndpoint.sol b/evm/src/interfaces/IWormholeTransceiver.sol similarity index 69% rename from evm/src/interfaces/IWormholeEndpoint.sol rename to evm/src/interfaces/IWormholeTransceiver.sol index 02fcd2b89..a2a959c49 100644 --- a/evm/src/interfaces/IWormholeEndpoint.sol +++ b/evm/src/interfaces/IWormholeTransceiver.sol @@ -1,16 +1,18 @@ // SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; -import "../libraries/EndpointStructs.sol"; +import "../libraries/TransceiverStructs.sol"; -interface IWormholeEndpoint { +interface IWormholeTransceiver { event ReceivedRelayedMessage(bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress); event ReceivedMessage( bytes32 digest, uint16 emitterChainId, bytes32 emitterAddress, uint64 sequence ); - event SendEndpointMessage(uint16 recipientChain, EndpointStructs.EndpointMessage message); - event SetWormholeSibling(uint16 chainId, bytes32 siblingContract); + event SendTransceiverMessage( + uint16 recipientChain, TransceiverStructs.TransceiverMessage message + ); + event SetWormholePeer(uint16 chainId, bytes32 peerContract); event SetIsWormholeRelayingEnabled(uint16 chainId, bool isRelayingEnabled); event SetIsSpecialRelayingEnabled(uint16 chainId, bool isRelayingEnabled); event SetIsWormholeEvmChain(uint16 chainId); @@ -19,15 +21,15 @@ interface IWormholeEndpoint { error CallerNotRelayer(address caller); error UnexpectedAdditionalMessages(); error InvalidVaa(string reason); - error InvalidWormholeSibling(uint16 chainId, bytes32 siblingAddress); - error SiblingAlreadySet(uint16 chainId, bytes32 siblingAddress); + error InvalidWormholePeer(uint16 chainId, bytes32 peerAddress); + error PeerAlreadySet(uint16 chainId, bytes32 peerAddress); error TransferAlreadyCompleted(bytes32 vaaHash); - error InvalidWormholeSiblingZeroAddress(); + error InvalidWormholePeerZeroAddress(); error InvalidWormholeChainIdZero(); function receiveMessage(bytes memory encodedMessage) external; function isVAAConsumed(bytes32 hash) external view returns (bool); - function getWormholeSibling(uint16 chainId) external view returns (bytes32); + function getWormholePeer(uint16 chainId) external view returns (bytes32); function isWormholeRelayingEnabled(uint16 chainId) external view returns (bool); function isSpecialRelayingEnabled(uint16 chainId) external view returns (bool); function isWormholeEvmChain(uint16 chainId) external view returns (bool); diff --git a/evm/src/libraries/RateLimiter.sol b/evm/src/libraries/RateLimiter.sol index 8dcdb8a05..927ce055c 100644 --- a/evm/src/libraries/RateLimiter.sol +++ b/evm/src/libraries/RateLimiter.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.8 <0.9.0; import "../interfaces/IRateLimiter.sol"; import "../interfaces/IRateLimiterEvents.sol"; -import "./EndpointHelpers.sol"; -import "./EndpointStructs.sol"; +import "./TransceiverHelpers.sol"; +import "./TransceiverStructs.sol"; import "../libraries/NormalizedAmount.sol"; abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { @@ -272,7 +272,7 @@ abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { uint16 recipientChain, bytes32 recipient, address senderAddress, - bytes memory endpointInstructions + bytes memory transceiverInstructions ) internal { _getOutboundQueueStorage()[sequence] = OutboundQueuedTransfer({ amount: amount, @@ -280,7 +280,7 @@ abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { recipient: recipient, txTimestamp: uint64(block.timestamp), sender: senderAddress, - endpointInstructions: endpointInstructions + transceiverInstructions: transceiverInstructions }); emit OutboundTransferQueued(sequence); diff --git a/evm/src/libraries/EndpointHelpers.sol b/evm/src/libraries/TransceiverHelpers.sol similarity index 100% rename from evm/src/libraries/EndpointHelpers.sol rename to evm/src/libraries/TransceiverHelpers.sol diff --git a/evm/src/libraries/EndpointStructs.sol b/evm/src/libraries/TransceiverStructs.sol similarity index 50% rename from evm/src/libraries/EndpointStructs.sol rename to evm/src/libraries/TransceiverStructs.sol index f3eb9cc87..7650d2b68 100644 --- a/evm/src/libraries/EndpointStructs.sol +++ b/evm/src/libraries/TransceiverStructs.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.8 <0.9.0; import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; import "./NormalizedAmount.sol"; -library EndpointStructs { +library TransceiverStructs { using BytesParsing for bytes; using NormalizedAmountLib for NormalizedAmount; @@ -24,13 +24,13 @@ library EndpointStructs { /// This is 0x99'N''T''T' bytes4 constant NTT_PREFIX = 0x994E5454; - /// @dev Message emitted and received by the manager contract. + /// @dev Message emitted and received by the nttManager contract. /// The wire format is as follows: /// - sequence - 8 bytes /// - sender - 32 bytes /// - payloadLength - 2 bytes /// - payload - `payloadLength` bytes - struct ManagerMessage { + struct NttManagerMessage { /// @notice unique sequence number uint64 sequence; /// @notice original message sender address. @@ -39,14 +39,14 @@ library EndpointStructs { bytes payload; } - function managerMessageDigest( + function nttManagerMessageDigest( uint16 sourceChainId, - ManagerMessage memory m + NttManagerMessage memory m ) public pure returns (bytes32) { - return keccak256(abi.encodePacked(sourceChainId, encodeManagerMessage(m))); + return keccak256(abi.encodePacked(sourceChainId, encodeNttManagerMessage(m))); } - function encodeManagerMessage(ManagerMessage memory m) + function encodeNttManagerMessage(NttManagerMessage memory m) public pure returns (bytes memory encoded) @@ -58,20 +58,20 @@ library EndpointStructs { return abi.encodePacked(m.sequence, m.sender, payloadLength, m.payload); } - /// @notice Parse a ManagerMessage. + /// @notice Parse a NttManagerMessage. /// @param encoded The byte array corresponding to the encoded message - /// @return managerMessage The parsed ManagerMessage struct. - function parseManagerMessage(bytes memory encoded) + /// @return nttManagerMessage The parsed NttManagerMessage struct. + function parseNttManagerMessage(bytes memory encoded) public pure - returns (ManagerMessage memory managerMessage) + returns (NttManagerMessage memory nttManagerMessage) { uint256 offset = 0; - (managerMessage.sequence, offset) = encoded.asUint64Unchecked(offset); - (managerMessage.sender, offset) = encoded.asBytes32Unchecked(offset); + (nttManagerMessage.sequence, offset) = encoded.asUint64Unchecked(offset); + (nttManagerMessage.sender, offset) = encoded.asBytes32Unchecked(offset); uint256 payloadLength; (payloadLength, offset) = encoded.asUint16Unchecked(offset); - (managerMessage.payload, offset) = encoded.sliceUnchecked(offset, payloadLength); + (nttManagerMessage.payload, offset) = encoded.sliceUnchecked(offset, payloadLength); encoded.checkLength(offset); } @@ -137,84 +137,84 @@ library EndpointStructs { encoded.checkLength(offset); } - /// @dev Message emitted by Endpoint implementations. - /// Each message includes an Endpoint-specified 4-byte prefix. + /// @dev Message emitted by Transceiver implementations. + /// Each message includes an Transceiver-specified 4-byte prefix. /// The wire format is as follows: /// - prefix - 4 bytes - /// - sourceManagerAddress - 32 bytes - /// - recipientManagerAddress - 32 bytes - /// - managerPayloadLength - 2 bytes - /// - managerPayload - `managerPayloadLength` bytes - /// - endpointPayloadLength - 2 bytes - /// - endpointPayload - `endpointPayloadLength` bytes - struct EndpointMessage { - /// @notice Address of the Manager contract that emitted this message. - bytes32 sourceManagerAddress; - /// @notice Address of the Manager contract that receives this message. - bytes32 recipientManagerAddress; - /// @notice Payload provided to the Endpoint contract by the Manager contract. - bytes managerPayload; - /// @notice Optional payload that the endpoint can encode and use for its own message passing purposes. - bytes endpointPayload; + /// - sourceNttManagerAddress - 32 bytes + /// - recipientNttManagerAddress - 32 bytes + /// - nttManagerPayloadLength - 2 bytes + /// - nttManagerPayload - `nttManagerPayloadLength` bytes + /// - transceiverPayloadLength - 2 bytes + /// - transceiverPayload - `transceiverPayloadLength` bytes + struct TransceiverMessage { + /// @notice Address of the NttManager contract that emitted this message. + bytes32 sourceNttManagerAddress; + /// @notice Address of the NttManager contract that receives this message. + bytes32 recipientNttManagerAddress; + /// @notice Payload provided to the Transceiver contract by the NttManager contract. + bytes nttManagerPayload; + /// @notice Optional payload that the transceiver can encode and use for its own message passing purposes. + bytes transceiverPayload; } - // @notice Encodes an Endpoint message for communication between the - // Manager and the Endpoint. - // @param m The EndpointMessage struct containing the message details. + // @notice Encodes an Transceiver message for communication between the + // NttManager and the Transceiver. + // @param m The TransceiverMessage struct containing the message details. // @return encoded The byte array corresponding to the encoded message. - // @custom:throw PayloadTooLong if the length of endpointId, managerPayload, - // or endpointPayload exceeds the allowed maximum. - function encodeEndpointMessage( + // @custom:throw PayloadTooLong if the length of transceiverId, nttManagerPayload, + // or transceiverPayload exceeds the allowed maximum. + function encodeTransceiverMessage( bytes4 prefix, - EndpointMessage memory m + TransceiverMessage memory m ) public pure returns (bytes memory encoded) { - if (m.managerPayload.length > type(uint16).max) { - revert PayloadTooLong(m.managerPayload.length); + if (m.nttManagerPayload.length > type(uint16).max) { + revert PayloadTooLong(m.nttManagerPayload.length); } - uint16 managerPayloadLength = uint16(m.managerPayload.length); + uint16 nttManagerPayloadLength = uint16(m.nttManagerPayload.length); - if (m.endpointPayload.length > type(uint16).max) { - revert PayloadTooLong(m.endpointPayload.length); + if (m.transceiverPayload.length > type(uint16).max) { + revert PayloadTooLong(m.transceiverPayload.length); } - uint16 endpointPayloadLength = uint16(m.endpointPayload.length); + uint16 transceiverPayloadLength = uint16(m.transceiverPayload.length); return abi.encodePacked( prefix, - m.sourceManagerAddress, - m.recipientManagerAddress, - managerPayloadLength, - m.managerPayload, - endpointPayloadLength, - m.endpointPayload + m.sourceNttManagerAddress, + m.recipientNttManagerAddress, + nttManagerPayloadLength, + m.nttManagerPayload, + transceiverPayloadLength, + m.transceiverPayload ); } - function buildAndEncodeEndpointMessage( + function buildAndEncodeTransceiverMessage( bytes4 prefix, - bytes32 sourceManagerAddress, - bytes32 recipientManagerAddress, - bytes memory managerMessage, - bytes memory endpointPayload - ) public pure returns (EndpointMessage memory, bytes memory) { - EndpointMessage memory endpointMessage = EndpointMessage({ - sourceManagerAddress: sourceManagerAddress, - recipientManagerAddress: recipientManagerAddress, - managerPayload: managerMessage, - endpointPayload: endpointPayload + bytes32 sourceNttManagerAddress, + bytes32 recipientNttManagerAddress, + bytes memory nttManagerMessage, + bytes memory transceiverPayload + ) public pure returns (TransceiverMessage memory, bytes memory) { + TransceiverMessage memory transceiverMessage = TransceiverMessage({ + sourceNttManagerAddress: sourceNttManagerAddress, + recipientNttManagerAddress: recipientNttManagerAddress, + nttManagerPayload: nttManagerMessage, + transceiverPayload: transceiverPayload }); - bytes memory encoded = encodeEndpointMessage(prefix, endpointMessage); - return (endpointMessage, encoded); + bytes memory encoded = encodeTransceiverMessage(prefix, transceiverMessage); + return (transceiverMessage, encoded); } - /// @dev Parses an encoded message and extracts information into an EndpointMessage struct. - /// @param encoded The encoded bytes containing information about the EndpointMessage. - /// @return endpointMessage The parsed EndpointMessage struct. + /// @dev Parses an encoded message and extracts information into an TransceiverMessage struct. + /// @param encoded The encoded bytes containing information about the TransceiverMessage. + /// @return transceiverMessage The parsed TransceiverMessage struct. /// @custom:throw IncorrectPrefix if the prefix of the encoded message does not /// match the expected prefix. - function parseEndpointMessage( + function parseTransceiverMessage( bytes4 expectedPrefix, bytes memory encoded - ) internal pure returns (EndpointMessage memory endpointMessage) { + ) internal pure returns (TransceiverMessage memory transceiverMessage) { uint256 offset = 0; bytes4 prefix; @@ -224,51 +224,52 @@ library EndpointStructs { revert IncorrectPrefix(prefix); } - (endpointMessage.sourceManagerAddress, offset) = encoded.asBytes32Unchecked(offset); - (endpointMessage.recipientManagerAddress, offset) = encoded.asBytes32Unchecked(offset); - uint16 managerPayloadLength; - (managerPayloadLength, offset) = encoded.asUint16Unchecked(offset); - (endpointMessage.managerPayload, offset) = - encoded.sliceUnchecked(offset, managerPayloadLength); - uint16 endpointPayloadLength; - (endpointPayloadLength, offset) = encoded.asUint16Unchecked(offset); - (endpointMessage.endpointPayload, offset) = - encoded.sliceUnchecked(offset, endpointPayloadLength); + (transceiverMessage.sourceNttManagerAddress, offset) = encoded.asBytes32Unchecked(offset); + (transceiverMessage.recipientNttManagerAddress, offset) = encoded.asBytes32Unchecked(offset); + uint16 nttManagerPayloadLength; + (nttManagerPayloadLength, offset) = encoded.asUint16Unchecked(offset); + (transceiverMessage.nttManagerPayload, offset) = + encoded.sliceUnchecked(offset, nttManagerPayloadLength); + uint16 transceiverPayloadLength; + (transceiverPayloadLength, offset) = encoded.asUint16Unchecked(offset); + (transceiverMessage.transceiverPayload, offset) = + encoded.sliceUnchecked(offset, transceiverPayloadLength); // Check if the entire byte array has been processed encoded.checkLength(offset); } - /// @dev Parses the payload of an Endpoint message and returns - /// the parsed ManagerMessage struct. - /// @param expectedPrefix The prefix that should be encoded in the manager message. + /// @dev Parses the payload of an Transceiver message and returns + /// the parsed NttManagerMessage struct. + /// @param expectedPrefix The prefix that should be encoded in the nttManager message. /// @param payload The payload sent across the wire. - function parseEndpointAndManagerMessage( + function parseTransceiverAndNttManagerMessage( bytes4 expectedPrefix, bytes memory payload - ) public pure returns (EndpointMessage memory, ManagerMessage memory) { - // parse the encoded message payload from the Endpoint - EndpointMessage memory parsedEndpointMessage = parseEndpointMessage(expectedPrefix, payload); + ) public pure returns (TransceiverMessage memory, NttManagerMessage memory) { + // parse the encoded message payload from the Transceiver + TransceiverMessage memory parsedTransceiverMessage = + parseTransceiverMessage(expectedPrefix, payload); - // parse the encoded message payload from the Manager - ManagerMessage memory parsedManagerMessage = - parseManagerMessage(parsedEndpointMessage.managerPayload); + // parse the encoded message payload from the NttManager + NttManagerMessage memory parsedNttManagerMessage = + parseNttManagerMessage(parsedTransceiverMessage.nttManagerPayload); - return (parsedEndpointMessage, parsedManagerMessage); + return (parsedTransceiverMessage, parsedNttManagerMessage); } - /// @dev Variable-length endpoint-specific instruction that can be passed by the caller to the manager. - /// The index field refers to the index of the registeredEndpoint that this instruction should be passed to. + /// @dev Variable-length transceiver-specific instruction that can be passed by the caller to the nttManager. + /// The index field refers to the index of the registeredTransceiver that this instruction should be passed to. /// The serialization format is: /// - index - 1 byte /// - payloadLength - 1 byte /// - payload - `payloadLength` bytes - struct EndpointInstruction { + struct TransceiverInstruction { uint8 index; bytes payload; } - function encodeEndpointInstruction(EndpointInstruction memory instruction) + function encodeTransceiverInstruction(TransceiverInstruction memory instruction) public pure returns (bytes memory) @@ -280,31 +281,31 @@ library EndpointStructs { return abi.encodePacked(instruction.index, payloadLength, instruction.payload); } - function parseEndpointInstructionUnchecked( + function parseTransceiverInstructionUnchecked( bytes memory encoded, uint256 offset - ) public pure returns (EndpointInstruction memory instruction, uint256 nextOffset) { + ) public pure returns (TransceiverInstruction memory instruction, uint256 nextOffset) { (instruction.index, nextOffset) = encoded.asUint8Unchecked(offset); uint8 instructionLength; (instructionLength, nextOffset) = encoded.asUint8Unchecked(nextOffset); (instruction.payload, nextOffset) = encoded.sliceUnchecked(nextOffset, instructionLength); } - function parseEndpointInstructionChecked(bytes memory encoded) + function parseTransceiverInstructionChecked(bytes memory encoded) public pure - returns (EndpointInstruction memory instruction) + returns (TransceiverInstruction memory instruction) { uint256 offset = 0; - (instruction, offset) = parseEndpointInstructionUnchecked(encoded, offset); + (instruction, offset) = parseTransceiverInstructionUnchecked(encoded, offset); encoded.checkLength(offset); } - /// @dev Encode an array of multiple variable-length endpoint-specific instructions. + /// @dev Encode an array of multiple variable-length transceiver-specific instructions. /// The serialization format is: /// - instructionsLength - 1 byte - /// - `instructionsLength` number of serialized `EndpointInstruction` types. - function encodeEndpointInstructions(EndpointInstruction[] memory instructions) + /// - `instructionsLength` number of serialized `TransceiverInstruction` types. + function encodeTransceiverInstructions(TransceiverInstruction[] memory instructions) public pure returns (bytes memory) @@ -316,33 +317,34 @@ library EndpointStructs { bytes memory encoded; for (uint256 i = 0; i < instructionsLength; i++) { - bytes memory innerEncoded = encodeEndpointInstruction(instructions[i]); + bytes memory innerEncoded = encodeTransceiverInstruction(instructions[i]); encoded = bytes.concat(encoded, innerEncoded); } return abi.encodePacked(uint8(instructionsLength), encoded); } - function parseEndpointInstructions( + function parseTransceiverInstructions( bytes memory encoded, - uint256 numEnabledEndpoints - ) public pure returns (EndpointInstruction[] memory) { + uint256 numEnabledTransceivers + ) public pure returns (TransceiverInstruction[] memory) { uint256 offset = 0; uint256 instructionsLength; (instructionsLength, offset) = encoded.asUint8Unchecked(offset); - // We allocate an array with the length of the number of enabled endpoints - // This gives us the flexibility to not have to pass instructions for endpoints that + // We allocate an array with the length of the number of enabled transceivers + // This gives us the flexibility to not have to pass instructions for transceivers that // don't need them - EndpointInstruction[] memory instructions = new EndpointInstruction[](numEnabledEndpoints); + TransceiverInstruction[] memory instructions = + new TransceiverInstruction[](numEnabledTransceivers); uint256 lastIndex = 0; for (uint256 i = 0; i < instructionsLength; i++) { - EndpointInstruction memory instruction; - (instruction, offset) = parseEndpointInstructionUnchecked(encoded, offset); + TransceiverInstruction memory instruction; + (instruction, offset) = parseTransceiverInstructionUnchecked(encoded, offset); uint8 instructionIndex = instruction.index; - // The instructions passed in have to be strictly increasing in terms of endpoint index + // The instructions passed in have to be strictly increasing in terms of transceiver index if (i != 0 && instructionIndex <= lastIndex) { revert UnorderedInstructions(); } @@ -356,65 +358,69 @@ library EndpointStructs { return instructions; } - struct EndpointInit { - bytes4 endpointIdentifier; - bytes32 managerAddress; - uint8 managerMode; + struct TransceiverInit { + bytes4 transceiverIdentifier; + bytes32 nttManagerAddress; + uint8 nttManagerMode; bytes32 tokenAddress; uint8 tokenDecimals; } - function encodeEndpointInit(EndpointInit memory init) public pure returns (bytes memory) { + function encodeTransceiverInit(TransceiverInit memory init) + public + pure + returns (bytes memory) + { return abi.encodePacked( - init.endpointIdentifier, - init.managerAddress, - init.managerMode, + init.transceiverIdentifier, + init.nttManagerAddress, + init.nttManagerMode, init.tokenAddress, init.tokenDecimals ); } - function decodeEndpointInit(bytes memory encoded) + function decodeTransceiverInit(bytes memory encoded) public pure - returns (EndpointInit memory init) + returns (TransceiverInit memory init) { uint256 offset = 0; - (init.endpointIdentifier, offset) = encoded.asBytes4Unchecked(offset); - (init.managerAddress, offset) = encoded.asBytes32Unchecked(offset); - (init.managerMode, offset) = encoded.asUint8Unchecked(offset); + (init.transceiverIdentifier, offset) = encoded.asBytes4Unchecked(offset); + (init.nttManagerAddress, offset) = encoded.asBytes32Unchecked(offset); + (init.nttManagerMode, offset) = encoded.asUint8Unchecked(offset); (init.tokenAddress, offset) = encoded.asBytes32Unchecked(offset); (init.tokenDecimals, offset) = encoded.asUint8Unchecked(offset); encoded.checkLength(offset); } - struct EndpointRegistration { - bytes4 endpointIdentifier; - uint16 endpointChainId; - bytes32 endpointAddress; + struct TransceiverRegistration { + bytes4 transceiverIdentifier; + uint16 transceiverChainId; + bytes32 transceiverAddress; } - function encodeEndpointRegistration(EndpointRegistration memory registration) + function encodeTransceiverRegistration(TransceiverRegistration memory registration) public pure returns (bytes memory) { return abi.encodePacked( - registration.endpointIdentifier, - registration.endpointChainId, - registration.endpointAddress + registration.transceiverIdentifier, + registration.transceiverChainId, + registration.transceiverAddress ); } - function decodeEndpointRegistration(bytes memory encoded) + function decodeTransceiverRegistration(bytes memory encoded) public pure - returns (EndpointRegistration memory registration) + returns (TransceiverRegistration memory registration) { uint256 offset = 0; - (registration.endpointIdentifier, offset) = encoded.asBytes4Unchecked(offset); - (registration.endpointChainId, offset) = encoded.asUint16Unchecked(offset); - (registration.endpointAddress, offset) = encoded.asBytes32Unchecked(offset); + (registration.transceiverIdentifier, offset) = encoded.asBytes4Unchecked(offset); + (registration.transceiverChainId, offset) = encoded.asUint16Unchecked(offset); + (registration.transceiverAddress, offset) = encoded.asBytes32Unchecked(offset); encoded.checkLength(offset); } } diff --git a/evm/test/EndpointStructs.t.sol b/evm/test/EndpointStructs.t.sol deleted file mode 100644 index 3dfd0a0b0..000000000 --- a/evm/test/EndpointStructs.t.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; - -import "forge-std/Test.sol"; - -import "../src/libraries/EndpointStructs.sol"; -import "../src/WormholeEndpoint.sol"; - -contract TestEndpointStructs is Test { - using NormalizedAmountLib for uint256; - using NormalizedAmountLib for NormalizedAmount; - - // TODO: add some negative tests for unknown message types etc - - function test_serialize_EndpointMessage() public { - EndpointStructs.NativeTokenTransfer memory ntt = EndpointStructs.NativeTokenTransfer({ - amount: NormalizedAmount({amount: 1234567, decimals: 7}), - sourceToken: hex"BEEFFACE", - to: hex"FEEBCAFE", - toChain: 17 - }); - - EndpointStructs.ManagerMessage memory mm = EndpointStructs.ManagerMessage({ - sequence: 233968345345, - sender: hex"46679213412343", - payload: EndpointStructs.encodeNativeTokenTransfer(ntt) - }); - - bytes4 wh_prefix = 0x9945FF10; - EndpointStructs.EndpointMessage memory em = EndpointStructs.EndpointMessage({ - sourceManagerAddress: hex"042942FAFABE", - recipientManagerAddress: hex"042942FABABE", - managerPayload: EndpointStructs.encodeManagerMessage(mm), - endpointPayload: new bytes(0) - }); - - bytes memory encodedEndpointMessage = EndpointStructs.encodeEndpointMessage(wh_prefix, em); - - // this is a useful test case for implementations on other runtimes - bytes memory encodedExpected = - hex"9945ff10042942fafabe0000000000000000000000000000000000000000000000000000042942fababe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe0000000000000000000000000000000000000000000000000000000000110000"; - assertEq(encodedEndpointMessage, encodedExpected); - - EndpointStructs.EndpointMessage memory emParsed = - EndpointStructs.parseEndpointMessage(wh_prefix, encodedEndpointMessage); - - EndpointStructs.ManagerMessage memory mmParsed = - EndpointStructs.parseManagerMessage(emParsed.managerPayload); - - // deep equality check - assertEq(abi.encode(mmParsed), abi.encode(mm)); - - EndpointStructs.NativeTokenTransfer memory nttParsed = - EndpointStructs.parseNativeTokenTransfer(mmParsed.payload); - - // deep equality check - assertEq(abi.encode(nttParsed), abi.encode(ntt)); - } - - function test_SerdeRoundtrip_ManagerMessage(EndpointStructs.ManagerMessage memory m) public { - bytes memory message = EndpointStructs.encodeManagerMessage(m); - - EndpointStructs.ManagerMessage memory parsed = EndpointStructs.parseManagerMessage(message); - - assertEq(m.sequence, parsed.sequence); - assertEq(m.sender, parsed.sender); - assertEq(m.payload, parsed.payload); - } - - function test_SerdeJunk_ManagerMessage(EndpointStructs.ManagerMessage memory m) public { - bytes memory message = EndpointStructs.encodeManagerMessage(m); - - bytes memory junk = "junk"; - - vm.expectRevert( - abi.encodeWithSignature( - "LengthMismatch(uint256,uint256)", message.length + junk.length, message.length - ) - ); - EndpointStructs.parseManagerMessage(abi.encodePacked(message, junk)); - } - - function test_SerdeRoundtrip_NativeTokenTransfer(EndpointStructs.NativeTokenTransfer memory m) - public - { - bytes memory message = EndpointStructs.encodeNativeTokenTransfer(m); - - EndpointStructs.NativeTokenTransfer memory parsed = - EndpointStructs.parseNativeTokenTransfer(message); - - assertEq(m.amount.getAmount(), parsed.amount.getAmount()); - assertEq(m.to, parsed.to); - assertEq(m.toChain, parsed.toChain); - } - - function test_SerdeJunk_NativeTokenTransfer(EndpointStructs.NativeTokenTransfer memory m) - public - { - bytes memory message = EndpointStructs.encodeNativeTokenTransfer(m); - - bytes memory junk = "junk"; - - vm.expectRevert( - abi.encodeWithSignature( - "LengthMismatch(uint256,uint256)", message.length + junk.length, message.length - ) - ); - EndpointStructs.parseNativeTokenTransfer(abi.encodePacked(message, junk)); - } -} diff --git a/evm/test/IntegrationRelayer.t.sol b/evm/test/IntegrationRelayer.t.sol index 7b2f9a9e2..95a4fec9d 100755 --- a/evm/test/IntegrationRelayer.t.sol +++ b/evm/test/IntegrationRelayer.t.sol @@ -4,19 +4,19 @@ pragma solidity 0.8.19; import "forge-std/Test.sol"; import "forge-std/console.sol"; -import "../src/Manager.sol"; -import "../src/Endpoint.sol"; -import "../src/interfaces/IManager.sol"; +import "../src/NttManager.sol"; +import "../src/Transceiver.sol"; +import "../src/interfaces/INttManager.sol"; import "../src/interfaces/IRateLimiter.sol"; -import "../src/interfaces/IManagerEvents.sol"; +import "../src/interfaces/INttManagerEvents.sol"; import "../src/interfaces/IRateLimiterEvents.sol"; -import "../src/interfaces/IWormholeEndpoint.sol"; +import "../src/interfaces/IWormholeTransceiver.sol"; import {Utils} from "./libraries/Utils.sol"; import {DummyToken, DummyTokenMintAndBurn} from "./mocks/DummyToken.sol"; -import {WormholeEndpoint} from "../src/WormholeEndpoint.sol"; -import "../src/libraries/EndpointStructs.sol"; -import "./mocks/MockManager.sol"; -import "./mocks/MockEndpoints.sol"; +import {WormholeTransceiver} from "../src/WormholeTransceiver.sol"; +import "../src/libraries/TransceiverStructs.sol"; +import "./mocks/MockNttManager.sol"; +import "./mocks/MockTransceivers.sol"; import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -26,47 +26,50 @@ import "wormhole-solidity-sdk/Utils.sol"; import {WormholeRelayerBasicTest} from "wormhole-solidity-sdk/testing/WormholeRelayerTest.sol"; contract TestEndToEndRelayerBase is Test { - WormholeEndpoint wormholeEndpointChain1; - WormholeEndpoint wormholeEndpointChain2; + WormholeTransceiver wormholeTransceiverChain1; + WormholeTransceiver wormholeTransceiverChain2; - function buildEndpointInstruction(bool relayer_off) + function buildTransceiverInstruction(bool relayer_off) public view - returns (EndpointStructs.EndpointInstruction memory) + returns (TransceiverStructs.TransceiverInstruction memory) { - WormholeEndpoint.WormholeEndpointInstruction memory instruction = - WormholeEndpoint.WormholeEndpointInstruction(relayer_off); + WormholeTransceiver.WormholeTransceiverInstruction memory instruction = + WormholeTransceiver.WormholeTransceiverInstruction(relayer_off); bytes memory encodedInstructionWormhole; // Source fork has id 0 and corresponds to chain 1 if (vm.activeFork() == 0) { encodedInstructionWormhole = - wormholeEndpointChain1.encodeWormholeEndpointInstruction(instruction); + wormholeTransceiverChain1.encodeWormholeTransceiverInstruction(instruction); } else { encodedInstructionWormhole = - wormholeEndpointChain2.encodeWormholeEndpointInstruction(instruction); + wormholeTransceiverChain2.encodeWormholeTransceiverInstruction(instruction); } - return EndpointStructs.EndpointInstruction({index: 0, payload: encodedInstructionWormhole}); + return TransceiverStructs.TransceiverInstruction({ + index: 0, + payload: encodedInstructionWormhole + }); } - function encodeEndpointInstruction(bool relayer_off) public view returns (bytes memory) { - EndpointStructs.EndpointInstruction memory EndpointInstruction = - buildEndpointInstruction(relayer_off); - EndpointStructs.EndpointInstruction[] memory EndpointInstructions = - new EndpointStructs.EndpointInstruction[](1); - EndpointInstructions[0] = EndpointInstruction; - return EndpointStructs.encodeEndpointInstructions(EndpointInstructions); + function encodeTransceiverInstruction(bool relayer_off) public view returns (bytes memory) { + TransceiverStructs.TransceiverInstruction memory TransceiverInstruction = + buildTransceiverInstruction(relayer_off); + TransceiverStructs.TransceiverInstruction[] memory TransceiverInstructions = + new TransceiverStructs.TransceiverInstruction[](1); + TransceiverInstructions[0] = TransceiverInstruction; + return TransceiverStructs.encodeTransceiverInstructions(TransceiverInstructions); } } contract TestEndToEndRelayer is TestEndToEndRelayerBase, - IManagerEvents, + INttManagerEvents, IRateLimiterEvents, WormholeRelayerBasicTest { - Manager managerChain1; - Manager managerChain2; + NttManager nttManagerChain1; + NttManager nttManagerChain2; using NormalizedAmountLib for uint256; using NormalizedAmountLib for NormalizedAmount; @@ -93,29 +96,30 @@ contract TestEndToEndRelayer is vm.deal(userA, 1 ether); DummyToken t1 = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t1), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t1), NttManager.Mode.LOCKING, chainId1, 1 days); - managerChain1 = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - managerChain1.initialize(); + nttManagerChain1 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerChain1.initialize(); - wormholeEndpointChain1 = new MockWormholeEndpointContract( - address(managerChain1), + wormholeTransceiverChain1 = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(chainInfosTestnet[chainId1].wormhole), address(relayerSource), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain1), "")) + wormholeTransceiverChain1 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain1), "")) ); - wormholeEndpointChain1.initialize(); + wormholeTransceiverChain1.initialize(); - managerChain1.setEndpoint(address(wormholeEndpointChain1)); - managerChain1.setOutboundLimit(type(uint64).max); - managerChain1.setInboundLimit(type(uint64).max, chainId2); - managerChain1.setThreshold(1); + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1)); + nttManagerChain1.setOutboundLimit(type(uint64).max); + nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); + nttManagerChain1.setThreshold(1); } // Setup the chain to relay to of the network @@ -124,30 +128,30 @@ contract TestEndToEndRelayer is // Chain 2 setup DummyToken t2 = new DummyTokenMintAndBurn(); - Manager implementationChain2 = - new MockManagerContract(address(t2), Manager.Mode.BURNING, chainId2, 1 days); - - managerChain2 = - MockManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); - managerChain2.initialize(); - wormholeEndpointChain2 = new MockWormholeEndpointContract( - address(managerChain2), + NttManager implementationChain2 = + new MockNttManagerContract(address(t2), NttManager.Mode.BURNING, chainId2, 1 days); + + nttManagerChain2 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); + nttManagerChain2.initialize(); + wormholeTransceiverChain2 = new MockWormholeTransceiverContract( + address(nttManagerChain2), address(chainInfosTestnet[chainId2].wormhole), address(relayerTarget), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain2 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain2), "")) + wormholeTransceiverChain2 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain2), "")) ); - wormholeEndpointChain2.initialize(); + wormholeTransceiverChain2.initialize(); - managerChain2.setEndpoint(address(wormholeEndpointChain2)); - managerChain2.setOutboundLimit(type(uint64).max); - managerChain2.setInboundLimit(type(uint64).max, chainId1); + nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2)); + nttManagerChain2.setOutboundLimit(type(uint64).max); + nttManagerChain2.setInboundLimit(type(uint64).max, chainId1); - managerChain2.setThreshold(1); + nttManagerChain2.setThreshold(1); } function test_chainToChainReverts() public { @@ -156,67 +160,68 @@ contract TestEndToEndRelayer is // Setup the information for interacting with the chains vm.selectFork(targetFork); - wormholeEndpointChain2.setWormholeSibling( - chainId1, bytes32(uint256(uint160(address(wormholeEndpointChain1)))) + wormholeTransceiverChain2.setWormholePeer( + chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(managerChain1))))); - DummyToken token2 = DummyTokenMintAndBurn(managerChain2.token()); - wormholeEndpointChain2.setIsWormholeRelayingEnabled(chainId1, true); - wormholeEndpointChain2.setIsWormholeEvmChain(chainId1); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1))))); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); + wormholeTransceiverChain2.setIsWormholeRelayingEnabled(chainId1, true); + wormholeTransceiverChain2.setIsWormholeEvmChain(chainId1); - // Register sibling contracts for the manager and endpoint. Endpoints and manager each have the concept of siblings here. + // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here. vm.selectFork(sourceFork); - DummyToken token1 = DummyToken(managerChain1.token()); - wormholeEndpointChain1.setWormholeSibling( - chainId2, bytes32(uint256(uint160((address(wormholeEndpointChain2))))) + DummyToken token1 = DummyToken(nttManagerChain1.token()); + wormholeTransceiverChain1.setWormholePeer( + chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2))))) ); - managerChain1.setSibling(chainId2, bytes32(uint256(uint160(address(managerChain2))))); + nttManagerChain1.setPeer(chainId2, bytes32(uint256(uint160(address(nttManagerChain2))))); // Enable general relaying on the chain to transfer for the funds. - wormholeEndpointChain1.setIsWormholeRelayingEnabled(chainId2, true); - wormholeEndpointChain1.setIsWormholeEvmChain(chainId2); + wormholeTransceiverChain1.setIsWormholeRelayingEnabled(chainId2, true); + wormholeTransceiverChain1.setIsWormholeEvmChain(chainId2); // Setting up the transfer uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), sendingAmount); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); // Send token through standard means (not relayer) { - uint256 managerBalanceBefore = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceBefore = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceBefore = token1.balanceOf(address(userA)); - uint256 priceQuote1 = - wormholeEndpointChain1.quoteDeliveryPrice(chainId2, buildEndpointInstruction(false)); + uint256 priceQuote1 = wormholeTransceiverChain1.quoteDeliveryPrice( + chainId2, buildTransceiverInstruction(false) + ); - bytes memory instructions = encodeEndpointInstruction(false); + bytes memory instructions = encodeTransceiverInstruction(false); vm.expectRevert(); // Dust error - managerChain1.transfer{value: priceQuote1}( + nttManagerChain1.transfer{value: priceQuote1}( sendingAmount - 1, chainId2, bytes32(uint256(uint160(userB))), false, instructions ); vm.expectRevert(); // Zero funds error - managerChain1.transfer{value: priceQuote1}( + nttManagerChain1.transfer{value: priceQuote1}( 0, chainId2, bytes32(uint256(uint160(userB))), false, instructions ); vm.expectRevert(); // Not enough in gas costs from the 'quote'. - managerChain1.transfer{value: priceQuote1 - 1}( + nttManagerChain1.transfer{value: priceQuote1 - 1}( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, instructions ); // Do the payment with slightly more gas than needed. This should result in a *payback* of 1 wei. - managerChain1.transfer{value: priceQuote1 + 1}( + nttManagerChain1.transfer{value: priceQuote1 + 1}( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, instructions ); // Balance check on funds going in and out working as expected - uint256 managerBalanceAfter = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); require( - managerBalanceBefore + sendingAmount == managerBalanceAfter, + nttManagerBalanceBefore + sendingAmount == nttManagerBalanceAfter, "Should be locking the tokens" ); require( @@ -244,7 +249,7 @@ contract TestEndToEndRelayer is require(sendingAmount + supplyBefore == supplyAfter, "Supplies dont match"); require(token2.balanceOf(userB) == sendingAmount, "User didn't receive tokens"); - require(token2.balanceOf(address(managerChain2)) == 0, "Manager has unintended funds"); + require(token2.balanceOf(address(nttManagerChain2)) == 0, "NttManager has unintended funds"); } function test_chainToChainBase() public { @@ -253,55 +258,55 @@ contract TestEndToEndRelayer is // Setup the information for interacting with the chains vm.selectFork(targetFork); - wormholeEndpointChain2.setWormholeSibling( - chainId1, bytes32(uint256(uint160(address(wormholeEndpointChain1)))) + wormholeTransceiverChain2.setWormholePeer( + chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(managerChain1))))); - DummyToken token2 = DummyTokenMintAndBurn(managerChain2.token()); - wormholeEndpointChain2.setIsWormholeRelayingEnabled(chainId1, true); - wormholeEndpointChain2.setIsWormholeEvmChain(chainId1); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1))))); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); + wormholeTransceiverChain2.setIsWormholeRelayingEnabled(chainId1, true); + wormholeTransceiverChain2.setIsWormholeEvmChain(chainId1); - // Register sibling contracts for the manager and endpoint. Endpoints and manager each have the concept of siblings here. + // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here. vm.selectFork(sourceFork); - managerChain1.setSibling(chainId2, bytes32(uint256(uint160(address(managerChain2))))); - wormholeEndpointChain1.setWormholeSibling( - chainId2, bytes32(uint256(uint160((address(wormholeEndpointChain2))))) + nttManagerChain1.setPeer(chainId2, bytes32(uint256(uint160(address(nttManagerChain2))))); + wormholeTransceiverChain1.setWormholePeer( + chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2))))) ); - DummyToken token1 = DummyToken(managerChain1.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); // Enable general relaying on the chain to transfer for the funds. - wormholeEndpointChain1.setIsWormholeRelayingEnabled(chainId2, true); - wormholeEndpointChain1.setIsWormholeEvmChain(chainId2); + wormholeTransceiverChain1.setIsWormholeRelayingEnabled(chainId2, true); + wormholeTransceiverChain1.setIsWormholeEvmChain(chainId2); // Setting up the transfer uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), 5 * 10 ** decimals); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); // Send token through standard means (not relayer) { - uint256 managerBalanceBefore = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceBefore = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceBefore = token1.balanceOf(address(userA)); - managerChain1.transfer{ - value: wormholeEndpointChain1.quoteDeliveryPrice( - chainId2, buildEndpointInstruction(false) + nttManagerChain1.transfer{ + value: wormholeTransceiverChain1.quoteDeliveryPrice( + chainId2, buildTransceiverInstruction(false) ) }( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, - encodeEndpointInstruction(false) + encodeTransceiverInstruction(false) ); // Balance check on funds going in and out working as expected - uint256 managerBalanceAfter = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); require( - managerBalanceBefore + sendingAmount == managerBalanceAfter, + nttManagerBalanceBefore + sendingAmount == nttManagerBalanceAfter, "Should be locking the tokens" ); require( @@ -326,27 +331,27 @@ contract TestEndToEndRelayer is require(sendingAmount + supplyBefore == supplyAfter, "Supplies not changed - minting"); require(token2.balanceOf(userB) == sendingAmount, "User didn't receive tokens"); - require(token2.balanceOf(address(managerChain2)) == 0, "Manager has unintended funds"); + require(token2.balanceOf(address(nttManagerChain2)) == 0, "NttManager has unintended funds"); // Go back the other way from a THIRD user vm.prank(userB); token2.transfer(userC, sendingAmount); vm.startPrank(userC); - token2.approve(address(managerChain2), sendingAmount); + token2.approve(address(nttManagerChain2), sendingAmount); { supplyBefore = token2.totalSupply(); - managerChain2.transfer{ - value: wormholeEndpointChain2.quoteDeliveryPrice( - chainId1, buildEndpointInstruction(false) + nttManagerChain2.transfer{ + value: wormholeTransceiverChain2.quoteDeliveryPrice( + chainId1, buildTransceiverInstruction(false) ) }( sendingAmount, chainId1, bytes32(uint256(uint160(userD))), false, - encodeEndpointInstruction(false) + encodeTransceiverInstruction(false) ); supplyAfter = token2.totalSupply(); @@ -358,8 +363,8 @@ contract TestEndToEndRelayer is require(token2.balanceOf(userB) == 0, "OG user receive tokens"); require(token2.balanceOf(userC) == 0, "Sending user didn't receive tokens"); require( - token2.balanceOf(address(managerChain2)) == 0, - "Manager didn't receive unintended funds" + token2.balanceOf(address(nttManagerChain2)) == 0, + "NttManager didn't receive unintended funds" ); } @@ -380,7 +385,8 @@ contract TestEndToEndRelayer is require(token1.balanceOf(userC) == 0, "UserC received funds on the transfer back"); require(token1.balanceOf(userD) == sendingAmount, "User didn't receive tokens going back"); require( - token1.balanceOf(address(managerChain1)) == 0, "Manager has unintended funds going back" + token1.balanceOf(address(nttManagerChain1)) == 0, + "NttManager has unintended funds going back" ); } @@ -398,11 +404,11 @@ contract TestEndToEndRelayer is contract TestRelayerEndToEndManual is TestEndToEndRelayerBase, - IManagerEvents, + INttManagerEvents, IRateLimiterEvents { - Manager managerChain1; - Manager managerChain2; + NttManager nttManagerChain1; + NttManager nttManagerChain2; using NormalizedAmountLib for uint256; using NormalizedAmountLib for NormalizedAmount; @@ -433,92 +439,93 @@ contract TestRelayerEndToEndManual is vm.chainId(chainId1); DummyToken t1 = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t1), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t1), NttManager.Mode.LOCKING, chainId1, 1 days); - managerChain1 = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - managerChain1.initialize(); + nttManagerChain1 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerChain1.initialize(); - wormholeEndpointChain1 = new MockWormholeEndpointContract( - address(managerChain1), + wormholeTransceiverChain1 = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain1), "")) + wormholeTransceiverChain1 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain1), "")) ); - wormholeEndpointChain1.initialize(); + wormholeTransceiverChain1.initialize(); - managerChain1.setEndpoint(address(wormholeEndpointChain1)); - managerChain1.setOutboundLimit(type(uint64).max); - managerChain1.setInboundLimit(type(uint64).max, chainId2); + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1)); + nttManagerChain1.setOutboundLimit(type(uint64).max); + nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); // Chain 2 setup vm.chainId(chainId2); DummyToken t2 = new DummyTokenMintAndBurn(); - Manager implementationChain2 = - new MockManagerContract(address(t2), Manager.Mode.BURNING, chainId2, 1 days); - - managerChain2 = - MockManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); - managerChain2.initialize(); - wormholeEndpointChain2 = new MockWormholeEndpointContract( - address(managerChain2), + NttManager implementationChain2 = + new MockNttManagerContract(address(t2), NttManager.Mode.BURNING, chainId2, 1 days); + + nttManagerChain2 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); + nttManagerChain2.initialize(); + wormholeTransceiverChain2 = new MockWormholeTransceiverContract( + address(nttManagerChain2), address(wormhole), address(relayer), // TODO - add support for this later address(0x0), // TODO - add support for this later FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain2 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain2), "")) + wormholeTransceiverChain2 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain2), "")) ); - wormholeEndpointChain2.initialize(); + wormholeTransceiverChain2.initialize(); - managerChain2.setEndpoint(address(wormholeEndpointChain2)); - managerChain2.setOutboundLimit(type(uint64).max); - managerChain2.setInboundLimit(type(uint64).max, chainId1); + nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2)); + nttManagerChain2.setOutboundLimit(type(uint64).max); + nttManagerChain2.setInboundLimit(type(uint64).max, chainId1); - // Register sibling contracts for the manager and endpoint. Endpoints and manager each have the concept of siblings here. - managerChain1.setSibling(chainId2, bytes32(uint256(uint160(address(managerChain2))))); - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(managerChain1))))); + // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here. + nttManagerChain1.setPeer(chainId2, bytes32(uint256(uint160(address(nttManagerChain2))))); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1))))); } - function test_relayerEndpointAuth() public { - // Set up sensible WH endpoint siblings - wormholeEndpointChain1.setWormholeSibling( - chainId2, bytes32(uint256(uint160((address(wormholeEndpointChain2))))) + function test_relayerTransceiverAuth() public { + // Set up sensible WH transceiver peers + wormholeTransceiverChain1.setWormholePeer( + chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2))))) ); - wormholeEndpointChain2.setWormholeSibling( - chainId1, bytes32(uint256(uint160(address(wormholeEndpointChain1)))) + wormholeTransceiverChain2.setWormholePeer( + chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); vm.recordLogs(); vm.chainId(chainId1); // Setting up the transfer - DummyToken token1 = DummyToken(managerChain1.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), 5 * 10 ** decimals); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); // Send token through the relayer { vm.deal(userA, 1 ether); - managerChain1.transfer{ - value: wormholeEndpointChain1.quoteDeliveryPrice( - chainId2, buildEndpointInstruction(false) + nttManagerChain1.transfer{ + value: wormholeTransceiverChain1.quoteDeliveryPrice( + chainId2, buildTransceiverInstruction(false) ) }( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, - encodeEndpointInstruction(false) + encodeTransceiverInstruction(false) ); } @@ -537,44 +544,46 @@ contract TestRelayerEndToEndManual is bytes[] memory a; - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(0x1))))); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(0x1))))); vm.startPrank(relayer); - vm.expectRevert(); // bad manager sibling - wormholeEndpointChain2.receiveWormholeMessages( + vm.expectRevert(); // bad nttManager peer + wormholeTransceiverChain2.receiveWormholeMessages( vaa.payload, a, - bytes32(uint256(uint160(address(wormholeEndpointChain1)))), + bytes32(uint256(uint160(address(wormholeTransceiverChain1)))), vaa.emitterChainId, vaa.hash ); vm.stopPrank(); // Wrong caller - aka not relayer contract - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(managerChain1))))); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1))))); vm.prank(userD); - vm.expectRevert(abi.encodeWithSelector(IWormholeEndpoint.CallerNotRelayer.selector, userD)); - wormholeEndpointChain2.receiveWormholeMessages( + vm.expectRevert( + abi.encodeWithSelector(IWormholeTransceiver.CallerNotRelayer.selector, userD) + ); + wormholeTransceiverChain2.receiveWormholeMessages( vaa.payload, a, - bytes32(uint256(uint160(address(wormholeEndpointChain1)))), + bytes32(uint256(uint160(address(wormholeTransceiverChain1)))), vaa.emitterChainId, vaa.hash ); vm.startPrank(relayer); - // Bad chain ID for a given endpoint + // Bad chain ID for a given transceiver vm.expectRevert( abi.encodeWithSelector( - IWormholeEndpoint.InvalidWormholeSibling.selector, + IWormholeTransceiver.InvalidWormholePeer.selector, 0xFF, - address(wormholeEndpointChain1) + address(wormholeTransceiverChain1) ) ); - wormholeEndpointChain2.receiveWormholeMessages( + wormholeTransceiverChain2.receiveWormholeMessages( vaa.payload, a, - bytes32(uint256(uint160(address(wormholeEndpointChain1)))), + bytes32(uint256(uint160(address(wormholeTransceiverChain1)))), 0xFF, vaa.hash ); @@ -585,57 +594,57 @@ contract TestRelayerEndToEndManual is This attempt should actually work this time. */ - wormholeEndpointChain2.receiveWormholeMessages( + wormholeTransceiverChain2.receiveWormholeMessages( vaa.payload, // Verified a, // Should be zero - bytes32(uint256(uint160(address(wormholeEndpointChain1)))), // Must be a wormhole siblings + bytes32(uint256(uint160(address(wormholeTransceiverChain1)))), // Must be a wormhole peers vaa.emitterChainId, // ChainID from the call vaa.hash // Hash of the VAA being used ); // Should from sending a *duplicate* message vm.expectRevert(); // Uses a custom error with a hash - don't know how to calculate the hash - wormholeEndpointChain2.receiveWormholeMessages( + wormholeTransceiverChain2.receiveWormholeMessages( vaa.payload, // Verified a, // Should be zero - bytes32(uint256(uint160(address(wormholeEndpointChain1)))), // Must be a wormhole siblings + bytes32(uint256(uint160(address(wormholeTransceiverChain1)))), // Must be a wormhole peers vaa.emitterChainId, // ChainID from the call vaa.hash // Hash of the VAA being used ); } - function test_relayerWithInvalidWHEndpoint() public { - // Set up dodgy wormhole endpoint siblings - wormholeEndpointChain2.setWormholeSibling(chainId1, bytes32(uint256(uint160(address(0x1))))); - wormholeEndpointChain1.setWormholeSibling( - chainId2, bytes32(uint256(uint160(address(wormholeEndpointChain2)))) + function test_relayerWithInvalidWHTransceiver() public { + // Set up dodgy wormhole transceiver peers + wormholeTransceiverChain2.setWormholePeer(chainId1, bytes32(uint256(uint160(address(0x1))))); + wormholeTransceiverChain1.setWormholePeer( + chainId2, bytes32(uint256(uint160(address(wormholeTransceiverChain2)))) ); vm.recordLogs(); vm.chainId(chainId1); // Setting up the transfer - DummyToken token1 = DummyToken(managerChain1.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), 5 * 10 ** decimals); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); // Send token through the relayer { vm.deal(userA, 1 ether); - managerChain1.transfer{ - value: wormholeEndpointChain1.quoteDeliveryPrice( - chainId2, buildEndpointInstruction(false) + nttManagerChain1.transfer{ + value: wormholeTransceiverChain1.quoteDeliveryPrice( + chainId2, buildTransceiverInstruction(false) ) }( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, - encodeEndpointInstruction(false) + encodeTransceiverInstruction(false) ); } @@ -657,15 +666,15 @@ contract TestRelayerEndToEndManual is vm.startPrank(relayer); vm.expectRevert( abi.encodeWithSelector( - IWormholeEndpoint.InvalidWormholeSibling.selector, + IWormholeTransceiver.InvalidWormholePeer.selector, chainId1, - address(wormholeEndpointChain1) + address(wormholeTransceiverChain1) ) ); - wormholeEndpointChain2.receiveWormholeMessages( + wormholeTransceiverChain2.receiveWormholeMessages( vaa.payload, a, - bytes32(uint256(uint160(address(wormholeEndpointChain1)))), + bytes32(uint256(uint160(address(wormholeTransceiverChain1)))), vaa.emitterChainId, vaa.hash ); diff --git a/evm/test/IntegrationStandalone.t.sol b/evm/test/IntegrationStandalone.t.sol index 17911f6fe..c9210f16f 100755 --- a/evm/test/IntegrationStandalone.t.sol +++ b/evm/test/IntegrationStandalone.t.sol @@ -4,19 +4,19 @@ pragma solidity >=0.8.8 <0.9.0; import "forge-std/Test.sol"; import "forge-std/console.sol"; -import "../src/Manager.sol"; -import "../src/Endpoint.sol"; -import "../src/interfaces/IManager.sol"; +import "../src/NttManager.sol"; +import "../src/Transceiver.sol"; +import "../src/interfaces/INttManager.sol"; import "../src/interfaces/IRateLimiter.sol"; -import "../src/interfaces/IManagerEvents.sol"; +import "../src/interfaces/INttManagerEvents.sol"; import "../src/interfaces/IRateLimiterEvents.sol"; import {Utils} from "./libraries/Utils.sol"; -import {DummyToken, DummyTokenMintAndBurn} from "./Manager.t.sol"; -import "../src/interfaces/IWormholeEndpoint.sol"; -import {WormholeEndpoint} from "../src/WormholeEndpoint.sol"; -import "../src/libraries/EndpointStructs.sol"; -import "./mocks/MockManager.sol"; -import "./mocks/MockEndpoints.sol"; +import {DummyToken, DummyTokenMintAndBurn} from "./NttManager.t.sol"; +import "../src/interfaces/IWormholeTransceiver.sol"; +import {WormholeTransceiver} from "../src/WormholeTransceiver.sol"; +import "../src/libraries/TransceiverStructs.sol"; +import "./mocks/MockNttManager.sol"; +import "./mocks/MockTransceivers.sol"; import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -25,9 +25,9 @@ import "wormhole-solidity-sdk/testing/helpers/WormholeSimulator.sol"; import "wormhole-solidity-sdk/Utils.sol"; //import "wormhole-solidity-sdk/testing/WormholeRelayerTest.sol"; -contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { - Manager managerChain1; - Manager managerChain2; +contract TestEndToEndBase is Test, INttManagerEvents, IRateLimiterEvents { + NttManager nttManagerChain1; + NttManager nttManagerChain2; using NormalizedAmountLib for uint256; using NormalizedAmountLib for NormalizedAmount; @@ -42,8 +42,8 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { WormholeSimulator guardian; uint256 initialBlockTimestamp; - WormholeEndpoint wormholeEndpointChain1; - WormholeEndpoint wormholeEndpointChain2; + WormholeTransceiver wormholeTransceiverChain1; + WormholeTransceiver wormholeTransceiverChain2; address userA = address(0x123); address userB = address(0x456); address userC = address(0x789); @@ -61,99 +61,100 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId1); DummyToken t1 = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t1), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t1), NttManager.Mode.LOCKING, chainId1, 1 days); - managerChain1 = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - managerChain1.initialize(); + nttManagerChain1 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerChain1.initialize(); - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointContract( - address(managerChain1), + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain1Implementation), "")) + wormholeTransceiverChain1 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain1Implementation), "")) ); - wormholeEndpointChain1.initialize(); + wormholeTransceiverChain1.initialize(); - managerChain1.setEndpoint(address(wormholeEndpointChain1)); - managerChain1.setOutboundLimit(type(uint64).max); - managerChain1.setInboundLimit(type(uint64).max, chainId2); + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1)); + nttManagerChain1.setOutboundLimit(type(uint64).max); + nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); // Chain 2 setup vm.chainId(chainId2); DummyToken t2 = new DummyTokenMintAndBurn(); - Manager implementationChain2 = - new MockManagerContract(address(t2), Manager.Mode.BURNING, chainId2, 1 days); + NttManager implementationChain2 = + new MockNttManagerContract(address(t2), NttManager.Mode.BURNING, chainId2, 1 days); - managerChain2 = - MockManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); - managerChain2.initialize(); + nttManagerChain2 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); + nttManagerChain2.initialize(); - WormholeEndpoint wormholeEndpointChain2Implementation = new MockWormholeEndpointContract( - address(managerChain2), + WormholeTransceiver wormholeTransceiverChain2Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain2), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain2 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain2Implementation), "")) + wormholeTransceiverChain2 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain2Implementation), "")) ); - wormholeEndpointChain2.initialize(); + wormholeTransceiverChain2.initialize(); - managerChain2.setEndpoint(address(wormholeEndpointChain2)); - managerChain2.setOutboundLimit(type(uint64).max); - managerChain2.setInboundLimit(type(uint64).max, chainId1); + nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2)); + nttManagerChain2.setOutboundLimit(type(uint64).max); + nttManagerChain2.setInboundLimit(type(uint64).max, chainId1); - // Register sibling contracts for the manager and endpoint. Endpoints and manager each have the concept of siblings here. - managerChain1.setSibling(chainId2, bytes32(uint256(uint160(address(managerChain2))))); - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(managerChain1))))); + // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here. + nttManagerChain1.setPeer(chainId2, bytes32(uint256(uint160(address(nttManagerChain2))))); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1))))); - // Set siblings for the endpoints - wormholeEndpointChain1.setWormholeSibling( - chainId2, bytes32(uint256(uint160(address(wormholeEndpointChain2)))) + // Set peers for the transceivers + wormholeTransceiverChain1.setWormholePeer( + chainId2, bytes32(uint256(uint160(address(wormholeTransceiverChain2)))) ); - wormholeEndpointChain2.setWormholeSibling( - chainId1, bytes32(uint256(uint160(address(wormholeEndpointChain1)))) + wormholeTransceiverChain2.setWormholePeer( + chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); - require(managerChain1.getThreshold() != 0, "Threshold is zero with active endpoints"); + require(nttManagerChain1.getThreshold() != 0, "Threshold is zero with active transceivers"); // Actually set it - managerChain1.setThreshold(1); - managerChain2.setThreshold(1); + nttManagerChain1.setThreshold(1); + nttManagerChain2.setThreshold(1); } function test_chainToChainBase() public { vm.chainId(chainId1); // Setting up the transfer - DummyToken token1 = DummyToken(managerChain1.token()); - DummyToken token2 = DummyTokenMintAndBurn(managerChain2.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), 5 * 10 ** decimals); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); vm.recordLogs(); // Send token through standard means (not relayer) { - uint256 managerBalanceBefore = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceBefore = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceBefore = token1.balanceOf(address(userA)); - managerChain1.transfer(sendingAmount, chainId2, bytes32(uint256(uint160(userB)))); + nttManagerChain1.transfer(sendingAmount, chainId2, bytes32(uint256(uint160(userB)))); // Balance check on funds going in and out working as expected - uint256 managerBalanceAfter = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); require( - managerBalanceBefore + sendingAmount == managerBalanceAfter, + nttManagerBalanceBefore + sendingAmount == nttManagerBalanceAfter, "Should be locking the tokens" ); require( @@ -175,38 +176,40 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId2); vm.expectRevert(); // Wrong chain receiving the signed VAA - wormholeEndpointChain1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); { uint256 supplyBefore = token2.totalSupply(); - wormholeEndpointChain2.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); uint256 supplyAfter = token2.totalSupply(); require(sendingAmount + supplyBefore == supplyAfter, "Supplies dont match"); require(token2.balanceOf(userB) == sendingAmount, "User didn't receive tokens"); - require(token2.balanceOf(address(managerChain2)) == 0, "Manager has unintended funds"); + require( + token2.balanceOf(address(nttManagerChain2)) == 0, "NttManager has unintended funds" + ); } // Can't resubmit the same message twice vm.expectRevert(); // TransferAlreadyCompleted error - wormholeEndpointChain2.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); // Go back the other way from a THIRD user vm.prank(userB); token2.transfer(userC, sendingAmount); vm.startPrank(userC); - token2.approve(address(managerChain2), sendingAmount); + token2.approve(address(nttManagerChain2), sendingAmount); vm.recordLogs(); // Supply checks on the transfer { uint256 supplyBefore = token2.totalSupply(); - managerChain2.transfer( + nttManagerChain2.transfer( sendingAmount, chainId1, bytes32(uint256(uint160(userD))), false, - encodeEndpointInstruction(true) + encodeTransceiverInstruction(true) ); uint256 supplyAfter = token2.totalSupply(); @@ -215,8 +218,8 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { require(token2.balanceOf(userB) == 0, "OG user receive tokens"); require(token2.balanceOf(userC) == 0, "Sending user didn't receive tokens"); require( - token2.balanceOf(address(managerChain2)) == 0, - "Manager didn't receive unintended funds" + token2.balanceOf(address(nttManagerChain2)) == 0, + "NttManager didn't receive unintended funds" ); } @@ -232,7 +235,7 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { { uint256 supplyBefore = token1.totalSupply(); - wormholeEndpointChain1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); uint256 supplyAfter = token1.totalSupply(); @@ -247,34 +250,34 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId1); // Setting up the transfer - DummyToken token1 = DummyToken(managerChain1.token()); - DummyToken token2 = DummyTokenMintAndBurn(managerChain2.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), 5 * 10 ** decimals); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); vm.recordLogs(); // Send token through standard means (not relayer) { - uint256 managerBalanceBefore = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceBefore = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceBefore = token1.balanceOf(address(userA)); - managerChain1.transfer( + nttManagerChain1.transfer( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), true, - encodeEndpointInstruction(true) + encodeTransceiverInstruction(true) ); // Balance check on funds going in and out working as expected - uint256 managerBalanceAfter = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); require( - managerBalanceBefore + sendingAmount == managerBalanceAfter, + nttManagerBalanceBefore + sendingAmount == nttManagerBalanceAfter, "Should be locking the tokens" ); require( @@ -294,32 +297,36 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { vm.expectRevert( abi.encodeWithSelector( - IWormholeEndpoint.InvalidWormholeSibling.selector, chainId1, wormholeEndpointChain1 + IWormholeTransceiver.InvalidWormholePeer.selector, + chainId1, + wormholeTransceiverChain1 ) ); // Wrong chain receiving the signed VAA - wormholeEndpointChain1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); vm.chainId(chainId2); { uint256 supplyBefore = token2.totalSupply(); - wormholeEndpointChain2.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); uint256 supplyAfter = token2.totalSupply(); require(sendingAmount + supplyBefore == supplyAfter, "Supplies dont match"); require(token2.balanceOf(userB) == sendingAmount, "User didn't receive tokens"); - require(token2.balanceOf(address(managerChain2)) == 0, "Manager has unintended funds"); + require( + token2.balanceOf(address(nttManagerChain2)) == 0, "NttManager has unintended funds" + ); } // Can't resubmit the same message twice vm.expectRevert(); // TransferAlreadyCompleted error - wormholeEndpointChain2.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); // Go back the other way from a THIRD user vm.prank(userB); token2.transfer(userC, sendingAmount); vm.startPrank(userC); - token2.approve(address(managerChain2), sendingAmount); + token2.approve(address(nttManagerChain2), sendingAmount); vm.recordLogs(); // Supply checks on the transfer @@ -327,31 +334,31 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { uint256 supplyBefore = token2.totalSupply(); vm.stopPrank(); - managerChain2.setOutboundLimit(0); + nttManagerChain2.setOutboundLimit(0); vm.startPrank(userC); - managerChain2.transfer( + nttManagerChain2.transfer( sendingAmount, chainId1, bytes32(uint256(uint160(userD))), true, - encodeEndpointInstruction(true) + encodeTransceiverInstruction(true) ); // Test timing on the queues vm.expectRevert(); - managerChain2.completeOutboundQueuedTransfer(0); + nttManagerChain2.completeOutboundQueuedTransfer(0); vm.warp(vm.getBlockTimestamp() + 1 days - 1); vm.expectRevert(); - managerChain2.completeOutboundQueuedTransfer(0); + nttManagerChain2.completeOutboundQueuedTransfer(0); vm.warp(vm.getBlockTimestamp() + 1); - managerChain2.completeOutboundQueuedTransfer(0); + nttManagerChain2.completeOutboundQueuedTransfer(0); vm.expectRevert(); // Replay - should be deleted - managerChain2.completeOutboundQueuedTransfer(0); + nttManagerChain2.completeOutboundQueuedTransfer(0); vm.expectRevert(); // Non-existant - managerChain2.completeOutboundQueuedTransfer(1); + nttManagerChain2.completeOutboundQueuedTransfer(1); uint256 supplyAfter = token2.totalSupply(); @@ -359,8 +366,8 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { require(token2.balanceOf(userB) == 0, "OG user receive tokens"); require(token2.balanceOf(userC) == 0, "Sending user didn't receive tokens"); require( - token2.balanceOf(address(managerChain2)) == 0, - "Manager didn't receive unintended funds" + token2.balanceOf(address(nttManagerChain2)) == 0, + "NttManager didn't receive unintended funds" ); } @@ -379,19 +386,19 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { { uint256 supplyBefore = token1.totalSupply(); - managerChain1.setInboundLimit(0, chainId2); - wormholeEndpointChain1.receiveMessage(encodedVMs[0]); + nttManagerChain1.setInboundLimit(0, chainId2); + wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); bytes32[] memory queuedDigests = Utils.fetchQueuedTransferDigestsFromLogs(vm.getRecordedLogs()); vm.warp(vm.getBlockTimestamp() + 100000); - managerChain1.completeInboundQueuedTransfer(queuedDigests[0]); + nttManagerChain1.completeInboundQueuedTransfer(queuedDigests[0]); // Double redeem vm.warp(vm.getBlockTimestamp() + 100000); vm.expectRevert(); - managerChain1.completeInboundQueuedTransfer(queuedDigests[0]); + nttManagerChain1.completeInboundQueuedTransfer(queuedDigests[0]); uint256 supplyAfter = token1.totalSupply(); @@ -402,77 +409,77 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { } } - function test_multiEndpoint() public { + function test_multiTransceiver() public { vm.chainId(chainId1); - WormholeEndpoint wormholeEndpointChain1_1 = wormholeEndpointChain1; + WormholeTransceiver wormholeTransceiverChain1_1 = wormholeTransceiverChain1; - // Dual endpoint setup - WormholeEndpoint wormholeEndpointChain1_2 = new MockWormholeEndpointContract( - address(managerChain1), + // Dual transceiver setup + WormholeTransceiver wormholeTransceiverChain1_2 = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1_2 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain1_2), "")) + wormholeTransceiverChain1_2 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain1_2), "")) ); - wormholeEndpointChain1_2.initialize(); + wormholeTransceiverChain1_2.initialize(); vm.chainId(chainId2); - WormholeEndpoint wormholeEndpointChain2_1 = wormholeEndpointChain2; + WormholeTransceiver wormholeTransceiverChain2_1 = wormholeTransceiverChain2; - // Dual endpoint setup - WormholeEndpoint wormholeEndpointChain2_2 = new MockWormholeEndpointContract( - address(managerChain2), + // Dual transceiver setup + WormholeTransceiver wormholeTransceiverChain2_2 = new MockWormholeTransceiverContract( + address(nttManagerChain2), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain2_2 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain2_2), "")) + wormholeTransceiverChain2_2 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain2_2), "")) ); - wormholeEndpointChain2_2.initialize(); + wormholeTransceiverChain2_2.initialize(); // Setup the new entrypoint hook ups to allow the transfers to occur - wormholeEndpointChain1_2.setWormholeSibling( - chainId2, bytes32(uint256(uint160((address(wormholeEndpointChain2_2))))) + wormholeTransceiverChain1_2.setWormholePeer( + chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2_2))))) ); - wormholeEndpointChain2_2.setWormholeSibling( - chainId1, bytes32(uint256(uint160((address(wormholeEndpointChain1_2))))) + wormholeTransceiverChain2_2.setWormholePeer( + chainId1, bytes32(uint256(uint160((address(wormholeTransceiverChain1_2))))) ); - managerChain2.setEndpoint(address(wormholeEndpointChain2_2)); - managerChain1.setEndpoint(address(wormholeEndpointChain1_2)); + nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2_2)); + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1_2)); // Change the threshold from the setUp functions 1 to 2. - managerChain1.setThreshold(2); - managerChain2.setThreshold(2); + nttManagerChain1.setThreshold(2); + nttManagerChain2.setThreshold(2); // Setting up the transfer - DummyToken token1 = DummyToken(managerChain1.token()); - DummyToken token2 = DummyTokenMintAndBurn(managerChain2.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); vm.startPrank(userA); uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), sendingAmount); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); vm.recordLogs(); // Send token through standard means (not relayer) { - managerChain1.transfer( + nttManagerChain1.transfer( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, - encodeEndpointInstructions(true) + encodeTransceiverInstructions(true) ); } @@ -485,49 +492,51 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId2); - // Send in the messages for the two endpoints to complete the transfer from chain1 to chain2 + // Send in the messages for the two transceivers to complete the transfer from chain1 to chain2 { // vm.stopPrank(); uint256 supplyBefore = token2.totalSupply(); - wormholeEndpointChain2_1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2_1.receiveMessage(encodedVMs[0]); - vm.expectRevert(); // Invalid wormhole sibling - wormholeEndpointChain2_2.receiveMessage(encodedVMs[0]); + vm.expectRevert(); // Invalid wormhole peer + wormholeTransceiverChain2_2.receiveMessage(encodedVMs[0]); // Threshold check require(supplyBefore == token2.totalSupply(), "Supplies have been updated too early"); require(token2.balanceOf(userB) == 0, "User received tokens to early"); // Finish the transfer out once the second VAA arrives - wormholeEndpointChain2_2.receiveMessage(encodedVMs[1]); + wormholeTransceiverChain2_2.receiveMessage(encodedVMs[1]); uint256 supplyAfter = token2.totalSupply(); require(sendingAmount + supplyBefore == supplyAfter, "Supplies dont match"); require(token2.balanceOf(userB) == sendingAmount, "User didn't receive tokens"); - require(token2.balanceOf(address(managerChain2)) == 0, "Manager has unintended funds"); + require( + token2.balanceOf(address(nttManagerChain2)) == 0, "NttManager has unintended funds" + ); } // Back the other way for the burn! vm.startPrank(userB); - token2.approve(address(managerChain2), sendingAmount); + token2.approve(address(nttManagerChain2), sendingAmount); vm.recordLogs(); // Send token through standard means (not relayer) { uint256 userBalanceBefore = token1.balanceOf(address(userB)); - managerChain2.transfer( + nttManagerChain2.transfer( sendingAmount, chainId1, bytes32(uint256(uint160(userA))), false, - encodeEndpointInstructions(true) + encodeTransceiverInstructions(true) ); - uint256 managerBalanceAfter = token1.balanceOf(address(managerChain2)); + uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain2)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); require(userBalanceBefore - userBalanceAfter == 0, "No funds left for user"); - require(managerBalanceAfter == 0, "Manager should burn all tranferred tokens"); + require(nttManagerBalanceAfter == 0, "NttManager should burn all tranferred tokens"); } // Get the VAA proof for the transfers to use @@ -540,13 +549,13 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId1); { uint256 supplyBefore = token1.totalSupply(); - wormholeEndpointChain1_1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain1_1.receiveMessage(encodedVMs[0]); require(supplyBefore == token1.totalSupply(), "Supplies have been updated too early"); require(token2.balanceOf(userA) == 0, "User received tokens to early"); // Finish the transfer out once the second VAA arrives - wormholeEndpointChain1_2.receiveMessage(encodedVMs[1]); + wormholeTransceiverChain1_2.receiveMessage(encodedVMs[1]); uint256 supplyAfter = token1.totalSupply(); require( @@ -573,38 +582,38 @@ contract TestEndToEndBase is Test, IManagerEvents, IRateLimiterEvents { return copy; } - function encodeEndpointInstruction(bool relayer_off) public view returns (bytes memory) { - WormholeEndpoint.WormholeEndpointInstruction memory instruction = - WormholeEndpoint.WormholeEndpointInstruction(relayer_off); + function encodeTransceiverInstruction(bool relayer_off) public view returns (bytes memory) { + WormholeTransceiver.WormholeTransceiverInstruction memory instruction = + WormholeTransceiver.WormholeTransceiverInstruction(relayer_off); bytes memory encodedInstructionWormhole = - wormholeEndpointChain1.encodeWormholeEndpointInstruction(instruction); - EndpointStructs.EndpointInstruction memory EndpointInstruction = - EndpointStructs.EndpointInstruction({index: 0, payload: encodedInstructionWormhole}); - EndpointStructs.EndpointInstruction[] memory EndpointInstructions = - new EndpointStructs.EndpointInstruction[](1); - EndpointInstructions[0] = EndpointInstruction; - return EndpointStructs.encodeEndpointInstructions(EndpointInstructions); + wormholeTransceiverChain1.encodeWormholeTransceiverInstruction(instruction); + TransceiverStructs.TransceiverInstruction memory TransceiverInstruction = TransceiverStructs + .TransceiverInstruction({index: 0, payload: encodedInstructionWormhole}); + TransceiverStructs.TransceiverInstruction[] memory TransceiverInstructions = + new TransceiverStructs.TransceiverInstruction[](1); + TransceiverInstructions[0] = TransceiverInstruction; + return TransceiverStructs.encodeTransceiverInstructions(TransceiverInstructions); } // Encode an instruction for each of the relayers - function encodeEndpointInstructions(bool relayer_off) public view returns (bytes memory) { - WormholeEndpoint.WormholeEndpointInstruction memory instruction = - WormholeEndpoint.WormholeEndpointInstruction(relayer_off); + function encodeTransceiverInstructions(bool relayer_off) public view returns (bytes memory) { + WormholeTransceiver.WormholeTransceiverInstruction memory instruction = + WormholeTransceiver.WormholeTransceiverInstruction(relayer_off); bytes memory encodedInstructionWormhole = - wormholeEndpointChain1.encodeWormholeEndpointInstruction(instruction); + wormholeTransceiverChain1.encodeWormholeTransceiverInstruction(instruction); - EndpointStructs.EndpointInstruction memory EndpointInstruction1 = - EndpointStructs.EndpointInstruction({index: 0, payload: encodedInstructionWormhole}); - EndpointStructs.EndpointInstruction memory EndpointInstruction2 = - EndpointStructs.EndpointInstruction({index: 1, payload: encodedInstructionWormhole}); + TransceiverStructs.TransceiverInstruction memory TransceiverInstruction1 = + TransceiverStructs.TransceiverInstruction({index: 0, payload: encodedInstructionWormhole}); + TransceiverStructs.TransceiverInstruction memory TransceiverInstruction2 = + TransceiverStructs.TransceiverInstruction({index: 1, payload: encodedInstructionWormhole}); - EndpointStructs.EndpointInstruction[] memory EndpointInstructions = - new EndpointStructs.EndpointInstruction[](2); + TransceiverStructs.TransceiverInstruction[] memory TransceiverInstructions = + new TransceiverStructs.TransceiverInstruction[](2); - EndpointInstructions[0] = EndpointInstruction1; - EndpointInstructions[1] = EndpointInstruction2; + TransceiverInstructions[0] = TransceiverInstruction1; + TransceiverInstructions[1] = TransceiverInstruction2; - return EndpointStructs.encodeEndpointInstructions(EndpointInstructions); + return TransceiverStructs.encodeTransceiverInstructions(TransceiverInstructions); } } diff --git a/evm/test/Manager.t.sol b/evm/test/Manager.t.sol deleted file mode 100644 index 2ba77c6f0..000000000 --- a/evm/test/Manager.t.sol +++ /dev/null @@ -1,539 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity >=0.8.8 <0.9.0; - -import "forge-std/Test.sol"; -import "forge-std/console.sol"; - -import "../src/Manager.sol"; -import "../src/interfaces/IManager.sol"; -import "../src/interfaces/IRateLimiter.sol"; -import "../src/interfaces/IManagerEvents.sol"; -import "../src/interfaces/IRateLimiterEvents.sol"; -import {Utils} from "./libraries/Utils.sol"; - -import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; -import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; -import "wormhole-solidity-sdk/testing/helpers/WormholeSimulator.sol"; -import "wormhole-solidity-sdk/Utils.sol"; -import "./libraries/EndpointHelpers.sol"; -import "./libraries/ManagerHelpers.sol"; -import "./interfaces/IEndpointReceiver.sol"; -import "./mocks/DummyEndpoint.sol"; -import "./mocks/DummyToken.sol"; -import "./mocks/MockManager.sol"; - -// TODO: set this up so the common functionality tests can be run against both -contract TestManager is Test, IManagerEvents, IRateLimiterEvents { - MockManagerContract manager; - MockManagerContract managerOther; - - using NormalizedAmountLib for uint256; - using NormalizedAmountLib for NormalizedAmount; - - // 0x99'E''T''T' - uint16 constant chainId = 7; - uint256 constant DEVNET_GUARDIAN_PK = - 0xcfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0; - WormholeSimulator guardian; - uint256 initialBlockTimestamp; - - function setUp() public { - string memory url = "https://ethereum-goerli.publicnode.com"; - IWormhole wormhole = IWormhole(0x706abc4E45D419950511e474C7B9Ed348A4a716c); - vm.createSelectFork(url); - initialBlockTimestamp = vm.getBlockTimestamp(); - - guardian = new WormholeSimulator(address(wormhole), DEVNET_GUARDIAN_PK); - - DummyToken t = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t), Manager.Mode.LOCKING, chainId, 1 days); - - Manager otherImplementation = - new MockManagerContract(address(t), Manager.Mode.LOCKING, chainId, 1 days); - - manager = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - manager.initialize(); - - managerOther = - MockManagerContract(address(new ERC1967Proxy(address(otherImplementation), ""))); - managerOther.initialize(); - } - - // === pure unit tests - - function test_countSetBits() public { - assertEq(countSetBits(5), 2); - assertEq(countSetBits(0), 0); - assertEq(countSetBits(15), 4); - assertEq(countSetBits(16), 1); - assertEq(countSetBits(65535), 16); - } - - // === ownership - - function test_owner() public { - // TODO: implement separate governance contract - assertEq(manager.owner(), address(this)); - } - - function test_transferOwnership() public { - address newOwner = address(0x123); - manager.transferOwnership(newOwner); - assertEq(manager.owner(), newOwner); - } - - function test_onlyOwnerCanTransferOwnership() public { - address notOwner = address(0x123); - vm.startPrank(notOwner); - - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); - manager.transferOwnership(address(0x456)); - } - - // === endpoint registration - - function test_registerEndpoint() public { - DummyEndpoint e = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e)); - } - - function test_onlyOwnerCanModifyEndpoints() public { - DummyEndpoint e = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e)); - - address notOwner = address(0x123); - vm.startPrank(notOwner); - - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); - manager.setEndpoint(address(e)); - - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); - manager.removeEndpoint(address(e)); - } - - function test_cantEnableEndpointTwice() public { - DummyEndpoint e = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e)); - - vm.expectRevert(abi.encodeWithSignature("EndpointAlreadyEnabled(address)", address(e))); - manager.setEndpoint(address(e)); - } - - function test_disableReenableEndpoint() public { - DummyEndpoint e = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e)); - manager.removeEndpoint(address(e)); - manager.setEndpoint(address(e)); - } - - function test_multipleEndpoints() public { - DummyEndpoint e1 = new DummyEndpoint(address(manager)); - DummyEndpoint e2 = new DummyEndpoint(address(manager)); - - manager.setEndpoint(address(e1)); - manager.setEndpoint(address(e2)); - } - - function test_endpointIncompatibleManager() public { - // Endpoint instantiation reverts if the manager doesn't have the proper token method - vm.expectRevert(bytes("")); - new DummyEndpoint(address(0xBEEF)); - } - - function test_endpointWrongManager() public { - // TODO: this is accepted currently. should we include a check to ensure - // only endpoints whose manager is us can be registered? (this would be - // a convenience check, not a security one) - DummyToken t = new DummyToken(); - Manager altManager = - new MockManagerContract(address(t), Manager.Mode.LOCKING, chainId, 1 days); - DummyEndpoint e = new DummyEndpoint(address(altManager)); - manager.setEndpoint(address(e)); - } - - function test_notEndpoint() public { - // TODO: this is accepted currently. should we include a check to ensure - // only endpoints can be registered? (this would be a convenience check, not a security one) - manager.setEndpoint(address(0x123)); - } - - // == threshold - - function test_cantSetThresholdTooHigh() public { - // no endpoints set, so can't set threshold to 1 - vm.expectRevert(abi.encodeWithSignature("ThresholdTooHigh(uint256,uint256)", 1, 0)); - manager.setThreshold(1); - } - - function test_canSetThreshold() public { - DummyEndpoint e1 = new DummyEndpoint(address(manager)); - DummyEndpoint e2 = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e1)); - manager.setEndpoint(address(e2)); - - manager.setThreshold(1); - manager.setThreshold(2); - manager.setThreshold(1); - } - - function test_cantSetThresholdToZero() public { - DummyEndpoint e = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e)); - - vm.expectRevert(abi.encodeWithSignature("ZeroThreshold()")); - manager.setThreshold(0); - } - - function test_onlyOwnerCanSetThreshold() public { - address notOwner = address(0x123); - vm.startPrank(notOwner); - - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); - manager.setThreshold(1); - } - - // === attestation - - function test_onlyEnabledEndpointsCanAttest() public { - (DummyEndpoint e1,) = EndpointHelpersLib.setup_endpoints(managerOther); - managerOther.removeEndpoint(address(e1)); - bytes32 sibling = toWormholeFormat(address(manager)); - managerOther.setSibling(EndpointHelpersLib.SENDING_CHAIN_ID, sibling); - - bytes memory endpointMessage; - (, endpointMessage) = EndpointHelpersLib.buildEndpointMessageWithManagerPayload( - 0, bytes32(0), sibling, toWormholeFormat(address(managerOther)), abi.encode("payload") - ); - - vm.expectRevert(abi.encodeWithSignature("CallerNotEndpoint(address)", address(e1))); - e1.receiveMessage(endpointMessage); - } - - function test_onlySiblingManagerCanAttest() public { - (DummyEndpoint e1,) = EndpointHelpersLib.setup_endpoints(managerOther); - managerOther.setThreshold(2); - - bytes32 sibling = toWormholeFormat(address(manager)); - - EndpointStructs.ManagerMessage memory managerMessage; - bytes memory endpointMessage; - (managerMessage, endpointMessage) = EndpointHelpersLib - .buildEndpointMessageWithManagerPayload( - 0, bytes32(0), sibling, toWormholeFormat(address(managerOther)), abi.encode("payload") - ); - - vm.expectRevert( - abi.encodeWithSignature( - "InvalidSibling(uint16,bytes32)", EndpointHelpersLib.SENDING_CHAIN_ID, sibling - ) - ); - e1.receiveMessage(endpointMessage); - } - - function test_attestSimple() public { - (DummyEndpoint e1,) = EndpointHelpersLib.setup_endpoints(managerOther); - managerOther.setThreshold(2); - - // register manager sibling - bytes32 sibling = toWormholeFormat(address(manager)); - managerOther.setSibling(EndpointHelpersLib.SENDING_CHAIN_ID, sibling); - - EndpointStructs.ManagerMessage memory managerMessage; - bytes memory endpointMessage; - (managerMessage, endpointMessage) = EndpointHelpersLib - .buildEndpointMessageWithManagerPayload( - 0, bytes32(0), sibling, toWormholeFormat(address(managerOther)), abi.encode("payload") - ); - - e1.receiveMessage(endpointMessage); - - bytes32 hash = EndpointStructs.managerMessageDigest( - EndpointHelpersLib.SENDING_CHAIN_ID, managerMessage - ); - assertEq(managerOther.messageAttestations(hash), 1); - } - - function test_attestTwice() public { - (DummyEndpoint e1,) = EndpointHelpersLib.setup_endpoints(managerOther); - managerOther.setThreshold(2); - - // register manager sibling - bytes32 sibling = toWormholeFormat(address(manager)); - managerOther.setSibling(EndpointHelpersLib.SENDING_CHAIN_ID, sibling); - - EndpointStructs.ManagerMessage memory managerMessage; - bytes memory endpointMessage; - (managerMessage, endpointMessage) = EndpointHelpersLib - .buildEndpointMessageWithManagerPayload( - 0, bytes32(0), sibling, toWormholeFormat(address(managerOther)), abi.encode("payload") - ); - - bytes32 hash = EndpointStructs.managerMessageDigest( - EndpointHelpersLib.SENDING_CHAIN_ID, managerMessage - ); - - e1.receiveMessage(endpointMessage); - vm.expectRevert(abi.encodeWithSignature("EndpointAlreadyAttestedToMessage(bytes32)", hash)); - e1.receiveMessage(endpointMessage); - - // can't double vote - assertEq(managerOther.messageAttestations(hash), 1); - } - - function test_attestDisabled() public { - (DummyEndpoint e1,) = EndpointHelpersLib.setup_endpoints(managerOther); - managerOther.setThreshold(2); - - bytes32 sibling = toWormholeFormat(address(manager)); - managerOther.setSibling(EndpointHelpersLib.SENDING_CHAIN_ID, sibling); - - IEndpointReceiver[] memory endpoints = new IEndpointReceiver[](1); - endpoints[0] = e1; - - EndpointStructs.ManagerMessage memory m; - (m,) = EndpointHelpersLib.attestEndpointsHelper( - address(0x456), - 0, - chainId, - manager, - managerOther, - NormalizedAmount(50, 8), - NormalizedAmount(type(uint64).max, 8), - endpoints - ); - - managerOther.removeEndpoint(address(e1)); - - bytes32 hash = EndpointStructs.managerMessageDigest(EndpointHelpersLib.SENDING_CHAIN_ID, m); - // a disabled endpoint's vote no longer counts - assertEq(managerOther.messageAttestations(hash), 0); - - managerOther.setEndpoint(address(e1)); - // it counts again when reenabled - assertEq(managerOther.messageAttestations(hash), 1); - } - - function test_transfer_sequences() public { - address user_A = address(0x123); - address user_B = address(0x456); - - DummyToken token = DummyToken(manager.token()); - - uint8 decimals = token.decimals(); - - manager.setOutboundLimit(NormalizedAmount(type(uint64).max, 8).denormalize(decimals)); - - token.mintDummy(address(user_A), 5 * 10 ** decimals); - - vm.startPrank(user_A); - - token.approve(address(manager), 3 * 10 ** decimals); - - uint64 s1 = manager.transfer( - 1 * 10 ** decimals, chainId, toWormholeFormat(user_B), false, new bytes(1) - ); - uint64 s2 = manager.transfer( - 1 * 10 ** decimals, chainId, toWormholeFormat(user_B), false, new bytes(1) - ); - uint64 s3 = manager.transfer( - 1 * 10 ** decimals, chainId, toWormholeFormat(user_B), false, new bytes(1) - ); - - assertEq(s1, 0); - assertEq(s2, 1); - assertEq(s3, 2); - } - - function test_attestationQuorum() public { - address user_B = address(0x456); - - (DummyEndpoint e1, DummyEndpoint e2) = EndpointHelpersLib.setup_endpoints(managerOther); - - NormalizedAmount memory transferAmount = NormalizedAmount(50, 8); - - EndpointStructs.ManagerMessage memory m; - bytes memory encodedEm; - { - IEndpointReceiver[] memory endpoints = new IEndpointReceiver[](2); - endpoints[0] = e1; - endpoints[1] = e2; - - EndpointStructs.EndpointMessage memory em; - (m, em) = EndpointHelpersLib.attestEndpointsHelper( - user_B, - 0, - chainId, - manager, - managerOther, - transferAmount, - NormalizedAmount(type(uint64).max, 8), - endpoints - ); - encodedEm = EndpointStructs.encodeEndpointMessage( - EndpointHelpersLib.TEST_ENDPOINT_PAYLOAD_PREFIX, em - ); - } - - { - DummyToken token = DummyToken(manager.token()); - assertEq(token.balanceOf(address(user_B)), transferAmount.denormalize(token.decimals())); - } - - // replay protection - vm.recordLogs(); - e2.receiveMessage(encodedEm); - - { - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 2); - assertEq(entries[1].topics.length, 3); - assertEq(entries[1].topics[0], keccak256("MessageAlreadyExecuted(bytes32,bytes32)")); - assertEq(entries[1].topics[1], toWormholeFormat(address(manager))); - assertEq( - entries[1].topics[2], - EndpointStructs.managerMessageDigest(EndpointHelpersLib.SENDING_CHAIN_ID, m) - ); - } - } - - // TODO: - // currently there is no way to test the threshold logic and the duplicate - // protection logic without setting up the business logic as well. - // - // we should separate the business logic out from the endpoint handling. - // that way the functionality could be tested separately (and the contracts - // would also be more reusable) - - // === storage - - function test_noAutomaticSlot() public { - DummyToken t = new DummyToken(); - MockManagerContract c = new MockManagerContract(address(t), Manager.Mode.LOCKING, 1, 1 days); - assertEq(c.lastSlot(), 0x0); - } - - function test_constructor() public { - DummyToken t = new DummyToken(); - - vm.startStateDiffRecording(); - - new MockManagerContract(address(t), Manager.Mode.LOCKING, 1, 1 days); - - Utils.assertSafeUpgradeableConstructor(vm.stopAndReturnStateDiff()); - } - - // === token transfer logic - - function test_dustReverts() public { - // transfer 3 tokens - address from = address(0x123); - address to = address(0x456); - - DummyToken token = DummyToken(manager.token()); - - uint8 decimals = token.decimals(); - - uint256 maxAmount = 5 * 10 ** decimals; - token.mintDummy(from, maxAmount); - manager.setOutboundLimit(NormalizedAmount(type(uint64).max, 8).denormalize(decimals)); - manager.setInboundLimit( - NormalizedAmount(type(uint64).max, 8).denormalize(decimals), - EndpointHelpersLib.SENDING_CHAIN_ID - ); - - vm.startPrank(from); - - uint256 transferAmount = 3 * 10 ** decimals; - assertEq( - transferAmount < maxAmount - 500, true, "Transferring more tokens than what exists" - ); - - uint256 dustAmount = 500; - uint256 amountWithDust = transferAmount + dustAmount; // An amount with 19 digits, which will result in dust due to 18 decimals - token.approve(address(manager), amountWithDust); - - vm.expectRevert( - abi.encodeWithSignature( - "TransferAmountHasDust(uint256,uint256)", amountWithDust, dustAmount - ) - ); - manager.transfer(amountWithDust, chainId, toWormholeFormat(to), false, new bytes(1)); - - vm.stopPrank(); - } - - // === upgradeability - function expectRevert( - address contractAddress, - bytes memory encodedSignature, - bytes memory expectedRevert - ) internal { - (bool success, bytes memory result) = contractAddress.call(encodedSignature); - require(!success, "call did not revert"); - - require(keccak256(result) == keccak256(expectedRevert), "call did not revert as expected"); - } - - function test_upgradeManager() public { - // The testing strategy here is as follows: - // Step 1: Deploy the manager contract with two endpoints and - // receive a message through it. - // Step 2: Upgrade it to a new manager contract an use the same endpoints to receive - // a new message through it. - // Step 3: Upgrade back to the standalone contract (with two - // endpoints) and receive a message through it. - // This ensures that the storage slots don't get clobbered through the upgrades. - - address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); - NormalizedAmount memory transferAmount = NormalizedAmount(50, 8); - (IEndpointReceiver e1, IEndpointReceiver e2) = - EndpointHelpersLib.setup_endpoints(managerOther); - - // Step 1 (contract is deployed by setUp()) - IEndpointReceiver[] memory endpoints = new IEndpointReceiver[](2); - endpoints[0] = e1; - endpoints[1] = e2; - - EndpointStructs.ManagerMessage memory m; - bytes memory encodedEm; - { - EndpointStructs.EndpointMessage memory em; - (m, em) = EndpointHelpersLib.attestEndpointsHelper( - user_B, - 0, - chainId, - manager, - managerOther, - transferAmount, - NormalizedAmount(type(uint64).max, 8), - endpoints - ); - encodedEm = EndpointStructs.encodeEndpointMessage( - EndpointHelpersLib.TEST_ENDPOINT_PAYLOAD_PREFIX, em - ); - } - - assertEq(token.balanceOf(address(user_B)), transferAmount.denormalize(token.decimals())); - - // Step 2 (upgrade to a new manager) - MockManagerContract newManager = - new MockManagerContract(manager.token(), Manager.Mode.LOCKING, chainId, 1 days); - managerOther.upgrade(address(newManager)); - - EndpointHelpersLib.attestEndpointsHelper( - user_B, - 1, - chainId, - manager, // this is the proxy - managerOther, // this is the proxy - transferAmount, - NormalizedAmount(type(uint64).max, 8), - endpoints - ); - - assertEq(token.balanceOf(address(user_B)), transferAmount.denormalize(token.decimals()) * 2); - } -} diff --git a/evm/test/NttManager.t.sol b/evm/test/NttManager.t.sol new file mode 100644 index 000000000..df297b592 --- /dev/null +++ b/evm/test/NttManager.t.sol @@ -0,0 +1,546 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import "../src/NttManager.sol"; +import "../src/interfaces/INttManager.sol"; +import "../src/interfaces/IRateLimiter.sol"; +import "../src/interfaces/INttManagerEvents.sol"; +import "../src/interfaces/IRateLimiterEvents.sol"; +import {Utils} from "./libraries/Utils.sol"; + +import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; +import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; +import "wormhole-solidity-sdk/testing/helpers/WormholeSimulator.sol"; +import "wormhole-solidity-sdk/Utils.sol"; +import "./libraries/TransceiverHelpers.sol"; +import "./libraries/NttManagerHelpers.sol"; +import "./interfaces/ITransceiverReceiver.sol"; +import "./mocks/DummyTransceiver.sol"; +import "./mocks/DummyToken.sol"; +import "./mocks/MockNttManager.sol"; + +// TODO: set this up so the common functionality tests can be run against both +contract TestNttManager is Test, INttManagerEvents, IRateLimiterEvents { + MockNttManagerContract nttManager; + MockNttManagerContract nttManagerOther; + + using NormalizedAmountLib for uint256; + using NormalizedAmountLib for NormalizedAmount; + + // 0x99'E''T''T' + uint16 constant chainId = 7; + uint256 constant DEVNET_GUARDIAN_PK = + 0xcfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0; + WormholeSimulator guardian; + uint256 initialBlockTimestamp; + + function setUp() public { + string memory url = "https://ethereum-goerli.publicnode.com"; + IWormhole wormhole = IWormhole(0x706abc4E45D419950511e474C7B9Ed348A4a716c); + vm.createSelectFork(url); + initialBlockTimestamp = vm.getBlockTimestamp(); + + guardian = new WormholeSimulator(address(wormhole), DEVNET_GUARDIAN_PK); + + DummyToken t = new DummyToken(); + NttManager implementation = + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, chainId, 1 days); + + NttManager otherImplementation = + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, chainId, 1 days); + + nttManager = MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManager.initialize(); + + nttManagerOther = + MockNttManagerContract(address(new ERC1967Proxy(address(otherImplementation), ""))); + nttManagerOther.initialize(); + } + + // === pure unit tests + + function test_countSetBits() public { + assertEq(countSetBits(5), 2); + assertEq(countSetBits(0), 0); + assertEq(countSetBits(15), 4); + assertEq(countSetBits(16), 1); + assertEq(countSetBits(65535), 16); + } + + // === ownership + + function test_owner() public { + // TODO: implement separate governance contract + assertEq(nttManager.owner(), address(this)); + } + + function test_transferOwnership() public { + address newOwner = address(0x123); + nttManager.transferOwnership(newOwner); + assertEq(nttManager.owner(), newOwner); + } + + function test_onlyOwnerCanTransferOwnership() public { + address notOwner = address(0x123); + vm.startPrank(notOwner); + + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); + nttManager.transferOwnership(address(0x456)); + } + + // === transceiver registration + + function test_registerTransceiver() public { + DummyTransceiver e = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e)); + } + + function test_onlyOwnerCanModifyTransceivers() public { + DummyTransceiver e = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e)); + + address notOwner = address(0x123); + vm.startPrank(notOwner); + + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); + nttManager.setTransceiver(address(e)); + + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); + nttManager.removeTransceiver(address(e)); + } + + function test_cantEnableTransceiverTwice() public { + DummyTransceiver e = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e)); + + vm.expectRevert(abi.encodeWithSignature("TransceiverAlreadyEnabled(address)", address(e))); + nttManager.setTransceiver(address(e)); + } + + function test_disableReenableTransceiver() public { + DummyTransceiver e = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e)); + nttManager.removeTransceiver(address(e)); + nttManager.setTransceiver(address(e)); + } + + function test_multipleTransceivers() public { + DummyTransceiver e1 = new DummyTransceiver(address(nttManager)); + DummyTransceiver e2 = new DummyTransceiver(address(nttManager)); + + nttManager.setTransceiver(address(e1)); + nttManager.setTransceiver(address(e2)); + } + + function test_transceiverIncompatibleNttManager() public { + // Transceiver instantiation reverts if the nttManager doesn't have the proper token method + vm.expectRevert(bytes("")); + new DummyTransceiver(address(0xBEEF)); + } + + function test_transceiverWrongNttManager() public { + // TODO: this is accepted currently. should we include a check to ensure + // only transceivers whose nttManager is us can be registered? (this would be + // a convenience check, not a security one) + DummyToken t = new DummyToken(); + NttManager altNttManager = + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, chainId, 1 days); + DummyTransceiver e = new DummyTransceiver(address(altNttManager)); + nttManager.setTransceiver(address(e)); + } + + function test_notTransceiver() public { + // TODO: this is accepted currently. should we include a check to ensure + // only transceivers can be registered? (this would be a convenience check, not a security one) + nttManager.setTransceiver(address(0x123)); + } + + // == threshold + + function test_cantSetThresholdTooHigh() public { + // no transceivers set, so can't set threshold to 1 + vm.expectRevert(abi.encodeWithSignature("ThresholdTooHigh(uint256,uint256)", 1, 0)); + nttManager.setThreshold(1); + } + + function test_canSetThreshold() public { + DummyTransceiver e1 = new DummyTransceiver(address(nttManager)); + DummyTransceiver e2 = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e1)); + nttManager.setTransceiver(address(e2)); + + nttManager.setThreshold(1); + nttManager.setThreshold(2); + nttManager.setThreshold(1); + } + + function test_cantSetThresholdToZero() public { + DummyTransceiver e = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e)); + + vm.expectRevert(abi.encodeWithSignature("ZeroThreshold()")); + nttManager.setThreshold(0); + } + + function test_onlyOwnerCanSetThreshold() public { + address notOwner = address(0x123); + vm.startPrank(notOwner); + + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", notOwner)); + nttManager.setThreshold(1); + } + + // === attestation + + function test_onlyEnabledTransceiversCanAttest() public { + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.removeTransceiver(address(e1)); + bytes32 peer = toWormholeFormat(address(nttManager)); + nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer); + + bytes memory transceiverMessage; + (, transceiverMessage) = TransceiverHelpersLib.buildTransceiverMessageWithNttManagerPayload( + 0, bytes32(0), peer, toWormholeFormat(address(nttManagerOther)), abi.encode("payload") + ); + + vm.expectRevert(abi.encodeWithSignature("CallerNotTransceiver(address)", address(e1))); + e1.receiveMessage(transceiverMessage); + } + + function test_onlyPeerNttManagerCanAttest() public { + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setThreshold(2); + + bytes32 peer = toWormholeFormat(address(nttManager)); + + TransceiverStructs.NttManagerMessage memory nttManagerMessage; + bytes memory transceiverMessage; + (nttManagerMessage, transceiverMessage) = TransceiverHelpersLib + .buildTransceiverMessageWithNttManagerPayload( + 0, bytes32(0), peer, toWormholeFormat(address(nttManagerOther)), abi.encode("payload") + ); + + vm.expectRevert( + abi.encodeWithSignature( + "InvalidPeer(uint16,bytes32)", TransceiverHelpersLib.SENDING_CHAIN_ID, peer + ) + ); + e1.receiveMessage(transceiverMessage); + } + + function test_attestSimple() public { + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setThreshold(2); + + // register nttManager peer + bytes32 peer = toWormholeFormat(address(nttManager)); + nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer); + + TransceiverStructs.NttManagerMessage memory nttManagerMessage; + bytes memory transceiverMessage; + (nttManagerMessage, transceiverMessage) = TransceiverHelpersLib + .buildTransceiverMessageWithNttManagerPayload( + 0, bytes32(0), peer, toWormholeFormat(address(nttManagerOther)), abi.encode("payload") + ); + + e1.receiveMessage(transceiverMessage); + + bytes32 hash = TransceiverStructs.nttManagerMessageDigest( + TransceiverHelpersLib.SENDING_CHAIN_ID, nttManagerMessage + ); + assertEq(nttManagerOther.messageAttestations(hash), 1); + } + + function test_attestTwice() public { + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setThreshold(2); + + // register nttManager peer + bytes32 peer = toWormholeFormat(address(nttManager)); + nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer); + + TransceiverStructs.NttManagerMessage memory nttManagerMessage; + bytes memory transceiverMessage; + (nttManagerMessage, transceiverMessage) = TransceiverHelpersLib + .buildTransceiverMessageWithNttManagerPayload( + 0, bytes32(0), peer, toWormholeFormat(address(nttManagerOther)), abi.encode("payload") + ); + + bytes32 hash = TransceiverStructs.nttManagerMessageDigest( + TransceiverHelpersLib.SENDING_CHAIN_ID, nttManagerMessage + ); + + e1.receiveMessage(transceiverMessage); + vm.expectRevert( + abi.encodeWithSignature("TransceiverAlreadyAttestedToMessage(bytes32)", hash) + ); + e1.receiveMessage(transceiverMessage); + + // can't double vote + assertEq(nttManagerOther.messageAttestations(hash), 1); + } + + function test_attestDisabled() public { + (DummyTransceiver e1,) = TransceiverHelpersLib.setup_transceivers(nttManagerOther); + nttManagerOther.setThreshold(2); + + bytes32 peer = toWormholeFormat(address(nttManager)); + nttManagerOther.setPeer(TransceiverHelpersLib.SENDING_CHAIN_ID, peer); + + ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](1); + transceivers[0] = e1; + + TransceiverStructs.NttManagerMessage memory m; + (m,) = TransceiverHelpersLib.attestTransceiversHelper( + address(0x456), + 0, + chainId, + nttManager, + nttManagerOther, + NormalizedAmount(50, 8), + NormalizedAmount(type(uint64).max, 8), + transceivers + ); + + nttManagerOther.removeTransceiver(address(e1)); + + bytes32 hash = + TransceiverStructs.nttManagerMessageDigest(TransceiverHelpersLib.SENDING_CHAIN_ID, m); + // a disabled transceiver's vote no longer counts + assertEq(nttManagerOther.messageAttestations(hash), 0); + + nttManagerOther.setTransceiver(address(e1)); + // it counts again when reenabled + assertEq(nttManagerOther.messageAttestations(hash), 1); + } + + function test_transfer_sequences() public { + address user_A = address(0x123); + address user_B = address(0x456); + + DummyToken token = DummyToken(nttManager.token()); + + uint8 decimals = token.decimals(); + + nttManager.setOutboundLimit(NormalizedAmount(type(uint64).max, 8).denormalize(decimals)); + + token.mintDummy(address(user_A), 5 * 10 ** decimals); + + vm.startPrank(user_A); + + token.approve(address(nttManager), 3 * 10 ** decimals); + + uint64 s1 = nttManager.transfer( + 1 * 10 ** decimals, chainId, toWormholeFormat(user_B), false, new bytes(1) + ); + uint64 s2 = nttManager.transfer( + 1 * 10 ** decimals, chainId, toWormholeFormat(user_B), false, new bytes(1) + ); + uint64 s3 = nttManager.transfer( + 1 * 10 ** decimals, chainId, toWormholeFormat(user_B), false, new bytes(1) + ); + + assertEq(s1, 0); + assertEq(s2, 1); + assertEq(s3, 2); + } + + function test_attestationQuorum() public { + address user_B = address(0x456); + + (DummyTransceiver e1, DummyTransceiver e2) = + TransceiverHelpersLib.setup_transceivers(nttManagerOther); + + NormalizedAmount memory transferAmount = NormalizedAmount(50, 8); + + TransceiverStructs.NttManagerMessage memory m; + bytes memory encodedEm; + { + ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](2); + transceivers[0] = e1; + transceivers[1] = e2; + + TransceiverStructs.TransceiverMessage memory em; + (m, em) = TransceiverHelpersLib.attestTransceiversHelper( + user_B, + 0, + chainId, + nttManager, + nttManagerOther, + transferAmount, + NormalizedAmount(type(uint64).max, 8), + transceivers + ); + encodedEm = TransceiverStructs.encodeTransceiverMessage( + TransceiverHelpersLib.TEST_TRANSCEIVER_PAYLOAD_PREFIX, em + ); + } + + { + DummyToken token = DummyToken(nttManager.token()); + assertEq(token.balanceOf(address(user_B)), transferAmount.denormalize(token.decimals())); + } + + // replay protection + vm.recordLogs(); + e2.receiveMessage(encodedEm); + + { + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 2); + assertEq(entries[1].topics.length, 3); + assertEq(entries[1].topics[0], keccak256("MessageAlreadyExecuted(bytes32,bytes32)")); + assertEq(entries[1].topics[1], toWormholeFormat(address(nttManager))); + assertEq( + entries[1].topics[2], + TransceiverStructs.nttManagerMessageDigest( + TransceiverHelpersLib.SENDING_CHAIN_ID, m + ) + ); + } + } + + // TODO: + // currently there is no way to test the threshold logic and the duplicate + // protection logic without setting up the business logic as well. + // + // we should separate the business logic out from the transceiver handling. + // that way the functionality could be tested separately (and the contracts + // would also be more reusable) + + // === storage + + function test_noAutomaticSlot() public { + DummyToken t = new DummyToken(); + MockNttManagerContract c = + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, 1, 1 days); + assertEq(c.lastSlot(), 0x0); + } + + function test_constructor() public { + DummyToken t = new DummyToken(); + + vm.startStateDiffRecording(); + + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, 1, 1 days); + + Utils.assertSafeUpgradeableConstructor(vm.stopAndReturnStateDiff()); + } + + // === token transfer logic + + function test_dustReverts() public { + // transfer 3 tokens + address from = address(0x123); + address to = address(0x456); + + DummyToken token = DummyToken(nttManager.token()); + + uint8 decimals = token.decimals(); + + uint256 maxAmount = 5 * 10 ** decimals; + token.mintDummy(from, maxAmount); + nttManager.setOutboundLimit(NormalizedAmount(type(uint64).max, 8).denormalize(decimals)); + nttManager.setInboundLimit( + NormalizedAmount(type(uint64).max, 8).denormalize(decimals), + TransceiverHelpersLib.SENDING_CHAIN_ID + ); + + vm.startPrank(from); + + uint256 transferAmount = 3 * 10 ** decimals; + assertEq( + transferAmount < maxAmount - 500, true, "Transferring more tokens than what exists" + ); + + uint256 dustAmount = 500; + uint256 amountWithDust = transferAmount + dustAmount; // An amount with 19 digits, which will result in dust due to 18 decimals + token.approve(address(nttManager), amountWithDust); + + vm.expectRevert( + abi.encodeWithSignature( + "TransferAmountHasDust(uint256,uint256)", amountWithDust, dustAmount + ) + ); + nttManager.transfer(amountWithDust, chainId, toWormholeFormat(to), false, new bytes(1)); + + vm.stopPrank(); + } + + // === upgradeability + function expectRevert( + address contractAddress, + bytes memory encodedSignature, + bytes memory expectedRevert + ) internal { + (bool success, bytes memory result) = contractAddress.call(encodedSignature); + require(!success, "call did not revert"); + + require(keccak256(result) == keccak256(expectedRevert), "call did not revert as expected"); + } + + function test_upgradeNttManager() public { + // The testing strategy here is as follows: + // Step 1: Deploy the nttManager contract with two transceivers and + // receive a message through it. + // Step 2: Upgrade it to a new nttManager contract an use the same transceivers to receive + // a new message through it. + // Step 3: Upgrade back to the standalone contract (with two + // transceivers) and receive a message through it. + // This ensures that the storage slots don't get clobbered through the upgrades. + + address user_B = address(0x456); + DummyToken token = DummyToken(nttManager.token()); + NormalizedAmount memory transferAmount = NormalizedAmount(50, 8); + (ITransceiverReceiver e1, ITransceiverReceiver e2) = + TransceiverHelpersLib.setup_transceivers(nttManagerOther); + + // Step 1 (contract is deployed by setUp()) + ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](2); + transceivers[0] = e1; + transceivers[1] = e2; + + TransceiverStructs.NttManagerMessage memory m; + bytes memory encodedEm; + { + TransceiverStructs.TransceiverMessage memory em; + (m, em) = TransceiverHelpersLib.attestTransceiversHelper( + user_B, + 0, + chainId, + nttManager, + nttManagerOther, + transferAmount, + NormalizedAmount(type(uint64).max, 8), + transceivers + ); + encodedEm = TransceiverStructs.encodeTransceiverMessage( + TransceiverHelpersLib.TEST_TRANSCEIVER_PAYLOAD_PREFIX, em + ); + } + + assertEq(token.balanceOf(address(user_B)), transferAmount.denormalize(token.decimals())); + + // Step 2 (upgrade to a new nttManager) + MockNttManagerContract newNttManager = + new MockNttManagerContract(nttManager.token(), NttManager.Mode.LOCKING, chainId, 1 days); + nttManagerOther.upgrade(address(newNttManager)); + + TransceiverHelpersLib.attestTransceiversHelper( + user_B, + 1, + chainId, + nttManager, // this is the proxy + nttManagerOther, // this is the proxy + transferAmount, + NormalizedAmount(type(uint64).max, 8), + transceivers + ); + + assertEq(token.balanceOf(address(user_B)), transferAmount.denormalize(token.decimals()) * 2); + } +} diff --git a/evm/test/Ownership.t.sol b/evm/test/Ownership.t.sol index 5853ec2d3..00baa0226 100644 --- a/evm/test/Ownership.t.sol +++ b/evm/test/Ownership.t.sol @@ -3,36 +3,36 @@ pragma solidity >=0.8.8 <0.9.0; import "forge-std/Test.sol"; -import "./mocks/MockManager.sol"; +import "./mocks/MockNttManager.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import {DummyEndpoint} from "./Manager.t.sol"; -import {DummyToken} from "./Manager.t.sol"; +import {DummyTransceiver} from "./NttManager.t.sol"; +import {DummyToken} from "./NttManager.t.sol"; contract OwnershipTests is Test { - Manager manager; + NttManager nttManager; uint16 constant chainId = 7; function setUp() public { DummyToken t = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t), Manager.Mode.LOCKING, chainId, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, chainId, 1 days); - manager = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - manager.initialize(); + nttManager = MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManager.initialize(); } - function checkOwnership(DummyEndpoint e, address managerOwner) public { - address endpointManager = e.getManagerOwner(); - assertEq(endpointManager, managerOwner); + function checkOwnership(DummyTransceiver e, address nttManagerOwner) public { + address transceiverNttManager = e.getNttManagerOwner(); + assertEq(transceiverNttManager, nttManagerOwner); } - /// endpoint retrieves the manager owner correctly - function testEndpointOwnership() public { - // TODO: use setup_endpoints here - DummyEndpoint e1 = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e1)); - manager.setThreshold(1); + /// transceiver retrieves the nttManager owner correctly + function testTransceiverOwnership() public { + // TODO: use setup_transceivers here + DummyTransceiver e1 = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e1)); + nttManager.setThreshold(1); - checkOwnership(e1, manager.owner()); + checkOwnership(e1, nttManager.owner()); } } diff --git a/evm/test/RateLimit.t.sol b/evm/test/RateLimit.t.sol index 8f79d0576..3958ab5b8 100644 --- a/evm/test/RateLimit.t.sol +++ b/evm/test/RateLimit.t.sol @@ -2,19 +2,19 @@ import "forge-std/Test.sol"; import "../src/interfaces/IRateLimiterEvents.sol"; -import "../src/Manager.sol"; -import "./mocks/DummyEndpoint.sol"; +import "../src/NttManager.sol"; +import "./mocks/DummyTransceiver.sol"; import "./mocks/DummyToken.sol"; -import "./mocks/MockManager.sol"; +import "./mocks/MockNttManager.sol"; import "wormhole-solidity-sdk/testing/helpers/WormholeSimulator.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import "./libraries/EndpointHelpers.sol"; -import "./libraries/ManagerHelpers.sol"; +import "./libraries/TransceiverHelpers.sol"; +import "./libraries/NttManagerHelpers.sol"; pragma solidity >=0.8.8 <0.9.0; contract TestRateLimit is Test, IRateLimiterEvents { - MockManagerContract manager; + MockNttManagerContract nttManager; using NormalizedAmountLib for uint256; using NormalizedAmountLib for NormalizedAmount; @@ -35,21 +35,22 @@ contract TestRateLimit is Test, IRateLimiterEvents { guardian = new WormholeSimulator(address(wormhole), DEVNET_GUARDIAN_PK); DummyToken t = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t), Manager.Mode.LOCKING, chainId, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t), NttManager.Mode.LOCKING, chainId, 1 days); - manager = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - manager.initialize(); + nttManager = MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManager.initialize(); } function test_outboundRateLimit_setLimitSimple() public { - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); uint256 limit = 1 * 10 ** 6; - manager.setOutboundLimit(limit); + nttManager.setOutboundLimit(limit); - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq(outboundLimitParams.limit.getAmount(), limit.normalize(decimals).getAmount()); assertEq( @@ -63,24 +64,25 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 3 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); vm.stopPrank(); // assert outbound rate limit was updated - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq( outboundLimitParams.currentCapacity.getAmount(), (outboundLimit - transferAmount).normalize(decimals).getAmount() @@ -90,7 +92,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { // assert inbound rate limit for destination chain is still at the max. // the backflow should not override the limit. IRateLimiter.RateLimitParams memory inboundLimitParams = - manager.getInboundLimitParams(chainId); + nttManager.getInboundLimitParams(chainId); assertEq( inboundLimitParams.currentCapacity.getAmount(), inboundLimitParams.limit.getAmount() ); @@ -102,19 +104,19 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 3 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); vm.stopPrank(); @@ -122,9 +124,10 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.startPrank(address(this)); uint256 higherLimit = 5 * 10 ** decimals; - manager.setOutboundLimit(higherLimit); + nttManager.setOutboundLimit(higherLimit); - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq(outboundLimitParams.limit.getAmount(), higherLimit.normalize(decimals).getAmount()); assertEq(outboundLimitParams.lastTxTimestamp, initialBlockTimestamp); @@ -139,19 +142,19 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 3 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); vm.stopPrank(); @@ -159,9 +162,10 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.startPrank(address(this)); uint256 lowerLimit = 2 * 10 ** decimals; - manager.setOutboundLimit(lowerLimit); + nttManager.setOutboundLimit(lowerLimit); - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq(outboundLimitParams.limit.denormalize(decimals), lowerLimit); assertEq(outboundLimitParams.lastTxTimestamp, initialBlockTimestamp); @@ -173,19 +177,19 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 3 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); vm.stopPrank(); @@ -197,9 +201,10 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.startPrank(address(this)); uint256 higherLimit = 5 * 10 ** decimals; - manager.setOutboundLimit(higherLimit); + nttManager.setOutboundLimit(higherLimit); - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq(outboundLimitParams.limit.getAmount(), higherLimit.normalize(decimals).getAmount()); assertEq(outboundLimitParams.lastTxTimestamp, sixHoursLater); @@ -209,7 +214,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { outboundLimitParams.currentCapacity.getAmount(), ( (1 * 10 ** decimals) + (1 * 10 ** decimals) - + (outboundLimit * (6 hours)) / manager.rateLimitDuration() + + (outboundLimit * (6 hours)) / nttManager.rateLimitDuration() ).normalize(decimals).getAmount() ); } @@ -219,19 +224,19 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 5 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 4 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); vm.stopPrank(); @@ -243,9 +248,10 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.startPrank(address(this)); uint256 lowerLimit = 3 * 10 ** decimals; - manager.setOutboundLimit(lowerLimit); + nttManager.setOutboundLimit(lowerLimit); - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq(outboundLimitParams.limit.getAmount(), lowerLimit.normalize(decimals).getAmount()); assertEq(outboundLimitParams.lastTxTimestamp, sixHoursLater); @@ -257,21 +263,21 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); // set the outbound limit to 5 tokens uint256 outboundLimit = 5 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); // transfer 2 tokens uint256 transferAmount = 2 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); vm.stopPrank(); @@ -283,9 +289,10 @@ contract TestRateLimit is Test, IRateLimiterEvents { // update the outbound limit to 4 tokens uint256 lowerLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(lowerLimit); + nttManager.setOutboundLimit(lowerLimit); - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq(outboundLimitParams.limit.getAmount(), lowerLimit.normalize(decimals).getAmount()); assertEq(outboundLimitParams.lastTxTimestamp, sixHoursLater); @@ -295,7 +302,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { outboundLimitParams.currentCapacity.getAmount(), ( (3 * 10 ** decimals) - (1 * 10 ** decimals) - + (outboundLimit * (6 hours)) / manager.rateLimitDuration() + + (outboundLimit * (6 hours)) / nttManager.rateLimitDuration() ).normalize(decimals).getAmount() ); } @@ -304,59 +311,61 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 1 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 3 * 10 ** decimals; - token.approve(address(manager), transferAmount); + token.approve(address(nttManager), transferAmount); bytes4 selector = bytes4(keccak256("NotEnoughCapacity(uint256,uint256)")); vm.expectRevert(abi.encodeWithSelector(selector, outboundLimit, transferAmount)); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); } function test_outboundRateLimit_multiHit() public { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 3 * 10 ** decimals; - token.approve(address(manager), transferAmount); - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + token.approve(address(nttManager), transferAmount); + nttManager.transfer(transferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); // assert that first transfer went through assertEq(token.balanceOf(address(user_A)), 2 * 10 ** decimals); - assertEq(token.balanceOf(address(manager)), transferAmount); + assertEq(token.balanceOf(address(nttManager)), transferAmount); // assert currentCapacity is updated NormalizedAmount memory newCapacity = outboundLimit.normalize(decimals).sub(transferAmount.normalize(decimals)); - assertEq(manager.getCurrentOutboundCapacity(), newCapacity.denormalize(decimals)); + assertEq(nttManager.getCurrentOutboundCapacity(), newCapacity.denormalize(decimals)); uint256 badTransferAmount = 2 * 10 ** decimals; - token.approve(address(manager), badTransferAmount); + token.approve(address(nttManager), badTransferAmount); bytes4 selector = bytes4(keccak256("NotEnoughCapacity(uint256,uint256)")); vm.expectRevert( abi.encodeWithSelector(selector, newCapacity.denormalize(decimals), badTransferAmount) ); - manager.transfer(badTransferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1)); + nttManager.transfer( + badTransferAmount, chainId, toWormholeFormat(user_B), false, new bytes(1) + ); } // make a transfer with shouldQueue == true @@ -368,26 +377,27 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); token.mintDummy(address(user_A), 5 * 10 ** decimals); uint256 outboundLimit = 4 * 10 ** decimals; - manager.setOutboundLimit(outboundLimit); + nttManager.setOutboundLimit(outboundLimit); vm.startPrank(user_A); uint256 transferAmount = 5 * 10 ** decimals; - token.approve(address(manager), transferAmount); + token.approve(address(nttManager), transferAmount); // transfer with shouldQueue == true - uint64 qSeq = - manager.transfer(transferAmount, chainId, toWormholeFormat(user_B), true, new bytes(1)); + uint64 qSeq = nttManager.transfer( + transferAmount, chainId, toWormholeFormat(user_B), true, new bytes(1) + ); // assert that the transfer got queued up assertEq(qSeq, 0); - IRateLimiter.OutboundQueuedTransfer memory qt = manager.getOutboundQueuedTransfer(0); + IRateLimiter.OutboundQueuedTransfer memory qt = nttManager.getOutboundQueuedTransfer(0); assertEq(qt.amount.getAmount(), transferAmount.normalize(decimals).getAmount()); assertEq(qt.recipientChain, chainId); assertEq(qt.recipient, toWormholeFormat(user_B)); @@ -395,44 +405,45 @@ contract TestRateLimit is Test, IRateLimiterEvents { // assert that the contract also locked funds from the user assertEq(token.balanceOf(address(user_A)), 0); - assertEq(token.balanceOf(address(manager)), transferAmount); + assertEq(token.balanceOf(address(nttManager)), transferAmount); // elapse rate limit duration - 1 - uint256 durationElapsedTime = initialBlockTimestamp + manager.rateLimitDuration(); + uint256 durationElapsedTime = initialBlockTimestamp + nttManager.rateLimitDuration(); vm.warp(durationElapsedTime - 1); // assert that transfer still can't be completed bytes4 stillQueuedSelector = bytes4(keccak256("OutboundQueuedTransferStillQueued(uint64,uint256)")); vm.expectRevert(abi.encodeWithSelector(stillQueuedSelector, 0, initialBlockTimestamp)); - manager.completeOutboundQueuedTransfer(0); + nttManager.completeOutboundQueuedTransfer(0); // now complete transfer vm.warp(durationElapsedTime); - uint64 seq = manager.completeOutboundQueuedTransfer(0); + uint64 seq = nttManager.completeOutboundQueuedTransfer(0); assertEq(seq, 0); // now ensure transfer was removed from queue bytes4 notFoundSelector = bytes4(keccak256("OutboundQueuedTransferNotFound(uint64)")); vm.expectRevert(abi.encodeWithSelector(notFoundSelector, 0)); - manager.completeOutboundQueuedTransfer(0); + nttManager.completeOutboundQueuedTransfer(0); } function test_inboundRateLimit_simple() public { address user_B = address(0x456); - (DummyEndpoint e1, DummyEndpoint e2) = EndpointHelpersLib.setup_endpoints(manager); + (DummyTransceiver e1, DummyTransceiver e2) = + TransceiverHelpersLib.setup_transceivers(nttManager); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); - IEndpointReceiver[] memory endpoints = new IEndpointReceiver[](2); - endpoints[0] = e1; - endpoints[1] = e2; + ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](2); + transceivers[0] = e1; + transceivers[1] = e2; NormalizedAmount memory transferAmount = NormalizedAmount(50, 8); NormalizedAmount memory limitAmount = NormalizedAmount(100, 8); - EndpointHelpersLib.attestEndpointsHelper( - user_B, 0, chainId, manager, manager, transferAmount, limitAmount, endpoints + TransceiverHelpersLib.attestTransceiversHelper( + user_B, 0, chainId, nttManager, nttManager, transferAmount, limitAmount, transceivers ); // assert that the user received tokens @@ -440,7 +451,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { // assert that the inbound limits updated IRateLimiter.RateLimitParams memory inboundLimitParams = - manager.getInboundLimitParams(EndpointHelpersLib.SENDING_CHAIN_ID); + nttManager.getInboundLimitParams(TransceiverHelpersLib.SENDING_CHAIN_ID); assertEq( inboundLimitParams.currentCapacity.getAmount(), limitAmount.sub(transferAmount).getAmount() @@ -449,7 +460,8 @@ contract TestRateLimit is Test, IRateLimiterEvents { // assert that the outbound limit is still at the max // backflow should not go over the max limit - IRateLimiter.RateLimitParams memory outboundLimitParams = manager.getOutboundLimitParams(); + IRateLimiter.RateLimitParams memory outboundLimitParams = + nttManager.getOutboundLimitParams(); assertEq( outboundLimitParams.currentCapacity.getAmount(), outboundLimitParams.limit.getAmount() ); @@ -459,45 +471,47 @@ contract TestRateLimit is Test, IRateLimiterEvents { function test_inboundRateLimit_queue() public { address user_B = address(0x456); - (DummyEndpoint e1, DummyEndpoint e2) = EndpointHelpersLib.setup_endpoints(manager); + (DummyTransceiver e1, DummyTransceiver e2) = + TransceiverHelpersLib.setup_transceivers(nttManager); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); - IEndpointReceiver[] memory endpoints = new IEndpointReceiver[](1); - endpoints[0] = e1; + ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](1); + transceivers[0] = e1; - EndpointStructs.ManagerMessage memory m; + TransceiverStructs.NttManagerMessage memory m; bytes memory encodedEm; { - EndpointStructs.EndpointMessage memory em; - (m, em) = EndpointHelpersLib.attestEndpointsHelper( + TransceiverStructs.TransceiverMessage memory em; + (m, em) = TransceiverHelpersLib.attestTransceiversHelper( user_B, 0, chainId, - manager, - manager, + nttManager, + nttManager, NormalizedAmount(50, 8), uint256(5).normalize(token.decimals()), - endpoints + transceivers ); - encodedEm = EndpointStructs.encodeEndpointMessage( - EndpointHelpersLib.TEST_ENDPOINT_PAYLOAD_PREFIX, em + encodedEm = TransceiverStructs.encodeTransceiverMessage( + TransceiverHelpersLib.TEST_TRANSCEIVER_PAYLOAD_PREFIX, em ); } bytes32 digest = - EndpointStructs.managerMessageDigest(EndpointHelpersLib.SENDING_CHAIN_ID, m); + TransceiverStructs.nttManagerMessageDigest(TransceiverHelpersLib.SENDING_CHAIN_ID, m); // no quorum yet assertEq(token.balanceOf(address(user_B)), 0); - vm.expectEmit(address(manager)); + vm.expectEmit(address(nttManager)); emit InboundTransferQueued(digest); e2.receiveMessage(encodedEm); { // now we have quorum but it'll hit limit - IRateLimiter.InboundQueuedTransfer memory qt = manager.getInboundQueuedTransfer(digest); + IRateLimiter.InboundQueuedTransfer memory qt = + nttManager.getInboundQueuedTransfer(digest); assertEq(qt.amount.getAmount(), 50); assertEq(qt.txTimestamp, initialBlockTimestamp); assertEq(qt.recipient, user_B); @@ -507,7 +521,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { assertEq(token.balanceOf(address(user_B)), 0); // change block time to (duration - 1) seconds later - uint256 durationElapsedTime = initialBlockTimestamp + manager.rateLimitDuration(); + uint256 durationElapsedTime = initialBlockTimestamp + nttManager.rateLimitDuration(); vm.warp(durationElapsedTime - 1); { @@ -517,18 +531,18 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.expectRevert( abi.encodeWithSelector(stillQueuedSelector, digest, initialBlockTimestamp) ); - manager.completeInboundQueuedTransfer(digest); + nttManager.completeInboundQueuedTransfer(digest); } // now complete transfer vm.warp(durationElapsedTime); - manager.completeInboundQueuedTransfer(digest); + nttManager.completeInboundQueuedTransfer(digest); { // assert transfer no longer in queue bytes4 notQueuedSelector = bytes4(keccak256("InboundQueuedTransferNotFound(bytes32)")); vm.expectRevert(abi.encodeWithSelector(notQueuedSelector, digest)); - manager.completeInboundQueuedTransfer(digest); + nttManager.completeInboundQueuedTransfer(digest); } // assert user now has funds @@ -543,10 +557,12 @@ contract TestRateLimit is Test, IRateLimiterEvents { assertEq(entries.length, 2); assertEq(entries[1].topics.length, 3); assertEq(entries[1].topics[0], keccak256("MessageAlreadyExecuted(bytes32,bytes32)")); - assertEq(entries[1].topics[1], toWormholeFormat(address(manager))); + assertEq(entries[1].topics[1], toWormholeFormat(address(nttManager))); assertEq( entries[1].topics[2], - EndpointStructs.managerMessageDigest(EndpointHelpersLib.SENDING_CHAIN_ID, m) + TransceiverStructs.nttManagerMessageDigest( + TransceiverHelpersLib.SENDING_CHAIN_ID, m + ) ); } } @@ -555,20 +571,20 @@ contract TestRateLimit is Test, IRateLimiterEvents { address user_A = address(0x123); address user_B = address(0x456); - DummyToken token = DummyToken(manager.token()); + DummyToken token = DummyToken(nttManager.token()); uint8 decimals = token.decimals(); NormalizedAmount memory mintAmount = NormalizedAmount(50, 8); token.mintDummy(address(user_A), mintAmount.denormalize(decimals)); - manager.setOutboundLimit(mintAmount.denormalize(decimals)); + nttManager.setOutboundLimit(mintAmount.denormalize(decimals)); // transfer 10 tokens vm.startPrank(user_A); NormalizedAmount memory transferAmount = NormalizedAmount(10, 8); - token.approve(address(manager), type(uint256).max); - manager.transfer( + token.approve(address(nttManager), type(uint256).max); + nttManager.transfer( transferAmount.denormalize(decimals), chainId, toWormholeFormat(user_B), @@ -578,14 +594,14 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.stopPrank(); - // assert manager has 10 tokens and user_A has 10 fewer tokens - assertEq(token.balanceOf(address(manager)), transferAmount.denormalize(decimals)); + // assert nttManager has 10 tokens and user_A has 10 fewer tokens + assertEq(token.balanceOf(address(nttManager)), transferAmount.denormalize(decimals)); assertEq(token.balanceOf(user_A), mintAmount.sub(transferAmount).denormalize(decimals)); { // assert outbound rate limit decreased IRateLimiter.RateLimitParams memory outboundLimitParams = - manager.getOutboundLimitParams(); + nttManager.getOutboundLimitParams(); assertEq( outboundLimitParams.currentCapacity.getAmount(), outboundLimitParams.limit.sub(transferAmount).getAmount() @@ -598,14 +614,15 @@ contract TestRateLimit is Test, IRateLimiterEvents { vm.warp(receiveTime); // now receive 10 tokens from user_B -> user_A - (DummyEndpoint e1, DummyEndpoint e2) = EndpointHelpersLib.setup_endpoints(manager); + (DummyTransceiver e1, DummyTransceiver e2) = + TransceiverHelpersLib.setup_transceivers(nttManager); - IEndpointReceiver[] memory endpoints = new IEndpointReceiver[](2); - endpoints[0] = e1; - endpoints[1] = e2; + ITransceiverReceiver[] memory transceivers = new ITransceiverReceiver[](2); + transceivers[0] = e1; + transceivers[1] = e2; - EndpointHelpersLib.attestEndpointsHelper( - user_A, 0, chainId, manager, manager, transferAmount, mintAmount, endpoints + TransceiverHelpersLib.attestTransceiversHelper( + user_A, 0, chainId, nttManager, nttManager, transferAmount, mintAmount, transceivers ); // assert that user_A has original amount @@ -614,7 +631,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { { // assert that the inbound limits decreased IRateLimiter.RateLimitParams memory inboundLimitParams = - manager.getInboundLimitParams(EndpointHelpersLib.SENDING_CHAIN_ID); + nttManager.getInboundLimitParams(TransceiverHelpersLib.SENDING_CHAIN_ID); assertEq( inboundLimitParams.currentCapacity.getAmount(), inboundLimitParams.limit.sub(transferAmount).getAmount() @@ -625,7 +642,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { { // assert that outbound limit is at max again (because of backflow) IRateLimiter.RateLimitParams memory outboundLimitParams = - manager.getOutboundLimitParams(); + nttManager.getOutboundLimitParams(); assertEq( outboundLimitParams.currentCapacity.getAmount(), outboundLimitParams.limit.getAmount() @@ -640,9 +657,9 @@ contract TestRateLimit is Test, IRateLimiterEvents { // transfer 10 back to the contract vm.startPrank(user_A); - manager.transfer( + nttManager.transfer( transferAmount.denormalize(decimals), - EndpointHelpersLib.SENDING_CHAIN_ID, + TransceiverHelpersLib.SENDING_CHAIN_ID, toWormholeFormat(user_B), false, new bytes(1) @@ -653,7 +670,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { { // assert outbound rate limit decreased IRateLimiter.RateLimitParams memory outboundLimitParams = - manager.getOutboundLimitParams(); + nttManager.getOutboundLimitParams(); assertEq( outboundLimitParams.currentCapacity.getAmount(), outboundLimitParams.limit.sub(transferAmount).getAmount() @@ -664,7 +681,7 @@ contract TestRateLimit is Test, IRateLimiterEvents { { // assert that the inbound limit is at max again (because of backflow) IRateLimiter.RateLimitParams memory inboundLimitParams = - manager.getInboundLimitParams(EndpointHelpersLib.SENDING_CHAIN_ID); + nttManager.getInboundLimitParams(TransceiverHelpersLib.SENDING_CHAIN_ID); assertEq( inboundLimitParams.currentCapacity.getAmount(), inboundLimitParams.limit.getAmount() ); diff --git a/evm/test/TransceiverStructs.t.sol b/evm/test/TransceiverStructs.t.sol new file mode 100644 index 000000000..159fc8b61 --- /dev/null +++ b/evm/test/TransceiverStructs.t.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity >=0.8.8 <0.9.0; + +import "forge-std/Test.sol"; + +import "../src/libraries/TransceiverStructs.sol"; +import "../src/WormholeTransceiver.sol"; + +contract TestTransceiverStructs is Test { + using NormalizedAmountLib for uint256; + using NormalizedAmountLib for NormalizedAmount; + + // TODO: add some negative tests for unknown message types etc + + function test_serialize_TransceiverMessage() public { + TransceiverStructs.NativeTokenTransfer memory ntt = TransceiverStructs.NativeTokenTransfer({ + amount: NormalizedAmount({amount: 1234567, decimals: 7}), + sourceToken: hex"BEEFFACE", + to: hex"FEEBCAFE", + toChain: 17 + }); + + TransceiverStructs.NttManagerMessage memory mm = TransceiverStructs.NttManagerMessage({ + sequence: 233968345345, + sender: hex"46679213412343", + payload: TransceiverStructs.encodeNativeTokenTransfer(ntt) + }); + + bytes4 wh_prefix = 0x9945FF10; + TransceiverStructs.TransceiverMessage memory em = TransceiverStructs.TransceiverMessage({ + sourceNttManagerAddress: hex"042942FAFABE", + recipientNttManagerAddress: hex"042942FABABE", + nttManagerPayload: TransceiverStructs.encodeNttManagerMessage(mm), + transceiverPayload: new bytes(0) + }); + + bytes memory encodedTransceiverMessage = + TransceiverStructs.encodeTransceiverMessage(wh_prefix, em); + + // this is a useful test case for implementations on other runtimes + bytes memory encodedExpected = + hex"9945ff10042942fafabe0000000000000000000000000000000000000000000000000000042942fababe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe0000000000000000000000000000000000000000000000000000000000110000"; + assertEq(encodedTransceiverMessage, encodedExpected); + + TransceiverStructs.TransceiverMessage memory emParsed = + TransceiverStructs.parseTransceiverMessage(wh_prefix, encodedTransceiverMessage); + + TransceiverStructs.NttManagerMessage memory mmParsed = + TransceiverStructs.parseNttManagerMessage(emParsed.nttManagerPayload); + + // deep equality check + assertEq(abi.encode(mmParsed), abi.encode(mm)); + + TransceiverStructs.NativeTokenTransfer memory nttParsed = + TransceiverStructs.parseNativeTokenTransfer(mmParsed.payload); + + // deep equality check + assertEq(abi.encode(nttParsed), abi.encode(ntt)); + } + + function test_SerdeRoundtrip_NttManagerMessage(TransceiverStructs.NttManagerMessage memory m) + public + { + bytes memory message = TransceiverStructs.encodeNttManagerMessage(m); + + TransceiverStructs.NttManagerMessage memory parsed = + TransceiverStructs.parseNttManagerMessage(message); + + assertEq(m.sequence, parsed.sequence); + assertEq(m.sender, parsed.sender); + assertEq(m.payload, parsed.payload); + } + + function test_SerdeJunk_NttManagerMessage(TransceiverStructs.NttManagerMessage memory m) + public + { + bytes memory message = TransceiverStructs.encodeNttManagerMessage(m); + + bytes memory junk = "junk"; + + vm.expectRevert( + abi.encodeWithSignature( + "LengthMismatch(uint256,uint256)", message.length + junk.length, message.length + ) + ); + TransceiverStructs.parseNttManagerMessage(abi.encodePacked(message, junk)); + } + + function test_SerdeRoundtrip_NativeTokenTransfer( + TransceiverStructs.NativeTokenTransfer memory m + ) public { + bytes memory message = TransceiverStructs.encodeNativeTokenTransfer(m); + + TransceiverStructs.NativeTokenTransfer memory parsed = + TransceiverStructs.parseNativeTokenTransfer(message); + + assertEq(m.amount.getAmount(), parsed.amount.getAmount()); + assertEq(m.to, parsed.to); + assertEq(m.toChain, parsed.toChain); + } + + function test_SerdeJunk_NativeTokenTransfer(TransceiverStructs.NativeTokenTransfer memory m) + public + { + bytes memory message = TransceiverStructs.encodeNativeTokenTransfer(m); + + bytes memory junk = "junk"; + + vm.expectRevert( + abi.encodeWithSignature( + "LengthMismatch(uint256,uint256)", message.length + junk.length, message.length + ) + ); + TransceiverStructs.parseNativeTokenTransfer(abi.encodePacked(message, junk)); + } +} diff --git a/evm/test/Upgrades.t.sol b/evm/test/Upgrades.t.sol index a12370818..59802dd5b 100644 --- a/evm/test/Upgrades.t.sol +++ b/evm/test/Upgrades.t.sol @@ -4,21 +4,21 @@ pragma solidity >=0.8.8 <0.9.0; import "forge-std/Test.sol"; import "forge-std/console.sol"; -import "../src/Manager.sol"; -import "../src/interfaces/IManager.sol"; +import "../src/NttManager.sol"; +import "../src/interfaces/INttManager.sol"; import "../src/interfaces/IRateLimiter.sol"; -import "../src/interfaces/IManagerEvents.sol"; +import "../src/interfaces/INttManagerEvents.sol"; import "../src/interfaces/IRateLimiterEvents.sol"; import "../src/libraries/external/OwnableUpgradeable.sol"; import "../src/libraries/external/Initializable.sol"; import "../src/libraries/Implementation.sol"; import {Utils} from "./libraries/Utils.sol"; -import {DummyToken, DummyTokenMintAndBurn} from "./Manager.t.sol"; -import {WormholeEndpoint} from "../src/WormholeEndpoint.sol"; -import {WormholeEndpoint} from "../src/WormholeEndpoint.sol"; -import "../src/libraries/EndpointStructs.sol"; -import "./mocks/MockManager.sol"; -import "./mocks/MockEndpoints.sol"; +import {DummyToken, DummyTokenMintAndBurn} from "./NttManager.t.sol"; +import {WormholeTransceiver} from "../src/WormholeTransceiver.sol"; +import {WormholeTransceiver} from "../src/WormholeTransceiver.sol"; +import "../src/libraries/TransceiverStructs.sol"; +import "./mocks/MockNttManager.sol"; +import "./mocks/MockTransceivers.sol"; import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -26,9 +26,9 @@ import "wormhole-solidity-sdk/interfaces/IWormhole.sol"; import "wormhole-solidity-sdk/testing/helpers/WormholeSimulator.sol"; import "wormhole-solidity-sdk/Utils.sol"; -contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { - Manager managerChain1; - Manager managerChain2; +contract TestUpgrades is Test, INttManagerEvents, IRateLimiterEvents { + NttManager nttManagerChain1; + NttManager nttManagerChain2; using NormalizedAmountLib for uint256; using NormalizedAmountLib for NormalizedAmount; @@ -43,8 +43,8 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { uint256 initialBlockTimestamp; uint8 constant FAST_CONSISTENCY_LEVEL = 200; - WormholeEndpoint wormholeEndpointChain1; - WormholeEndpoint wormholeEndpointChain2; + WormholeTransceiver wormholeTransceiverChain1; + WormholeTransceiver wormholeTransceiverChain2; address userA = address(0x123); address userB = address(0x456); address userC = address(0x789); @@ -62,185 +62,186 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId1); DummyToken t1 = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t1), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t1), NttManager.Mode.LOCKING, chainId1, 1 days); - managerChain1 = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); - managerChain1.initialize(); + nttManagerChain1 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerChain1.initialize(); - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointContract( - address(managerChain1), + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain1Implementation), "")) + wormholeTransceiverChain1 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain1Implementation), "")) ); - wormholeEndpointChain1.initialize(); + wormholeTransceiverChain1.initialize(); - managerChain1.setEndpoint(address(wormholeEndpointChain1)); - managerChain1.setOutboundLimit(type(uint64).max); - managerChain1.setInboundLimit(type(uint64).max, chainId2); + nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1)); + nttManagerChain1.setOutboundLimit(type(uint64).max); + nttManagerChain1.setInboundLimit(type(uint64).max, chainId2); // Chain 2 setup vm.chainId(chainId2); DummyToken t2 = new DummyTokenMintAndBurn(); - Manager implementationChain2 = - new MockManagerContract(address(t2), Manager.Mode.BURNING, chainId2, 1 days); + NttManager implementationChain2 = + new MockNttManagerContract(address(t2), NttManager.Mode.BURNING, chainId2, 1 days); - managerChain2 = - MockManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); - managerChain2.initialize(); + nttManagerChain2 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementationChain2), ""))); + nttManagerChain2.initialize(); - WormholeEndpoint wormholeEndpointChain2Implementation = new MockWormholeEndpointContract( - address(managerChain2), + WormholeTransceiver wormholeTransceiverChain2Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain2), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain2 = MockWormholeEndpointContract( - address(new ERC1967Proxy(address(wormholeEndpointChain2Implementation), "")) + wormholeTransceiverChain2 = MockWormholeTransceiverContract( + address(new ERC1967Proxy(address(wormholeTransceiverChain2Implementation), "")) ); - wormholeEndpointChain2.initialize(); + wormholeTransceiverChain2.initialize(); - managerChain2.setEndpoint(address(wormholeEndpointChain2)); - managerChain2.setOutboundLimit(type(uint64).max); - managerChain2.setInboundLimit(type(uint64).max, chainId1); + nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2)); + nttManagerChain2.setOutboundLimit(type(uint64).max); + nttManagerChain2.setInboundLimit(type(uint64).max, chainId1); - // Register sibling contracts for the manager and endpoint. Endpoints and manager each have the concept of siblings here. - managerChain1.setSibling(chainId2, bytes32(uint256(uint160(address(managerChain2))))); - managerChain2.setSibling(chainId1, bytes32(uint256(uint160(address(managerChain1))))); + // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here. + nttManagerChain1.setPeer(chainId2, bytes32(uint256(uint160(address(nttManagerChain2))))); + nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1))))); - wormholeEndpointChain1.setWormholeSibling( - chainId2, bytes32(uint256(uint160((address(wormholeEndpointChain2))))) + wormholeTransceiverChain1.setWormholePeer( + chainId2, bytes32(uint256(uint160((address(wormholeTransceiverChain2))))) ); - wormholeEndpointChain2.setWormholeSibling( - chainId1, bytes32(uint256(uint160(address(wormholeEndpointChain1)))) + wormholeTransceiverChain2.setWormholePeer( + chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1)))) ); - managerChain1.setThreshold(1); - managerChain2.setThreshold(1); + nttManagerChain1.setThreshold(1); + nttManagerChain2.setThreshold(1); vm.chainId(chainId1); } - function test_basicUpgradeManager() public { + function test_basicUpgradeNttManager() public { // Basic call to upgrade with the same contact as ewll - Manager newImplementation = new MockManagerContract( - address(managerChain1.token()), Manager.Mode.LOCKING, chainId1, 1 days + NttManager newImplementation = new MockNttManagerContract( + address(nttManagerChain1.token()), NttManager.Mode.LOCKING, chainId1, 1 days ); - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); basicFunctionality(); } - //Upgradability stuff for endpoints is real borked because of some missing implementation. Test this later once fixed. - function test_basicUpgradeEndpoint() public { + //Upgradability stuff for transceivers is real borked because of some missing implementation. Test this later once fixed. + function test_basicUpgradeTransceiver() public { // Basic call to upgrade with the same contact as well - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointContract( - address(managerChain1), + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); basicFunctionality(); } - // Confirm that we can handle multiple upgrades as a manager - function test_doubleUpgradeManager() public { + // Confirm that we can handle multiple upgrades as a nttManager + function test_doubleUpgradeNttManager() public { // Basic call to upgrade with the same contact as ewll - Manager newImplementation = new MockManagerContract( - address(managerChain1.token()), Manager.Mode.LOCKING, chainId1, 1 days + NttManager newImplementation = new MockNttManagerContract( + address(nttManagerChain1.token()), NttManager.Mode.LOCKING, chainId1, 1 days ); - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); basicFunctionality(); - newImplementation = new MockManagerContract( - address(managerChain1.token()), Manager.Mode.LOCKING, chainId1, 1 days + newImplementation = new MockNttManagerContract( + address(nttManagerChain1.token()), NttManager.Mode.LOCKING, chainId1, 1 days ); - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); basicFunctionality(); } - //Upgradability stuff for endpoints is real borked because of some missing implementation. Test this later once fixed. - function test_doubleUpgradeEndpoint() public { + //Upgradability stuff for transceivers is real borked because of some missing implementation. Test this later once fixed. + function test_doubleUpgradeTransceiver() public { // Basic call to upgrade with the same contact as well - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointContract( - address(managerChain1), + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); basicFunctionality(); // Basic call to upgrade with the same contact as well - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); basicFunctionality(); } - function test_storageSlotManager() public { + function test_storageSlotNttManager() public { // Basic call to upgrade with the same contact as ewll - Manager newImplementation = new MockManagerStorageLayoutChange( - address(managerChain1.token()), Manager.Mode.LOCKING, chainId1, 1 days + NttManager newImplementation = new MockNttManagerStorageLayoutChange( + address(nttManagerChain1.token()), NttManager.Mode.LOCKING, chainId1, 1 days ); - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); - address oldOwner = managerChain1.owner(); - MockManagerStorageLayoutChange(address(managerChain1)).setData(); + address oldOwner = nttManagerChain1.owner(); + MockNttManagerStorageLayoutChange(address(nttManagerChain1)).setData(); // If we overrode something important, it would probably break here basicFunctionality(); - require(oldOwner == managerChain1.owner(), "Owner changed in an unintended way."); + require(oldOwner == nttManagerChain1.owner(), "Owner changed in an unintended way."); } - function test_storageSlotEndpoint() public { + function test_storageSlotTransceiver() public { // Basic call to upgrade with the same contact as ewll - WormholeEndpoint newImplementation = new MockWormholeEndpointLayoutChange( - address(managerChain1), + WormholeTransceiver newImplementation = new MockWormholeTransceiverLayoutChange( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1.upgrade(address(newImplementation)); + wormholeTransceiverChain1.upgrade(address(newImplementation)); - address oldOwner = managerChain1.owner(); - MockWormholeEndpointLayoutChange(address(wormholeEndpointChain1)).setData(); + address oldOwner = nttManagerChain1.owner(); + MockWormholeTransceiverLayoutChange(address(wormholeTransceiverChain1)).setData(); // If we overrode something important, it would probably break here basicFunctionality(); - require(oldOwner == managerChain1.owner(), "Owner changed in an unintended way."); + require(oldOwner == nttManagerChain1.owner(), "Owner changed in an unintended way."); } - function test_callMigrateManager() public { + function test_callMigrateNttManager() public { // Basic call to upgrade with the same contact as ewll - Manager newImplementation = new MockManagerMigrateBasic( - address(managerChain1.token()), Manager.Mode.LOCKING, chainId1, 1 days + NttManager newImplementation = new MockNttManagerMigrateBasic( + address(nttManagerChain1.token()), NttManager.Mode.LOCKING, chainId1, 1 days ); vm.expectRevert("Proper migrate called"); - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); basicFunctionality(); } - //Upgradability stuff for endpoints is real borked because of some missing implementation. Test this later once fixed. - function test_callMigrateEndpoint() public { + //Upgradability stuff for transceivers is real borked because of some missing implementation. Test this later once fixed. + function test_callMigrateTransceiver() public { // Basic call to upgrade with the same contact as well - MockWormholeEndpointMigrateBasic wormholeEndpointChain1Implementation = new MockWormholeEndpointMigrateBasic( - address(managerChain1), + MockWormholeTransceiverMigrateBasic wormholeTransceiverChain1Implementation = new MockWormholeTransceiverMigrateBasic( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), @@ -248,32 +249,33 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { ); vm.expectRevert("Proper migrate called"); - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); basicFunctionality(); } - function test_immutableBlockUpdateFailureManager() public { + function test_immutableBlockUpdateFailureNttManager() public { DummyToken tnew = new DummyToken(); // Basic call to upgrade with the same contact as ewll - Manager newImplementation = - new MockManagerImmutableCheck(address(tnew), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager newImplementation = new MockNttManagerImmutableCheck( + address(tnew), NttManager.Mode.LOCKING, chainId1, 1 days + ); vm.expectRevert(); // Reverts with a panic on the assert. So, no way to tell WHY this happened. - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); - require(managerChain1.token() != address(tnew), "Token updated when it shouldn't be"); + require(nttManagerChain1.token() != address(tnew), "Token updated when it shouldn't be"); basicFunctionality(); } - function test_immutableBlockUpdateFailureEndpoint() public { + function test_immutableBlockUpdateFailureTransceiver() public { // Don't allow upgrade to work with a change immutable - address oldManager = wormholeEndpointChain1.manager(); - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointMigrateBasic( - address(managerChain2), + address oldNttManager = wormholeTransceiverChain1.nttManager(); + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverMigrateBasic( + address(nttManagerChain2), address(wormhole), address(relayer), address(0x0), @@ -281,31 +283,32 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { ); vm.expectRevert(); // Reverts with a panic on the assert. So, no way to tell WHY this happened. - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); require( - wormholeEndpointChain1.manager() == oldManager, "Manager updated when it shouldn't be" + wormholeTransceiverChain1.nttManager() == oldNttManager, + "NttManager updated when it shouldn't be" ); } - function test_immutableBlockUpdateSuccessManager() public { + function test_immutableBlockUpdateSuccessNttManager() public { DummyToken tnew = new DummyToken(); // Basic call to upgrade with the same contact as ewll - Manager newImplementation = new MockManagerImmutableRemoveCheck( - address(tnew), Manager.Mode.LOCKING, chainId1, 1 days + NttManager newImplementation = new MockNttManagerImmutableRemoveCheck( + address(tnew), NttManager.Mode.LOCKING, chainId1, 1 days ); // Allow an upgrade, since we enabled the ability to edit the immutables within the code - managerChain1.upgrade(address(newImplementation)); - require(managerChain1.token() == address(tnew), "Token not updated"); + nttManagerChain1.upgrade(address(newImplementation)); + require(nttManagerChain1.token() == address(tnew), "Token not updated"); basicFunctionality(); } - function test_immutableBlockUpdateSuccessEndpoint() public { - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointImmutableAllow( - address(managerChain1), + function test_immutableBlockUpdateSuccessTransceiver() public { + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverImmutableAllow( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), @@ -313,32 +316,32 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { ); //vm.expectRevert(); // Reverts with a panic on the assert. So, no way to tell WHY this happened. - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); require( - wormholeEndpointChain1.manager() == address(managerChain1), - "Manager updated when it shouldn't be" + wormholeTransceiverChain1.nttManager() == address(nttManagerChain1), + "NttManager updated when it shouldn't be" ); } - function test_authManager() public { + function test_authNttManager() public { // User not owner so this should fail vm.prank(userA); vm.expectRevert( abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, userA) ); - managerChain1.upgrade(address(0x1)); + nttManagerChain1.upgrade(address(0x1)); // Basic call to upgrade so that we can get the real implementation. - Manager newImplementation = new MockManagerContract( - address(managerChain1.token()), Manager.Mode.LOCKING, chainId1, 1 days + NttManager newImplementation = new MockNttManagerContract( + address(nttManagerChain1.token()), NttManager.Mode.LOCKING, chainId1, 1 days ); - managerChain1.upgrade(address(newImplementation)); + nttManagerChain1.upgrade(address(newImplementation)); basicFunctionality(); // Ensure that the upgrade was proper vm.expectRevert(abi.encodeWithSelector(Implementation.NotMigrating.selector)); - managerChain1.migrate(); + nttManagerChain1.migrate(); // Test if we can 'migrate' from this point // Migrate without delegatecall @@ -350,93 +353,93 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { vm.expectRevert( abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, userA) ); - managerChain1.transferOwnership(address(0x1)); + nttManagerChain1.transferOwnership(address(0x1)); // Should fail because it's already initialized vm.expectRevert(Initializable.InvalidInitialization.selector); - managerChain1.initialize(); + nttManagerChain1.initialize(); // Should fail because we're calling the implementation directly instead of the proxy. vm.expectRevert(Implementation.OnlyDelegateCall.selector); newImplementation.initialize(); } - function test_authEndpoint() public { + function test_authTransceiver() public { // User not owner so this should fail vm.prank(userA); vm.expectRevert( abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, userA) ); - wormholeEndpointChain1.upgrade(address(0x01)); + wormholeTransceiverChain1.upgrade(address(0x01)); - // Basic call so that we can easily see what the new endpoint is. - WormholeEndpoint wormholeEndpointChain1Implementation = new MockWormholeEndpointContract( - address(managerChain1), + // Basic call so that we can easily see what the new transceiver is. + WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverContract( + address(nttManagerChain1), address(wormhole), address(relayer), address(0x0), FAST_CONSISTENCY_LEVEL ); - wormholeEndpointChain1.upgrade(address(wormholeEndpointChain1Implementation)); + wormholeTransceiverChain1.upgrade(address(wormholeTransceiverChain1Implementation)); basicFunctionality(); // Ensure that the upgrade was proper // Test if we can 'migrate' from this point // Migrate without delegatecall vm.expectRevert(abi.encodeWithSelector(Implementation.OnlyDelegateCall.selector)); - wormholeEndpointChain1Implementation.migrate(); + wormholeTransceiverChain1Implementation.migrate(); // Migrate - should fail since we're executing something outside of a migration vm.expectRevert(abi.encodeWithSelector(Implementation.NotMigrating.selector)); - wormholeEndpointChain1.migrate(); + wormholeTransceiverChain1.migrate(); // Transfer the ownership - shouldn't have permission for that vm.prank(userA); vm.expectRevert( abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, userA) ); - wormholeEndpointChain1.transferOwnership(address(0x1)); + wormholeTransceiverChain1.transferOwnership(address(0x1)); // Should fail because it's already initialized vm.expectRevert(Initializable.InvalidInitialization.selector); - wormholeEndpointChain1.initialize(); + wormholeTransceiverChain1.initialize(); // // Should fail because we're calling the implementation directly instead of the proxy. vm.expectRevert(Implementation.OnlyDelegateCall.selector); - wormholeEndpointChain1Implementation.initialize(); + wormholeTransceiverChain1Implementation.initialize(); } function basicFunctionality() public { vm.chainId(chainId1); // Setting up the transfer - DummyToken token1 = DummyToken(managerChain1.token()); - DummyToken token2 = DummyTokenMintAndBurn(managerChain2.token()); + DummyToken token1 = DummyToken(nttManagerChain1.token()); + DummyToken token2 = DummyTokenMintAndBurn(nttManagerChain2.token()); uint8 decimals = token1.decimals(); uint256 sendingAmount = 5 * 10 ** decimals; token1.mintDummy(address(userA), 5 * 10 ** decimals); vm.startPrank(userA); - token1.approve(address(managerChain1), sendingAmount); + token1.approve(address(nttManagerChain1), sendingAmount); vm.recordLogs(); // Send token through standard means (not relayer) { - uint256 managerBalanceBefore = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceBefore = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceBefore = token1.balanceOf(address(userA)); - managerChain1.transfer( + nttManagerChain1.transfer( sendingAmount, chainId2, bytes32(uint256(uint160(userB))), false, - encodeEndpointInstruction(true) + encodeTransceiverInstruction(true) ); // Balance check on funds going in and out working as expected - uint256 managerBalanceAfter = token1.balanceOf(address(managerChain1)); + uint256 nttManagerBalanceAfter = token1.balanceOf(address(nttManagerChain1)); uint256 userBalanceAfter = token1.balanceOf(address(userB)); require( - managerBalanceBefore + sendingAmount == managerBalanceAfter, + nttManagerBalanceBefore + sendingAmount == nttManagerBalanceAfter, "Should be locking the tokens" ); require( @@ -458,20 +461,22 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { vm.chainId(chainId2); vm.expectRevert(); // Wrong chain receiving the signed VAA - wormholeEndpointChain1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); { uint256 supplyBefore = token2.totalSupply(); - wormholeEndpointChain2.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); uint256 supplyAfter = token2.totalSupply(); require(sendingAmount + supplyBefore == supplyAfter, "Supplies dont match"); require(token2.balanceOf(userB) == sendingAmount, "User didn't receive tokens"); - require(token2.balanceOf(address(managerChain2)) == 0, "Manager has unintended funds"); + require( + token2.balanceOf(address(nttManagerChain2)) == 0, "NttManager has unintended funds" + ); } // Can't resubmit the same message twice vm.expectRevert(); // TransferAlreadyCompleted error - wormholeEndpointChain2.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain2.receiveMessage(encodedVMs[0]); // Go back the other way from a THIRD user vm.prank(userB); @@ -479,18 +484,18 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { vm.startPrank(userC); - token2.approve(address(managerChain2), sendingAmount); + token2.approve(address(nttManagerChain2), sendingAmount); vm.recordLogs(); // Supply checks on the transfer { uint256 supplyBefore = token2.totalSupply(); - managerChain2.transfer( + nttManagerChain2.transfer( sendingAmount, chainId1, bytes32(uint256(uint160(userD))), false, - encodeEndpointInstruction(true) + encodeTransceiverInstruction(true) ); uint256 supplyAfter = token2.totalSupply(); @@ -499,8 +504,8 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { require(token2.balanceOf(userB) == 0, "OG user receive tokens"); require(token2.balanceOf(userC) == 0, "Sending user didn't receive tokens"); require( - token2.balanceOf(address(managerChain2)) == 0, - "Manager didn't receive unintended funds" + token2.balanceOf(address(nttManagerChain2)) == 0, + "NttManager didn't receive unintended funds" ); } @@ -517,7 +522,7 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { { uint256 supplyBefore = token1.totalSupply(); uint256 userDBalanceBefore = token1.balanceOf(userD); - wormholeEndpointChain1.receiveMessage(encodedVMs[0]); + wormholeTransceiverChain1.receiveMessage(encodedVMs[0]); uint256 supplyAfter = token1.totalSupply(); @@ -532,25 +537,25 @@ contract TestUpgrades is Test, IManagerEvents, IRateLimiterEvents { vm.stopPrank(); } - function encodeEndpointInstruction(bool relayer_off) public view returns (bytes memory) { - WormholeEndpoint.WormholeEndpointInstruction memory instruction = - WormholeEndpoint.WormholeEndpointInstruction(relayer_off); + function encodeTransceiverInstruction(bool relayer_off) public view returns (bytes memory) { + WormholeTransceiver.WormholeTransceiverInstruction memory instruction = + WormholeTransceiver.WormholeTransceiverInstruction(relayer_off); bytes memory encodedInstructionWormhole = - wormholeEndpointChain1.encodeWormholeEndpointInstruction(instruction); - EndpointStructs.EndpointInstruction memory EndpointInstruction = - EndpointStructs.EndpointInstruction({index: 0, payload: encodedInstructionWormhole}); - EndpointStructs.EndpointInstruction[] memory EndpointInstructions = - new EndpointStructs.EndpointInstruction[](1); - EndpointInstructions[0] = EndpointInstruction; - return EndpointStructs.encodeEndpointInstructions(EndpointInstructions); + wormholeTransceiverChain1.encodeWormholeTransceiverInstruction(instruction); + TransceiverStructs.TransceiverInstruction memory TransceiverInstruction = TransceiverStructs + .TransceiverInstruction({index: 0, payload: encodedInstructionWormhole}); + TransceiverStructs.TransceiverInstruction[] memory TransceiverInstructions = + new TransceiverStructs.TransceiverInstruction[](1); + TransceiverInstructions[0] = TransceiverInstruction; + return TransceiverStructs.encodeTransceiverInstructions(TransceiverInstructions); } } contract TestInitialize is Test { function setUp() public {} - Manager managerChain1; - Manager managerChain2; + NttManager nttManagerChain1; + NttManager nttManagerChain2; using NormalizedAmountLib for uint256; using NormalizedAmountLib for NormalizedAmount; @@ -560,7 +565,7 @@ contract TestInitialize is Test { uint256 constant DEVNET_GUARDIAN_PK = 0xcfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0; - WormholeEndpoint wormholeEndpointChain1; + WormholeTransceiver wormholeTransceiverChain1; address userA = address(0x123); address relayer = address(0x28D8F1Be96f97C1387e94A53e00eCcFb4E75175a); @@ -572,17 +577,18 @@ contract TestInitialize is Test { vm.chainId(chainId1); DummyToken t1 = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t1), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t1), NttManager.Mode.LOCKING, chainId1, 1 days); - managerChain1 = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerChain1 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); // Initialize once - managerChain1.initialize(); + nttManagerChain1.initialize(); // Initialize twice vm.expectRevert(Initializable.InvalidInitialization.selector); - managerChain1.initialize(); + nttManagerChain1.initialize(); } function test_cannotFrontrunInitialize() public { @@ -591,16 +597,17 @@ contract TestInitialize is Test { vm.chainId(chainId1); DummyToken t1 = new DummyToken(); - Manager implementation = - new MockManagerContract(address(t1), Manager.Mode.LOCKING, chainId1, 1 days); + NttManager implementation = + new MockNttManagerContract(address(t1), NttManager.Mode.LOCKING, chainId1, 1 days); - managerChain1 = MockManagerContract(address(new ERC1967Proxy(address(implementation), ""))); + nttManagerChain1 = + MockNttManagerContract(address(new ERC1967Proxy(address(implementation), ""))); // Attempt to initialize the contract from a non-deployer account. vm.prank(userA); vm.expectRevert( abi.encodeWithSignature("UnexpectedOwner(address,address)", address(this), userA) ); - managerChain1.initialize(); + nttManagerChain1.initialize(); } } diff --git a/evm/test/interfaces/IEndpointReceiver.sol b/evm/test/interfaces/ITransceiverReceiver.sol similarity index 80% rename from evm/test/interfaces/IEndpointReceiver.sol rename to evm/test/interfaces/ITransceiverReceiver.sol index 8553223cb..6f66ecc3e 100644 --- a/evm/test/interfaces/IEndpointReceiver.sol +++ b/evm/test/interfaces/ITransceiverReceiver.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; -interface IEndpointReceiver { +interface ITransceiverReceiver { function receiveMessage(bytes memory encodedMessage) external; } diff --git a/evm/test/libraries/EndpointHelpers.sol b/evm/test/libraries/EndpointHelpers.sol deleted file mode 100644 index 7e79575fc..000000000 --- a/evm/test/libraries/EndpointHelpers.sol +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity >=0.8.8 <0.9.0; - -import "./ManagerHelpers.sol"; -import "../mocks/DummyEndpoint.sol"; -import "../mocks/DummyToken.sol"; -import "../../src/Manager.sol"; -import "../../src/libraries/NormalizedAmount.sol"; - -library EndpointHelpersLib { - using NormalizedAmountLib for NormalizedAmount; - - // 0x99'E''T''T' - bytes4 constant TEST_ENDPOINT_PAYLOAD_PREFIX = 0x99455454; - uint16 constant SENDING_CHAIN_ID = 1; - - function setup_endpoints(Manager manager) internal returns (DummyEndpoint, DummyEndpoint) { - DummyEndpoint e1 = new DummyEndpoint(address(manager)); - DummyEndpoint e2 = new DummyEndpoint(address(manager)); - manager.setEndpoint(address(e1)); - manager.setEndpoint(address(e2)); - manager.setThreshold(2); - return (e1, e2); - } - - function attestEndpointsHelper( - address to, - uint64 sequence, - uint16 toChain, - Manager manager, - Manager recipientManager, - NormalizedAmount memory amount, - NormalizedAmount memory inboundLimit, - IEndpointReceiver[] memory endpoints - ) - internal - returns (EndpointStructs.ManagerMessage memory, EndpointStructs.EndpointMessage memory) - { - EndpointStructs.ManagerMessage memory m = - buildManagerMessage(to, sequence, toChain, manager, amount); - bytes memory encodedM = EndpointStructs.encodeManagerMessage(m); - - prepTokenReceive(manager, recipientManager, amount, inboundLimit); - - EndpointStructs.EndpointMessage memory em; - bytes memory encodedEm; - (em, encodedEm) = EndpointStructs.buildAndEncodeEndpointMessage( - TEST_ENDPOINT_PAYLOAD_PREFIX, - toWormholeFormat(address(manager)), - toWormholeFormat(address(recipientManager)), - encodedM, - new bytes(0) - ); - - for (uint256 i; i < endpoints.length; i++) { - IEndpointReceiver e = endpoints[i]; - e.receiveMessage(encodedEm); - } - - return (m, em); - } - - function buildManagerMessage( - address to, - uint64 sequence, - uint16 toChain, - Manager manager, - NormalizedAmount memory amount - ) internal view returns (EndpointStructs.ManagerMessage memory) { - DummyToken token = DummyToken(manager.token()); - - return EndpointStructs.ManagerMessage( - sequence, - bytes32(0), - EndpointStructs.encodeNativeTokenTransfer( - EndpointStructs.NativeTokenTransfer({ - amount: amount, - sourceToken: toWormholeFormat(address(token)), - to: toWormholeFormat(to), - toChain: toChain - }) - ) - ); - } - - function prepTokenReceive( - Manager manager, - Manager recipientManager, - NormalizedAmount memory amount, - NormalizedAmount memory inboundLimit - ) internal { - DummyToken token = DummyToken(manager.token()); - token.mintDummy(address(recipientManager), amount.denormalize(token.decimals())); - ManagerHelpersLib.setConfigs(inboundLimit, manager, recipientManager, token.decimals()); - } - - function buildEndpointMessageWithManagerPayload( - uint64 sequence, - bytes32 sender, - bytes32 sourceManager, - bytes32 recipientManager, - bytes memory payload - ) internal pure returns (EndpointStructs.ManagerMessage memory, bytes memory) { - EndpointStructs.ManagerMessage memory m = - EndpointStructs.ManagerMessage(sequence, sender, payload); - bytes memory managerMessage = EndpointStructs.encodeManagerMessage(m); - bytes memory endpointMessage; - (, endpointMessage) = EndpointStructs.buildAndEncodeEndpointMessage( - TEST_ENDPOINT_PAYLOAD_PREFIX, - sourceManager, - recipientManager, - managerMessage, - new bytes(0) - ); - return (m, endpointMessage); - } -} diff --git a/evm/test/libraries/ManagerHelpers.sol b/evm/test/libraries/NttManagerHelpers.sol similarity index 50% rename from evm/test/libraries/ManagerHelpers.sol rename to evm/test/libraries/NttManagerHelpers.sol index 1ec962702..878d9d1a7 100644 --- a/evm/test/libraries/ManagerHelpers.sol +++ b/evm/test/libraries/NttManagerHelpers.sol @@ -3,20 +3,20 @@ pragma solidity >=0.8.8 <0.9.0; import "../../src/libraries/NormalizedAmount.sol"; -import "../../src/Manager.sol"; +import "../../src/NttManager.sol"; -library ManagerHelpersLib { +library NttManagerHelpersLib { uint16 constant SENDING_CHAIN_ID = 1; using NormalizedAmountLib for NormalizedAmount; function setConfigs( NormalizedAmount memory inboundLimit, - Manager manager, - Manager recipientManager, + NttManager nttManager, + NttManager recipientNttManager, uint8 decimals ) internal { - recipientManager.setSibling(SENDING_CHAIN_ID, toWormholeFormat(address(manager))); - recipientManager.setInboundLimit(inboundLimit.denormalize(decimals), SENDING_CHAIN_ID); + recipientNttManager.setPeer(SENDING_CHAIN_ID, toWormholeFormat(address(nttManager))); + recipientNttManager.setInboundLimit(inboundLimit.denormalize(decimals), SENDING_CHAIN_ID); } } diff --git a/evm/test/libraries/TransceiverHelpers.sol b/evm/test/libraries/TransceiverHelpers.sol new file mode 100644 index 000000000..9f8f0d2c1 --- /dev/null +++ b/evm/test/libraries/TransceiverHelpers.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity >=0.8.8 <0.9.0; + +import "./NttManagerHelpers.sol"; +import "../mocks/DummyTransceiver.sol"; +import "../mocks/DummyToken.sol"; +import "../../src/NttManager.sol"; +import "../../src/libraries/NormalizedAmount.sol"; + +library TransceiverHelpersLib { + using NormalizedAmountLib for NormalizedAmount; + + // 0x99'E''T''T' + bytes4 constant TEST_TRANSCEIVER_PAYLOAD_PREFIX = 0x99455454; + uint16 constant SENDING_CHAIN_ID = 1; + + function setup_transceivers(NttManager nttManager) + internal + returns (DummyTransceiver, DummyTransceiver) + { + DummyTransceiver e1 = new DummyTransceiver(address(nttManager)); + DummyTransceiver e2 = new DummyTransceiver(address(nttManager)); + nttManager.setTransceiver(address(e1)); + nttManager.setTransceiver(address(e2)); + nttManager.setThreshold(2); + return (e1, e2); + } + + function attestTransceiversHelper( + address to, + uint64 sequence, + uint16 toChain, + NttManager nttManager, + NttManager recipientNttManager, + NormalizedAmount memory amount, + NormalizedAmount memory inboundLimit, + ITransceiverReceiver[] memory transceivers + ) + internal + returns ( + TransceiverStructs.NttManagerMessage memory, + TransceiverStructs.TransceiverMessage memory + ) + { + TransceiverStructs.NttManagerMessage memory m = + buildNttManagerMessage(to, sequence, toChain, nttManager, amount); + bytes memory encodedM = TransceiverStructs.encodeNttManagerMessage(m); + + prepTokenReceive(nttManager, recipientNttManager, amount, inboundLimit); + + TransceiverStructs.TransceiverMessage memory em; + bytes memory encodedEm; + (em, encodedEm) = TransceiverStructs.buildAndEncodeTransceiverMessage( + TEST_TRANSCEIVER_PAYLOAD_PREFIX, + toWormholeFormat(address(nttManager)), + toWormholeFormat(address(recipientNttManager)), + encodedM, + new bytes(0) + ); + + for (uint256 i; i < transceivers.length; i++) { + ITransceiverReceiver e = transceivers[i]; + e.receiveMessage(encodedEm); + } + + return (m, em); + } + + function buildNttManagerMessage( + address to, + uint64 sequence, + uint16 toChain, + NttManager nttManager, + NormalizedAmount memory amount + ) internal view returns (TransceiverStructs.NttManagerMessage memory) { + DummyToken token = DummyToken(nttManager.token()); + + return TransceiverStructs.NttManagerMessage( + sequence, + bytes32(0), + TransceiverStructs.encodeNativeTokenTransfer( + TransceiverStructs.NativeTokenTransfer({ + amount: amount, + sourceToken: toWormholeFormat(address(token)), + to: toWormholeFormat(to), + toChain: toChain + }) + ) + ); + } + + function prepTokenReceive( + NttManager nttManager, + NttManager recipientNttManager, + NormalizedAmount memory amount, + NormalizedAmount memory inboundLimit + ) internal { + DummyToken token = DummyToken(nttManager.token()); + token.mintDummy(address(recipientNttManager), amount.denormalize(token.decimals())); + NttManagerHelpersLib.setConfigs( + inboundLimit, nttManager, recipientNttManager, token.decimals() + ); + } + + function buildTransceiverMessageWithNttManagerPayload( + uint64 sequence, + bytes32 sender, + bytes32 sourceNttManager, + bytes32 recipientNttManager, + bytes memory payload + ) internal pure returns (TransceiverStructs.NttManagerMessage memory, bytes memory) { + TransceiverStructs.NttManagerMessage memory m = + TransceiverStructs.NttManagerMessage(sequence, sender, payload); + bytes memory nttManagerMessage = TransceiverStructs.encodeNttManagerMessage(m); + bytes memory transceiverMessage; + (, transceiverMessage) = TransceiverStructs.buildAndEncodeTransceiverMessage( + TEST_TRANSCEIVER_PAYLOAD_PREFIX, + sourceNttManager, + recipientNttManager, + nttManagerMessage, + new bytes(0) + ); + return (m, transceiverMessage); + } +} diff --git a/evm/test/mocks/DummyEndpoint.sol b/evm/test/mocks/DummyEndpoint.sol deleted file mode 100644 index 749294d2e..000000000 --- a/evm/test/mocks/DummyEndpoint.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity >=0.8.8 <0.9.0; - -import "forge-std/Test.sol"; -import "../../src/Endpoint.sol"; -import "../interfaces/IEndpointReceiver.sol"; - -contract DummyEndpoint is Endpoint, IEndpointReceiver { - uint16 constant SENDING_CHAIN_ID = 1; - bytes4 constant TEST_ENDPOINT_PAYLOAD_PREFIX = 0x99455454; - - constructor(address manager) Endpoint(manager) {} - - function _quoteDeliveryPrice( - uint16, /* recipientChain */ - EndpointStructs.EndpointInstruction memory /* endpointInstruction */ - ) internal pure override returns (uint256) { - return 0; - } - - function _sendMessage( - uint16, /* recipientChain */ - uint256, /* deliveryPayment */ - address, /* caller */ - bytes32, /* recipientManagerAddress */ - EndpointStructs.EndpointInstruction memory, /* instruction */ - bytes memory /* payload */ - ) internal override { - // do nothing - } - - function receiveMessage(bytes memory encodedMessage) external { - EndpointStructs.EndpointMessage memory parsedEndpointMessage; - EndpointStructs.ManagerMessage memory parsedManagerMessage; - (parsedEndpointMessage, parsedManagerMessage) = EndpointStructs - .parseEndpointAndManagerMessage(TEST_ENDPOINT_PAYLOAD_PREFIX, encodedMessage); - _deliverToManager( - SENDING_CHAIN_ID, - parsedEndpointMessage.sourceManagerAddress, - parsedEndpointMessage.recipientManagerAddress, - parsedManagerMessage - ); - } - - function parseMessageFromLogs(Vm.Log[] memory logs) - public - pure - returns (uint16 recipientChain, bytes memory payload) - {} -} diff --git a/evm/test/mocks/DummyToken.sol b/evm/test/mocks/DummyToken.sol index 42c0ed566..896d41af9 100644 --- a/evm/test/mocks/DummyToken.sol +++ b/evm/test/mocks/DummyToken.sol @@ -8,17 +8,17 @@ contract DummyToken is ERC20 { constructor() ERC20("DummyToken", "DTKN") {} // NOTE: this is purposefully not called mint() to so we can test that in - // locking mode the Manager contract doesn't call mint (or burn) + // locking mode the NttManager contract doesn't call mint (or burn) function mintDummy(address to, uint256 amount) public { _mint(to, amount); } function mint(address, uint256) public virtual { - revert("Locking manager should not call 'mint()'"); + revert("Locking nttManager should not call 'mint()'"); } function burnFrom(address, uint256) public virtual { - revert("Locking manager should not call 'burnFrom()'"); + revert("Locking nttManager should not call 'burnFrom()'"); } } diff --git a/evm/test/mocks/DummyTransceiver.sol b/evm/test/mocks/DummyTransceiver.sol new file mode 100644 index 000000000..91c80a654 --- /dev/null +++ b/evm/test/mocks/DummyTransceiver.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity >=0.8.8 <0.9.0; + +import "forge-std/Test.sol"; +import "../../src/Transceiver.sol"; +import "../interfaces/ITransceiverReceiver.sol"; + +contract DummyTransceiver is Transceiver, ITransceiverReceiver { + uint16 constant SENDING_CHAIN_ID = 1; + bytes4 constant TEST_TRANSCEIVER_PAYLOAD_PREFIX = 0x99455454; + + constructor(address nttManager) Transceiver(nttManager) {} + + function _quoteDeliveryPrice( + uint16, /* recipientChain */ + TransceiverStructs.TransceiverInstruction memory /* transceiverInstruction */ + ) internal pure override returns (uint256) { + return 0; + } + + function _sendMessage( + uint16, /* recipientChain */ + uint256, /* deliveryPayment */ + address, /* caller */ + bytes32, /* recipientNttManagerAddress */ + TransceiverStructs.TransceiverInstruction memory, /* instruction */ + bytes memory /* payload */ + ) internal override { + // do nothing + } + + function receiveMessage(bytes memory encodedMessage) external { + TransceiverStructs.TransceiverMessage memory parsedTransceiverMessage; + TransceiverStructs.NttManagerMessage memory parsedNttManagerMessage; + (parsedTransceiverMessage, parsedNttManagerMessage) = TransceiverStructs + .parseTransceiverAndNttManagerMessage(TEST_TRANSCEIVER_PAYLOAD_PREFIX, encodedMessage); + _deliverToNttManager( + SENDING_CHAIN_ID, + parsedTransceiverMessage.sourceNttManagerAddress, + parsedTransceiverMessage.recipientNttManagerAddress, + parsedNttManagerMessage + ); + } + + function parseMessageFromLogs(Vm.Log[] memory logs) + public + pure + returns (uint16 recipientChain, bytes memory payload) + {} +} diff --git a/evm/test/mocks/MockManager.sol b/evm/test/mocks/MockNttManager.sol similarity index 75% rename from evm/test/mocks/MockManager.sol rename to evm/test/mocks/MockNttManager.sol index 0109b46b5..bc1d2882c 100644 --- a/evm/test/mocks/MockManager.sol +++ b/evm/test/mocks/MockNttManager.sol @@ -2,15 +2,15 @@ pragma solidity >=0.8.8 <0.9.0; -import "../../src/Manager.sol"; +import "../../src/NttManager.sol"; -contract MockManagerContract is Manager { +contract MockNttManagerContract is NttManager { constructor( address token, Mode mode, uint16 chainId, uint64 rateLimitDuration - ) Manager(token, mode, chainId, rateLimitDuration) {} + ) NttManager(token, mode, chainId, rateLimitDuration) {} /// We create a dummy storage variable here with standard solidity slot assignment. /// Then we check that its assigned slot is 0, i.e. that the super contract doesn't @@ -33,40 +33,40 @@ contract MockManagerContract is Manager { } } -contract MockManagerMigrateBasic is Manager { +contract MockNttManagerMigrateBasic is NttManager { // Call the parents constructor constructor( address token, Mode mode, uint16 chainId, uint64 rateLimitDuration - ) Manager(token, mode, chainId, rateLimitDuration) {} + ) NttManager(token, mode, chainId, rateLimitDuration) {} function _migrate() internal view override { _checkThresholdInvariants(); - _checkEndpointsInvariants(); + _checkTransceiversInvariants(); revert("Proper migrate called"); } } -contract MockManagerImmutableCheck is Manager { +contract MockNttManagerImmutableCheck is NttManager { // Call the parents constructor constructor( address token, Mode mode, uint16 chainId, uint64 rateLimitDuration - ) Manager(token, mode, chainId, rateLimitDuration) {} + ) NttManager(token, mode, chainId, rateLimitDuration) {} } -contract MockManagerImmutableRemoveCheck is Manager { +contract MockNttManagerImmutableRemoveCheck is NttManager { // Call the parents constructor constructor( address token, Mode mode, uint16 chainId, uint64 rateLimitDuration - ) Manager(token, mode, chainId, rateLimitDuration) {} + ) NttManager(token, mode, chainId, rateLimitDuration) {} // Turns on the capability to EDIT the immutables function _migrate() internal override { @@ -74,7 +74,7 @@ contract MockManagerImmutableRemoveCheck is Manager { } } -contract MockManagerStorageLayoutChange is Manager { +contract MockNttManagerStorageLayoutChange is NttManager { address a; address b; address c; @@ -85,7 +85,7 @@ contract MockManagerStorageLayoutChange is Manager { Mode mode, uint16 chainId, uint64 rateLimitDuration - ) Manager(token, mode, chainId, rateLimitDuration) {} + ) NttManager(token, mode, chainId, rateLimitDuration) {} function setData() public { a = address(0x1); diff --git a/evm/test/mocks/MockEndpoints.sol b/evm/test/mocks/MockTransceivers.sol similarity index 72% rename from evm/test/mocks/MockEndpoints.sol rename to evm/test/mocks/MockTransceivers.sol index 5e0dd3a69..17f60f1d9 100644 --- a/evm/test/mocks/MockEndpoints.sol +++ b/evm/test/mocks/MockTransceivers.sol @@ -2,18 +2,18 @@ pragma solidity >=0.8.8 <0.9.0; -import "../../src/WormholeEndpoint.sol"; +import "../../src/WormholeTransceiver.sol"; -contract MockWormholeEndpointContract is WormholeEndpoint { +contract MockWormholeTransceiverContract is WormholeTransceiver { constructor( - address manager, + address nttManager, address wormholeCoreBridge, address wormholeRelayerAddr, address specialRelayerAddr, uint8 _consistencyLevel ) - WormholeEndpoint( - manager, + WormholeTransceiver( + nttManager, wormholeCoreBridge, wormholeRelayerAddr, specialRelayerAddr, @@ -22,22 +22,22 @@ contract MockWormholeEndpointContract is WormholeEndpoint { {} /// @dev Override the [`transferOwnership`] method from OwnableUpgradeable - /// to ensure owner of this contract is in sync with the onwer of the Manager contract. + /// to ensure owner of this contract is in sync with the onwer of the NttManager contract. function transferOwnership(address newOwner) public view override onlyOwner { - revert CannotTransferEndpointOwnership(owner(), newOwner); + revert CannotTransferTransceiverOwnership(owner(), newOwner); } } -contract MockWormholeEndpointMigrateBasic is WormholeEndpoint { +contract MockWormholeTransceiverMigrateBasic is WormholeTransceiver { constructor( - address manager, + address nttManager, address wormholeCoreBridge, address wormholeRelayerAddr, address specialRelayerAddr, uint8 _consistencyLevel ) - WormholeEndpoint( - manager, + WormholeTransceiver( + nttManager, wormholeCoreBridge, wormholeRelayerAddr, specialRelayerAddr, @@ -50,16 +50,16 @@ contract MockWormholeEndpointMigrateBasic is WormholeEndpoint { } } -contract MockWormholeEndpointImmutableAllow is WormholeEndpoint { +contract MockWormholeTransceiverImmutableAllow is WormholeTransceiver { constructor( - address manager, + address nttManager, address wormholeCoreBridge, address wormholeRelayerAddr, address specialRelayerAddr, uint8 _consistencyLevel ) - WormholeEndpoint( - manager, + WormholeTransceiver( + nttManager, wormholeCoreBridge, wormholeRelayerAddr, specialRelayerAddr, @@ -73,21 +73,21 @@ contract MockWormholeEndpointImmutableAllow is WormholeEndpoint { } } -contract MockWormholeEndpointLayoutChange is WormholeEndpoint { +contract MockWormholeTransceiverLayoutChange is WormholeTransceiver { address a; address b; address c; // Call the parents constructor constructor( - address manager, + address nttManager, address wormholeCoreBridge, address wormholeRelayerAddr, address specialRelayerAddr, uint8 _consistencyLevel ) - WormholeEndpoint( - manager, + WormholeTransceiver( + nttManager, wormholeCoreBridge, wormholeRelayerAddr, specialRelayerAddr, diff --git a/solana/modules/ntt-messages/src/endpoints/wormhole.rs b/solana/modules/ntt-messages/src/endpoints/wormhole.rs deleted file mode 100644 index 92119a7b3..000000000 --- a/solana/modules/ntt-messages/src/endpoints/wormhole.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::endpoint::Endpoint; - -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct WormholeEndpoint {} - -impl Endpoint for WormholeEndpoint { - const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10]; -} diff --git a/solana/modules/ntt-messages/src/lib.rs b/solana/modules/ntt-messages/src/lib.rs index d4450d4d8..4d77c4c87 100644 --- a/solana/modules/ntt-messages/src/lib.rs +++ b/solana/modules/ntt-messages/src/lib.rs @@ -1,7 +1,7 @@ pub mod chain_id; -pub mod endpoint; -pub mod endpoints; -pub mod manager; pub mod normalized_amount; pub mod ntt; +pub mod ntt_manager; +pub mod transceiver; +pub mod transceivers; pub mod utils; diff --git a/solana/modules/ntt-messages/src/manager.rs b/solana/modules/ntt-messages/src/ntt_manager.rs similarity index 82% rename from solana/modules/ntt-messages/src/manager.rs rename to solana/modules/ntt-messages/src/ntt_manager.rs index c4a8f850c..4e6482e28 100644 --- a/solana/modules/ntt-messages/src/manager.rs +++ b/solana/modules/ntt-messages/src/ntt_manager.rs @@ -12,16 +12,16 @@ use crate::utils::maybe_space::MaybeSpace; feature = "anchor", derive(AnchorSerialize, AnchorDeserialize, InitSpace) )] -pub struct ManagerMessage { +pub struct NttManagerMessage { pub sequence: u64, pub sender: [u8; 32], pub payload: A, } #[cfg(feature = "hash")] -impl ManagerMessage +impl NttManagerMessage where - ManagerMessage: TypePrefixedPayload, + NttManagerMessage: TypePrefixedPayload, { pub fn keccak256(&self, chain_id: crate::chain_id::ChainId) -> solana_program::keccak::Hash { let mut bytes: Vec = Vec::new(); @@ -31,11 +31,11 @@ where } } -impl TypePrefixedPayload for ManagerMessage { +impl TypePrefixedPayload for NttManagerMessage { const TYPE: Option = None; } -impl Readable for ManagerMessage { +impl Readable for NttManagerMessage { const SIZE: Option = None; fn read(reader: &mut R) -> io::Result @@ -45,7 +45,7 @@ impl Readable for ManagerMessage { { let sequence = Readable::read(reader)?; let sender = Readable::read(reader)?; - // TODO: same as below for manager payload + // TODO: same as below for ntt_manager payload let _payload_len: u16 = Readable::read(reader)?; let payload = A::read_payload(reader)?; @@ -57,7 +57,7 @@ impl Readable for ManagerMessage { } } -impl Writeable for ManagerMessage { +impl Writeable for NttManagerMessage { fn written_size(&self) -> usize { u64::SIZE.unwrap() + self.sender.len() @@ -69,7 +69,7 @@ impl Writeable for ManagerMessage { where W: io::Write, { - let ManagerMessage { + let NttManagerMessage { sequence, sender, payload, diff --git a/solana/modules/ntt-messages/src/endpoint.rs b/solana/modules/ntt-messages/src/transceiver.rs similarity index 55% rename from solana/modules/ntt-messages/src/endpoint.rs rename to solana/modules/ntt-messages/src/transceiver.rs index 0bb1c3361..a3e6dd700 100644 --- a/solana/modules/ntt-messages/src/endpoint.rs +++ b/solana/modules/ntt-messages/src/transceiver.rs @@ -6,9 +6,9 @@ use anchor_lang::prelude::*; use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; -use crate::{manager::ManagerMessage, utils::maybe_space::MaybeSpace}; +use crate::{ntt_manager::NttManagerMessage, utils::maybe_space::MaybeSpace}; -pub trait Endpoint { +pub trait Transceiver { const PREFIX: [u8; 4]; } @@ -17,36 +17,36 @@ pub trait Endpoint { feature = "anchor", derive(AnchorSerialize, AnchorDeserialize, InitSpace) )] -pub struct EndpointMessageData { - pub source_manager: [u8; 32], - pub recipient_manager: [u8; 32], - pub manager_payload: ManagerMessage, +pub struct TransceiverMessageData { + pub source_ntt_manager: [u8; 32], + pub recipient_ntt_manager: [u8; 32], + pub ntt_manager_payload: NttManagerMessage, } #[derive(Eq, PartialEq, Clone, Debug)] -pub struct EndpointMessage { +pub struct TransceiverMessage { _phantom: PhantomData, - // TODO: check sibling registration at the manager level - pub message_data: EndpointMessageData, - pub endpoint_payload: Vec, + // TODO: check peer registration at the ntt_manager level + pub message_data: TransceiverMessageData, + pub transceiver_payload: Vec, } -impl std::ops::Deref for EndpointMessage { - type Target = EndpointMessageData; +impl std::ops::Deref for TransceiverMessage { + type Target = TransceiverMessageData; fn deref(&self) -> &Self::Target { &self.message_data } } -impl std::ops::DerefMut for EndpointMessage { +impl std::ops::DerefMut for TransceiverMessage { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.message_data } } #[cfg(feature = "anchor")] -impl AnchorDeserialize for EndpointMessage +impl AnchorDeserialize for TransceiverMessage where A: MaybeSpace, { @@ -56,7 +56,7 @@ where } #[cfg(feature = "anchor")] -impl AnchorSerialize for EndpointMessage +impl AnchorSerialize for TransceiverMessage where A: MaybeSpace, { @@ -65,37 +65,37 @@ where } } -impl EndpointMessage +impl TransceiverMessage where A: MaybeSpace, { pub fn new( - source_manager: [u8; 32], - recipient_manager: [u8; 32], - manager_payload: ManagerMessage, - endpoint_payload: Vec, + source_ntt_manager: [u8; 32], + recipient_ntt_manager: [u8; 32], + ntt_manager_payload: NttManagerMessage, + transceiver_payload: Vec, ) -> Self { Self { _phantom: PhantomData, - message_data: EndpointMessageData { - source_manager, - recipient_manager, - manager_payload, + message_data: TransceiverMessageData { + source_ntt_manager, + recipient_ntt_manager, + ntt_manager_payload, }, - endpoint_payload, + transceiver_payload, } } } -impl TypePrefixedPayload - for EndpointMessage +impl TypePrefixedPayload + for TransceiverMessage where A: MaybeSpace + Clone, { const TYPE: Option = None; } -impl Readable for EndpointMessage +impl Readable for TransceiverMessage where A: MaybeSpace, { @@ -110,68 +110,68 @@ where if prefix != E::PREFIX { return Err(io::Error::new( io::ErrorKind::InvalidData, - "Invalid prefix for EndpointMessage", + "Invalid prefix for TransceiverMessage", )); } - let source_manager = Readable::read(reader)?; - let recipient_manager = Readable::read(reader)?; + let source_ntt_manager = Readable::read(reader)?; + let recipient_ntt_manager = Readable::read(reader)?; // TODO: we need a way to easily check that decoding the payload // consumes the expected amount of bytes - let _manager_payload_len: u16 = Readable::read(reader)?; - let manager_payload = ManagerMessage::read(reader)?; - let endpoint_payload_len: u16 = Readable::read(reader)?; - let mut endpoint_payload = vec![0; endpoint_payload_len as usize]; - reader.read_exact(&mut endpoint_payload)?; - - Ok(EndpointMessage::new( - source_manager, - recipient_manager, - manager_payload, - endpoint_payload, + let _ntt_manager_payload_len: u16 = Readable::read(reader)?; + let ntt_manager_payload = NttManagerMessage::read(reader)?; + let transceiver_payload_len: u16 = Readable::read(reader)?; + let mut transceiver_payload = vec![0; transceiver_payload_len as usize]; + reader.read_exact(&mut transceiver_payload)?; + + Ok(TransceiverMessage::new( + source_ntt_manager, + recipient_ntt_manager, + ntt_manager_payload, + transceiver_payload, )) } } -impl Writeable for EndpointMessage +impl Writeable for TransceiverMessage where A: MaybeSpace, { fn written_size(&self) -> usize { 4 // prefix - + self.source_manager.len() + + self.source_ntt_manager.len() + u16::SIZE.unwrap() // length prefix - + self.manager_payload.written_size() + + self.ntt_manager_payload.written_size() } fn write(&self, writer: &mut W) -> io::Result<()> where W: io::Write, { - let EndpointMessage { + let TransceiverMessage { _phantom, message_data: - EndpointMessageData { - source_manager, - recipient_manager, - manager_payload, + TransceiverMessageData { + source_ntt_manager, + recipient_ntt_manager, + ntt_manager_payload, }, - endpoint_payload, + transceiver_payload, } = self; E::PREFIX.write(writer)?; - source_manager.write(writer)?; - recipient_manager.write(writer)?; - let len: u16 = u16::try_from(manager_payload.written_size()).expect("u16 overflow"); + source_ntt_manager.write(writer)?; + recipient_ntt_manager.write(writer)?; + let len: u16 = u16::try_from(ntt_manager_payload.written_size()).expect("u16 overflow"); len.write(writer)?; // TODO: review this in wormhole-io. The written_size logic is error prone. Instead, // a better API would be // foo.write_with_prefix_be::(writer) // which writes the length as a big endian u16. - manager_payload.write(writer)?; - let len: u16 = u16::try_from(endpoint_payload.len()).expect("u16 overflow"); + ntt_manager_payload.write(writer)?; + let len: u16 = u16::try_from(transceiver_payload.len()).expect("u16 overflow"); len.write(writer)?; - writer.write_all(endpoint_payload)?; + writer.write_all(transceiver_payload)?; Ok(()) } } @@ -179,31 +179,31 @@ where #[cfg(test)] mod test { use crate::{ - chain_id::ChainId, endpoints::wormhole::WormholeEndpoint, - normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + chain_id::ChainId, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + transceivers::wormhole::WormholeTransceiver, }; use super::*; // #[test] - fn test_deserialize_endpoint_message() { + fn test_deserialize_transceiver_message() { let data = hex::decode("9945ff10042942fafabe0000000000000000000000000000000000000000000000000000042942fababe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe0000000000000000000000000000000000000000000000000000000000110000").unwrap(); let mut vec = &data[..]; - let message: EndpointMessage = + let message: TransceiverMessage = TypePrefixedPayload::read_payload(&mut vec).unwrap(); - let expected = EndpointMessage { - _phantom: PhantomData::, - message_data: EndpointMessageData { - source_manager: [ + let expected = TransceiverMessage { + _phantom: PhantomData::, + message_data: TransceiverMessageData { + source_ntt_manager: [ 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], - recipient_manager: [ + recipient_ntt_manager: [ 0x04, 0x29, 0x42, 0xFA, 0xBA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], - manager_payload: ManagerMessage { + ntt_manager_payload: NttManagerMessage { sequence: 233968345345, sender: [ 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -226,7 +226,7 @@ mod test { }, }, }, - endpoint_payload: vec![], + transceiver_payload: vec![], }; assert_eq!(message, expected); assert_eq!(vec.len(), 0); diff --git a/solana/modules/ntt-messages/src/endpoints/mod.rs b/solana/modules/ntt-messages/src/transceivers/mod.rs similarity index 100% rename from solana/modules/ntt-messages/src/endpoints/mod.rs rename to solana/modules/ntt-messages/src/transceivers/mod.rs diff --git a/solana/modules/ntt-messages/src/transceivers/wormhole.rs b/solana/modules/ntt-messages/src/transceivers/wormhole.rs new file mode 100644 index 000000000..710ba3af6 --- /dev/null +++ b/solana/modules/ntt-messages/src/transceivers/wormhole.rs @@ -0,0 +1,8 @@ +use crate::transceiver::Transceiver; + +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct WormholeTransceiver {} + +impl Transceiver for WormholeTransceiver { + const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10]; +} diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 6a1668017..888abd1bc 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -26,13 +26,13 @@ pub struct Config { /// hardcode this so that the program is deployable on any potential SVM /// forks. pub chain_id: ChainId, - /// The next endpoint id to use when registering an endpoint. - pub next_endpoint_id: u8, - /// The number of endpoints that must attest to a transfer before it is + /// The next transceiver id to use when registering an transceiver. + pub next_transceiver_id: u8, + /// The number of transceivers that must attest to a transfer before it is /// accepted. pub threshold: u8, - /// Bitmap of enabled endpoints - pub enabled_endpoints: Bitmap, + /// Bitmap of enabled transceivers + pub enabled_transceivers: Bitmap, /// Pause the program. This is useful for upgrades and other maintenance. pub paused: bool, } diff --git a/solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs deleted file mode 100644 index 36075717f..000000000 --- a/solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod sibling; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs b/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs deleted file mode 100644 index 84c941e3b..000000000 --- a/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs +++ /dev/null @@ -1,13 +0,0 @@ -use anchor_lang::prelude::*; - -#[account] -#[derive(InitSpace)] -/// A sibling on another chain. Stored in a PDA seeded by the chain id. -pub struct EndpointSibling { - pub bump: u8, - pub address: [u8; 32], -} - -impl EndpointSibling { - pub const SEED_PREFIX: &'static [u8] = b"endpoint_sibling"; -} diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index 113d94af0..17bb26610 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -11,12 +11,12 @@ pub enum NTTError { InvalidChainId, #[msg("InvalidRecipientAddress")] InvalidRecipientAddress, - #[msg("InvalidEndpointSibling")] - InvalidEndpointSibling, - #[msg("InvalidManagerSibling")] - InvalidManagerSibling, - #[msg("InvalidRecipientManager")] - InvalidRecipientManager, + #[msg("InvalidTransceiverPeer")] + InvalidTransceiverPeer, + #[msg("InvalidNttManagerPeer")] + InvalidNttManagerPeer, + #[msg("InvalidRecipientNttManager")] + InvalidRecipientNttManager, #[msg("TransferAlreadyRedeemed")] TransferAlreadyRedeemed, #[msg("TransferNotApproved")] @@ -31,8 +31,8 @@ pub enum NTTError { TransferExceedsRateLimit, #[msg("Paused")] Paused, - #[msg("DisabledEndpoint")] - DisabledEndpoint, + #[msg("DisabledTransceiver")] + DisabledTransceiver, #[msg("InvalidDeployer")] InvalidDeployer, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index bf6e07dd4..cdddf8fab 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -8,9 +8,9 @@ use crate::messages::Hack; use crate::{ config::Config, error::NTTError, + peer::NttManagerPeer, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, - registered_endpoint::RegisteredEndpoint, - sibling::ManagerSibling, + registered_transceiver::RegisteredTransceiver, }; // * Transfer ownership @@ -124,13 +124,13 @@ pub fn claim_ownership(ctx: Context) -> Result<()> { ) } -// * Set siblings -// TODO: update siblings? should that be a separate instruction? take timestamp +// * Set peers +// TODO: update peers? should that be a separate instruction? take timestamp // for modification? (for total ordering) #[derive(Accounts)] -#[instruction(args: SetSiblingArgs)] -pub struct SetSibling<'info> { +#[instruction(args: SetPeerArgs)] +pub struct SetPeer<'info> { #[account(mut)] pub payer: Signer<'info>, @@ -143,12 +143,12 @@ pub struct SetSibling<'info> { #[account( init, - space = 8 + ManagerSibling::INIT_SPACE, + space = 8 + NttManagerPeer::INIT_SPACE, payer = payer, - seeds = [ManagerSibling::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], + seeds = [NttManagerPeer::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], bump )] - pub sibling: Account<'info, ManagerSibling>, + pub peer: Account<'info, NttManagerPeer>, #[account( init, @@ -166,15 +166,15 @@ pub struct SetSibling<'info> { } #[derive(AnchorDeserialize, AnchorSerialize)] -pub struct SetSiblingArgs { +pub struct SetPeerArgs { pub chain_id: ChainId, pub address: [u8; 32], pub limit: u64, } -pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { - ctx.accounts.sibling.set_inner(ManagerSibling { - bump: ctx.bumps.sibling, +pub fn set_peer(ctx: Context, args: SetPeerArgs) -> Result<()> { + ctx.accounts.peer.set_inner(NttManagerPeer { + bump: ctx.bumps.peer, address: args.address, }); @@ -185,10 +185,10 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> Ok(()) } -// * Register endpoints +// * Register transceivers #[derive(Accounts)] -pub struct RegisterEndpoint<'info> { +pub struct RegisterTransceiver<'info> { #[account( mut, has_one = owner, @@ -201,32 +201,32 @@ pub struct RegisterEndpoint<'info> { pub payer: Signer<'info>, #[account(executable)] - pub endpoint: AccountInfo<'info>, + pub transceiver: AccountInfo<'info>, #[account( init, - space = 8 + RegisteredEndpoint::INIT_SPACE, + space = 8 + RegisteredTransceiver::INIT_SPACE, payer = payer, - seeds = [RegisteredEndpoint::SEED_PREFIX, endpoint.key().as_ref()], + seeds = [RegisteredTransceiver::SEED_PREFIX, transceiver.key().as_ref()], bump )] - pub registered_endpoint: Account<'info, RegisteredEndpoint>, + pub registered_transceiver: Account<'info, RegisteredTransceiver>, pub system_program: Program<'info, System>, } -pub fn register_endpoint(ctx: Context) -> Result<()> { - let id = ctx.accounts.config.next_endpoint_id; - ctx.accounts.config.next_endpoint_id += 1; +pub fn register_transceiver(ctx: Context) -> Result<()> { + let id = ctx.accounts.config.next_transceiver_id; + ctx.accounts.config.next_transceiver_id += 1; ctx.accounts - .registered_endpoint - .set_inner(RegisteredEndpoint { - bump: ctx.bumps.registered_endpoint, + .registered_transceiver + .set_inner(RegisteredTransceiver { + bump: ctx.bumps.registered_transceiver, id, - endpoint_address: ctx.accounts.endpoint.key(), + transceiver_address: ctx.accounts.transceiver.key(), }); - ctx.accounts.config.enabled_endpoints.set(id, true); + ctx.accounts.config.enabled_transceivers.set(id, true); Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 525da4d49..c312be457 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -108,10 +108,10 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> owner: ctx.accounts.deployer.key(), pending_owner: None, paused: false, - next_endpoint_id: 0, + next_transceiver_id: 0, // NOTE: can't be changed for now threshold: 1, - enabled_endpoints: Bitmap::new(), + enabled_transceivers: Bitmap::new(), }); ctx.accounts.seq.set_inner(Sequence { diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 48355429a..509222d33 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,19 +1,19 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; -use ntt_messages::{manager::ManagerMessage, ntt::NativeTokenTransfer}; +use ntt_messages::{ntt::NativeTokenTransfer, ntt_manager::NttManagerMessage}; use crate::{ bitmap::Bitmap, config::*, error::NTTError, - messages::ValidatedEndpointMessage, + messages::ValidatedTransceiverMessage, + peer::NttManagerPeer, queue::{ inbox::{InboxItem, InboxRateLimit, ReleaseStatus}, outbox::OutboxRateLimit, rate_limit::RateLimitResult, }, - registered_endpoint::*, - sibling::ManagerSibling, + registered_transceiver::*, }; #[derive(Accounts)] @@ -25,27 +25,27 @@ pub struct Redeem<'info> { pub config: Account<'info, Config>, #[account( - seeds = [ManagerSibling::SEED_PREFIX, endpoint_message.from_chain.id.to_be_bytes().as_ref()], - constraint = sibling.address == endpoint_message.message.source_manager @ NTTError::InvalidManagerSibling, - bump = sibling.bump, + seeds = [NttManagerPeer::SEED_PREFIX, transceiver_message.from_chain.id.to_be_bytes().as_ref()], + constraint = peer.address == transceiver_message.message.source_ntt_manager @ NTTError::InvalidNttManagerPeer, + bump = peer.bump, )] - pub sibling: Account<'info, ManagerSibling>, + pub peer: Account<'info, NttManagerPeer>, #[account( // check that the message is targeted to this chain - constraint = endpoint_message.message.manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + constraint = transceiver_message.message.ntt_manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, // check that we're the intended recipient - constraint = endpoint_message.message.recipient_manager == crate::ID.to_bytes() @ NTTError::InvalidRecipientManager, + constraint = transceiver_message.message.recipient_ntt_manager == crate::ID.to_bytes() @ NTTError::InvalidRecipientNttManager, // NOTE: we don't replay protect VAAs. Instead, we replay protect // executing the messages themselves with the [`released`] flag. - owner = endpoint.endpoint_address, + owner = transceiver.transceiver_address, )] - pub endpoint_message: Account<'info, ValidatedEndpointMessage>, + pub transceiver_message: Account<'info, ValidatedTransceiverMessage>, #[account( - constraint = config.enabled_endpoints.get(endpoint.id) @ NTTError::DisabledEndpoint + constraint = config.enabled_transceivers.get(transceiver.id) @ NTTError::DisabledTransceiver )] - pub endpoint: Account<'info, RegisteredEndpoint>, + pub transceiver: Account<'info, RegisteredTransceiver>, #[account( constraint = mint.key() == config.mint @@ -58,15 +58,15 @@ pub struct Redeem<'info> { space = 8 + InboxItem::INIT_SPACE, seeds = [ InboxItem::SEED_PREFIX, - endpoint_message.message.manager_payload.keccak256( - endpoint_message.from_chain + transceiver_message.message.ntt_manager_payload.keccak256( + transceiver_message.from_chain ).as_ref(), ], bump, )] /// NOTE: This account is content-addressed (PDA seeded by the message hash). - /// This is because in a multi-endpoint configuration, the different - /// endpoints "vote" on messages (by delivering them). By making the inbox + /// This is because in a multi-transceiver configuration, the different + /// transceivers "vote" on messages (by delivering them). By making the inbox /// items content-addressed, we can ensure that disagreeing votes don't /// interfere with each other. pub inbox_item: Account<'info, InboxItem>, @@ -75,7 +75,7 @@ pub struct Redeem<'info> { mut, seeds = [ InboxRateLimit::SEED_PREFIX, - endpoint_message.from_chain.id.to_be_bytes().as_ref(), + transceiver_message.from_chain.id.to_be_bytes().as_ref(), ], bump, )] @@ -93,8 +93,8 @@ pub struct RedeemArgs {} pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let accs = ctx.accounts; - let message: ManagerMessage = - accs.endpoint_message.message.manager_payload.clone(); + let message: NttManagerMessage = + accs.transceiver_message.message.ntt_manager_payload.clone(); let amount = message.payload.amount.denormalize(accs.mint.decimals); @@ -113,12 +113,12 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { } // idempotent - accs.inbox_item.votes.set(accs.endpoint.id, true); + accs.inbox_item.votes.set(accs.transceiver.id, true); if accs .inbox_item .votes - .count_enabled_votes(accs.config.enabled_endpoints) + .count_enabled_votes(accs.config.enabled_transceivers) < accs.config.threshold { return Ok(()); diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 9e2f48e54..f1d77b43b 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -6,12 +6,12 @@ use crate::{ bitmap::Bitmap, config::*, error::NTTError, + peer::NttManagerPeer, queue::{ inbox::InboxRateLimit, outbox::{OutboxItem, OutboxRateLimit}, rate_limit::RateLimitResult, }, - sibling::ManagerSibling, }; // this will burn the funds and create an account that either allows sending the @@ -94,10 +94,10 @@ pub struct TransferBurn<'info> { pub inbox_rate_limit: Account<'info, InboxRateLimit>, #[account( - seeds = [ManagerSibling::SEED_PREFIX, args.recipient_chain.id.to_be_bytes().as_ref()], - bump = sibling.bump, + seeds = [NttManagerPeer::SEED_PREFIX, args.recipient_chain.id.to_be_bytes().as_ref()], + bump = peer.bump, )] - pub sibling: Account<'info, ManagerSibling>, + pub peer: Account<'info, NttManagerPeer>, } // TODO: fees for relaying? @@ -135,14 +135,14 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( amount, )?; - let recipient_manager = accs.sibling.address; + let recipient_ntt_manager = accs.peer.address; insert_into_outbox( &mut accs.common, &mut accs.inbox_rate_limit, amount, recipient_chain, - recipient_manager, + recipient_ntt_manager, recipient_address, should_queue, ) @@ -165,10 +165,10 @@ pub struct TransferLock<'info> { pub inbox_rate_limit: Account<'info, InboxRateLimit>, #[account( - seeds = [ManagerSibling::SEED_PREFIX, args.recipient_chain.id.to_be_bytes().as_ref()], - bump = sibling.bump, + seeds = [NttManagerPeer::SEED_PREFIX, args.recipient_chain.id.to_be_bytes().as_ref()], + bump = peer.bump, )] - pub sibling: Account<'info, ManagerSibling>, + pub peer: Account<'info, NttManagerPeer>, #[account( mut, @@ -216,14 +216,14 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( accs.common.mint.decimals, )?; - let recipient_manager = accs.sibling.address; + let recipient_ntt_manager = accs.peer.address; insert_into_outbox( &mut accs.common, &mut accs.inbox_rate_limit, amount, recipient_chain, - recipient_manager, + recipient_ntt_manager, recipient_address, should_queue, ) @@ -234,7 +234,7 @@ fn insert_into_outbox( inbox_rate_limit: &mut InboxRateLimit, amount: u64, recipient_chain: ChainId, - recipient_manager: [u8; 32], + recipient_ntt_manager: [u8; 32], recipient_address: [u8; 32], should_queue: bool, ) -> Result<()> { @@ -261,7 +261,7 @@ fn insert_into_outbox( amount: NormalizedAmount::normalize(amount, common.mint.decimals), sender: common.sender.key(), recipient_chain, - recipient_manager, + recipient_ntt_manager, recipient_address, release_timestamp, released: Bitmap::new(), diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index e122a2a96..74c4974e9 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -3,16 +3,16 @@ use anchor_lang::prelude::*; pub mod bitmap; pub mod clock; pub mod config; -pub mod endpoints; pub mod error; pub mod instructions; pub mod messages; +pub mod peer; pub mod queue; -pub mod registered_endpoint; +pub mod registered_transceiver; pub mod sequence; -pub mod sibling; +pub mod transceivers; -use endpoints::wormhole::instructions::*; +use transceivers::wormhole::instructions::*; use instructions::*; @@ -67,12 +67,12 @@ pub mod example_native_token_transfers { instructions::set_paused(ctx, pause) } - pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { - instructions::set_sibling(ctx, args) + pub fn set_peer(ctx: Context, args: SetPeerArgs) -> Result<()> { + instructions::set_peer(ctx, args) } - pub fn register_endpoint(ctx: Context) -> Result<()> { - instructions::register_endpoint(ctx) + pub fn register_transceiver(ctx: Context) -> Result<()> { + instructions::register_transceiver(ctx) } pub fn set_outbound_limit( @@ -89,23 +89,23 @@ pub mod example_native_token_transfers { instructions::set_inbound_limit(ctx, args) } - // standalone endpoint stuff + // standalone transceiver stuff - pub fn set_wormhole_sibling( - ctx: Context, - args: SetEndpointSiblingArgs, + pub fn set_wormhole_peer( + ctx: Context, + args: SetTransceiverPeerArgs, ) -> Result<()> { - endpoints::wormhole::instructions::set_endpoint_sibling(ctx, args) + transceivers::wormhole::instructions::set_transceiver_peer(ctx, args) } pub fn receive_wormhole_message(ctx: Context) -> Result<()> { - endpoints::wormhole::instructions::receive_message(ctx) + transceivers::wormhole::instructions::receive_message(ctx) } pub fn release_wormhole_outbound( ctx: Context, args: ReleaseOutboundArgs, ) -> Result<()> { - endpoints::wormhole::instructions::release_outbound(ctx, args) + transceivers::wormhole::instructions::release_outbound(ctx, args) } } diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 99c598322..d33b598e6 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -1,16 +1,16 @@ use anchor_lang::prelude::*; -use ntt_messages::{chain_id::ChainId, endpoint::EndpointMessageData}; +use ntt_messages::{chain_id::ChainId, transceiver::TransceiverMessageData}; use std::{collections::HashMap, marker::PhantomData}; #[account] #[derive(InitSpace)] -pub struct ValidatedEndpointMessage { +pub struct ValidatedTransceiverMessage { pub from_chain: ChainId, - pub message: EndpointMessageData, + pub message: TransceiverMessageData, } -impl ValidatedEndpointMessage { - pub const SEED_PREFIX: &'static [u8] = b"endpoint_message"; +impl ValidatedTransceiverMessage { + pub const SEED_PREFIX: &'static [u8] = b"transceiver_message"; } // This is a hack to get around the fact that the IDL generator doesn't support diff --git a/solana/programs/example-native-token-transfers/src/peer.rs b/solana/programs/example-native-token-transfers/src/peer.rs new file mode 100644 index 000000000..12a75ce4b --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/peer.rs @@ -0,0 +1,14 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +/// A peer on another chain. Stored in a PDA seeded by the chain id. +pub struct NttManagerPeer { + pub bump: u8, + // TODO: variable address length? + pub address: [u8; 32], +} + +impl NttManagerPeer { + pub const SEED_PREFIX: &'static [u8] = b"peer"; +} diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 616aaf876..20d0f47f9 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -15,7 +15,7 @@ pub struct OutboxItem { pub amount: NormalizedAmount, pub sender: Pubkey, pub recipient_chain: ChainId, - pub recipient_manager: [u8; 32], + pub recipient_ntt_manager: [u8; 32], pub recipient_address: [u8; 32], pub release_timestamp: i64, pub released: Bitmap, @@ -25,18 +25,18 @@ impl OutboxItem { /// Attempt to release the transfer. /// Returns true if the transfer was released, false if it was not yet time to release it. /// TODO: this is duplicated in inbox.rs. factor out? - pub fn try_release(&mut self, endpoint_index: u8) -> Result { + pub fn try_release(&mut self, transceiver_index: u8) -> Result { let now = current_timestamp(); if self.release_timestamp > now { return Ok(false); } - if self.released.get(endpoint_index) { + if self.released.get(transceiver_index) { return Err(NTTError::MessageAlreadySent.into()); } - self.released.set(endpoint_index, true); + self.released.set(transceiver_index, true); Ok(true) } diff --git a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs deleted file mode 100644 index 935c895dc..000000000 --- a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs +++ /dev/null @@ -1,13 +0,0 @@ -use anchor_lang::prelude::*; - -#[account] -#[derive(InitSpace)] -pub struct RegisteredEndpoint { - pub bump: u8, - pub id: u8, - pub endpoint_address: Pubkey, -} - -impl RegisteredEndpoint { - pub const SEED_PREFIX: &'static [u8] = b"registered_endpoint"; -} diff --git a/solana/programs/example-native-token-transfers/src/registered_transceiver.rs b/solana/programs/example-native-token-transfers/src/registered_transceiver.rs new file mode 100644 index 000000000..ffb402953 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/registered_transceiver.rs @@ -0,0 +1,13 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct RegisteredTransceiver { + pub bump: u8, + pub id: u8, + pub transceiver_address: Pubkey, +} + +impl RegisteredTransceiver { + pub const SEED_PREFIX: &'static [u8] = b"registered_transceiver"; +} diff --git a/solana/programs/example-native-token-transfers/src/sibling.rs b/solana/programs/example-native-token-transfers/src/sibling.rs deleted file mode 100644 index 75b6a76bd..000000000 --- a/solana/programs/example-native-token-transfers/src/sibling.rs +++ /dev/null @@ -1,14 +0,0 @@ -use anchor_lang::prelude::*; - -#[account] -#[derive(InitSpace)] -/// A sibling on another chain. Stored in a PDA seeded by the chain id. -pub struct ManagerSibling { - pub bump: u8, - // TODO: variable address length? - pub address: [u8; 32], -} - -impl ManagerSibling { - pub const SEED_PREFIX: &'static [u8] = b"sibling"; -} diff --git a/solana/programs/example-native-token-transfers/src/transceivers/accounts/mod.rs b/solana/programs/example-native-token-transfers/src/transceivers/accounts/mod.rs new file mode 100644 index 000000000..3735d5d81 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/transceivers/accounts/mod.rs @@ -0,0 +1 @@ +pub mod peer; diff --git a/solana/programs/example-native-token-transfers/src/transceivers/accounts/peer.rs b/solana/programs/example-native-token-transfers/src/transceivers/accounts/peer.rs new file mode 100644 index 000000000..4080c439d --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/transceivers/accounts/peer.rs @@ -0,0 +1,13 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +/// A peer on another chain. Stored in a PDA seeded by the chain id. +pub struct TransceiverPeer { + pub bump: u8, + pub address: [u8; 32], +} + +impl TransceiverPeer { + pub const SEED_PREFIX: &'static [u8] = b"transceiver_peer"; +} diff --git a/solana/programs/example-native-token-transfers/src/endpoints/mod.rs b/solana/programs/example-native-token-transfers/src/transceivers/mod.rs similarity index 100% rename from solana/programs/example-native-token-transfers/src/endpoints/mod.rs rename to solana/programs/example-native-token-transfers/src/transceivers/mod.rs diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/admin.rs similarity index 51% rename from solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs rename to solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/admin.rs index 0cbaf4106..0ead95ba5 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/admin.rs @@ -1,11 +1,11 @@ use anchor_lang::prelude::*; use ntt_messages::chain_id::ChainId; -use crate::{config::Config, endpoints::accounts::sibling::EndpointSibling}; +use crate::{config::Config, transceivers::accounts::peer::TransceiverPeer}; #[derive(Accounts)] -#[instruction(args: SetEndpointSiblingArgs)] -pub struct SetEndpointSibling<'info> { +#[instruction(args: SetTransceiverPeerArgs)] +pub struct SetTransceiverPeer<'info> { #[account( has_one = owner, )] @@ -18,28 +18,28 @@ pub struct SetEndpointSibling<'info> { #[account( init, - space = 8 + EndpointSibling::INIT_SPACE, + space = 8 + TransceiverPeer::INIT_SPACE, payer = payer, - seeds = [EndpointSibling::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], + seeds = [TransceiverPeer::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], bump )] - pub sibling: Account<'info, EndpointSibling>, + pub peer: Account<'info, TransceiverPeer>, pub system_program: Program<'info, System>, } #[derive(AnchorDeserialize, AnchorSerialize)] -pub struct SetEndpointSiblingArgs { +pub struct SetTransceiverPeerArgs { pub chain_id: ChainId, pub address: [u8; 32], } -pub fn set_endpoint_sibling( - ctx: Context, - args: SetEndpointSiblingArgs, +pub fn set_transceiver_peer( + ctx: Context, + args: SetTransceiverPeerArgs, ) -> Result<()> { - ctx.accounts.sibling.set_inner(EndpointSibling { - bump: ctx.bumps.sibling, + ctx.accounts.peer.set_inner(TransceiverPeer { + bump: ctx.bumps.peer, address: args.address, }); diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/mod.rs similarity index 100% rename from solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs rename to solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/mod.rs diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/receive_message.rs similarity index 53% rename from solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs rename to solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/receive_message.rs index cb3f75568..cb2197863 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs +++ b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/receive_message.rs @@ -2,15 +2,15 @@ use anchor_lang::prelude::*; use ntt_messages::{ chain_id::ChainId, - endpoint::{EndpointMessage, EndpointMessageData}, - endpoints::wormhole::WormholeEndpoint, ntt::NativeTokenTransfer, + transceiver::{TransceiverMessage, TransceiverMessageData}, + transceivers::wormhole::WormholeTransceiver, }; use wormhole_anchor_sdk::wormhole::PostedVaa; use crate::{ - config::*, endpoints::accounts::sibling::EndpointSibling, error::NTTError, - messages::ValidatedEndpointMessage, + config::*, error::NTTError, messages::ValidatedTransceiverMessage, + transceivers::accounts::peer::TransceiverPeer, }; #[derive(Accounts)] @@ -22,39 +22,40 @@ pub struct ReceiveMessage<'info> { pub config: Account<'info, Config>, #[account( - seeds = [EndpointSibling::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], - constraint = sibling.address == *vaa.emitter_address() @ NTTError::InvalidEndpointSibling, - bump = sibling.bump, + seeds = [TransceiverPeer::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], + constraint = peer.address == *vaa.emitter_address() @ NTTError::InvalidTransceiverPeer, + bump = peer.bump, )] - pub sibling: Account<'info, EndpointSibling>, + pub peer: Account<'info, TransceiverPeer>, // TODO: Consider using VaaAccount from wormhole-solana-vaa crate. Using a zero-copy reader // will allow this instruction to be generic (instead of strictly specifying NativeTokenTransfer // as the message type). #[account( // check that the messages is targeted to this chain - constraint = vaa.message().manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + constraint = vaa.message().ntt_manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, // NOTE: we don't replay protect VAAs. Instead, we replay protect // executing the messages themselves with the [`released`] flag. )] - pub vaa: Account<'info, PostedVaa>>, + pub vaa: + Account<'info, PostedVaa>>, #[account( init, payer = payer, - space = 8 + ValidatedEndpointMessage::>::INIT_SPACE, + space = 8 + ValidatedTransceiverMessage::>::INIT_SPACE, seeds = [ - ValidatedEndpointMessage::>::SEED_PREFIX, + ValidatedTransceiverMessage::>::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref(), - vaa.message().manager_payload.sequence.to_be_bytes().as_ref(), + vaa.message().ntt_manager_payload.sequence.to_be_bytes().as_ref(), ], bump, )] - // NOTE: in order to handle multiple endpoints, we can just augment the - // inbox item transfer struct with a bitmap storing which endpoints have + // NOTE: in order to handle multiple transceivers, we can just augment the + // inbox item transfer struct with a bitmap storing which transceivers have // attested to the transfer. Then we only release it if there's quorum. // We would need to maybe_init this account in that case. - pub endpoint_message: Account<'info, ValidatedEndpointMessage>, + pub transceiver_message: Account<'info, ValidatedTransceiverMessage>, pub system_program: Program<'info, System>, } @@ -63,8 +64,8 @@ pub fn receive_message(ctx: Context) -> Result<()> { let message = ctx.accounts.vaa.message().message_data.clone(); let chain_id = ctx.accounts.vaa.emitter_chain(); ctx.accounts - .endpoint_message - .set_inner(ValidatedEndpointMessage { + .transceiver_message + .set_inner(ValidatedTransceiverMessage { from_chain: ChainId { id: chain_id }, message, }); diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/release_outbound.rs similarity index 71% rename from solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs rename to solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/release_outbound.rs index c4d993af2..fb34d7084 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/release_outbound.rs @@ -1,13 +1,13 @@ use anchor_lang::prelude::*; use ntt_messages::{ - endpoint::EndpointMessage, endpoints::wormhole::WormholeEndpoint, manager::ManagerMessage, - ntt::NativeTokenTransfer, + ntt::NativeTokenTransfer, ntt_manager::NttManagerMessage, transceiver::TransceiverMessage, + transceivers::wormhole::WormholeTransceiver, }; use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; -use crate::{config::*, error::NTTError, queue::outbox::OutboxItem, registered_endpoint::*}; +use crate::{config::*, error::NTTError, queue::outbox::OutboxItem, registered_transceiver::*}; #[derive(Accounts)] pub struct ReleaseOutbound<'info> { @@ -18,15 +18,15 @@ pub struct ReleaseOutbound<'info> { #[account( mut, - constraint = !outbox_item.released.get(endpoint.id) @ NTTError::MessageAlreadySent, + constraint = !outbox_item.released.get(transceiver.id) @ NTTError::MessageAlreadySent, )] pub outbox_item: Account<'info, OutboxItem>, #[account( - constraint = endpoint.endpoint_address == crate::ID, - constraint = config.enabled_endpoints.get(endpoint.id) @ NTTError::DisabledEndpoint + constraint = transceiver.transceiver_address == crate::ID, + constraint = config.enabled_transceivers.get(transceiver.id) @ NTTError::DisabledTransceiver )] - pub endpoint: Account<'info, RegisteredEndpoint>, + pub transceiver: Account<'info, RegisteredTransceiver>, #[account( mut, @@ -76,7 +76,7 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs let accs = ctx.accounts; let batch_id = 0; - let released = accs.outbox_item.try_release(accs.endpoint.id)?; + let released = accs.outbox_item.try_release(accs.transceiver.id)?; if !released { if args.revert_on_delay { @@ -86,23 +86,24 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs } } - assert!(accs.outbox_item.released.get(accs.endpoint.id)); - let message: EndpointMessage = EndpointMessage::new( - // TODO: should we just put the ntt id here statically? - accs.outbox_item.to_account_info().owner.to_bytes(), - accs.outbox_item.recipient_manager, - ManagerMessage { - sequence: accs.outbox_item.sequence, - sender: accs.outbox_item.sender.to_bytes(), - payload: NativeTokenTransfer { - amount: accs.outbox_item.amount, - source_token: accs.config.mint.to_bytes(), - to: accs.outbox_item.recipient_address, - to_chain: accs.outbox_item.recipient_chain, + assert!(accs.outbox_item.released.get(accs.transceiver.id)); + let message: TransceiverMessage = + TransceiverMessage::new( + // TODO: should we just put the ntt id here statically? + accs.outbox_item.to_account_info().owner.to_bytes(), + accs.outbox_item.recipient_ntt_manager, + NttManagerMessage { + sequence: accs.outbox_item.sequence, + sender: accs.outbox_item.sender.to_bytes(), + payload: NativeTokenTransfer { + amount: accs.outbox_item.amount, + source_token: accs.config.mint.to_bytes(), + to: accs.outbox_item.recipient_address, + to_chain: accs.outbox_item.recipient_chain, + }, }, - }, - vec![], - ); + vec![], + ); if accs.wormhole_bridge.fee() > 0 { anchor_lang::system_program::transfer( diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs b/solana/programs/example-native-token-transfers/src/transceivers/wormhole/mod.rs similarity index 100% rename from solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs rename to solana/programs/example-native-token-transfers/src/transceivers/wormhole/mod.rs diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 4c56fd64e..eb303e5de 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -2,7 +2,7 @@ #![feature(type_changing_struct_update)] use anchor_lang::prelude::*; -use common::setup::{TestData, OTHER_CHAIN, OTHER_ENDPOINT, OTHER_MANAGER, THIS_CHAIN}; +use common::setup::{TestData, OTHER_CHAIN, OTHER_MANAGER, OTHER_TRANSCEIVER, THIS_CHAIN}; use example_native_token_transfers::{ config::Mode, error::NTTError, @@ -10,10 +10,11 @@ use example_native_token_transfers::{ queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit}, }; use ntt_messages::{ - chain_id::ChainId, endpoint::EndpointMessage, endpoints::wormhole::WormholeEndpoint, - manager::ManagerMessage, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + chain_id::ChainId, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + ntt_manager::NttManagerMessage, transceiver::TransceiverMessage, + transceivers::wormhole::WormholeTransceiver, }; -use sdk::endpoints::wormhole::instructions::receive_message::ReceiveMessage; +use sdk::transceivers::wormhole::instructions::receive_message::ReceiveMessage; use solana_program::instruction::InstructionError; use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer, transaction::TransactionError}; @@ -26,12 +27,12 @@ use crate::{ use crate::{ common::{query::GetAccountDataAnchor, setup::setup}, sdk::{ - endpoints::wormhole::instructions::receive_message::receive_message, instructions::{ post_vaa::post_vaa, redeem::{redeem, Redeem}, transfer::Transfer, }, + transceivers::wormhole::instructions::receive_message::receive_message, }, }; @@ -47,7 +48,7 @@ fn init_transfer_accs_args( ) -> (Transfer, TransferArgs) { let accs = Transfer { payer: ctx.payer.pubkey(), - sibling: test_data.ntt.sibling(OTHER_CHAIN), + peer: test_data.ntt.peer(OTHER_CHAIN), mint: test_data.mint, from: test_data.user_token_account, from_authority: test_data.user.pubkey(), @@ -68,16 +69,16 @@ fn init_redeem_accs( ctx: &mut ProgramTestContext, test_data: &TestData, chain_id: u16, - manager_message: ManagerMessage, + ntt_manager_message: NttManagerMessage, ) -> Redeem { Redeem { payer: ctx.payer.pubkey(), - sibling: test_data.ntt.sibling(chain_id), - endpoint: test_data.ntt.program, - endpoint_message: test_data + peer: test_data.ntt.peer(chain_id), + transceiver: test_data.ntt.program, + transceiver_message: test_data .ntt - .endpoint_message(chain_id, manager_message.sequence), - inbox_item: test_data.ntt.inbox_item(chain_id, manager_message), + .transceiver_message(chain_id, ntt_manager_message.sequence), + inbox_item: test_data.ntt.inbox_item(chain_id, ntt_manager_message), inbox_rate_limit: test_data.ntt.inbox_rate_limit(chain_id), mint: test_data.mint, } @@ -92,7 +93,7 @@ fn init_receive_message_accs( ) -> ReceiveMessage { ReceiveMessage { payer: ctx.payer.pubkey(), - sibling: test_data.ntt.endpoint_sibling(chain_id), + peer: test_data.ntt.transceiver_peer(chain_id), vaa, chain_id, sequence, @@ -104,13 +105,13 @@ async fn post_transfer_vaa( test_data: &TestData, sequence: u64, amount: u64, - // TODO: this is used for a negative testing of the recipient manager + // TODO: this is used for a negative testing of the recipient ntt_manager // address. this should not be done in the cancel flow tests, but instead a // dedicated receive transfer test suite - recipient_manager: Option<&Pubkey>, + recipient_ntt_manager: Option<&Pubkey>, recipient: &Keypair, -) -> (Pubkey, ManagerMessage) { - let manager_message = ManagerMessage { +) -> (Pubkey, NttManagerMessage) { + let ntt_manager_message = NttManagerMessage { sequence, sender: [4u8; 32], payload: NativeTokenTransfer { @@ -124,13 +125,13 @@ async fn post_transfer_vaa( }, }; - let endpoint_message: EndpointMessage = - EndpointMessage::new( + let transceiver_message: TransceiverMessage = + TransceiverMessage::new( OTHER_MANAGER, - recipient_manager + recipient_ntt_manager .map(|k| k.to_bytes()) .unwrap_or_else(|| test_data.ntt.program.to_bytes()), - manager_message.clone(), + ntt_manager_message.clone(), vec![], ); @@ -141,15 +142,15 @@ async fn post_transfer_vaa( timestamp: 123232, nonce: 0, emitter_chain: OTHER_CHAIN.into(), - emitter_address: Address(OTHER_ENDPOINT), + emitter_address: Address(OTHER_TRANSCEIVER), sequence: 0, consistency_level: 0, - payload: endpoint_message, + payload: transceiver_message, }; let posted_vaa = post_vaa(&test_data.ntt.wormhole, ctx, vaa).await; - (posted_vaa, manager_message) + (posted_vaa, ntt_manager_message) } async fn outbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> u64 { @@ -268,7 +269,7 @@ async fn test_cancel() { // TODO: this should not live in this file, move to a dedicated receive test suite #[tokio::test] -async fn test_wrong_recipient_manager() { +async fn test_wrong_recipient_ntt_manager() { let recipient = Keypair::new(); let (mut ctx, test_data) = setup(Mode::Locking).await; @@ -303,7 +304,7 @@ async fn test_wrong_recipient_manager() { err.unwrap(), TransactionError::InstructionError( 0, - InstructionError::Custom(NTTError::InvalidRecipientManager.into()) + InstructionError::Custom(NTTError::InvalidRecipientNttManager.into()) ) ); } diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index eae479c24..384ec0c1b 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -4,8 +4,8 @@ use anchor_lang::prelude::{Error, Id, Pubkey}; use anchor_spl::token::{Mint, Token}; use example_native_token_transfers::{ config::Mode, - endpoints::wormhole::SetEndpointSiblingArgs, - instructions::{InitializeArgs, SetSiblingArgs}, + instructions::{InitializeArgs, SetPeerArgs}, + transceivers::wormhole::SetTransceiverPeerArgs, }; use ntt_messages::chain_id::ChainId; use solana_program::{bpf_loader_upgradeable::UpgradeableLoaderState, rent::Rent}; @@ -24,11 +24,11 @@ use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector}; use crate::sdk::{ accounts::{Governance, Wormhole, NTT}, - endpoints::wormhole::instructions::admin::{set_endpoint_sibling, SetEndpointSibling}, instructions::{ - admin::{register_endpoint, set_sibling, RegisterEndpoint, SetSibling}, + admin::{register_transceiver, set_peer, RegisterTransceiver, SetPeer}, initialize::{initialize, Initialize}, }, + transceivers::wormhole::instructions::admin::{set_transceiver_peer, SetTransceiverPeer}, }; use super::{ @@ -42,7 +42,7 @@ pub const MINT_AMOUNT: u64 = 100000; pub const OUTBOUND_LIMIT: u64 = 10000; pub const INBOUND_LIMIT: u64 = 50000; -pub const OTHER_ENDPOINT: [u8; 32] = [7u8; 32]; +pub const OTHER_TRANSCEIVER: [u8; 32] = [7u8; 32]; pub const OTHER_MANAGER: [u8; 32] = [9u8; 32]; pub const THIS_CHAIN: u16 = 1; @@ -131,7 +131,7 @@ pub async fn setup_programs(program_owner: Pubkey) -> Result } /// Set up test accounts, and mint MINT_AMOUNT to the user's token account -/// Set up the program for locking mode, and registers a sibling +/// Set up the program for locking mode, and registers a peer pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { if mode == Mode::Burning { // we set the mint authority to the ntt contract in burn/mint mode @@ -167,41 +167,41 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: .await .unwrap(); - register_endpoint( + register_transceiver( &test_data.ntt, - RegisterEndpoint { + RegisterTransceiver { payer: ctx.payer.pubkey(), owner: test_data.program_owner.pubkey(), - endpoint: example_native_token_transfers::ID, // standalone manager&endpoint + transceiver: example_native_token_transfers::ID, // standalone ntt_manager&transceiver }, ) .submit_with_signers(&[&test_data.program_owner], ctx) .await .unwrap(); - set_endpoint_sibling( + set_transceiver_peer( &test_data.ntt, - SetEndpointSibling { + SetTransceiverPeer { payer: ctx.payer.pubkey(), owner: test_data.program_owner.pubkey(), }, - SetEndpointSiblingArgs { + SetTransceiverPeerArgs { chain_id: ChainId { id: OTHER_CHAIN }, - address: OTHER_ENDPOINT, + address: OTHER_TRANSCEIVER, }, ) .submit_with_signers(&[&test_data.program_owner], ctx) .await .unwrap(); - set_sibling( + set_peer( &test_data.ntt, - SetSibling { + SetPeer { payer: ctx.payer.pubkey(), owner: test_data.program_owner.pubkey(), mint: test_data.mint, }, - SetSiblingArgs { + SetPeerArgs { chain_id: ChainId { id: OTHER_CHAIN }, address: OTHER_MANAGER, limit: INBOUND_LIMIT, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index d13c73ebf..fe02b777f 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -5,10 +5,10 @@ use example_native_token_transfers::{ inbox::{InboxItem, InboxRateLimit}, outbox::OutboxRateLimit, }, - registered_endpoint::RegisteredEndpoint, + registered_transceiver::RegisteredTransceiver, sequence::Sequence, }; -use ntt_messages::{manager::ManagerMessage, ntt::NativeTokenTransfer}; +use ntt_messages::{ntt::NativeTokenTransfer, ntt_manager::NttManagerMessage}; use sha3::{Digest, Keccak256}; use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; @@ -98,11 +98,11 @@ impl NTT { pub fn inbox_item( &self, chain: u16, - manager_message: ManagerMessage, + ntt_manager_message: NttManagerMessage, ) -> Pubkey { let mut hasher = Keccak256::new(); hasher.update(chain.to_be_bytes()); - hasher.update(&TypePrefixedPayload::to_vec_payload(&manager_message)); + hasher.update(&TypePrefixedPayload::to_vec_payload(&ntt_manager_message)); let (inbox_item, _) = Pubkey::find_program_address( &[InboxItem::SEED_PREFIX, &hasher.finalize()], @@ -117,12 +117,12 @@ impl NTT { token_authority } - pub fn registered_endpoint(&self, endpoint: &Pubkey) -> Pubkey { - let (registered_endpoint, _) = Pubkey::find_program_address( - &[RegisteredEndpoint::SEED_PREFIX, endpoint.as_ref()], + pub fn registered_transceiver(&self, transceiver: &Pubkey) -> Pubkey { + let (registered_transceiver, _) = Pubkey::find_program_address( + &[RegisteredTransceiver::SEED_PREFIX, transceiver.as_ref()], &self.program, ); - registered_endpoint + registered_transceiver } pub fn emitter(&self) -> Pubkey { @@ -138,32 +138,30 @@ impl NTT { wormhole_message } - pub fn sibling(&self, chain: u16) -> Pubkey { - let (sibling, _) = Pubkey::find_program_address( - &[b"sibling".as_ref(), &chain.to_be_bytes()], - &self.program, - ); - sibling + pub fn peer(&self, chain: u16) -> Pubkey { + let (peer, _) = + Pubkey::find_program_address(&[b"peer".as_ref(), &chain.to_be_bytes()], &self.program); + peer } - pub fn endpoint_sibling(&self, chain: u16) -> Pubkey { - let (sibling, _) = Pubkey::find_program_address( - &[b"endpoint_sibling".as_ref(), &chain.to_be_bytes()], + pub fn transceiver_peer(&self, chain: u16) -> Pubkey { + let (peer, _) = Pubkey::find_program_address( + &[b"transceiver_peer".as_ref(), &chain.to_be_bytes()], &self.program, ); - sibling + peer } - pub fn endpoint_message(&self, chain: u16, sequence: u64) -> Pubkey { - let (endpoint_message, _) = Pubkey::find_program_address( + pub fn transceiver_message(&self, chain: u16, sequence: u64) -> Pubkey { + let (transceiver_message, _) = Pubkey::find_program_address( &[ - b"endpoint_message".as_ref(), + b"transceiver_message".as_ref(), &chain.to_be_bytes(), &sequence.to_be_bytes(), ], &self.program, ); - endpoint_message + transceiver_message } pub fn custody(&self, mint: &Pubkey) -> Pubkey { diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs index ea9c3b141..2f860b439 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs @@ -1,24 +1,24 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; -use example_native_token_transfers::instructions::SetSiblingArgs; +use example_native_token_transfers::instructions::SetPeerArgs; use solana_sdk::instruction::Instruction; use crate::sdk::accounts::NTT; -pub struct SetSibling { +pub struct SetPeer { pub payer: Pubkey, pub owner: Pubkey, pub mint: Pubkey, } -pub fn set_sibling(ntt: &NTT, accounts: SetSibling, args: SetSiblingArgs) -> Instruction { +pub fn set_peer(ntt: &NTT, accounts: SetPeer, args: SetPeerArgs) -> Instruction { let chain_id = args.chain_id.id; - let data = example_native_token_transfers::instruction::SetSibling { args }; + let data = example_native_token_transfers::instruction::SetPeer { args }; - let accounts = example_native_token_transfers::accounts::SetSibling { + let accounts = example_native_token_transfers::accounts::SetPeer { config: ntt.config(), owner: accounts.owner, payer: accounts.payer, - sibling: ntt.sibling(chain_id), + peer: ntt.peer(chain_id), inbox_rate_limit: ntt.inbox_rate_limit(chain_id), system_program: System::id(), }; @@ -49,21 +49,21 @@ pub fn set_paused(ntt: &NTT, accounts: SetPaused, pause: bool) -> Instruction { } } -pub struct RegisterEndpoint { +pub struct RegisterTransceiver { pub payer: Pubkey, pub owner: Pubkey, - pub endpoint: Pubkey, + pub transceiver: Pubkey, } -pub fn register_endpoint(ntt: &NTT, accounts: RegisterEndpoint) -> Instruction { - let data = example_native_token_transfers::instruction::RegisterEndpoint {}; +pub fn register_transceiver(ntt: &NTT, accounts: RegisterTransceiver) -> Instruction { + let data = example_native_token_transfers::instruction::RegisterTransceiver {}; - let accounts = example_native_token_transfers::accounts::RegisterEndpoint { + let accounts = example_native_token_transfers::accounts::RegisterTransceiver { config: ntt.config(), owner: accounts.owner, payer: accounts.payer, - endpoint: accounts.endpoint, - registered_endpoint: ntt.registered_endpoint(&accounts.endpoint), + transceiver: accounts.transceiver, + registered_transceiver: ntt.registered_transceiver(&accounts.transceiver), system_program: System::id(), }; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs index 7d7448ec3..a25867942 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs @@ -7,9 +7,9 @@ use crate::sdk::accounts::NTT; #[derive(Debug, Clone)] pub struct Redeem { pub payer: Pubkey, - pub sibling: Pubkey, - pub endpoint_message: Pubkey, - pub endpoint: Pubkey, + pub peer: Pubkey, + pub transceiver_message: Pubkey, + pub transceiver: Pubkey, pub mint: Pubkey, pub inbox_item: Pubkey, pub inbox_rate_limit: Pubkey, @@ -21,9 +21,9 @@ pub fn redeem(ntt: &NTT, accs: Redeem, args: RedeemArgs) -> Instruction { let accounts = example_native_token_transfers::accounts::Redeem { payer: accs.payer, config: ntt.config(), - sibling: accs.sibling, - endpoint_message: accs.endpoint_message, - endpoint: ntt.registered_endpoint(&accs.endpoint), + peer: accs.peer, + transceiver_message: accs.transceiver_message, + transceiver: ntt.registered_transceiver(&accs.transceiver), mint: accs.mint, inbox_item: accs.inbox_item, inbox_rate_limit: accs.inbox_rate_limit, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs index f50b5258e..5240be1a5 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs @@ -13,7 +13,7 @@ pub struct Transfer { pub mint: Pubkey, pub from: Pubkey, pub from_authority: Pubkey, - pub sibling: Pubkey, + pub peer: Pubkey, pub outbox_item: Pubkey, } @@ -31,7 +31,7 @@ pub fn transfer_burn(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instr let accounts = example_native_token_transfers::accounts::TransferBurn { common: common(ntt, &transfer), inbox_rate_limit: ntt.inbox_rate_limit(chain_id), - sibling: transfer.sibling, + peer: transfer.peer, }; Instruction { @@ -48,7 +48,7 @@ pub fn transfer_lock(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instr let accounts = example_native_token_transfers::accounts::TransferLock { common: common(ntt, &transfer), inbox_rate_limit: ntt.inbox_rate_limit(chain_id), - sibling: transfer.sibling, + peer: transfer.peer, custody: ntt.custody(&transfer.mint), }; Instruction { diff --git a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs index 5623dba3d..146485053 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs @@ -1,3 +1,3 @@ pub mod accounts; -pub mod endpoints; pub mod instructions; +pub mod transceivers; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/mod.rs similarity index 100% rename from solana/programs/example-native-token-transfers/tests/sdk/endpoints/mod.rs rename to solana/programs/example-native-token-transfers/tests/sdk/transceivers/mod.rs diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/admin.rs similarity index 70% rename from solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs rename to solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/admin.rs index 0566e1221..74d809440 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/admin.rs @@ -1,27 +1,27 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; -use example_native_token_transfers::endpoints::wormhole::SetEndpointSiblingArgs; +use example_native_token_transfers::transceivers::wormhole::SetTransceiverPeerArgs; use solana_sdk::instruction::Instruction; use crate::sdk::accounts::NTT; -pub struct SetEndpointSibling { +pub struct SetTransceiverPeer { pub payer: Pubkey, pub owner: Pubkey, } -pub fn set_endpoint_sibling( +pub fn set_transceiver_peer( ntt: &NTT, - accounts: SetEndpointSibling, - args: SetEndpointSiblingArgs, + accounts: SetTransceiverPeer, + args: SetTransceiverPeerArgs, ) -> Instruction { let chain_id = args.chain_id.id; - let data = example_native_token_transfers::instruction::SetWormholeSibling { args }; + let data = example_native_token_transfers::instruction::SetWormholePeer { args }; - let accounts = example_native_token_transfers::accounts::SetEndpointSibling { + let accounts = example_native_token_transfers::accounts::SetTransceiverPeer { config: ntt.config(), owner: accounts.owner, payer: accounts.payer, - sibling: ntt.endpoint_sibling(chain_id), + peer: ntt.transceiver_peer(chain_id), system_program: System::id(), }; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/mod.rs similarity index 100% rename from solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs rename to solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/mod.rs diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/receive_message.rs similarity index 86% rename from solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs rename to solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/receive_message.rs index 4a931f3c5..b7136fa14 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/receive_message.rs @@ -6,7 +6,7 @@ use crate::sdk::accounts::NTT; #[derive(Debug, Clone)] pub struct ReceiveMessage { pub payer: Pubkey, - pub sibling: Pubkey, + pub peer: Pubkey, pub vaa: Pubkey, pub chain_id: u16, pub sequence: u64, @@ -18,9 +18,9 @@ pub fn receive_message(ntt: &NTT, accs: ReceiveMessage) -> Instruction { let accounts = example_native_token_transfers::accounts::ReceiveMessage { payer: accs.payer, config: ntt.config(), - sibling: accs.sibling, + peer: accs.peer, vaa: accs.vaa, - endpoint_message: ntt.endpoint_message(accs.chain_id, accs.sequence), + transceiver_message: ntt.transceiver_message(accs.chain_id, accs.sequence), system_program: System::id(), }; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/release_outbound.rs similarity index 90% rename from solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/release_outbound.rs rename to solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/release_outbound.rs index 948c5574b..5aeee3aa9 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/instructions/release_outbound.rs @@ -1,6 +1,6 @@ use anchor_lang::{prelude::*, InstructionData}; use example_native_token_transfers::{ - accounts::NotPausedConfig, endpoints::wormhole::ReleaseOutboundArgs, + accounts::NotPausedConfig, transceivers::wormhole::ReleaseOutboundArgs, }; use solana_sdk::{instruction::Instruction, sysvar::SysvarId}; @@ -25,7 +25,7 @@ pub fn release_outbound( outbox_item: release_outbound.outbox_item, wormhole_message: ntt.wormhole_message(&release_outbound.outbox_item), emitter: ntt.emitter(), - endpoint: ntt.registered_endpoint(&ntt.program), + transceiver: ntt.registered_transceiver(&ntt.program), wormhole_bridge: ntt.wormhole.bridge(), wormhole_fee_collector: ntt.wormhole.fee_collector(), wormhole_sequence: ntt.wormhole_sequence(), diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/mod.rs similarity index 100% rename from solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/mod.rs rename to solana/programs/example-native-token-transfers/tests/sdk/transceivers/wormhole/mod.rs diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 0e9e49e10..fcf9de32b 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -7,15 +7,16 @@ use common::setup::{TestData, OTHER_CHAIN}; use example_native_token_transfers::{ bitmap::Bitmap, config::Mode, - endpoints::wormhole::ReleaseOutboundArgs, error::NTTError, instructions::TransferArgs, queue::outbox::{OutboxItem, OutboxRateLimit}, sequence::Sequence, + transceivers::wormhole::ReleaseOutboundArgs, }; use ntt_messages::{ - chain_id::ChainId, endpoint::EndpointMessage, endpoints::wormhole::WormholeEndpoint, - manager::ManagerMessage, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + chain_id::ChainId, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + ntt_manager::NttManagerMessage, transceiver::TransceiverMessage, + transceivers::wormhole::WormholeTransceiver, }; use solana_program_test::*; use solana_sdk::{ @@ -31,11 +32,13 @@ use crate::{ use crate::{ common::{setup::OTHER_MANAGER, submit::Submittable}, sdk::{ - endpoints::wormhole::instructions::release_outbound::{release_outbound, ReleaseOutbound}, instructions::{ admin::{set_paused, SetPaused}, transfer::{approve_token_authority, transfer}, }, + transceivers::wormhole::instructions::release_outbound::{ + release_outbound, ReleaseOutbound, + }, }, }; @@ -45,8 +48,8 @@ pub mod sdk; use crate::common::setup::setup; // TODO: some more tests -// - unregistered sibling can't transfer -// - can't transfer to unregistered sibling +// - unregistered peer can't transfer +// - can't transfer to unregistered peer // - can't transfer more than balance // - wrong inbox accounts // - paused contracts @@ -66,7 +69,7 @@ fn init_accs_args( mint: test_data.mint, from: test_data.user_token_account, from_authority: test_data.user.pubkey(), - sibling: test_data.ntt.sibling(OTHER_CHAIN), + peer: test_data.ntt.peer(OTHER_CHAIN), outbox_item, }; @@ -129,7 +132,7 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: }, sender: test_data.user.pubkey(), recipient_chain: ChainId { id: 2 }, - recipient_manager: OTHER_MANAGER, + recipient_ntt_manager: OTHER_MANAGER, recipient_address: [1u8; 32], release_timestamp: clock.unix_timestamp, released: Bitmap::new(), @@ -169,17 +172,17 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: // They are identical modulo the discriminator, which we just skip by using // the unchecked deserialiser. // TODO: update the sdk to export PostedMessage - let msg: PostedVaa> = + let msg: PostedVaa> = ctx.get_account_data_anchor_unchecked(wh_message).await; - let endpoint_message = msg.data(); + let transceiver_message = msg.data(); assert_eq!( - endpoint_message, - &EndpointMessage::new( + transceiver_message, + &TransceiverMessage::new( example_native_token_transfers::ID.to_bytes(), OTHER_MANAGER, - ManagerMessage { + NttManagerMessage { sequence: sequence.sequence, sender: test_data.user.pubkey().to_bytes(), payload: NativeTokenTransfer { diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 326ef88a6..926ae34d9 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -8,7 +8,7 @@ import { toChainId } from '@certusone/wormhole-sdk' import { MockEmitter, MockGuardians } from '@certusone/wormhole-sdk/lib/cjs/mock' import * as fs from "fs"; -import { type EndpointMessage, ManagerMessage, NativeTokenTransfer, NormalizedAmount, postVaa, WormholeEndpointMessage, NTT } from '../ts/sdk' +import { type TransceiverMessage, NttManagerMessage, NativeTokenTransfer, NormalizedAmount, postVaa, WormholeTransceiverMessage, NTT } from '../ts/sdk' export const GUARDIAN_KEY = 'cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0' @@ -66,24 +66,24 @@ describe('example-native-token-transfers', () => { mode: 'locking' }) - await ntt.registerEndpoint({ + await ntt.registerTransceiver({ payer, owner: payer, - endpoint: ntt.program.programId + transceiver: ntt.program.programId }) - await ntt.setWormholeEndpointSibling({ + await ntt.setWormholeTransceiverPeer({ payer, owner: payer, chain: 'ethereum', - address: Buffer.from('endpoint'.padStart(32, '\0')), + address: Buffer.from('transceiver'.padStart(32, '\0')), }) - await ntt.setSibling({ + await ntt.setPeer({ payer, owner: payer, chain: 'ethereum', - address: Buffer.from('manager'.padStart(32, '\0')), + address: Buffer.from('ntt_manager'.padStart(32, '\0')), limit: new BN(1000000) }) @@ -114,13 +114,13 @@ describe('example-native-token-transfers', () => { } const messageData = PostedMessageData.deserialize(wormholeMessageAccount.data) - const endpointMessage = WormholeEndpointMessage.deserialize( + const transceiverMessage = WormholeTransceiverMessage.deserialize( messageData.message.payload, - a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) + a => NttManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) ) // assert theat amount is what we expect - expect(endpointMessage.managerPayload.payload.normalizedAmount).to.deep.equal(new NormalizedAmount(BigInt(10000), 8)) + expect(transceiverMessage.ntt_managerPayload.payload.normalizedAmount).to.deep.equal(new NormalizedAmount(BigInt(10000), 8)) // get from balance const balance = await connection.getTokenAccountBalance(tokenAccount) expect(balance.value.amount).to.equal('9900000') @@ -137,23 +137,23 @@ describe('example-native-token-transfers', () => { // console.log(message); // TODO: assert other stuff in the message - // console.log(managerMessage); + // console.log(ntt_managerMessage); }); it('Can receive tokens', async () => { const emitter = new MockEmitter( - Buffer.from('endpoint'.padStart(32, '\0')).toString('hex'), + Buffer.from('transceiver'.padStart(32, '\0')).toString('hex'), toChainId('ethereum'), Number(0) // sequence ) const guardians = new MockGuardians(0, [GUARDIAN_KEY]) - const sendingEndpointMessage: EndpointMessage = { - sourceManager: Buffer.from('manager'.padStart(32, '\0')), - recipientManager: ntt.program.programId.toBuffer(), - managerPayload: new ManagerMessage( + const sendingTransceiverMessage: TransceiverMessage = { + sourceNttManager: Buffer.from('ntt_manager'.padStart(32, '\0')), + recipientNttManager: ntt.program.programId.toBuffer(), + ntt_managerPayload: new NttManagerMessage( BigInt(0), Buffer.from('FACE'.padStart(64, '0'), 'hex'), new NativeTokenTransfer( @@ -163,10 +163,10 @@ describe('example-native-token-transfers', () => { user.publicKey.toBuffer() ), ), - endpointPayload: Buffer.alloc(0) + transceiverPayload: Buffer.alloc(0) } - const serialized = WormholeEndpointMessage.serialize(sendingEndpointMessage, a => ManagerMessage.serialize(a, NativeTokenTransfer.serialize)) + const serialized = WormholeTransceiverMessage.serialize(sendingTransceiverMessage, a => NttManagerMessage.serialize(a, NativeTokenTransfer.serialize)) const published = emitter.publishMessage( 0, // nonce diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 1e93a8bf7..627826585 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -14,17 +14,17 @@ import { } from '@solana/web3.js' import { Keccak } from 'sha3' import { type ExampleNativeTokenTransfers as RawExampleNativeTokenTransfers } from '../../target/types/example_native_token_transfers' -import { ManagerMessage } from './payloads/common' +import { NttManagerMessage } from './payloads/common' import { NativeTokenTransfer } from './payloads/transfers' -import { WormholeEndpointMessage } from './payloads/wormhole' +import { WormholeTransceiverMessage } from './payloads/wormhole' import { BPF_LOADER_UPGRADEABLE_PROGRAM_ID, programDataAddress } from './utils' import * as splToken from '@solana/spl-token'; import IDL from '../../target/idl/example_native_token_transfers.json'; export { NormalizedAmount } from './normalized_amount' -export { EndpointMessage, ManagerMessage } from './payloads/common' +export { TransceiverMessage, NttManagerMessage } from './payloads/common' export { NativeTokenTransfer } from './payloads/transfers' -export { WormholeEndpointMessage } from './payloads/wormhole' +export { WormholeTransceiverMessage } from './payloads/wormhole' export * from './utils/wormhole' @@ -105,9 +105,9 @@ export class NTT { return this.derive_pda([Buffer.from('inbox_rate_limit'), new BN(chainId).toBuffer('be', 2)]) } - inboxItemAccountAddress(chain: ChainName | ChainId, managerMessage: ManagerMessage): PublicKey { + inboxItemAccountAddress(chain: ChainName | ChainId, ntt_managerMessage: NttManagerMessage): PublicKey { const chainId = coalesceChainId(chain) - const serialized = ManagerMessage.serialize(managerMessage, NativeTokenTransfer.serialize) + const serialized = NttManagerMessage.serialize(ntt_managerMessage, NativeTokenTransfer.serialize) const hasher = new Keccak(256) hasher.update(new BN(chainId).toBuffer('be', 2)) hasher.update(serialized) @@ -131,28 +131,28 @@ export class NTT { return this.derive_pda([Buffer.from('message'), outboxItem.toBuffer()]) } - siblingAccountAddress(chain: ChainName | ChainId): PublicKey { + peerAccountAddress(chain: ChainName | ChainId): PublicKey { const chainId = coalesceChainId(chain) - return this.derive_pda([Buffer.from('sibling'), new BN(chainId).toBuffer('be', 2)]) + return this.derive_pda([Buffer.from('peer'), new BN(chainId).toBuffer('be', 2)]) } - endpointSiblingAccountAddress(chain: ChainName | ChainId): PublicKey { + transceiverPeerAccountAddress(chain: ChainName | ChainId): PublicKey { const chainId = coalesceChainId(chain) - return this.derive_pda([Buffer.from('endpoint_sibling'), new BN(chainId).toBuffer('be', 2)]) + return this.derive_pda([Buffer.from('transceiver_peer'), new BN(chainId).toBuffer('be', 2)]) } - endpointMessageAccountAddress(chain: ChainName | ChainId, sequence: BN): PublicKey { + transceiverMessageAccountAddress(chain: ChainName | ChainId, sequence: BN): PublicKey { const chainId = coalesceChainId(chain) return this.derive_pda( [ - Buffer.from('endpoint_message'), + Buffer.from('transceiver_message'), new BN(chainId).toBuffer('be', 2), sequence.toBuffer('be', 8) ]) } - registeredEndpointAddress(endpoint: PublicKey): PublicKey { - return this.derive_pda([Buffer.from('registered_endpoint'), endpoint.toBuffer()]) + registeredTransceiverAddress(transceiver: PublicKey): PublicKey { + return this.derive_pda([Buffer.from('registered_transceiver'), transceiver.toBuffer()]) } // Instructions @@ -300,7 +300,7 @@ export class NTT { outboxRateLimit: this.outboxRateLimitAccountAddress(), tokenAuthority: this.tokenAuthorityAddress(), }, - sibling: this.siblingAccountAddress(args.recipientChain), + peer: this.peerAccountAddress(args.recipientChain), inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain) }) .instruction() @@ -350,7 +350,7 @@ export class NTT { outboxRateLimit: this.outboxRateLimitAccountAddress(), tokenAuthority: this.tokenAuthorityAddress(), }, - sibling: this.siblingAccountAddress(args.recipientChain), + peer: this.peerAccountAddress(args.recipientChain), inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain), custody: await this.custodyAccountAddress(config) }) @@ -377,7 +377,7 @@ export class NTT { outboxItem: args.outboxItem, wormholeMessage: this.wormholeMessageAccountAddress(args.outboxItem), emitter: whAccs.wormholeEmitter, - endpoint: this.registeredEndpointAddress(this.program.programId), + transceiver: this.registeredTransceiverAddress(this.program.programId), wormholeBridge: whAccs.wormholeBridge, wormholeFeeCollector: whAccs.wormholeFeeCollector, wormholeSequence: whAccs.wormholeSequence, @@ -413,7 +413,7 @@ export class NTT { async createReleaseInboundMintInstruction(args: { payer: PublicKey chain: ChainName | ChainId - managerMessage: ManagerMessage + ntt_managerMessage: NttManagerMessage revertOnDelay: boolean recipient?: PublicKey config?: Config @@ -425,7 +425,7 @@ export class NTT { } const recipientAddress = - args.recipient ?? (await this.getInboxItem(args.chain, args.managerMessage)).recipientAddress + args.recipient ?? (await this.getInboxItem(args.chain, args.ntt_managerMessage)).recipientAddress const mint = await this.mintAccountAddress(config) @@ -437,7 +437,7 @@ export class NTT { common: { payer: args.payer, config: { config: this.configAccountAddress() }, - inboxItem: this.inboxItemAccountAddress(args.chain, args.managerMessage), + inboxItem: this.inboxItemAccountAddress(args.chain, args.ntt_managerMessage), recipient: getAssociatedTokenAddressSync(mint, recipientAddress), mint, tokenAuthority: this.tokenAuthorityAddress(), @@ -449,7 +449,7 @@ export class NTT { async releaseInboundMint(args: { payer: Keypair chain: ChainName | ChainId - managerMessage: ManagerMessage + ntt_managerMessage: NttManagerMessage revertOnDelay: boolean config?: Config }): Promise { @@ -472,7 +472,7 @@ export class NTT { async createReleaseInboundUnlockInstruction(args: { payer: PublicKey chain: ChainName | ChainId - managerMessage: ManagerMessage + ntt_managerMessage: NttManagerMessage revertOnDelay: boolean recipient?: PublicKey config?: Config @@ -484,7 +484,7 @@ export class NTT { } const recipientAddress = - args.recipient ?? (await this.getInboxItem(args.chain, args.managerMessage)).recipientAddress + args.recipient ?? (await this.getInboxItem(args.chain, args.ntt_managerMessage)).recipientAddress const mint = await this.mintAccountAddress(config) @@ -496,7 +496,7 @@ export class NTT { common: { payer: args.payer, config: { config: this.configAccountAddress() }, - inboxItem: this.inboxItemAccountAddress(args.chain, args.managerMessage), + inboxItem: this.inboxItemAccountAddress(args.chain, args.ntt_managerMessage), recipient: getAssociatedTokenAddressSync(mint, recipientAddress), mint, tokenAuthority: this.tokenAuthorityAddress(), @@ -509,7 +509,7 @@ export class NTT { async releaseInboundUnlock(args: { payer: Keypair chain: ChainName | ChainId - managerMessage: ManagerMessage + ntt_managerMessage: NttManagerMessage revertOnDelay: boolean config?: Config }): Promise { @@ -529,7 +529,7 @@ export class NTT { await this.sendAndConfirmTransaction(tx, signers) } - async setSibling(args: { + async setPeer(args: { payer: Keypair owner: Keypair chain: ChainName @@ -537,7 +537,7 @@ export class NTT { limit: BN config?: Config }) { - const ix = await this.program.methods.setSibling({ + const ix = await this.program.methods.setPeer({ chainId: { id: toChainId(args.chain) }, address: Array.from(args.address), limit: args.limit @@ -546,21 +546,21 @@ export class NTT { payer: args.payer.publicKey, owner: args.owner.publicKey, config: this.configAccountAddress(), - sibling: this.siblingAccountAddress(args.chain), + peer: this.peerAccountAddress(args.chain), inboxRateLimit: this.inboxRateLimitAccountAddress(args.chain), }).instruction(); return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } - async setWormholeEndpointSibling(args: { + async setWormholeTransceiverPeer(args: { payer: Keypair owner: Keypair chain: ChainName address: ArrayLike config?: Config }) { - const ix = await this.program.methods.setWormholeSibling({ + const ix = await this.program.methods.setWormholePeer({ chainId: { id: toChainId(args.chain) }, address: Array.from(args.address) }) @@ -568,23 +568,23 @@ export class NTT { payer: args.payer.publicKey, owner: args.owner.publicKey, config: this.configAccountAddress(), - sibling: this.endpointSiblingAccountAddress(args.chain), + peer: this.transceiverPeerAccountAddress(args.chain), }).instruction(); return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } - async registerEndpoint(args: { + async registerTransceiver(args: { payer: Keypair owner: Keypair - endpoint: PublicKey + transceiver: PublicKey }) { - const ix = await this.program.methods.registerEndpoint() + const ix = await this.program.methods.registerTransceiver() .accounts({ payer: args.payer.publicKey, owner: args.owner.publicKey, config: this.configAccountAddress(), - endpoint: args.endpoint, - registeredEndpoint: this.registeredEndpointAddress(args.endpoint), + transceiver: args.transceiver, + registeredTransceiver: this.registeredTransceiverAddress(args.transceiver), }).instruction(); return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } @@ -601,24 +601,24 @@ export class NTT { } const parsedVaa = parseVaa(args.vaa) - const managerMessage = - WormholeEndpointMessage.deserialize( - parsedVaa.payload, a => ManagerMessage.deserialize(a, a => a) - ).managerPayload + const ntt_managerMessage = + WormholeTransceiverMessage.deserialize( + parsedVaa.payload, a => NttManagerMessage.deserialize(a, a => a) + ).ntt_managerPayload // NOTE: we do an 'as ChainId' cast here, which is generally unsafe. // TODO: explain why this is fine here const chainId = parsedVaa.emitterChain as ChainId - const endpointSibling = this.endpointSiblingAccountAddress(chainId) + const transceiverPeer = this.transceiverPeerAccountAddress(chainId) return await this.program.methods.receiveWormholeMessage().accounts({ payer: args.payer, config: this.configAccountAddress(), - sibling: endpointSibling, + peer: transceiverPeer, vaa: derivePostedVaaKey(this.wormholeId, parseVaa(args.vaa).hash), - endpointMessage: this.endpointMessageAccountAddress( + transceiverMessage: this.transceiverMessageAccountAddress( chainId, - new BN(managerMessage.sequence.toString()) + new BN(ntt_managerMessage.sequence.toString()) ), }).instruction(); } @@ -636,18 +636,18 @@ export class NTT { } const parsedVaa = parseVaa(args.vaa) - const endpointMessage = - WormholeEndpointMessage.deserialize( - parsedVaa.payload, a => ManagerMessage.deserialize( + const transceiverMessage = + WormholeTransceiverMessage.deserialize( + parsedVaa.payload, a => NttManagerMessage.deserialize( a, NativeTokenTransfer.deserialize ) ) - const managerMessage = endpointMessage.managerPayload + const ntt_managerMessage = transceiverMessage.ntt_managerPayload // NOTE: we do an 'as ChainId' cast here, which is generally unsafe. // TODO: explain why this is fine here const chainId = parsedVaa.emitterChain as ChainId - const managerSibling = this.siblingAccountAddress(chainId) + const ntt_managerPeer = this.peerAccountAddress(chainId) const inboxRateLimit = this.inboxRateLimitAccountAddress(chainId) return await this.program.methods @@ -655,11 +655,11 @@ export class NTT { .accounts({ payer: args.payer, config: this.configAccountAddress(), - sibling: managerSibling, - endpointMessage: this.endpointMessageAccountAddress(chainId, new BN(managerMessage.sequence.toString())), - endpoint: this.registeredEndpointAddress(this.program.programId), + peer: ntt_managerPeer, + transceiverMessage: this.transceiverMessageAccountAddress(chainId, new BN(ntt_managerMessage.sequence.toString())), + transceiver: this.registeredTransceiverAddress(this.program.programId), mint: await this.mintAccountAddress(config), - inboxItem: this.inboxItemAccountAddress(chainId, managerMessage), + inboxItem: this.inboxItemAccountAddress(chainId, ntt_managerMessage), inboxRateLimit, outboxRateLimit: this.outboxRateLimitAccountAddress(), }) @@ -688,10 +688,10 @@ export class NTT { const parsedVaa = parseVaa(args.vaa) - const managerMessage = - WormholeEndpointMessage.deserialize( - parsedVaa.payload, a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) - ).managerPayload + const ntt_managerMessage = + WormholeTransceiverMessage.deserialize( + parsedVaa.payload, a => NttManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) + ).ntt_managerPayload // TODO: explain why this is fine here const chainId = parsedVaa.emitterChain as ChainId @@ -717,8 +717,8 @@ export class NTT { const releaseArgs = { ...args, payer: args.payer.publicKey, - managerMessage, - recipient: new PublicKey(managerMessage.payload.recipientAddress), + ntt_managerMessage, + recipient: new PublicKey(ntt_managerMessage.payload.recipientAddress), chain: chainId, revertOnDelay: false } @@ -733,7 +733,7 @@ export class NTT { await this.sendAndConfirmTransaction(tx, signers) // Let's check if the transfer was released - const inboxItem = await this.getInboxItem(chainId, managerMessage) + const inboxItem = await this.getInboxItem(chainId, ntt_managerMessage) return inboxItem.releaseStatus.released !== null } @@ -763,8 +763,8 @@ export class NTT { return (await this.getConfig(config)).tokenProgram } - async getInboxItem(chain: ChainName | ChainId, managerMessage: ManagerMessage): Promise { - return await this.program.account.inboxItem.fetch(this.inboxItemAccountAddress(chain, managerMessage)) + async getInboxItem(chain: ChainName | ChainId, ntt_managerMessage: NttManagerMessage): Promise { + return await this.program.account.inboxItem.fetch(this.inboxItemAccountAddress(chain, ntt_managerMessage)) } /** diff --git a/solana/ts/sdk/payloads/common.ts b/solana/ts/sdk/payloads/common.ts index 1ce4b962c..a34f7cf2b 100644 --- a/solana/ts/sdk/payloads/common.ts +++ b/solana/ts/sdk/payloads/common.ts @@ -1,21 +1,21 @@ import { BN } from '@coral-xyz/anchor' import { assert } from 'chai' -export class EndpointMessage { +export class TransceiverMessage { static prefix: Buffer - sourceManager: Buffer - recipientManager: Buffer - managerPayload: ManagerMessage - endpointPayload: Buffer + sourceNttManager: Buffer + recipientNttManager: Buffer + ntt_managerPayload: NttManagerMessage + transceiverPayload: Buffer - constructor(sourceManager: Buffer, recipientManager: Buffer, managerPayload: ManagerMessage, endpointPayload: Buffer) { - this.sourceManager = sourceManager - this.recipientManager = recipientManager - this.managerPayload = managerPayload - this.endpointPayload = endpointPayload + constructor(sourceNttManager: Buffer, recipientNttManager: Buffer, ntt_managerPayload: NttManagerMessage, transceiverPayload: Buffer) { + this.sourceNttManager = sourceNttManager + this.recipientNttManager = recipientNttManager + this.ntt_managerPayload = ntt_managerPayload + this.transceiverPayload = transceiverPayload } - static deserialize(data: Buffer, deserializer: (data: Buffer) => ManagerMessage): EndpointMessage { + static deserialize(data: Buffer, deserializer: (data: Buffer) => NttManagerMessage): TransceiverMessage { if (this.prefix == undefined) { throw new Error('Unknown prefix.') } @@ -23,35 +23,35 @@ export class EndpointMessage { if (!prefix.equals(this.prefix)) { throw new Error('Invalid prefix') } - const sourceManager = data.subarray(4, 36) - const recipientManager = data.subarray(36, 68) - const managerPayloadLen = data.readUInt16BE(68) - const managerPayload = deserializer(data.subarray(70, 70 + managerPayloadLen)) - const endpointPayloadLen = data.readUInt16BE(70 + managerPayloadLen) - const endpointPayload = data.subarray(72 + managerPayloadLen, 72 + managerPayloadLen + endpointPayloadLen) - return new EndpointMessage(sourceManager, recipientManager, managerPayload, endpointPayload) + const sourceNttManager = data.subarray(4, 36) + const recipientNttManager = data.subarray(36, 68) + const ntt_managerPayloadLen = data.readUInt16BE(68) + const ntt_managerPayload = deserializer(data.subarray(70, 70 + ntt_managerPayloadLen)) + const transceiverPayloadLen = data.readUInt16BE(70 + ntt_managerPayloadLen) + const transceiverPayload = data.subarray(72 + ntt_managerPayloadLen, 72 + ntt_managerPayloadLen + transceiverPayloadLen) + return new TransceiverMessage(sourceNttManager, recipientNttManager, ntt_managerPayload, transceiverPayload) } - static serialize(msg: EndpointMessage, serializer: (payload: ManagerMessage) => Buffer): Buffer { - const payload = serializer(msg.managerPayload) - assert(msg.sourceManager.length == 32, 'sourceManager must be 32 bytes') - assert(msg.recipientManager.length == 32, 'recipientManager must be 32 bytes') + static serialize(msg: TransceiverMessage, serializer: (payload: NttManagerMessage) => Buffer): Buffer { + const payload = serializer(msg.ntt_managerPayload) + assert(msg.sourceNttManager.length == 32, 'sourceNttManager must be 32 bytes') + assert(msg.recipientNttManager.length == 32, 'recipientNttManager must be 32 bytes') const payloadLen = new BN(payload.length).toBuffer('be', 2) - const endpointPayloadLen = new BN(msg.endpointPayload.length).toBuffer('be', 2) + const transceiverPayloadLen = new BN(msg.transceiverPayload.length).toBuffer('be', 2) const buffer = Buffer.concat([ this.prefix, - msg.sourceManager, - msg.recipientManager, + msg.sourceNttManager, + msg.recipientNttManager, payloadLen, payload, - endpointPayloadLen, - msg.endpointPayload + transceiverPayloadLen, + msg.transceiverPayload ]) return buffer } } -export class ManagerMessage { +export class NttManagerMessage { sequence: bigint sender: Buffer payload: A @@ -62,15 +62,15 @@ export class ManagerMessage { this.payload = payload } - static deserialize = (data: Buffer, deserializer: (data: Buffer) => A): ManagerMessage => { + static deserialize = (data: Buffer, deserializer: (data: Buffer) => A): NttManagerMessage => { const sequence = data.readBigUInt64BE(0) const sender = data.subarray(8, 40) const payloadLen = data.readUint16BE(40) const payload = deserializer(data.subarray(42, 42 + payloadLen)) - return new ManagerMessage(sequence, sender, payload) + return new NttManagerMessage(sequence, sender, payload) } - static serialize = (msg: ManagerMessage, serializer: (payload: A) => Buffer): Buffer => { + static serialize = (msg: NttManagerMessage, serializer: (payload: A) => Buffer): Buffer => { const buffer = Buffer.alloc(40) buffer.writeBigUInt64BE(msg.sequence, 0) buffer.set(msg.sender, 8) diff --git a/solana/ts/sdk/payloads/wormhole.ts b/solana/ts/sdk/payloads/wormhole.ts index d672f76d2..45dd69fe0 100644 --- a/solana/ts/sdk/payloads/wormhole.ts +++ b/solana/ts/sdk/payloads/wormhole.ts @@ -1,5 +1,5 @@ -import { EndpointMessage } from './common' +import { TransceiverMessage } from './common' -export class WormholeEndpointMessage extends EndpointMessage { +export class WormholeTransceiverMessage extends TransceiverMessage { static prefix = Buffer.from([0x99, 0x45, 0xFF, 0x10]) }