Skip to content

Commit

Permalink
evm: Use adapter instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
bruce-riley committed Dec 5, 2024
1 parent 68fff98 commit 94fead9
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 24 deletions.
2 changes: 1 addition & 1 deletion evm/sh/deployWormholeGuardiansAdapter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# This script deploys the WormholeGuardiansAdapter contract.
# Usage: RPC_URL= MNEMONIC= OUR_CHAIN_ID= EVM_CHAIN_ID= ADMIN= ENDPOINT= WORMHOLE= CONSISTENCY_LEVEL= ./sh/deployWormholeGuardiansAdapter.sh
# tilt: ENDPOINT=0x1aBE68277AE236083947f2551FEe8b885efCA8f5 ./sh/deployWormholeGuardiansAdapter.sh
# tilt: ENDPOINT=0x8186Eaa8CE62Bb3a1a72DA4B103D98AFff417B4A ./sh/deployWormholeGuardiansAdapter.sh
#

[[ -z $ENDPOINT ]] && { echo "Missing ENDPOINT"; exit 1; }
Expand Down
2 changes: 1 addition & 1 deletion evm/sh/deployWormholeGuardiansAdapterWithExecutor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# This script deploys the WormholeGuardiansAdapterWithExecutor contract.
# Usage: RPC_URL= MNEMONIC= OUR_CHAIN_ID= EVM_CHAIN_ID= ADMIN= ENDPOINT= EXECUTOR= WORMHOLE= CONSISTENCY_LEVEL= ./sh/deployWormholeGuardiansAdapterWithExecutor.sh
# tilt: ENDPOINT=0x1aBE68277AE236083947f2551FEe8b885efCA8f5 EXECUTOR= ./sh/deployWormholeGuardiansAdapterWithExecutor.sh
# tilt: ENDPOINT=0x8186Eaa8CE62Bb3a1a72DA4B103D98AFff417B4A EXECUTOR=0xcF523aA101fcd2bF5E0429354308425D9a6CF1d5 ./sh/deployWormholeGuardiansAdapterWithExecutor.sh
#

[[ -z $ENDPOINT ]] && { echo "Missing ENDPOINT"; exit 1; }
Expand Down
11 changes: 8 additions & 3 deletions evm/src/WormholeGuardiansAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.19;

import "example-messaging-endpoint/evm/src/interfaces/IEndpointAdapter.sol";

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

Expand Down Expand Up @@ -171,7 +170,12 @@ contract WormholeGuardiansAdapter is IWormholeGuardiansAdapter {
}

/// @inheritdoc IAdapter
function quoteDeliveryPrice(uint16 /*dstChain*/ ) external view returns (uint256) {
function quoteDeliveryPrice(uint16, /*dstChain*/ bytes calldata /*instructions*/ )
external
view
virtual
returns (uint256)
{
return wormhole.messageFee();
}

Expand All @@ -183,7 +187,8 @@ contract WormholeGuardiansAdapter is IWormholeGuardiansAdapter {
uint16 dstChain,
UniversalAddress dstAddr,
bytes32 payloadHash,
address // refundAddr
address, // refundAddr
bytes calldata // instructions
) external payable virtual onlyEndpoint {
bytes memory payload = _encodePayload(srcAddr, sequence, dstChain, dstAddr, payloadHash);
wormhole.publishMessage{value: msg.value}(0, payload, consistencyLevel);
Expand Down
110 changes: 105 additions & 5 deletions evm/src/WormholeGuardiansAdapterWithExecutor.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
import "example-messaging-executor/evm/src/interfaces/IExecutor.sol";

import "./WormholeGuardiansAdapter.sol";

string constant wormholeGuardiansAdapterWithExecutorVersionString = "WormholeGuardiansAdapterWithExecutor-0.0.1";

contract WormholeGuardiansAdapterWithExecutor is WormholeGuardiansAdapter {
using BytesParsing for bytes; // Used to parse the instructions

// Version number of the encoded adapter instructions.
uint8 private constant INST_VERSION = 1;

/// @notice Length of adapter instructions is wrong.
/// @dev Selector: 0x345dac0f
/// @param received Number of instruction bytes received.
/// @param expected Number of instruction bytes expected.
error InvalidInstructionsLength(uint256 received, uint256 expected);

/// @notice Length of signed quote won't fit in a uint16.
/// @dev Selector: 0x05c610c6
error SignedQuoteTooLong();

/// @notice Length of relay instructions won't fit in a uint16.
/// @dev Selector: 0xff4aadf4
error RelayInstructionsTooLong();

// ==================== Immutables ===============================================

IExecutor public immutable executor;
Expand Down Expand Up @@ -39,16 +59,96 @@ contract WormholeGuardiansAdapterWithExecutor is WormholeGuardiansAdapter {
uint16 dstChain,
UniversalAddress dstAddr,
bytes32 payloadHash,
address refundAddr
address refundAddr,
bytes calldata instructions
) external payable override onlyEndpoint {
bytes memory payload = _encodePayload(srcAddr, sequence, dstChain, dstAddr, payloadHash);
wormhole.publishMessage{value: msg.value}(0, payload, consistencyLevel);
emit MessageSent(srcAddr, dstChain, dstAddr, sequence, payloadHash);

// TODO: These should be passed in.
bytes memory signedQuote = new bytes(0);
bytes memory relayInstructions = new bytes(0);
(uint256 execMsgValue, bytes memory signedQuote, bytes memory relayInstructions) =
_parseInstructions(instructions);

executor.requestExecution{value: execMsgValue}(
dstChain, dstAddr.toBytes32(), refundAddr, signedQuote, payload, relayInstructions
);
}

/// @inheritdoc IAdapter
function quoteDeliveryPrice(uint16, /*dstChain*/ bytes calldata instructions)
external
view
override
returns (uint256)
{
uint256 execMsgValue = _parseExecMsgValueOnly(instructions);
return wormhole.messageFee() + execMsgValue;
}

function _parseInstructions(bytes calldata buf)
internal
pure
returns (uint256 execMsgValue, bytes memory signedQuote, bytes memory relayInst)
{
uint256 offset = 0;
uint16 len = 0;

// For now we can just ignore the version, but maybe not someday. . .
uint8 version;
(version, offset) = buf.asUint8(offset);

// First 32 bytes is execMsgValue.
(execMsgValue, offset) = buf.asUint256(offset);

// Two byte length of signed quote.
(len, offset) = buf.asUint16(offset);
(signedQuote, offset) = buf.sliceUnchecked(offset, len);

// Two byte length of relay instructions.
(len, offset) = buf.asUint16(offset);
(relayInst, offset) = buf.sliceUnchecked(offset, len);

_checkInstructionsLength(buf, offset);
}

function _parseExecMsgValueOnly(bytes calldata buf) internal pure returns (uint256 execMsgValue) {
// First 32 bytes is execMsgValue.
uint256 offset = 0;

// For now we can just ignore the version, but maybe not someday. . .
uint8 version;
(version, offset) = buf.asUint8(offset);

(execMsgValue, offset) = buf.asUint256(offset);
// We don't check for extra bytes here because there are remaining fields we didn't parse.
}

function _checkInstructionsLength(bytes calldata buf, uint256 expected) private pure {
if (buf.length != expected) {
revert InvalidInstructionsLength(buf.length, expected);
}
}

function encodeInstructions(uint256 execMsgValue, bytes calldata signedQuote, bytes calldata relayInstructions)
external
pure
returns (bytes memory encoded)
{
if (signedQuote.length > type(uint16).max) {
revert SignedQuoteTooLong();
}

if (relayInstructions.length > type(uint16).max) {
revert RelayInstructionsTooLong();
}

executor.requestExecution(dstChain, dstAddr.toBytes32(), refundAddr, signedQuote, payload, relayInstructions);
return abi.encodePacked(
INST_VERSION,
execMsgValue,
uint16(signedQuote.length),
signedQuote,
uint16(relayInstructions.length),
relayInstructions
);
}
}
23 changes: 17 additions & 6 deletions evm/test/WormholeGuardiansAdapter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ contract WormholeGuardiansAdapterTest is Test {
srcAdapter.setPeer(0, UniversalAddressLibrary.fromAddress(peerAddress1).toBytes32());

// But you can quote the delivery price while a transfer is pending.
srcAdapter.quoteDeliveryPrice(peerChain1);
srcAdapter.quoteDeliveryPrice(peerChain1, new bytes(0));

// And you can send a message while a transfer is pending.
UniversalAddress srcAddr = UniversalAddressLibrary.fromAddress(address(userA));
Expand All @@ -176,7 +176,9 @@ contract WormholeGuardiansAdapterTest is Test {
uint256 deliverPrice = 382;

vm.startPrank(endpointAddr);
srcAdapter.sendMessage{value: deliverPrice}(srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr);
srcAdapter.sendMessage{value: deliverPrice}(
srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr, new bytes(0)
);

// And you can receive a message while a transfer is pending.
destAdapter.receiveMessage(srcWormhole.lastVaa());
Expand Down Expand Up @@ -280,7 +282,10 @@ contract WormholeGuardiansAdapterTest is Test {
}

function test_quoteDeliveryPrice() public view {
require(srcAdapter.quoteDeliveryPrice(peerChain1) == srcWormhole.fixedMessageFee(), "message fee is wrong");
require(
srcAdapter.quoteDeliveryPrice(peerChain1, new bytes(0)) == srcWormhole.fixedMessageFee(),
"message fee is wrong"
);
}

function test_sendMessage() public {
Expand All @@ -293,7 +298,9 @@ contract WormholeGuardiansAdapterTest is Test {
uint256 deliverPrice = 382;

vm.startPrank(endpointAddr);
srcAdapter.sendMessage{value: deliverPrice}(srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr);
srcAdapter.sendMessage{value: deliverPrice}(
srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr, new bytes(0)
);

require(srcWormhole.messagesSent() == 1, "Message count is wrong");
require(srcWormhole.lastNonce() == 0, "Nonce is wrong");
Expand All @@ -308,7 +315,9 @@ contract WormholeGuardiansAdapterTest is Test {
// Only the endpoint can call send message.
vm.startPrank(someoneElse);
vm.expectRevert(abi.encodeWithSelector(IAdapter.CallerNotEndpoint.selector, someoneElse));
srcAdapter.sendMessage{value: deliverPrice}(srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr);
srcAdapter.sendMessage{value: deliverPrice}(
srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr, new bytes(0)
);
}

function test_receiveMessage() public {
Expand All @@ -326,7 +335,9 @@ contract WormholeGuardiansAdapterTest is Test {
uint256 deliverPrice = 382;

vm.startPrank(endpointAddr);
srcAdapter.sendMessage{value: deliverPrice}(srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr);
srcAdapter.sendMessage{value: deliverPrice}(
srcAddr, sequence, dstChain, dstAddr, payloadHash, refundAddr, new bytes(0)
);
bytes memory vaa = srcWormhole.lastVaa();

// This should work.
Expand Down
Loading

0 comments on commit 94fead9

Please sign in to comment.