Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol": {
"content": "// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "wormhole-solidity-sdk/WormholeRelayerSDK.sol";
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
import "wormhole-solidity-sdk/interfaces/IWormhole.sol";
import "../../libraries/TransceiverHelpers.sol";
import "../../libraries/TransceiverStructs.sol";
import "../../interfaces/IWormholeTransceiver.sol";
import "../../interfaces/ISpecialRelayer.sol";
import "../../interfaces/INttManager.sol";
import "./WormholeTransceiverState.sol";
/// @title WormholeTransceiver
/// @author Wormhole Project Contributors.
/// @notice Transceiver implementation for Wormhole.
///
/// @dev This contract is responsible for sending and receiving NTT messages
/// that are authenticated through Wormhole Core.
///
/// @dev Messages can be delivered either via standard relaying or special relaying, or
/// manually via the core layer.
///
/// @dev Once a message is received, it is delivered to its corresponding
/// NttManager contract.
contract WormholeTransceiver is
IWormholeTransceiver,
IWormholeReceiver,
WormholeTransceiverState
{
using BytesParsing for bytes;
string public constant WORMHOLE_TRANSCEIVER_VERSION = "1.1.0";
constructor(
address nttManager,
address wormholeCoreBridge,
address wormholeRelayerAddr,
address specialRelayerAddr,
uint8 _consistencyLevel,
uint256 _gasLimit
)
WormholeTransceiverState(
nttManager,
wormholeCoreBridge,
wormholeRelayerAddr,
specialRelayerAddr,
_consistencyLevel,
_gasLimit
)
{}
// ==================== External Interface ===============================================
function getTransceiverType() external pure override returns (string memory) {
return "wormhole";
}
/// @inheritdoc IWormholeTransceiver
function receiveMessage(
bytes memory encodedMessage
) external {
uint16 sourceChainId;
bytes memory payload;
(sourceChainId, payload) = _verifyMessage(encodedMessage);
// parse the encoded Transceiver payload
TransceiverStructs.TransceiverMessage memory parsedTransceiverMessage;
TransceiverStructs.NttManagerMessage memory parsedNttManagerMessage;
(parsedTransceiverMessage, parsedNttManagerMessage) = TransceiverStructs
.parseTransceiverAndNttManagerMessage(WH_TRANSCEIVER_PAYLOAD_PREFIX, payload);
_deliverToNttManager(
sourceChainId,
parsedTransceiverMessage.sourceNttManagerAddress,
parsedTransceiverMessage.recipientNttManagerAddress,
parsedNttManagerMessage
);
}
/// @inheritdoc IWormholeReceiver
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory additionalMessages,
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 deliveryHash
) external payable onlyRelayer {
if (getWormholePeer(sourceChain) != sourceAddress) {
revert InvalidWormholePeer(sourceChain, sourceAddress);
}
// VAA replay protection:
// - Note that this VAA is for the AR delivery, not for the raw message emitted by the source
// - chain Transceiver contract. The VAAs received by this entrypoint are different than the
// - VAA received by the receiveMessage entrypoint.
if (isVAAConsumed(deliveryHash)) {
revert TransferAlreadyCompleted(deliveryHash);
}
_setVAAConsumed(deliveryHash);
// We don't honor additional messages in this handler.
if (additionalMessages.length > 0) {
revert UnexpectedAdditionalMessages();
}
// emit `ReceivedRelayedMessage` event
emit ReceivedRelayedMessage(deliveryHash, sourceChain, sourceAddress);
// parse the encoded Transceiver payload
TransceiverStructs.TransceiverMessage memory parsedTransceiverMessage;
TransceiverStructs.NttManagerMessage memory parsedNttManagerMessage;
(parsedTransceiverMessage, parsedNttManagerMessage) = TransceiverStructs
.parseTransceiverAndNttManagerMessage(WH_TRANSCEIVER_PAYLOAD_PREFIX, payload);
_deliverToNttManager(
sourceChain,
parsedTransceiverMessage.sourceNttManagerAddress,
parsedTransceiverMessage.recipientNttManagerAddress,
parsedNttManagerMessage
);
}
/// @inheritdoc IWormholeTransceiver
function parseWormholeTransceiverInstruction(
bytes memory encoded
) public pure returns (WormholeTransceiverInstruction memory instruction) {
// If the user doesn't pass in any transceiver instructions then the default is false
if (encoded.length == 0) {
instruction.shouldSkipRelayerSend = false;
return instruction;
}
uint256 offset = 0;
(instruction.shouldSkipRelayerSend, offset) = encoded.asBoolUnchecked(offset);
encoded.checkLength(offset);
}
/// @inheritdoc IWormholeTransceiver
function encodeWormholeTransceiverInstruction(
WormholeTransceiverInstruction memory instruction
) public pure returns (bytes memory) {
return abi.encodePacked(instruction.shouldSkipRelayerSend);
}
// ==================== Internal ========================================================
function _quoteDeliveryPrice(
uint16 targetChain,
TransceiverStructs.TransceiverInstruction memory instruction
) internal view override returns (uint256 nativePriceQuote) {
// Check the special instruction up front to see if we should skip sending via a relayer
WormholeTransceiverInstruction memory weIns =
parseWormholeTransceiverInstruction(instruction.payload);
if (weIns.shouldSkipRelayerSend) {
return wormhole.messageFee();
}
if (_checkInvalidRelayingConfig(targetChain)) {
revert InvalidRelayingConfig(targetChain);
}
if (_shouldRelayViaStandardRelaying(targetChain)) {
(uint256 cost,) = wormholeRelayer.quoteEVMDeliveryPrice(targetChain, 0, gasLimit);
return cost;
} else if (isSpecialRelayingEnabled(targetChain)) {
uint256 cost = specialRelayer.quoteDeliveryPrice(getNttManagerToken(), targetChain, 0);
// We need to pay both the special relayer cost and the Wormhole message fee independently
return cost + wormhole.messageFee();
} else {
return wormhole.messageFee();
}
}
function _sendMessage(
uint16 recipientChain,
uint256 deliveryPayment,
address caller,
bytes32 recipientNttManagerAddress,
bytes32 refundAddress,
TransceiverStructs.TransceiverInstruction memory instruction,
bytes memory nttManagerMessage
) internal override {
(
TransceiverStructs.TransceiverMessage memory transceiverMessage,
bytes memory encodedTransceiverPayload
) = TransceiverStructs.buildAndEncodeTransceiverMessage(
WH_TRANSCEIVER_PAYLOAD_PREFIX,
toWormholeFormat(caller),
recipientNttManagerAddress,
nttManagerMessage,
new bytes(0)
);
WormholeTransceiverInstruction memory weIns =
parseWormholeTransceiverInstruction(instruction.payload);
if (!weIns.shouldSkipRelayerSend && _shouldRelayViaStandardRelaying(recipientChain)) {
// NOTE: standard relaying supports refunds. The amount to be refunded will be sent
// to a refundAddress specified by the client on the destination chain.
// push onto the stack again to avoid stack too deep error
bytes32 refundRecipient = refundAddress;
uint16 destinationChain = recipientChain;
wormholeRelayer.sendToEvm{value: deliveryPayment}(
destinationChain,
fromWormholeFormat(getWormholePeer(destinationChain)),
encodedTransceiverPayload,
0, // receiverValue
0, // paymentForExtraReceiverValue,
gasLimit,
destinationChain,
fromWormholeFormat(refundRecipient),
wormholeRelayer.getDefaultDeliveryProvider(),
new VaaKey[](0),
consistencyLevel
);
emit RelayingInfo(uint8(RelayingType.Standard), refundAddress, deliveryPayment);
} else if (!weIns.shouldSkipRelayerSend && isSpecialRelayingEnabled(recipientChain)) {
uint256 wormholeFee = wormhole.messageFee();
uint64 sequence = wormhole.publishMessage{value: wormholeFee}(
0, encodedTransceiverPayload, consistencyLevel
);
specialRelayer.requestDelivery{value: deliveryPayment - wormholeFee}(
getNttManagerToken(), recipientChain, 0, sequence
);
// NOTE: specialized relaying does not currently support refunds. The zero address
// is used as a placeholder for the refund address until support is added.
emit RelayingInfo(uint8(RelayingType.Special), bytes32(0), deliveryPayment);
} else {
wormhole.publishMessage{value: deliveryPayment}(
0, encodedTransceiverPayload, consistencyLevel
);
// NOTE: manual relaying does not currently support refunds. The zero address
// is used as refundAddress.
emit RelayingInfo(uint8(RelayingType.Manual), bytes32(0), deliveryPayment);
}
emit SendTransceiverMessage(recipientChain, transceiverMessage);
}
function _verifyMessage(
bytes memory encodedMessage
) internal returns (uint16, bytes memory) {
// verify VAA against Wormhole Core Bridge contract
(IWormhole.VM memory vm, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(encodedMessage);
// ensure that the VAA is valid
if (!valid) {
revert InvalidVaa(reason);
}
// ensure that the message came from a registered peer contract
if (!_verifyBridgeVM(vm)) {
revert InvalidWormholePeer(vm.emitterChainId, vm.emitterAddress);
}
// save the VAA hash in storage to protect against replay attacks.
if (isVAAConsumed(vm.hash)) {
revert TransferAlreadyCompleted(vm.hash);
}
_setVAAConsumed(vm.hash);
// emit `ReceivedMessage` event
emit ReceivedMessage(vm.hash, vm.emitterChainId, vm.emitterAddress, vm.sequence);
return (vm.emitterChainId, vm.payload);
}
function _verifyBridgeVM(
IWormhole.VM memory vm
) internal view returns (bool) {
checkFork(wormholeTransceiver_evmChainId);
return getWormholePeer(vm.emitterChainId) == vm.emitterAddress;
}
}
"
},
"lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol": {
"content": "// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.13;
import "./interfaces/IWormholeReceiver.sol";
import "./interfaces/IWormholeRelayer.sol";
import "./Chains.sol";
import "./Utils.sol";
import {Base} from "./Base.sol";
import {TokenBase, TokenReceiver, TokenSender} from "./TokenBase.sol";
import {CCTPBase, CCTPReceiver, CCTPSender} from "./CCTPBase.sol";
import {CCTPAndTokenBase, CCTPAndTokenReceiver, CCTPAndTokenSender} from "./CCTPAndTokenBase.sol";
"
},
"lib/wormhole-solidity-sdk/src/libraries/BytesParsing.sol": {
"content": "// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.13;
library BytesParsing {
uint256 private constant freeMemoryPtr = 0x40;
uint256 private constant wordSize = 32;
error OutOfBounds(uint256 offset, uint256 length);
error LengthMismatch(uint256 encodedLength, uint256 expectedLength);
error InvalidBoolVal(uint8 val);
function checkBound(uint offset, uint length) internal pure {
if (offset > length)
revert OutOfBounds(offset, length);
}
function checkLength(bytes memory encoded, uint256 expected) internal pure {
if (encoded.length != expected)
revert LengthMismatch(encoded.length, expected);
}
function sliceUnchecked(
bytes memory encoded,
uint offset,
uint length
) internal pure returns (bytes memory ret, uint nextOffset) {
//bail early for degenerate case
if (length == 0)
return (new bytes(0), offset);
assembly ("memory-safe") {
nextOffset := add(offset, length)
ret := mload(freeMemoryPtr)
//Explanation on how we copy data here:
// The bytes type has the following layout in memory:
// [length: 32 bytes, data: length bytes]
// So if we allocate `bytes memory foo = new bytes(1);` then `foo` will be a pointer to 33
// bytes where the first 32 bytes contain the length and the last byte is the actual data.
// Since mload always loads 32 bytes of memory at once, we use our shift variable to align
// our reads so that our last read lines up exactly with the last 32 bytes of `encoded`.
// However this also means that if the length of `encoded` is not a multiple of 32 bytes, our
// first read will necessarily partly contain bytes from `encoded`'s 32 length bytes that
// will be written into the length part of our `ret` slice.
// We remedy this issue by writing the length of our `ret` slice at the end, thus
// overwritting those garbage bytes.
let shift := and(length, 31) //equivalent to `mod(length, 32)` but 2 gas cheaper
if iszero(shift) {
shift := wordSize
}
let dest := add(ret, shift)
let end := add(dest, length)
for {
let src := add(add(encoded, shift), offset)
} lt(dest, end) {
src := add(src, wordSize)
dest := add(dest, wordSize)
} {
mstore(dest, mload(src))
}
mstore(ret, length)
//When compiling with --via-ir then normally allocated memory (i.e. via new) will have 32 byte
// memory alignment and so we enforce the same memory alignment here.
mstore(freeMemoryPtr, and(add(dest, 31), not(31)))
}
}
function slice(
bytes memory encoded,
uint offset,
uint length
) internal pure returns (bytes memory ret, uint nextOffset) {
(ret, nextOffset) = sliceUnchecked(encoded, offset, length);
checkBound(nextOffset, encoded.length);
}
function asAddressUnchecked(
bytes memory encoded,
uint offset
) internal pure returns (address, uint) {
(uint160 ret, uint nextOffset) = asUint160Unchecked(encoded, offset);
return (address(ret), nextOffset);
}
function asAddress(
bytes memory encoded,
uint offset
) internal pure returns (address ret, uint nextOffset) {
(ret, nextOffset) = asAddressUnchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBoolUnchecked(
bytes memory encoded,
uint offset
) internal pure returns (bool, uint) {
(uint8 val, uint nextOffset) = asUint8Unchecked(encoded, offset);
if (val & 0xfe != 0)
revert InvalidBoolVal(val);
uint cleanedVal = uint(val);
bool ret;
//skip 2x iszero opcode
assembly ("memory-safe") {
ret := cleanedVal
}
return (ret, nextOffset);
}
function asBool(
bytes memory encoded,
uint offset
) internal pure returns (bool ret, uint nextOffset) {
(ret, nextOffset) = asBoolUnchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
/* -------------------------------------------------------------------------------------------------
Remaining library code below was auto-generated by via the following js/node code:
for (let bytes = 1; bytes <= 32; ++bytes) {
const bits = bytes*8;
console.log(
`function asUint${bits}Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint${bits} ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, ${bytes})
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint${bits}(
bytes memory encoded,
uint offset
) internal pure returns (uint${bits} ret, uint nextOffset) {
(ret, nextOffset) = asUint${bits}Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes${bytes}Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes${bytes}, uint) {
(uint${bits} ret, uint nextOffset) = asUint${bits}Unchecked(encoded, offset);
return (bytes${bytes}(ret), nextOffset);
}
function asBytes${bytes}(
bytes memory encoded,
uint offset
) internal pure returns (bytes${bytes}, uint) {
(uint${bits} ret, uint nextOffset) = asUint${bits}(encoded, offset);
return (bytes${bytes}(ret), nextOffset);
}
`
);
}
------------------------------------------------------------------------------------------------- */
function asUint8Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint8 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 1)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint8(
bytes memory encoded,
uint offset
) internal pure returns (uint8 ret, uint nextOffset) {
(ret, nextOffset) = asUint8Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes1Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes1, uint) {
(uint8 ret, uint nextOffset) = asUint8Unchecked(encoded, offset);
return (bytes1(ret), nextOffset);
}
function asBytes1(
bytes memory encoded,
uint offset
) internal pure returns (bytes1, uint) {
(uint8 ret, uint nextOffset) = asUint8(encoded, offset);
return (bytes1(ret), nextOffset);
}
function asUint16Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint16 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 2)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint16(
bytes memory encoded,
uint offset
) internal pure returns (uint16 ret, uint nextOffset) {
(ret, nextOffset) = asUint16Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes2Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes2, uint) {
(uint16 ret, uint nextOffset) = asUint16Unchecked(encoded, offset);
return (bytes2(ret), nextOffset);
}
function asBytes2(
bytes memory encoded,
uint offset
) internal pure returns (bytes2, uint) {
(uint16 ret, uint nextOffset) = asUint16(encoded, offset);
return (bytes2(ret), nextOffset);
}
function asUint24Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint24 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 3)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint24(
bytes memory encoded,
uint offset
) internal pure returns (uint24 ret, uint nextOffset) {
(ret, nextOffset) = asUint24Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes3Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes3, uint) {
(uint24 ret, uint nextOffset) = asUint24Unchecked(encoded, offset);
return (bytes3(ret), nextOffset);
}
function asBytes3(
bytes memory encoded,
uint offset
) internal pure returns (bytes3, uint) {
(uint24 ret, uint nextOffset) = asUint24(encoded, offset);
return (bytes3(ret), nextOffset);
}
function asUint32Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint32 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 4)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint32(
bytes memory encoded,
uint offset
) internal pure returns (uint32 ret, uint nextOffset) {
(ret, nextOffset) = asUint32Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes4Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes4, uint) {
(uint32 ret, uint nextOffset) = asUint32Unchecked(encoded, offset);
return (bytes4(ret), nextOffset);
}
function asBytes4(
bytes memory encoded,
uint offset
) internal pure returns (bytes4, uint) {
(uint32 ret, uint nextOffset) = asUint32(encoded, offset);
return (bytes4(ret), nextOffset);
}
function asUint40Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint40 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 5)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint40(
bytes memory encoded,
uint offset
) internal pure returns (uint40 ret, uint nextOffset) {
(ret, nextOffset) = asUint40Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes5Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes5, uint) {
(uint40 ret, uint nextOffset) = asUint40Unchecked(encoded, offset);
return (bytes5(ret), nextOffset);
}
function asBytes5(
bytes memory encoded,
uint offset
) internal pure returns (bytes5, uint) {
(uint40 ret, uint nextOffset) = asUint40(encoded, offset);
return (bytes5(ret), nextOffset);
}
function asUint48Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint48 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 6)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint48(
bytes memory encoded,
uint offset
) internal pure returns (uint48 ret, uint nextOffset) {
(ret, nextOffset) = asUint48Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes6Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes6, uint) {
(uint48 ret, uint nextOffset) = asUint48Unchecked(encoded, offset);
return (bytes6(ret), nextOffset);
}
function asBytes6(
bytes memory encoded,
uint offset
) internal pure returns (bytes6, uint) {
(uint48 ret, uint nextOffset) = asUint48(encoded, offset);
return (bytes6(ret), nextOffset);
}
function asUint56Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint56 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 7)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint56(
bytes memory encoded,
uint offset
) internal pure returns (uint56 ret, uint nextOffset) {
(ret, nextOffset) = asUint56Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes7Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes7, uint) {
(uint56 ret, uint nextOffset) = asUint56Unchecked(encoded, offset);
return (bytes7(ret), nextOffset);
}
function asBytes7(
bytes memory encoded,
uint offset
) internal pure returns (bytes7, uint) {
(uint56 ret, uint nextOffset) = asUint56(encoded, offset);
return (bytes7(ret), nextOffset);
}
function asUint64Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint64 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 8)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint64(
bytes memory encoded,
uint offset
) internal pure returns (uint64 ret, uint nextOffset) {
(ret, nextOffset) = asUint64Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes8Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes8, uint) {
(uint64 ret, uint nextOffset) = asUint64Unchecked(encoded, offset);
return (bytes8(ret), nextOffset);
}
function asBytes8(
bytes memory encoded,
uint offset
) internal pure returns (bytes8, uint) {
(uint64 ret, uint nextOffset) = asUint64(encoded, offset);
return (bytes8(ret), nextOffset);
}
function asUint72Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint72 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 9)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint72(
bytes memory encoded,
uint offset
) internal pure returns (uint72 ret, uint nextOffset) {
(ret, nextOffset) = asUint72Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes9Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes9, uint) {
(uint72 ret, uint nextOffset) = asUint72Unchecked(encoded, offset);
return (bytes9(ret), nextOffset);
}
function asBytes9(
bytes memory encoded,
uint offset
) internal pure returns (bytes9, uint) {
(uint72 ret, uint nextOffset) = asUint72(encoded, offset);
return (bytes9(ret), nextOffset);
}
function asUint80Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint80 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 10)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint80(
bytes memory encoded,
uint offset
) internal pure returns (uint80 ret, uint nextOffset) {
(ret, nextOffset) = asUint80Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes10Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes10, uint) {
(uint80 ret, uint nextOffset) = asUint80Unchecked(encoded, offset);
return (bytes10(ret), nextOffset);
}
function asBytes10(
bytes memory encoded,
uint offset
) internal pure returns (bytes10, uint) {
(uint80 ret, uint nextOffset) = asUint80(encoded, offset);
return (bytes10(ret), nextOffset);
}
function asUint88Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint88 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 11)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint88(
bytes memory encoded,
uint offset
) internal pure returns (uint88 ret, uint nextOffset) {
(ret, nextOffset) = asUint88Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes11Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes11, uint) {
(uint88 ret, uint nextOffset) = asUint88Unchecked(encoded, offset);
return (bytes11(ret), nextOffset);
}
function asBytes11(
bytes memory encoded,
uint offset
) internal pure returns (bytes11, uint) {
(uint88 ret, uint nextOffset) = asUint88(encoded, offset);
return (bytes11(ret), nextOffset);
}
function asUint96Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint96 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 12)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint96(
bytes memory encoded,
uint offset
) internal pure returns (uint96 ret, uint nextOffset) {
(ret, nextOffset) = asUint96Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes12Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes12, uint) {
(uint96 ret, uint nextOffset) = asUint96Unchecked(encoded, offset);
return (bytes12(ret), nextOffset);
}
function asBytes12(
bytes memory encoded,
uint offset
) internal pure returns (bytes12, uint) {
(uint96 ret, uint nextOffset) = asUint96(encoded, offset);
return (bytes12(ret), nextOffset);
}
function asUint104Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint104 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 13)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint104(
bytes memory encoded,
uint offset
) internal pure returns (uint104 ret, uint nextOffset) {
(ret, nextOffset) = asUint104Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes13Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes13, uint) {
(uint104 ret, uint nextOffset) = asUint104Unchecked(encoded, offset);
return (bytes13(ret), nextOffset);
}
function asBytes13(
bytes memory encoded,
uint offset
) internal pure returns (bytes13, uint) {
(uint104 ret, uint nextOffset) = asUint104(encoded, offset);
return (bytes13(ret), nextOffset);
}
function asUint112Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint112 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 14)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint112(
bytes memory encoded,
uint offset
) internal pure returns (uint112 ret, uint nextOffset) {
(ret, nextOffset) = asUint112Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes14Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes14, uint) {
(uint112 ret, uint nextOffset) = asUint112Unchecked(encoded, offset);
return (bytes14(ret), nextOffset);
}
function asBytes14(
bytes memory encoded,
uint offset
) internal pure returns (bytes14, uint) {
(uint112 ret, uint nextOffset) = asUint112(encoded, offset);
return (bytes14(ret), nextOffset);
}
function asUint120Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint120 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 15)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint120(
bytes memory encoded,
uint offset
) internal pure returns (uint120 ret, uint nextOffset) {
(ret, nextOffset) = asUint120Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes15Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes15, uint) {
(uint120 ret, uint nextOffset) = asUint120Unchecked(encoded, offset);
return (bytes15(ret), nextOffset);
}
function asBytes15(
bytes memory encoded,
uint offset
) internal pure returns (bytes15, uint) {
(uint120 ret, uint nextOffset) = asUint120(encoded, offset);
return (bytes15(ret), nextOffset);
}
function asUint128Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint128 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 16)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint128(
bytes memory encoded,
uint offset
) internal pure returns (uint128 ret, uint nextOffset) {
(ret, nextOffset) = asUint128Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes16Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes16, uint) {
(uint128 ret, uint nextOffset) = asUint128Unchecked(encoded, offset);
return (bytes16(ret), nextOffset);
}
function asBytes16(
bytes memory encoded,
uint offset
) internal pure returns (bytes16, uint) {
(uint128 ret, uint nextOffset) = asUint128(encoded, offset);
return (bytes16(ret), nextOffset);
}
function asUint136Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint136 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 17)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint136(
bytes memory encoded,
uint offset
) internal pure returns (uint136 ret, uint nextOffset) {
(ret, nextOffset) = asUint136Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes17Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes17, uint) {
(uint136 ret, uint nextOffset) = asUint136Unchecked(encoded, offset);
return (bytes17(ret), nextOffset);
}
function asBytes17(
bytes memory encoded,
uint offset
) internal pure returns (bytes17, uint) {
(uint136 ret, uint nextOffset) = asUint136(encoded, offset);
return (bytes17(ret), nextOffset);
}
function asUint144Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint144 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 18)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint144(
bytes memory encoded,
uint offset
) internal pure returns (uint144 ret, uint nextOffset) {
(ret, nextOffset) = asUint144Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes18Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes18, uint) {
(uint144 ret, uint nextOffset) = asUint144Unchecked(encoded, offset);
return (bytes18(ret), nextOffset);
}
function asBytes18(
bytes memory encoded,
uint offset
) internal pure returns (bytes18, uint) {
(uint144 ret, uint nextOffset) = asUint144(encoded, offset);
return (bytes18(ret), nextOffset);
}
function asUint152Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint152 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 19)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint152(
bytes memory encoded,
uint offset
) internal pure returns (uint152 ret, uint nextOffset) {
(ret, nextOffset) = asUint152Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes19Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes19, uint) {
(uint152 ret, uint nextOffset) = asUint152Unchecked(encoded, offset);
return (bytes19(ret), nextOffset);
}
function asBytes19(
bytes memory encoded,
uint offset
) internal pure returns (bytes19, uint) {
(uint152 ret, uint nextOffset) = asUint152(encoded, offset);
return (bytes19(ret), nextOffset);
}
function asUint160Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint160 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 20)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint160(
bytes memory encoded,
uint offset
) internal pure returns (uint160 ret, uint nextOffset) {
(ret, nextOffset) = asUint160Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes20Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes20, uint) {
(uint160 ret, uint nextOffset) = asUint160Unchecked(encoded, offset);
return (bytes20(ret), nextOffset);
}
function asBytes20(
bytes memory encoded,
uint offset
) internal pure returns (bytes20, uint) {
(uint160 ret, uint nextOffset) = asUint160(encoded, offset);
return (bytes20(ret), nextOffset);
}
function asUint168Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint168 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 21)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint168(
bytes memory encoded,
uint offset
) internal pure returns (uint168 ret, uint nextOffset) {
(ret, nextOffset) = asUint168Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes21Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes21, uint) {
(uint168 ret, uint nextOffset) = asUint168Unchecked(encoded, offset);
return (bytes21(ret), nextOffset);
}
function asBytes21(
bytes memory encoded,
uint offset
) internal pure returns (bytes21, uint) {
(uint168 ret, uint nextOffset) = asUint168(encoded, offset);
return (bytes21(ret), nextOffset);
}
function asUint176Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint176 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 22)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint176(
bytes memory encoded,
uint offset
) internal pure returns (uint176 ret, uint nextOffset) {
(ret, nextOffset) = asUint176Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes22Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes22, uint) {
(uint176 ret, uint nextOffset) = asUint176Unchecked(encoded, offset);
return (bytes22(ret), nextOffset);
}
function asBytes22(
bytes memory encoded,
uint offset
) internal pure returns (bytes22, uint) {
(uint176 ret, uint nextOffset) = asUint176(encoded, offset);
return (bytes22(ret), nextOffset);
}
function asUint184Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint184 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 23)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint184(
bytes memory encoded,
uint offset
) internal pure returns (uint184 ret, uint nextOffset) {
(ret, nextOffset) = asUint184Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes23Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes23, uint) {
(uint184 ret, uint nextOffset) = asUint184Unchecked(encoded, offset);
return (bytes23(ret), nextOffset);
}
function asBytes23(
bytes memory encoded,
uint offset
) internal pure returns (bytes23, uint) {
(uint184 ret, uint nextOffset) = asUint184(encoded, offset);
return (bytes23(ret), nextOffset);
}
function asUint192Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint192 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 24)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint192(
bytes memory encoded,
uint offset
) internal pure returns (uint192 ret, uint nextOffset) {
(ret, nextOffset) = asUint192Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes24Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes24, uint) {
(uint192 ret, uint nextOffset) = asUint192Unchecked(encoded, offset);
return (bytes24(ret), nextOffset);
}
function asBytes24(
bytes memory encoded,
uint offset
) internal pure returns (bytes24, uint) {
(uint192 ret, uint nextOffset) = asUint192(encoded, offset);
return (bytes24(ret), nextOffset);
}
function asUint200Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint200 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 25)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint200(
bytes memory encoded,
uint offset
) internal pure returns (uint200 ret, uint nextOffset) {
(ret, nextOffset) = asUint200Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes25Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes25, uint) {
(uint200 ret, uint nextOffset) = asUint200Unchecked(encoded, offset);
return (bytes25(ret), nextOffset);
}
function asBytes25(
bytes memory encoded,
uint offset
) internal pure returns (bytes25, uint) {
(uint200 ret, uint nextOffset) = asUint200(encoded, offset);
return (bytes25(ret), nextOffset);
}
function asUint208Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint208 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 26)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint208(
bytes memory encoded,
uint offset
) internal pure returns (uint208 ret, uint nextOffset) {
(ret, nextOffset) = asUint208Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes26Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes26, uint) {
(uint208 ret, uint nextOffset) = asUint208Unchecked(encoded, offset);
return (bytes26(ret), nextOffset);
}
function asBytes26(
bytes memory encoded,
uint offset
) internal pure returns (bytes26, uint) {
(uint208 ret, uint nextOffset) = asUint208(encoded, offset);
return (bytes26(ret), nextOffset);
}
function asUint216Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint216 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 27)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint216(
bytes memory encoded,
uint offset
) internal pure returns (uint216 ret, uint nextOffset) {
(ret, nextOffset) = asUint216Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes27Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes27, uint) {
(uint216 ret, uint nextOffset) = asUint216Unchecked(encoded, offset);
return (bytes27(ret), nextOffset);
}
function asBytes27(
bytes memory encoded,
uint offset
) internal pure returns (bytes27, uint) {
(uint216 ret, uint nextOffset) = asUint216(encoded, offset);
return (bytes27(ret), nextOffset);
}
function asUint224Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint224 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 28)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint224(
bytes memory encoded,
uint offset
) internal pure returns (uint224 ret, uint nextOffset) {
(ret, nextOffset) = asUint224Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes28Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes28, uint) {
(uint224 ret, uint nextOffset) = asUint224Unchecked(encoded, offset);
return (bytes28(ret), nextOffset);
}
function asBytes28(
bytes memory encoded,
uint offset
) internal pure returns (bytes28, uint) {
(uint224 ret, uint nextOffset) = asUint224(encoded, offset);
return (bytes28(ret), nextOffset);
}
function asUint232Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint232 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 29)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint232(
bytes memory encoded,
uint offset
) internal pure returns (uint232 ret, uint nextOffset) {
(ret, nextOffset) = asUint232Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes29Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes29, uint) {
(uint232 ret, uint nextOffset) = asUint232Unchecked(encoded, offset);
return (bytes29(ret), nextOffset);
}
function asBytes29(
bytes memory encoded,
uint offset
) internal pure returns (bytes29, uint) {
(uint232 ret, uint nextOffset) = asUint232(encoded, offset);
return (bytes29(ret), nextOffset);
}
function asUint240Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint240 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 30)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint240(
bytes memory encoded,
uint offset
) internal pure returns (uint240 ret, uint nextOffset) {
(ret, nextOffset) = asUint240Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes30Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes30, uint) {
(uint240 ret, uint nextOffset) = asUint240Unchecked(encoded, offset);
return (bytes30(ret), nextOffset);
}
function asBytes30(
bytes memory encoded,
uint offset
) internal pure returns (bytes30, uint) {
(uint240 ret, uint nextOffset) = asUint240(encoded, offset);
return (bytes30(ret), nextOffset);
}
function asUint248Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint248 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 31)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint248(
bytes memory encoded,
uint offset
) internal pure returns (uint248 ret, uint nextOffset) {
(ret, nextOffset) = asUint248Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes31Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes31, uint) {
(uint248 ret, uint nextOffset) = asUint248Unchecked(encoded, offset);
return (bytes31(ret), nextOffset);
}
function asBytes31(
bytes memory encoded,
uint offset
) internal pure returns (bytes31, uint) {
(uint248 ret, uint nextOffset) = asUint248(encoded, offset);
return (bytes31(ret), nextOffset);
}
function asUint256Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint256 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 32)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint256(
bytes memory encoded,
uint offset
) internal pure returns (uint256 ret, uint nextOffset) {
(ret, nextOffset) = asUint256Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes32Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes32, uint) {
(uint256 ret, uint nextOffset) = asUint256Unchecked(encoded, offset);
return (bytes32(ret), nextOffset);
}
function asBytes32(
bytes memory encoded,
uint offset
) internal pure returns (bytes32, uint) {
(uint256 ret, uint nextOffset) = asUint256(encoded, offset);
return (bytes32(ret), nextOffset);
}
}
"
},
"lib/wormhole-solidity-sdk/src/interfaces/IWormhole.sol": {
"content": "// contracts/Messages.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
interface IWormhole {
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
struct VM {
uint8 version;
uint32 timestamp;
uint32 nonce;
uint16 emitterChainId;
bytes32 emitterAddress;
uint64 sequence;
uint8 consistencyLevel;
bytes payload;
uint32 guardianSetIndex;
Signature[] signatures;
bytes32 hash;
}
struct ContractUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
address newContract;
}
struct GuardianSetUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
GuardianSet newGuardianSet;
uint32 newGuardianSetIndex;
}
struct SetMessageFee {
bytes32 module;
uint8 action;
uint16 chain;
uint256 messageFee;
}
struct TransferFees {
bytes32 module;
uint8 action;
uint16 chain;
uint256 amount;
bytes32 recipient;
}
struct RecoverChainId {
bytes32 module;
uint8 action;
uint256 evmChainId;
uint16 newChainId;
}
event LogMessagePublished(
address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel
);
event ContractUpgraded(address indexed oldContract, address indexed newContract);
event GuardianSetAdded(uint32 indexed index);
function publishMessage(uint32 nonce, bytes memory payload, uint8 consistencyLevel)
external
payable
returns (uint64 sequence);
function initialize() external;
function parseAndVerifyVM(bytes calldata encodedVM)
external
view
returns (VM memory vm, bool valid, string memory reason);
function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);
function verifySignatures(bytes32 hash, Signature[] memory signatures, GuardianSet memory guardianSet)
external
pure
returns (bool valid, string memory reason);
function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);
function quorum(uint256 numGuardians) external pure returns (uint256 numSignaturesRequiredForQuorum);
function getGuardianSet(uint32 index) external view returns (GuardianSet memory);
function getCurrentGuardianSetIndex() external view returns (uint32);
function getGuardianSetExpiry() external view returns (uint32);
function governanceActionIsConsumed(bytes32 hash) external view returns (bool);
function isInitialized(address impl) external view returns (bool);
function chainId() external view returns (uint16);
function isFork() external view returns (bool);
function governanceChainId() external view returns (uint16);
function governanceContract() external view returns (bytes32);
function messageFee() external view returns (uint256);
function evmChainId() external view returns (uint256);
function nextSequence(address emitter) external view returns (uint64);
function parseContractUpgrade(bytes memory encodedUpgrade) external pure returns (ContractUpgrade memory cu);
function parseGuardianSetUpgrade(bytes memory encodedUpgrade)
external
pure
returns (GuardianSetUpgrade memory gsu);
function parseSetMessageFee(bytes memory encodedSetMessageFee) external pure returns (SetMessageFee memory smf);
function parseTransferFees(bytes memory encodedTransferFees) external pure returns (TransferFees memory tf);
function parseRecoverChainId(bytes memory encodedRecoverChainId)
external
pure
returns (RecoverChainId memory rci);
function submitContractUpgrade(bytes memory _vm) external;
function submitSetMessageFee(bytes memory _vm) external;
function submitNewGuardianSet(bytes memory _vm) external;
function submitTransferFees(bytes memory _vm) external;
function submitRecoverChainId(bytes memory _vm) external;
}
"
},
"src/libraries/TransceiverHelpers.sol": {
"content": "// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
error InvalidFork(uint256 evmChainId, uint256 blockChainId);
function checkFork(
uint256 evmChainId
) view {
if (isFork(evmChainId)) {
revert InvalidFork(evmChainId, block.chainid);
}
}
function isFork(
uint256 evmChainId
) view returns (bool) {
return evmChainId != block.chainid;
}
function min(uint256 a, uint256 b) pure returns (uint256) {
return a < b ? a : b;
}
// @dev Count the number of set bits in a uint64
function countSetBits(
uint64 x
) pure returns (uint8 count) {
while (x != 0) {
x &= x - 1;
count++;
}
return count;
}
"
},
"src/libraries/TransceiverStructs.sol": {
"content": "// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
import "./TrimmedAmount.sol";
library TransceiverStructs {
using BytesParsing for bytes;
using TrimmedAmountLib for TrimmedAmount;
/// @notice Error thrown when the payload length exceeds the allowed maximum.
/// @dev Selector 0xa3419691.
/// @param size The size of the payload.
error PayloadTooLong(uint256 size);
/// @notice Error thrown when the prefix of an encoded message
/// does not match the expected value.
/// @dev Selector 0x56d2569d.
/// @param prefix The prefix that was found in the encoded message.
error IncorrectPrefix(bytes4 prefix);
/// @notice Error thrown when the transceiver instructions aren't
/// encoded with strictly increasing indices
/// @dev Selector 0x0555a4b9.
/// @param lastIndex Last parsed instruction index
/// @param instructionIndex The instruction index that was unordered
error UnorderedInstructions(uint256 lastIndex, uint256 instructionIndex);
/// @notice Error thrown when a transceiver instruction index
/// is greater than the number of registered transceivers
/// @dev We index from 0 so if providedIndex == numTransceivers then we're out-of-bounds too
/// @dev Selector 0x689f5016.
/// @param providedIndex The index specified in the instruction
/// @param numTransceivers The number of registered transceivers
error InvalidInstructionIndex(uint256 providedIndex, uint256 numTransceivers);
/// @dev Prefix for all NativeTokenTransfer payloads
/// This is 0x99'N''T''T'
bytes4 constant NTT_PREFIX = 0x994E5454;
/// @dev Message emitted and received by the nttManager contract.
/// The wire format is as follows:
/// - id - 32 bytes
/// - sender - 32 bytes
/// - payloadLength - 2 bytes
/// - payload - `payloadLength` bytes
struct NttManagerMessage {
/// @notice unique message identifier
/// @dev This is incrementally assigned on EVM chains, but this is not
/// guaranteed on other runtimes.
bytes32 id;
/// @notice original message sender address.
bytes32 sender;
/// @notice payload that corresponds to the type.
bytes payload;
}
function nttManagerMessageDigest(
uint16 sourceChainId,
NttManagerMessage memory m
) public pure returns (bytes32) {
return _nttManagerMessageDigest(sourceChainId, encodeNttManagerMessage(m));
}
function _nttManagerMessageDigest(
uint16 sourceChainId,
bytes memory encodedNttManagerMessage
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(sourceChainId, encodedNttManagerMessage));
}
function encodeNttManagerMessage(
NttManagerMessage memory m
) public pure returns (bytes memory encoded) {
if (m.payload.length > type(uint16).max) {
revert PayloadTooLong(m.payload.length);
}
uint16 payloadLength = uint16(m.payload.length);
return abi.encodePacked(m.id, m.sender, payloadLength, m.payload);
}
/// @notice Parse a NttManagerMessage.
/// @param encoded The byte array corresponding to the encoded message
/// @return nttManagerMessage The parsed NttManagerMessage struct.
function parseNttManagerMessage(
bytes memory encoded
) public pure returns (NttManagerMessage memory nttManagerMessage) {
uint256 offset = 0;
(nttManagerMessage.id, offset) = encoded.asBytes32Unchecked(offset);
(nttManagerMessage.sender, offset) = encoded.asBytes32Unchecked(offset);
uint256 payloadLength;
(payloadLength, offset) = encoded.asUint16Unchecked(offset);
(nttManagerMessage.payload, offset) = encoded.sliceUnchecked(offset, payloadLength);
encoded.checkLength(offset);
}
/// @dev Native Token Transfer payload.
/// The wire format is as follows:
/// - NTT_PREFIX - 4 bytes
/// - numDecimals - 1 byte
/// - amount - 8 bytes
/// - sourceToken - 32 bytes
/// - to - 32 bytes
/// - toChain - 2 bytes
/// - additionalPayloadLength - 2 bytes, optional
/// - additionalPayload - `additionalPayloadLength` bytes
struct NativeTokenTransfer {
/// @notice Amount being transferred (big-endian u64 and u8 for decimals)
TrimmedAmount amount;
/// @notice Source chain token address.
bytes32 sourceToken;
/// @notice Address of the recipient.
bytes32 to;
/// @notice Chain ID of the recipient
uint16 toChain;
/// @notice Custom payload
/// @dev Recommended that the first 4 bytes are a unique prefix
bytes additionalPayload;
}
function encodeNativeTokenTransfer(
NativeTokenTransfer memory m
) public pure returns (bytes memory encoded) {
// The `amount` and `decimals` fields are encoded in reverse order compared to how they are declared in the
// `TrimmedAmount` type. This is consistent with the Rust NTT implementation.
TrimmedAmount transferAmount = m.amount;
if (m.additionalPayload.length > 0) {
if (m.additionalPayload.length > type(uint16).max) {
revert PayloadTooLong(m.additionalPayload.length);
}
uint16 additionalPayloadLength = uint16(m.additionalPayload.length);
return abi.encodePacked(
NTT_PREFIX,
transferAmount.getDecimals(),
transferAmount.getAmount(),
m.sourceToken,
m.to,
m.toChain,
additionalPayloadLength,
m.additionalPayload
);
}
return abi.encodePacked(
NTT_PREFIX,
transferAmount.getDecimals(),
transferAmount.getAmount(),
m.sourceToken,
m.to,
m.toChain
);
}
/// @dev Parse a NativeTokenTransfer.
/// @param encoded The byte array corresponding to the encoded message
/// @return nativeTokenTransfer The parsed NativeTokenTransfer struct.
function parseNativeTokenTransfer(
bytes memory encoded
) public pure returns (NativeTokenTransfer memory nativeTokenTransfer) {
uint256 offset = 0;
bytes4 prefix;
(prefix, offset) = encoded.asBytes4Unchecked(offset);
if (prefix != NTT_PREFIX) {
revert IncorrectPrefix(prefix);
}
// The `amount` and `decimals` fields are parsed in reverse order compared to how they are declared in the
// `TrimmedAmount` struct. This is consistent with the Rust NTT implementation.
uint8 numDecimals;
(numDecimals, offset) = encoded.asUint8Unchecked(offset);
uint64 amount;
(amount, offset) = encoded.asUint64Unchecked(offset);
nativeTokenTransfer.amount = packTrimmedAmount(amount, numDecimals);
(nativeTokenTransfer.sourceToken, offset) = encoded.asBytes32Unchecked(offset);
(nativeTokenTransfer.to, offset) = encoded.asBytes32Unchecked(offset);
(nativeTokenTransfer.toChain, offset) = encoded.asUint16Unchecked(offset);
// The additional payload may be omitted, but if it is included, it is prefixed by a u16 for its length.
// If there are at least 2 bytes remaining, attempt to parse the additional payload.
if (encoded.length >= offset + 2) {
uint256 payloadLength;
(payloadLength, offset) = encoded.asUint16Unchecked(offset);
(nativeTokenTransfer.additionalPayload, offset) =
encoded.sliceUnchecked(offset, payloadLength);
}
encoded.checkLength(offset);
}
/// @dev Message emitted by Transceiver implementations.
/// Each message includes an Transceiver-specified 4-byte prefix.
/// The wire format is as follows:
/// - prefix - 4 bytes
/// - sourceNttManagerAddress - 32 bytes
/// - recipientNttManagerAddress - 32 bytes
/// - nttManagerPayloadLength - 2 bytes
/// - nttManagerPayload - `nttManagerPayloadLength` bytes
/// - transceiverPayloadLength - 2 bytes
/// - transceiverPayload - `transceiverPayloadLength` bytes
struct TransceiverMessage {
/// @notice Address of the NttManager contract that emitted this message.
bytes32 sourceNttManagerAddress;
/// @notice Address of the NttManager contract that receives this message.
bytes32 recipientNttManagerAddress;
/// @notice Payload provided to the Transceiver contract by the NttManager contract.
bytes nttManagerPayload;
/// @notice Optional payload that the transceiver can encode and use for its own message passing purposes.
bytes transceiverPayload;
}
// @notice Encodes an Transceiver message for communication between the
// NttManager and the Transceiver.
// @param m The TransceiverMessage struct containing the message details.
// @return encoded The byte array corresponding to the encoded message.
// @custom:throw PayloadTooLong if the length of transceiverId, nttManagerPayload,
// or transceiverPayload exceeds the allowed maximum.
function encodeTransceiverMessage(
bytes4 prefix,
TransceiverMessage memory m
) public pure returns (bytes memory encoded) {
if (m.nttManagerPayload.length > type(uint16).max) {
revert PayloadTooLong(m.nttManagerPayload.length);
}
uint16 nttManagerPayloadLength = uint16(m.nttManagerPayload.length);
if (m.transceiverPayload.length > type(uint16).max) {
revert PayloadTooLong(m.transceiverPayload.length);
}
uint16 transceiverPayloadLength = uint16(m.transceiverPayload.length);
return abi.encodePacked(
prefix,
m.sourceNttManagerAddress,
m.recipientNttManagerA
Submitted on: 2025-11-06 19:20:06
Comments
Log in to comment.
No comments yet.