|
| 1 | +// SPDX-License-Identifier: Apache 2 |
| 2 | +pragma solidity >=0.8.8 <0.9.0; |
| 3 | + |
| 4 | +import "wormhole-solidity-sdk/Utils.sol"; |
| 5 | +import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; |
| 6 | + |
| 7 | +import "../interfaces/IMsgManager.sol"; |
| 8 | +import "../interfaces/ITransceiver.sol"; |
| 9 | +import "../libraries/TransceiverHelpers.sol"; |
| 10 | + |
| 11 | +import {ManagerBase} from "./ManagerBase.sol"; |
| 12 | + |
| 13 | +contract MsgManager is IMsgManager, ManagerBase { |
| 14 | + string public constant MSG_MANAGER_VERSION = "1.0.0"; |
| 15 | + |
| 16 | + // =============== Setup ================================================================= |
| 17 | + |
| 18 | + constructor( |
| 19 | + uint16 _chainId |
| 20 | + ) ManagerBase(address(0), Mode.LOCKING, _chainId) {} |
| 21 | + |
| 22 | + function _initialize() internal virtual override { |
| 23 | + _init(); |
| 24 | + _checkThresholdInvariants(); |
| 25 | + _checkTransceiversInvariants(); |
| 26 | + } |
| 27 | + |
| 28 | + function _init() internal onlyInitializing { |
| 29 | + // check if the owner is the deployer of this contract |
| 30 | + if (msg.sender != deployer) { |
| 31 | + revert UnexpectedDeployer(deployer, msg.sender); |
| 32 | + } |
| 33 | + if (msg.value != 0) { |
| 34 | + revert UnexpectedMsgValue(); |
| 35 | + } |
| 36 | + __PausedOwnable_init(msg.sender, msg.sender); |
| 37 | + __ReentrancyGuard_init(); |
| 38 | + } |
| 39 | + |
| 40 | + // =============== Storage ============================================================== |
| 41 | + |
| 42 | + bytes32 private constant PEERS_SLOT = bytes32(uint256(keccak256("mmgr.peers")) - 1); |
| 43 | + |
| 44 | + // =============== Storage Getters/Setters ============================================== |
| 45 | + |
| 46 | + function _getPeersStorage() |
| 47 | + internal |
| 48 | + pure |
| 49 | + returns (mapping(uint16 => MsgManagerPeer) storage $) |
| 50 | + { |
| 51 | + uint256 slot = uint256(PEERS_SLOT); |
| 52 | + assembly ("memory-safe") { |
| 53 | + $.slot := slot |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + // =============== Public Getters ======================================================== |
| 58 | + |
| 59 | + /// @inheritdoc IMsgManager |
| 60 | + function getPeer( |
| 61 | + uint16 chainId_ |
| 62 | + ) external view returns (MsgManagerPeer memory) { |
| 63 | + return _getPeersStorage()[chainId_]; |
| 64 | + } |
| 65 | + |
| 66 | + // =============== Admin ============================================================== |
| 67 | + |
| 68 | + /// @inheritdoc IMsgManager |
| 69 | + function setPeer(uint16 peerChainId, bytes32 peerAddress) public onlyOwner { |
| 70 | + if (peerChainId == 0) { |
| 71 | + revert InvalidPeerChainIdZero(); |
| 72 | + } |
| 73 | + if (peerAddress == bytes32(0)) { |
| 74 | + revert InvalidPeerZeroAddress(); |
| 75 | + } |
| 76 | + if (peerChainId == chainId) { |
| 77 | + revert InvalidPeerSameChainId(); |
| 78 | + } |
| 79 | + |
| 80 | + MsgManagerPeer memory oldPeer = _getPeersStorage()[peerChainId]; |
| 81 | + |
| 82 | + _getPeersStorage()[peerChainId].peerAddress = peerAddress; |
| 83 | + |
| 84 | + emit PeerUpdated(peerChainId, oldPeer.peerAddress, peerAddress); |
| 85 | + } |
| 86 | + |
| 87 | + /// ============== Invariants ============================================= |
| 88 | + |
| 89 | + /// @dev When we add new immutables, this function should be updated |
| 90 | + function _checkImmutables() internal view virtual override { |
| 91 | + super._checkImmutables(); |
| 92 | + } |
| 93 | + |
| 94 | + // ==================== External Interface =============================================== |
| 95 | + |
| 96 | + /// @inheritdoc IMsgManager |
| 97 | + function sendMessage( |
| 98 | + uint16 recipientChain, |
| 99 | + bytes32 refundAddress, |
| 100 | + bytes calldata payload, |
| 101 | + bytes memory transceiverInstructions |
| 102 | + ) external payable nonReentrant whenNotPaused returns (uint64 sequence) { |
| 103 | + sequence = _useMessageSequence(); |
| 104 | + |
| 105 | + bytes32 recipientAddress = _getPeersStorage()[recipientChain].peerAddress; |
| 106 | + |
| 107 | + (uint256 totalPriceQuote, bytes memory encodedNttManagerPayload) = _sendMessage( |
| 108 | + sequence, |
| 109 | + recipientChain, |
| 110 | + recipientAddress, |
| 111 | + refundAddress, |
| 112 | + msg.sender, |
| 113 | + payload, |
| 114 | + transceiverInstructions |
| 115 | + ); |
| 116 | + |
| 117 | + emit MessageSent( |
| 118 | + recipientChain, recipientAddress, sequence, totalPriceQuote, encodedNttManagerPayload |
| 119 | + ); |
| 120 | + } |
| 121 | + |
| 122 | + /// @dev Override this function to handle your messages. |
| 123 | + function _handleMsg( |
| 124 | + uint16 sourceChainId, |
| 125 | + bytes32 sourceManagerAddress, |
| 126 | + TransceiverStructs.NttManagerMessage memory message, |
| 127 | + bytes32 digest |
| 128 | + ) internal virtual override {} |
| 129 | + |
| 130 | + // ==================== Internal Helpers =============================================== |
| 131 | + |
| 132 | + /// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`. |
| 133 | + function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view override { |
| 134 | + if (_getPeersStorage()[sourceChainId].peerAddress != peerAddress) { |
| 135 | + revert InvalidPeer(sourceChainId, peerAddress); |
| 136 | + } |
| 137 | + } |
| 138 | +} |
0 commit comments