Skip to content

Commit bf67b78

Browse files
committed
evm: Add MsgManager
1 parent 3d799d7 commit bf67b78

13 files changed

+1185
-160
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/NOTES.md

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,27 @@
1-
# Notes on splitting token from base
1+
# Notes on changes made in this integration branch
22

3-
## MangerBase
3+
This file is meant to document the work in progress on this integration branch. It can probably be deleted (or the information moved some place better) before this PR is merged.
44

5-
### Implements (Should it implement all these?)
5+
This integration branch is PR #21.
66

7-
- IManagerBase,
8-
- TransceiverRegistry,
9-
- PausableOwnable,
10-
- ReentrancyGuardUpgradeable,
11-
- Implementation
7+
## Sub Branches
128

13-
### Functionality Provided
9+
Note that the indentation indicates branch dependencies.
1410

15-
- Stores the following:
16-
- Transceiver registry
17-
- Thresholds
18-
- Attestations
19-
- Message sequence number
20-
- Has the following functionality:
21-
- `quoteDeliveryPrice`
22-
- Record attestation
23-
- Send message
11+
- **evm_TransceiverRegistry_split** (PR #22) - This branch splits transceiver admin into a separate contract.
12+
- **evm/add_MsgManager** (PR #23) - Creates `MsgManagerBase` and `MsgManager` and makes `NttManager` inherit from `MsgManagerBase`.
13+
- **evm/add_SharedWormholeTransceiver** (PR #25) - Adds a shareable transceiver.
2414

25-
### Simple Changes Made
15+
## The change that wasn't made
2616

27-
- Moved the following from `ManagerBase` to `NttManager:
17+
It is unfortunate that `token` and `mode` exist in `ManagerBase` rather than `NttManager`.
18+
I tried moving them, but that increases the size of `NttManagerNoRateLimiting` considerably.
19+
I'm not sure why that is, or how to avoid it, so I did not pursue that change at this time.
20+
However, some of the other changes also cause that increase, so maybe we can revist this.
2821

29-
- Token
30-
- Mode
31-
- `_prepareForTransfer`
22+
## Contract Sizes
3223

33-
### Possible Ideas
34-
35-
- Maybe we could [like an external library](https://book.getfoundry.sh/reference/forge/forge-create#linker-options) for admin functionality.
36-
37-
### Contract Sizes
38-
39-
#### Before we started
24+
### Before we started
4025

4126
```bash
4227
evm (main)$ forge build --sizes --via-ir --skip test
@@ -49,14 +34,10 @@ evm (main)$ forge build --sizes --via-ir --skip test
4934
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
5035
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
5136
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
52-
| TestManager | 8,981 | 10,259 | 15,595 | 38,893 |
53-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
5437

5538
```
5639

57-
- Note the `TestManager` just instantiates `ManagerBase.sol`.
58-
59-
#### After simple changes
40+
### After moving token and mode (the change that wasn't made)
6041

6142
```bash
6243
evm (main)$ forge build --sizes --via-ir --skip test
@@ -66,50 +47,35 @@ evm (main)$ forge build --sizes --via-ir --skip test
6647
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
6748
| NttManagerNoRateLimiting | 18,788 | 20,281 | 5,788 | 28,871 |
6849
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
69-
| TestManager | 8,368 | 9,511 | 16,208 | 39,641 |
70-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
7150

7251
```
7352

74-
```
75-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
76-
| NttManager | 23,907 | 25,510 | 669 | 23,642 |
77-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
78-
| NttManagerHelpersLib | 58 | 87 | 24,518 | 49,065 |
79-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
80-
| NttManagerNoRateLimiting | 18,644 | 20,130 | 5,932 | 29,022 |
81-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
82-
```
83-
84-
- Question: Why did `NttManagerNoRateLimiting` grow so much??
85-
86-
#### Creating TransceiverRegistryAdmin
87-
88-
#### Before
53+
## Creating TransceiverRegistryAdmin
8954

9055
```bash
9156
evm (main)$ forge build --sizes --via-ir --skip test
9257

93-
╭-----------------------------------------+------------------+-------------------+--------------------+---------------------╮
94-
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
95-
+===========================================================================================================================+
9658
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
97-
| NttManager | 24,066 | 25,673 | 510 | 23,479 |
59+
| NttManager | 23,220 | 26,937 | 1,356 | 22,215 |
9860
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
99-
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
61+
| NttManagerNoRateLimiting | 16,254 | 19,713 | 8,322 | 29,439 |
10062
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
10163

10264
```
10365

104-
#### After
66+
## Creating MsgManagerBase
10567

10668
```bash
10769
evm (main)$ forge build --sizes --via-ir --skip test
10870

10971
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
110-
| NttManager | 23,220 | 26,937 | 1,356 | 22,215 |
72+
| NttManager | 24,076 | 25,719 | 500 | 23,433 |
11173
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
112-
| NttManagerNoRateLimiting | 16,254 | 19,713 | 8,322 | 29,439 |
74+
| NttManagerNoRateLimiting | 18,496 | 19,949 | 6,080 | 29,203 |
75+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
76+
| MsgManager | 12,540 | 13,745 | 12,036 | 35,407 |
77+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
78+
| MsgManagerWithExecutor | 13,145 | 14,400 | 11,431 | 34,752 |
11379
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
11480

11581
```

evm/lib/example-messaging-executor

evm/src/NttManager/MsgManager.sol

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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 {MsgManagerBase} from "./MsgManagerBase.sol";
12+
13+
contract MsgManager is IMsgManager, MsgManagerBase {
14+
string public constant MSG_MANAGER_VERSION = "1.0.0";
15+
16+
// =============== Setup =================================================================
17+
18+
constructor(
19+
uint16 _chainId
20+
) MsgManagerBase(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+
bytes calldata payload,
100+
bytes memory transceiverInstructions
101+
) external payable nonReentrant whenNotPaused returns (uint64 sequence) {
102+
sequence = _useMessageSequence();
103+
104+
bytes32 recipientAddress = _getPeersStorage()[recipientChain].peerAddress;
105+
106+
(uint256 totalPriceQuote, bytes memory encodedNttManagerPayload) = _sendMessage(
107+
recipientChain, recipientAddress, sequence, payload, transceiverInstructions
108+
);
109+
110+
emit MessageSent(
111+
recipientChain, recipientAddress, sequence, totalPriceQuote, encodedNttManagerPayload
112+
);
113+
}
114+
115+
/// @dev Override this function to handle your messages.
116+
function _handleMsg(
117+
uint16 sourceChainId,
118+
bytes32 sourceManagerAddress,
119+
TransceiverStructs.NttManagerMessage memory message,
120+
bytes32 digest
121+
) internal virtual override {}
122+
123+
// ==================== Internal Helpers ===============================================
124+
125+
/// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`.
126+
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view override {
127+
if (_getPeersStorage()[sourceChainId].peerAddress != peerAddress) {
128+
revert InvalidPeer(sourceChainId, peerAddress);
129+
}
130+
}
131+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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/IMsgReceiver.sol";
8+
import "../interfaces/ITransceiver.sol";
9+
import "../libraries/TransceiverHelpers.sol";
10+
11+
import "./ManagerBase.sol";
12+
13+
abstract contract MsgManagerBase is ManagerBase, IMsgReceiver {
14+
// =============== Setup =================================================================
15+
16+
constructor(address _token, Mode _mode, uint16 _chainId) ManagerBase(_token, _mode, _chainId) {}
17+
18+
// ==================== External Interface ===============================================
19+
20+
function attestationReceived(
21+
uint16 sourceChainId,
22+
bytes32 sourceManagerAddress,
23+
TransceiverStructs.NttManagerMessage memory payload
24+
) external onlyTransceiver whenNotPaused {
25+
_verifyPeer(sourceChainId, sourceManagerAddress);
26+
27+
// Compute manager message digest and record transceiver attestation.
28+
bytes32 nttManagerMessageHash = _recordTransceiverAttestation(sourceChainId, payload);
29+
30+
if (isMessageApproved(nttManagerMessageHash)) {
31+
executeMsg(sourceChainId, sourceManagerAddress, payload);
32+
}
33+
}
34+
35+
function executeMsg(
36+
uint16 sourceChainId,
37+
bytes32 sourceNttManagerAddress,
38+
TransceiverStructs.NttManagerMessage memory message
39+
) public whenNotPaused {
40+
(bytes32 digest, bool alreadyExecuted) =
41+
_isMessageExecuted(sourceChainId, sourceNttManagerAddress, message);
42+
43+
if (alreadyExecuted) {
44+
return;
45+
}
46+
47+
_handleMsg(sourceChainId, sourceNttManagerAddress, message, digest);
48+
}
49+
50+
// ==================== Internal Helpers ===============================================
51+
52+
/// @dev Override this function to handle your messages.
53+
function _handleMsg(
54+
uint16 sourceChainId,
55+
bytes32 sourceManagerAddress,
56+
TransceiverStructs.NttManagerMessage memory message,
57+
bytes32 digest
58+
) internal virtual {}
59+
60+
function _sendMessage(
61+
uint16 recipientChain,
62+
bytes32 recipientManagerAddress,
63+
uint64 sequence,
64+
bytes memory payload,
65+
bytes memory transceiverInstructions
66+
) internal returns (uint256 totalPriceQuote, bytes memory encodedNttManagerPayload) {
67+
// verify chain has not forked
68+
checkFork(evmChainId);
69+
70+
address[] memory enabledTransceivers;
71+
TransceiverStructs.TransceiverInstruction[] memory instructions;
72+
uint256[] memory priceQuotes;
73+
(enabledTransceivers, instructions, priceQuotes, totalPriceQuote) =
74+
_prepareForTransfer(recipientChain, transceiverInstructions);
75+
(recipientChain, transceiverInstructions);
76+
77+
// construct the NttManagerMessage payload
78+
encodedNttManagerPayload = TransceiverStructs.encodeNttManagerMessage(
79+
TransceiverStructs.NttManagerMessage(
80+
bytes32(uint256(sequence)), toWormholeFormat(msg.sender), payload
81+
)
82+
);
83+
84+
// send the message
85+
_sendMessageToTransceivers(
86+
recipientChain,
87+
recipientManagerAddress, // refundAddress
88+
recipientManagerAddress,
89+
priceQuotes,
90+
instructions,
91+
enabledTransceivers,
92+
encodedNttManagerPayload
93+
);
94+
}
95+
96+
/// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`.
97+
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view virtual;
98+
}

0 commit comments

Comments
 (0)