Skip to content

Commit 2d9d13b

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

13 files changed

+1201
-152
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: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
1-
# Notes on splitting token from base
1+
# Notes on changes made in this integration branch
22

3-
## MangerBase
3+
## Change that wasn't made
44

5-
### Implements (Should it implement all these?)
5+
It is unfortunate that `token` and `mode` exist in `ManagerBase` rather than `NttManager`.
6+
I tried moving them, but that increases
67

7-
- IManagerBase,
8-
- TransceiverRegistry,
9-
- PausableOwnable,
10-
- ReentrancyGuardUpgradeable,
11-
- Implementation
8+
### Before we started
129

13-
### Functionality Provided
10+
```bash
11+
evm (main)$ forge build --sizes --via-ir --skip test
1412

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
13+
╭-----------------------------------------+------------------+-------------------+--------------------+---------------------╮
14+
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
15+
+===========================================================================================================================+
16+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
17+
| NttManager | 24,066 | 25,673 | 510 | 23,479 |
18+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
19+
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
20+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
2421

25-
### Simple Changes Made
22+
```
2623

27-
- Moved the following from `ManagerBase` to `NttManager:
24+
### After moving token and mode
2825

29-
- Token
30-
- Mode
31-
- `_prepareForTransfer`
26+
```bash
27+
evm (main)$ forge build --sizes --via-ir --skip test
28+
29+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
30+
| NttManager | 24,066 | 25,676 | 510 | 23,476 |
31+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
32+
| NttManagerNoRateLimiting | 18,788 | 20,281 | 5,788 | 28,871 |
33+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
3234

33-
### Possible Ideas
35+
```
3436

35-
- Maybe we could [like an external library](https://book.getfoundry.sh/reference/forge/forge-create#linker-options) for admin functionality.
37+
Question: Why did `NttManagerNoRateLimiting` grow so much?? Because of this, I am not pursuing moving these fields at this time.
3638

37-
### Contract Sizes
39+
## Creating TransceiverRegistryAdmin
3840

39-
#### Before we started
41+
### Before
4042

4143
```bash
4244
evm (main)$ forge build --sizes --via-ir --skip test
@@ -49,43 +51,27 @@ evm (main)$ forge build --sizes --via-ir --skip test
4951
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
5052
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
5153
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
52-
| TestManager | 8,981 | 10,259 | 15,595 | 38,893 |
53-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
5454

5555
```
5656

57-
- Note the `TestManager` just instantiates `ManagerBase.sol`.
58-
59-
#### After simple changes
57+
### After
6058

6159
```bash
6260
evm (main)$ forge build --sizes --via-ir --skip test
6361

6462
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
65-
| NttManager | 24,066 | 25,676 | 510 | 23,476 |
66-
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
67-
| NttManagerNoRateLimiting | 18,788 | 20,281 | 5,788 | 28,871 |
63+
| NttManager | 23,220 | 26,937 | 1,356 | 22,215 |
6864
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
69-
| TestManager | 8,368 | 9,511 | 16,208 | 39,641 |
65+
| NttManagerNoRateLimiting | 16,254 | 19,713 | 8,322 | 29,439 |
7066
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
7167

7268
```
7369

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??
70+
## Creating MsgManagerBase
8571

86-
#### Creating TransceiverRegistryAdmin
72+
Note that this change is not dependent on `TransceiverRegistryAdmin`.
8773

88-
#### Before
74+
### Before
8975

9076
```bash
9177
evm (main)$ forge build --sizes --via-ir --skip test
@@ -101,15 +87,19 @@ evm (main)$ forge build --sizes --via-ir --skip test
10187

10288
```
10389

104-
#### After
90+
### After
10591

10692
```bash
10793
evm (main)$ forge build --sizes --via-ir --skip test
10894

10995
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
110-
| NttManager | 23,220 | 26,937 | 1,356 | 22,215 |
96+
| NttManager | 24,076 | 25,719 | 500 | 23,433 |
11197
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
112-
| NttManagerNoRateLimiting | 16,254 | 19,713 | 8,322 | 29,439 |
98+
| NttManagerNoRateLimiting | 18,496 | 19,949 | 6,080 | 29,203 |
99+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
100+
| MsgManager | 12,540 | 13,745 | 12,036 | 35,407 |
101+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
102+
| MsgManagerWithExecutor | 13,145 | 14,400 | 11,431 | 34,752 |
113103
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
114104

115105
```

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)