Skip to content

Commit 0b529e3

Browse files
committed
evm: Add MsgManager
1 parent 7eb1451 commit 0b529e3

13 files changed

+1147
-96
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
[submodule "evm/lib/solidity-bytes-utils"]
1111
path = evm/lib/solidity-bytes-utils
1212
url = https://github.com/GNSPS/solidity-bytes-utils
13+
[submodule "evm/lib/example-messaging-executor"]
14+
path = evm/lib/example-messaging-executor
15+
url = https://github.com/wormholelabs-xyz/example-messaging-executor

evm/lib/example-messaging-executor

evm/src/NttManager/ManagerBase.sol

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import "../libraries/Implementation.sol";
1313

1414
import "../interfaces/ITransceiver.sol";
1515
import "../interfaces/IManagerBase.sol";
16+
import "../interfaces/IMsgReceiver.sol";
1617

1718
import "./TransceiverRegistry.sol";
1819

1920
abstract contract ManagerBase is
2021
IManagerBase,
22+
IMsgReceiver,
2123
TransceiverRegistry,
2224
PausableOwnable,
2325
ReentrancyGuardUpgradeable,
@@ -464,6 +466,85 @@ abstract contract ManagerBase is
464466
_getMessageSequenceStorage().num++;
465467
}
466468

469+
function attestationReceived(
470+
uint16 sourceChainId,
471+
bytes32 sourceManagerAddress,
472+
TransceiverStructs.NttManagerMessage memory payload
473+
) external onlyTransceiver whenNotPaused {
474+
_verifyPeer(sourceChainId, sourceManagerAddress);
475+
476+
// Compute manager message digest and record transceiver attestation.
477+
bytes32 nttManagerMessageHash = _recordTransceiverAttestation(sourceChainId, payload);
478+
479+
if (isMessageApproved(nttManagerMessageHash)) {
480+
executeMsg(sourceChainId, sourceManagerAddress, payload);
481+
}
482+
}
483+
484+
function executeMsg(
485+
uint16 sourceChainId,
486+
bytes32 sourceNttManagerAddress,
487+
TransceiverStructs.NttManagerMessage memory message
488+
) public whenNotPaused {
489+
(bytes32 digest, bool alreadyExecuted) =
490+
_isMessageExecuted(sourceChainId, sourceNttManagerAddress, message);
491+
492+
if (alreadyExecuted) {
493+
return;
494+
}
495+
496+
_handleMsg(sourceChainId, sourceNttManagerAddress, message, digest);
497+
}
498+
499+
/// @dev Override this function to handle your messages.
500+
function _handleMsg(
501+
uint16 sourceChainId,
502+
bytes32 sourceManagerAddress,
503+
TransceiverStructs.NttManagerMessage memory message,
504+
bytes32 digest
505+
) internal virtual {}
506+
507+
function _sendMessage(
508+
uint64 sequence,
509+
uint16 recipientChain,
510+
bytes32 recipientManagerAddress,
511+
bytes32 refundAddress,
512+
address sender,
513+
bytes memory payload,
514+
bytes memory transceiverInstructions
515+
) internal returns (uint256 totalPriceQuote, bytes memory encodedNttManagerPayload) {
516+
// verify chain has not forked
517+
checkFork(evmChainId);
518+
519+
address[] memory enabledTransceivers;
520+
TransceiverStructs.TransceiverInstruction[] memory instructions;
521+
uint256[] memory priceQuotes;
522+
(enabledTransceivers, instructions, priceQuotes, totalPriceQuote) =
523+
_prepareForTransfer(recipientChain, transceiverInstructions);
524+
(recipientChain, transceiverInstructions);
525+
526+
// construct the NttManagerMessage payload
527+
encodedNttManagerPayload = TransceiverStructs.encodeNttManagerMessage(
528+
TransceiverStructs.NttManagerMessage(
529+
bytes32(uint256(sequence)), toWormholeFormat(sender), payload
530+
)
531+
);
532+
533+
// send the message
534+
_sendMessageToTransceivers(
535+
recipientChain,
536+
refundAddress,
537+
recipientManagerAddress,
538+
priceQuotes,
539+
instructions,
540+
enabledTransceivers,
541+
encodedNttManagerPayload
542+
);
543+
}
544+
545+
/// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`.
546+
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view virtual;
547+
467548
/// ============== Invariants =============================================
468549

469550
/// @dev When we add new immutables, this function should be updated

evm/src/NttManager/MsgManager.sol

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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

Comments
 (0)