Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
[submodule "evm/lib/solidity-bytes-utils"]
path = evm/lib/solidity-bytes-utils
url = https://github.com/GNSPS/solidity-bytes-utils
[submodule "evm/lib/example-messaging-executor"]
path = evm/lib/example-messaging-executor
url = https://github.com/wormholelabs-xyz/example-messaging-executor
146 changes: 146 additions & 0 deletions evm/NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Notes on splitting token from base

## MangerBase

### Implements (Should it implement all these?)

- IManagerBase,
- TransceiverRegistry,
- PausableOwnable,
- ReentrancyGuardUpgradeable,
- Implementation

### Functionality Provided

- Stores the following:
- Transceiver registry
- Thresholds
- Attestations
- Message sequence number
- Has the following functionality:
- `quoteDeliveryPrice`
- Record attestation
- Send message

### Simple Changes Made

- Moved the following from `ManagerBase` to `NttManager:

- Token
- Mode
- `_prepareForTransfer`

### Possible Ideas

- Maybe we could [like an external library](https://book.getfoundry.sh/reference/forge/forge-create#linker-options) for admin functionality.

### Contract Sizes

#### Before we started

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

╭-----------------------------------------+------------------+-------------------+--------------------+---------------------╮
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
+===========================================================================================================================+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 24,066 | 25,673 | 510 | 23,479 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestManager | 8,981 | 10,259 | 15,595 | 38,893 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|

```

- Note the `TestManager` just instantiates `ManagerBase.sol`.

#### After simple changes

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

|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 24,066 | 25,676 | 510 | 23,476 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 18,788 | 20,281 | 5,788 | 28,871 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestManager | 8,368 | 9,511 | 16,208 | 39,641 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|

```

```
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 23,907 | 25,510 | 669 | 23,642 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerHelpersLib | 58 | 87 | 24,518 | 49,065 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 18,644 | 20,130 | 5,932 | 29,022 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
```

- Question: Why did `NttManagerNoRateLimiting` grow so much??

#### Creating TransceiverRegistryAdmin

#### Before

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

╭-----------------------------------------+------------------+-------------------+--------------------+---------------------╮
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
+===========================================================================================================================+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 24,066 | 25,673 | 510 | 23,479 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|

```

#### After

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

|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 23,220 | 26,937 | 1,356 | 22,215 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 16,254 | 19,713 | 8,322 | 29,439 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|

```

#### Creating MsgManagerBase

#### Before

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

╭-----------------------------------------+------------------+-------------------+--------------------+---------------------╮
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
+===========================================================================================================================+
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 24,066 | 25,673 | 510 | 23,479 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 17,141 | 18,557 | 7,435 | 30,595 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|

```

#### After

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

|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManager | 24,076 | 25,719 | 500 | 23,433 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|
| NttManagerNoRateLimiting | 18,496 | 19,949 | 6,080 | 29,203 |
|-----------------------------------------+------------------+-------------------+--------------------+---------------------|

```
1 change: 1 addition & 0 deletions evm/lib/example-messaging-executor
131 changes: 131 additions & 0 deletions evm/src/NttManager/MsgManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;

import "wormhole-solidity-sdk/Utils.sol";
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";

import "../interfaces/IMsgManager.sol";
import "../interfaces/ITransceiver.sol";
import "../libraries/TransceiverHelpers.sol";

import {MsgManagerBase} from "./MsgManagerBase.sol";

contract MsgManager is IMsgManager, MsgManagerBase {
string public constant MSG_MANAGER_VERSION = "1.0.0";

// =============== Setup =================================================================

constructor(
uint16 _chainId
) MsgManagerBase(address(0), Mode.LOCKING, _chainId) {}

function _initialize() internal virtual override {
_init();
_checkThresholdInvariants();
_checkTransceiversInvariants();
}

function _init() internal onlyInitializing {
// check if the owner is the deployer of this contract
if (msg.sender != deployer) {
revert UnexpectedDeployer(deployer, msg.sender);
}
if (msg.value != 0) {
revert UnexpectedMsgValue();
}
__PausedOwnable_init(msg.sender, msg.sender);
__ReentrancyGuard_init();
}

// =============== Storage ==============================================================

bytes32 private constant PEERS_SLOT = bytes32(uint256(keccak256("mmgr.peers")) - 1);

// =============== Storage Getters/Setters ==============================================

function _getPeersStorage()
internal
pure
returns (mapping(uint16 => MsgManagerPeer) storage $)
{
uint256 slot = uint256(PEERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}

// =============== Public Getters ========================================================

/// @inheritdoc IMsgManager
function getPeer(
uint16 chainId_
) external view returns (MsgManagerPeer memory) {
return _getPeersStorage()[chainId_];
}

// =============== Admin ==============================================================

/// @inheritdoc IMsgManager
function setPeer(uint16 peerChainId, bytes32 peerAddress) public onlyOwner {
if (peerChainId == 0) {
revert InvalidPeerChainIdZero();
}
if (peerAddress == bytes32(0)) {
revert InvalidPeerZeroAddress();
}
if (peerChainId == chainId) {
revert InvalidPeerSameChainId();
}

MsgManagerPeer memory oldPeer = _getPeersStorage()[peerChainId];

_getPeersStorage()[peerChainId].peerAddress = peerAddress;

emit PeerUpdated(peerChainId, oldPeer.peerAddress, peerAddress);
}

/// ============== Invariants =============================================

/// @dev When we add new immutables, this function should be updated
function _checkImmutables() internal view virtual override {
super._checkImmutables();
}

// ==================== External Interface ===============================================

/// @inheritdoc IMsgManager
function sendMessage(
uint16 recipientChain,
bytes calldata payload,
bytes memory transceiverInstructions
) external payable nonReentrant whenNotPaused returns (uint64 sequence) {
sequence = _useMessageSequence();

bytes32 recipientAddress = _getPeersStorage()[recipientChain].peerAddress;

(uint256 totalPriceQuote, bytes memory encodedNttManagerPayload) = _sendMessage(
recipientChain, recipientAddress, sequence, payload, transceiverInstructions
);

emit MessageSent(
recipientChain, recipientAddress, sequence, totalPriceQuote, encodedNttManagerPayload
);
}

/// @dev Override this function to handle your messages.
function _handleMsg(
uint16 sourceChainId,
bytes32 sourceManagerAddress,
TransceiverStructs.NttManagerMessage memory message,
bytes32 digest
) internal virtual override {}

// ==================== Internal Helpers ===============================================

/// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`.
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view override {
if (_getPeersStorage()[sourceChainId].peerAddress != peerAddress) {
revert InvalidPeer(sourceChainId, peerAddress);
}
}
}
98 changes: 98 additions & 0 deletions evm/src/NttManager/MsgManagerBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;

import "wormhole-solidity-sdk/Utils.sol";
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";

import "../interfaces/IMsgReceiver.sol";
import "../interfaces/ITransceiver.sol";
import "../libraries/TransceiverHelpers.sol";

import "./ManagerBase.sol";

abstract contract MsgManagerBase is ManagerBase, IMsgReceiver {
// =============== Setup =================================================================

constructor(address _token, Mode _mode, uint16 _chainId) ManagerBase(_token, _mode, _chainId) {}

// ==================== External Interface ===============================================

function attestationReceived(
uint16 sourceChainId,
bytes32 sourceManagerAddress,
TransceiverStructs.NttManagerMessage memory payload
) external onlyTransceiver whenNotPaused {
_verifyPeer(sourceChainId, sourceManagerAddress);

// Compute manager message digest and record transceiver attestation.
bytes32 nttManagerMessageHash = _recordTransceiverAttestation(sourceChainId, payload);

if (isMessageApproved(nttManagerMessageHash)) {
executeMsg(sourceChainId, sourceManagerAddress, payload);
}
}

function executeMsg(
uint16 sourceChainId,
bytes32 sourceNttManagerAddress,
TransceiverStructs.NttManagerMessage memory message
) public whenNotPaused {
(bytes32 digest, bool alreadyExecuted) =
_isMessageExecuted(sourceChainId, sourceNttManagerAddress, message);

if (alreadyExecuted) {
return;
}

_handleMsg(sourceChainId, sourceNttManagerAddress, message, digest);
}

// ==================== Internal Helpers ===============================================

/// @dev Override this function to handle your messages.
function _handleMsg(
uint16 sourceChainId,
bytes32 sourceManagerAddress,
TransceiverStructs.NttManagerMessage memory message,
bytes32 digest
) internal virtual {}

function _sendMessage(
uint16 recipientChain,
bytes32 recipientManagerAddress,
uint64 sequence,
bytes memory payload,
bytes memory transceiverInstructions
) internal returns (uint256 totalPriceQuote, bytes memory encodedNttManagerPayload) {
// verify chain has not forked
checkFork(evmChainId);

address[] memory enabledTransceivers;
TransceiverStructs.TransceiverInstruction[] memory instructions;
uint256[] memory priceQuotes;
(enabledTransceivers, instructions, priceQuotes, totalPriceQuote) =
_prepareForTransfer(recipientChain, transceiverInstructions);
(recipientChain, transceiverInstructions);

// construct the NttManagerMessage payload
encodedNttManagerPayload = TransceiverStructs.encodeNttManagerMessage(
TransceiverStructs.NttManagerMessage(
bytes32(uint256(sequence)), toWormholeFormat(msg.sender), payload
)
);

// send the message
_sendMessageToTransceivers(
recipientChain,
recipientManagerAddress, // refundAddress
recipientManagerAddress,
priceQuotes,
instructions,
enabledTransceivers,
encodedNttManagerPayload
);
}

/// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`.
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view virtual;
}
Loading
Loading