From bd85111ff973e494b40dc282dc4aec689209a28b Mon Sep 17 00:00:00 2001 From: kidneyweak Date: Wed, 23 Aug 2023 23:56:10 +0800 Subject: [PATCH] feat: wormhole all chain verify --- .../zk-circuits/contracts/WormExample.sol | 57 ++ .../zk-circuits/contracts/WormKamuiField.sol | 86 +++ .../contracts/interface/IWormhole.sol | 148 ++++ .../contracts/interface/IWormholeReceiver.sol | 49 ++ .../contracts/interface/IWormholeRelayer.sol | 704 ++++++++++++++++++ 5 files changed, 1044 insertions(+) create mode 100644 packages/zk-circuits/contracts/WormExample.sol create mode 100644 packages/zk-circuits/contracts/WormKamuiField.sol create mode 100644 packages/zk-circuits/contracts/interface/IWormhole.sol create mode 100644 packages/zk-circuits/contracts/interface/IWormholeReceiver.sol create mode 100644 packages/zk-circuits/contracts/interface/IWormholeRelayer.sol diff --git a/packages/zk-circuits/contracts/WormExample.sol b/packages/zk-circuits/contracts/WormExample.sol new file mode 100644 index 0000000..869f527 --- /dev/null +++ b/packages/zk-circuits/contracts/WormExample.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "./interface/IWormholeRelayer.sol"; +import "./interface/IWormholeReceiver.sol"; + +contract HelloWormhole is IWormholeReceiver { + event GreetingReceived(string greeting, uint16 senderChain, address sender); + + uint256 constant GAS_LIMIT = 50_000; + + IWormholeRelayer public immutable wormholeRelayer; + + string public latestGreeting; + + constructor(address _wormholeRelayer) { + wormholeRelayer = IWormholeRelayer(_wormholeRelayer); + } + + function quoteCrossChainGreeting(uint16 targetChain) public view returns (uint256 cost) { + (cost,) = wormholeRelayer.quoteEVMDeliveryPrice(targetChain, 0, GAS_LIMIT); + } + + function sendCrossChainGreeting(uint16 targetChain, address targetAddress, string memory greeting) public payable { + uint256 cost = quoteCrossChainGreeting(targetChain); + require(msg.value == cost); + wormholeRelayer.sendPayloadToEvm{value: cost}( + targetChain, + targetAddress, + abi.encode(greeting, msg.sender), // payload + 0, // no receiver value needed since we're just passing a message + GAS_LIMIT + ); + } + + mapping(bytes32 => bool) public seenDeliveryVaaHashes; + + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory, // additionalVaas + bytes32, // address that called 'sendPayloadToEvm' (HelloWormhole contract address) + uint16 sourceChain, + bytes32 deliveryHash // this can be stored in a mapping deliveryHash => bool to prevent duplicate deliveries + ) public payable override { + require(msg.sender == address(wormholeRelayer), "Only relayer allowed"); + + // Ensure no duplicate deliveries + require(!seenDeliveryVaaHashes[deliveryHash], "Message already processed"); + seenDeliveryVaaHashes[deliveryHash] = true; + + // Parse the payload and do the corresponding actions! + (string memory greeting, address sender) = abi.decode(payload, (string, address)); + latestGreeting = greeting; + emit GreetingReceived(latestGreeting, sourceChain, sender); + } + +} \ No newline at end of file diff --git a/packages/zk-circuits/contracts/WormKamuiField.sol b/packages/zk-circuits/contracts/WormKamuiField.sol new file mode 100644 index 0000000..a8049fc --- /dev/null +++ b/packages/zk-circuits/contracts/WormKamuiField.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +import "./interface/ICircuitsVerifier.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract KamuiField is Ownable { + struct Voter { + bool voted; + } + + struct Proposal { + string name; + address creator; + uint acceptCount; + uint denyCount; + uint256 endTime; + } + + struct ProofData { + uint[2] a; + uint[2][2] b; + uint[2] c; + } + + event Voted(address indexed from, uint256 proposal, bool accept); + + ICircuitsVerifier public verifier; + + constructor(address _verifierAddress) { + verifier = ICircuitsVerifier(_verifierAddress); + } + + mapping(address => mapping(uint256 => Voter)) public voters; + + mapping(uint256 => Proposal) public proposals; + + mapping(address => uint[1]) public users; + + uint public totalProposals = 0; + + function createProposals(string calldata name, uint256 continueSec) public { + Proposal storage poll = proposals[totalProposals]; + poll.creator = msg.sender; + poll.name = name; + poll.endTime = block.timestamp + continueSec; + totalProposals += 1; + } + + function vote( + uint256 proposal, + bool accept, + ProofData memory proofData + ) public { + require(verifyProof(proofData), "Verification Failed"); + Voter storage sender = voters[msg.sender][proposal]; + require(block.timestamp < proposals[proposal].endTime, "Vote End"); + require(!sender.voted, "Already voted."); + sender.voted = true; + if (accept) proposals[proposal].acceptCount += 1; + else proposals[proposal].denyCount += 1; + emit Voted(msg.sender, proposal, accept); + } + + function getResult(uint256 proposal) public view returns (bool) { + require(block.timestamp > proposals[proposal].endTime, "Vote Not End"); + if (proposals[proposal].acceptCount > proposals[proposal].denyCount) + return true; + else return false; + } + + function getBlockTime() public view returns (uint256) { + return block.timestamp; + } + + function verifyProof( + ProofData memory proofData + ) public view returns (bool) { + return verifier.verifyProof(proofData.a, proofData.b, proofData.c); + } + + function registerUser(address user, uint proof) public onlyOwner { + users[user] = [proof]; + } +} diff --git a/packages/zk-circuits/contracts/interface/IWormhole.sol b/packages/zk-circuits/contracts/interface/IWormhole.sol new file mode 100644 index 0000000..a2becdf --- /dev/null +++ b/packages/zk-circuits/contracts/interface/IWormhole.sol @@ -0,0 +1,148 @@ +// 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; +} \ No newline at end of file diff --git a/packages/zk-circuits/contracts/interface/IWormholeReceiver.sol b/packages/zk-circuits/contracts/interface/IWormholeReceiver.sol new file mode 100644 index 0000000..e80c970 --- /dev/null +++ b/packages/zk-circuits/contracts/interface/IWormholeReceiver.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +/** + * @notice Interface for a contract which can receive Wormhole messages. + */ +interface IWormholeReceiver { + /** + * @notice When a `send` is performed with this contract as the target, this function will be + * invoked by the WormholeRelayer contract + * + * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it. + * + * We also recommend that this function: + * - Stores all received `deliveryHash`s in a mapping `(bytes32 => bool)`, and + * on every call, checks that deliveryHash has not already been stored in the + * map (This is to prevent other users maliciously trying to relay the same message) + * - Checks that `sourceChain` and `sourceAddress` are indeed who + * you expect to have requested the calling of `send` or `forward` on the source chain + * + * The invocation of this function corresponding to the `send` request will have msg.value equal + * to the receiverValue specified in the send request. + * + * If the invocation of this function reverts or exceeds the gas limit + * specified by the send requester, this delivery will result in a `ReceiverFailure`. + * + * @param payload - an arbitrary message which was included in the delivery by the + * requester. + * @param additionalVaas - Additional VAAs which were requested to be included in this delivery. + * They are guaranteed to all be included and in the same order as was specified in the + * delivery request. + * @param sourceAddress - the (wormhole format) address on the sending chain which requested + * this delivery. + * @param sourceChain - the wormhole chain ID where this delivery was requested. + * @param deliveryHash - the VAA hash of the deliveryVAA. + * + * NOTE: These signedVaas are NOT verified by the Wormhole core contract prior to being provided + * to this call. Always make sure `parseAndVerify()` is called on the Wormhole core contract + * before trusting the content of a raw VAA, otherwise the VAA may be invalid or malicious. + */ + function receiveWormholeMessages( + bytes memory payload, + bytes[] memory additionalVaas, + bytes32 sourceAddress, + uint16 sourceChain, + bytes32 deliveryHash + ) external payable; +} \ No newline at end of file diff --git a/packages/zk-circuits/contracts/interface/IWormholeRelayer.sol b/packages/zk-circuits/contracts/interface/IWormholeRelayer.sol new file mode 100644 index 0000000..fbc5ffc --- /dev/null +++ b/packages/zk-circuits/contracts/interface/IWormholeRelayer.sol @@ -0,0 +1,704 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +/** + * @title WormholeRelayer + * @author + * @notice This project allows developers to build cross-chain applications powered by Wormhole without needing to + * write and run their own relaying infrastructure + * + * We implement the IWormholeRelayer interface that allows users to request a delivery provider to relay a payload (and/or additional VAAs) + * to a chain and address of their choice. + */ + +/** + * @notice VaaKey identifies a wormhole message + * + * @custom:member chainId Wormhole chain ID of the chain where this VAA was emitted from + * @custom:member emitterAddress Address of the emitter of the VAA, in Wormhole bytes32 format + * @custom:member sequence Sequence number of the VAA + */ +struct VaaKey { + uint16 chainId; + bytes32 emitterAddress; + uint64 sequence; +} + +interface IWormholeRelayerBase { + event SendEvent(uint64 indexed sequence, uint256 deliveryQuote, uint256 paymentForExtraReceiverValue); + + function getRegisteredWormholeRelayerContract(uint16 chainId) external view returns (bytes32); +} + +/** + * @title IWormholeRelayerSend + * @notice The interface to request deliveries + */ +interface IWormholeRelayerSend is IWormholeRelayerBase { + /** + * @notice Publishes an instruction for the default delivery provider + * to relay a payload to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and `msg.value` equal to `receiverValue` + * + * `targetAddress` must implement the IWormholeReceiver interface + * + * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)` + * + * Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendPayloadToEvm` function + * with `refundChain` and `refundAddress` as parameters + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. + * @return sequence sequence number of published VAA containing delivery instructions + */ + function sendPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit + ) external payable returns (uint64 sequence); + + /** + * @notice Publishes an instruction for the default delivery provider + * to relay a payload to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and `msg.value` equal to `receiverValue` + * + * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` + * `targetAddress` must implement the IWormholeReceiver interface + * + * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)` + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the + * `targetChainRefundPerGasUnused` rate quoted by the delivery provider + * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format + * @param refundAddress The address on `refundChain` to deliver any refund to + * @return sequence sequence number of published VAA containing delivery instructions + */ + function sendPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + uint16 refundChain, + address refundAddress + ) external payable returns (uint64 sequence); + + /** + * @notice Publishes an instruction for the default delivery provider + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and `msg.value` equal to `receiverValue` + * + * `targetAddress` must implement the IWormholeReceiver interface + * + * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)` + * + * Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendVaasToEvm` function + * with `refundChain` and `refundAddress` as parameters + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + * @return sequence sequence number of published VAA containing delivery instructions + */ + function sendVaasToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + VaaKey[] memory vaaKeys + ) external payable returns (uint64 sequence); + + /** + * @notice Publishes an instruction for the default delivery provider + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and `msg.value` equal to `receiverValue` + * + * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` + * `targetAddress` must implement the IWormholeReceiver interface + * + * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)` + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the + * `targetChainRefundPerGasUnused` rate quoted by the delivery provider + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format + * @param refundAddress The address on `refundChain` to deliver any refund to + * @return sequence sequence number of published VAA containing delivery instructions + */ + function sendVaasToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + VaaKey[] memory vaaKeys, + uint16 refundChain, + address refundAddress + ) external payable returns (uint64 sequence); + + /** + * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress` + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and `msg.value` equal to + * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei. + * + * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` + * `targetAddress` must implement the IWormholeReceiver interface + * + * This function must be called with `msg.value` equal to + * quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue + * (in addition to the `receiverValue` specified) + * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the + * `targetChainRefundPerGasUnused` rate quoted by the delivery provider + * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format + * @param refundAddress The address on `refundChain` to deliver any refund to + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + * @param consistencyLevel Consistency level with which to publish the delivery instructions - see + * https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels + * @return sequence sequence number of published VAA containing delivery instructions + */ + function sendToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 paymentForExtraReceiverValue, + uint256 gasLimit, + uint16 refundChain, + address refundAddress, + address deliveryProviderAddress, + VaaKey[] memory vaaKeys, + uint8 consistencyLevel + ) external payable returns (uint64 sequence); + + /** + * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress` + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with `msg.value` equal to + * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei. + * + * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` + * `targetAddress` must implement the IWormholeReceiver interface + * + * This function must be called with `msg.value` equal to + * quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue + * (in addition to the `receiverValue` specified) + * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing + * e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress` + * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format + * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + * @param consistencyLevel Consistency level with which to publish the delivery instructions - see + * https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels + * @return sequence sequence number of published VAA containing delivery instructions + */ + function send( + uint16 targetChain, + bytes32 targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 paymentForExtraReceiverValue, + bytes memory encodedExecutionParameters, + uint16 refundChain, + bytes32 refundAddress, + address deliveryProviderAddress, + VaaKey[] memory vaaKeys, + uint8 consistencyLevel + ) external payable returns (uint64 sequence); + + /** + * @notice Performs the same function as a `send`, except: + * 1) Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`) + * 2) Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery) + * 3) Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number) + * + * The refund from the delivery currently in progress will not be sent to the user; it will instead + * be paid to the delivery provider to perform the instruction specified here + * + * Publishes an instruction for the same delivery provider (or default, if the same one doesn't support the new target chain) + * to relay a payload to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and with `msg.value` equal to `receiverValue` + * + * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`): + * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f] + * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f)] + * + * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested + * + * Any refunds (from leftover gas) from this forward will be paid to the same refundChain and refundAddress specified for the current delivery. + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. + */ + function forwardPayloadToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit + ) external payable; + + /** + * @notice Performs the same function as a `send`, except: + * 1) Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`) + * 2) Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery) + * 3) Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number) + * + * The refund from the delivery currently in progress will not be sent to the user; it will instead + * be paid to the delivery provider to perform the instruction specified here + * + * Publishes an instruction for the same delivery provider (or default, if the same one doesn't support the new target chain) + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and with `msg.value` equal to `receiverValue` + * + * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`): + * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f] + * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f)] + * + * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested + * + * Any refunds (from leftover gas) from this forward will be paid to the same refundChain and refundAddress specified for the current delivery. + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + */ + function forwardVaasToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 gasLimit, + VaaKey[] memory vaaKeys + ) external payable; + + /** + * @notice Performs the same function as a `send`, except: + * 1) Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`) + * 2) Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery) + * 3) Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number) + * + * The refund from the delivery currently in progress will not be sent to the user; it will instead + * be paid to the delivery provider to perform the instruction specified here + * + * Publishes an instruction for the delivery provider at `deliveryProviderAddress` + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with gas limit `gasLimit` and with `msg.value` equal to + * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei. + * + * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` + * `targetAddress` must implement the IWormholeReceiver interface + * + * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`): + * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f] + * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f, deliveryProviderAddress_f) + paymentForExtraReceiverValue_f] + * + * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue + * (in addition to the `receiverValue` specified) + * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the + * `targetChainRefundPerGasUnused` rate quoted by the delivery provider + * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format + * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + * @param consistencyLevel Consistency level with which to publish the delivery instructions - see + * https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels + */ + function forwardToEvm( + uint16 targetChain, + address targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 paymentForExtraReceiverValue, + uint256 gasLimit, + uint16 refundChain, + address refundAddress, + address deliveryProviderAddress, + VaaKey[] memory vaaKeys, + uint8 consistencyLevel + ) external payable; + + /** + * @notice Performs the same function as a `send`, except: + * 1) Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`) + * 2) Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery) + * 3) Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number) + * + * The refund from the delivery currently in progress will not be sent to the user; it will instead + * be paid to the delivery provider to perform the instruction specified here + * + * Publishes an instruction for the delivery provider at `deliveryProviderAddress` + * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` + * with `msg.value` equal to + * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei. + * + * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain` + * `targetAddress` must implement the IWormholeReceiver interface + * + * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`): + * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f] + * >= sum_f [quoteDeliveryPrice(targetChain_f, receiverValue_f, encodedExecutionParameters_f, deliveryProviderAddress_f) + paymentForExtraReceiverValue_f] + * + * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested + * + * @param targetChain in Wormhole Chain ID format + * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format + * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress` + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue + * (in addition to the `receiverValue` specified) + * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing + * e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress` + * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format + * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress` + * @param consistencyLevel Consistency level with which to publish the delivery instructions - see + * https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels + */ + function forward( + uint16 targetChain, + bytes32 targetAddress, + bytes memory payload, + uint256 receiverValue, + uint256 paymentForExtraReceiverValue, + bytes memory encodedExecutionParameters, + uint16 refundChain, + bytes32 refundAddress, + address deliveryProviderAddress, + VaaKey[] memory vaaKeys, + uint8 consistencyLevel + ) external payable; + + /** + * @notice Requests a previously published delivery instruction to be redelivered + * (e.g. with a different delivery provider) + * + * This function must be called with `msg.value` equal to + * quoteEVMDeliveryPrice(targetChain, newReceiverValue, newGasLimit, newDeliveryProviderAddress) + * + * @notice *** This will only be able to succeed if the following is true ** + * - newGasLimit >= gas limit of the old instruction + * - newReceiverValue >= receiver value of the old instruction + * - newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused` + * + * @param deliveryVaaKey VaaKey identifying the wormhole message containing the + * previously published delivery instructions + * @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions + * @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param newGasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the + * `targetChainRefundPerGasUnused` rate quoted by the delivery provider, to the refund chain and address specified in the original request + * @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @return sequence sequence number of published VAA containing redelivery instructions + * + * @notice *** This will only be able to succeed if the following is true ** + * - newGasLimit >= gas limit of the old instruction + * - newReceiverValue >= receiver value of the old instruction + * - newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused` + */ + function resendToEvm( + VaaKey memory deliveryVaaKey, + uint16 targetChain, + uint256 newReceiverValue, + uint256 newGasLimit, + address newDeliveryProviderAddress + ) external payable returns (uint64 sequence); + + /** + * @notice Requests a previously published delivery instruction to be redelivered + * + * + * This function must be called with `msg.value` equal to + * quoteDeliveryPrice(targetChain, newReceiverValue, newEncodedExecutionParameters, newDeliveryProviderAddress) + * + * @param deliveryVaaKey VaaKey identifying the wormhole message containing the + * previously published delivery instructions + * @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions + * @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param newEncodedExecutionParameters new encoded information on how to execute delivery that may impact pricing + * e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress` + * @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @return sequence sequence number of published VAA containing redelivery instructions + * + * @notice *** This will only be able to succeed if the following is true ** + * - (For EVM_V1) newGasLimit >= gas limit of the old instruction + * - newReceiverValue >= receiver value of the old instruction + * - (For EVM_V1) newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused` + */ + function resend( + VaaKey memory deliveryVaaKey, + uint16 targetChain, + uint256 newReceiverValue, + bytes memory newEncodedExecutionParameters, + address newDeliveryProviderAddress + ) external payable returns (uint64 sequence); + + /** + * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider + * + * @param targetChain in Wormhole Chain ID format + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. + * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay + * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused, + * if a refundAddress is specified + */ + function quoteEVMDeliveryPrice(uint16 targetChain, uint256 receiverValue, uint256 gasLimit) + external + view + returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused); + + /** + * @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress` + * + * @param targetChain in Wormhole Chain ID format + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param gasLimit gas limit with which to call `targetAddress`. + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay + * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused, + * if a refundAddress is specified + */ + function quoteEVMDeliveryPrice( + uint16 targetChain, + uint256 receiverValue, + uint256 gasLimit, + address deliveryProviderAddress + ) external view returns (uint256 nativePriceQuote, uint256 targetChainRefundPerGasUnused); + + /** + * @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress` + * + * @param targetChain in Wormhole Chain ID format + * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units) + * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing + * e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress` + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay + * @return encodedExecutionInfo encoded information on how the delivery will be executed + * e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` and `targetChainRefundPerGasUnused` + * (which is the amount of target chain currency that will be refunded per unit of gas unused, + * if a refundAddress is specified) + */ + function quoteDeliveryPrice( + uint16 targetChain, + uint256 receiverValue, + bytes memory encodedExecutionParameters, + address deliveryProviderAddress + ) external view returns (uint256 nativePriceQuote, bytes memory encodedExecutionInfo); + + /** + * @notice Returns the (extra) amount of target chain currency that `targetAddress` + * will be called with, if the `paymentForExtraReceiverValue` field is set to `currentChainAmount` + * + * @param targetChain in Wormhole Chain ID format + * @param currentChainAmount The value that `paymentForExtraReceiverValue` will be set to + * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider + * @return targetChainAmount The amount such that if `targetAddress` will be called with `msg.value` equal to + * receiverValue + targetChainAmount + */ + function quoteNativeForChain(uint16 targetChain, uint256 currentChainAmount, address deliveryProviderAddress) + external + view + returns (uint256 targetChainAmount); + + /** + * @notice Returns the address of the current default delivery provider + * @return deliveryProvider The address of (the default delivery provider)'s contract on this source + * chain. This must be a contract that implements IDeliveryProvider. + */ + function getDefaultDeliveryProvider() external view returns (address deliveryProvider); +} + +/** + * @title IWormholeRelayerDelivery + * @notice The interface to execute deliveries. Only relevant for Delivery Providers + */ +interface IWormholeRelayerDelivery is IWormholeRelayerBase { + enum DeliveryStatus { + SUCCESS, + RECEIVER_FAILURE, + FORWARD_REQUEST_FAILURE, + FORWARD_REQUEST_SUCCESS + } + + enum RefundStatus { + REFUND_SENT, + REFUND_FAIL, + CROSS_CHAIN_REFUND_SENT, + CROSS_CHAIN_REFUND_FAIL_PROVIDER_NOT_SUPPORTED, + CROSS_CHAIN_REFUND_FAIL_NOT_ENOUGH + } + + /** + * @custom:member recipientContract - The target contract address + * @custom:member sourceChain - The chain which this delivery was requested from (in wormhole + * ChainID format) + * @custom:member sequence - The wormhole sequence number of the delivery VAA on the source chain + * corresponding to this delivery request + * @custom:member deliveryVaaHash - The hash of the delivery VAA corresponding to this delivery + * request + * @custom:member gasUsed - The amount of gas that was used to call your target contract + * @custom:member status: + * - RECEIVER_FAILURE, if the target contract reverts + * - SUCCESS, if the target contract doesn't revert and no forwards were requested + * - FORWARD_REQUEST_FAILURE, if the target contract doesn't revert, forwards were requested, + * but provided/leftover funds were not sufficient to cover them all + * - FORWARD_REQUEST_SUCCESS, if the target contract doesn't revert and all forwards are covered + * @custom:member additionalStatusInfo: + * - If status is SUCCESS or FORWARD_REQUEST_SUCCESS, then this is empty. + * - If status is RECEIVER_FAILURE, this is `RETURNDATA_TRUNCATION_THRESHOLD` bytes of the + * return data (i.e. potentially truncated revert reason information). + * - If status is FORWARD_REQUEST_FAILURE, this is also the revert data - the reason the forward failed. + * This will be either an encoded Cancelled, DeliveryProviderReverted, or DeliveryProviderPaymentFailed error + * @custom:member refundStatus - Result of the refund. REFUND_SUCCESS or REFUND_FAIL are for + * refunds where targetChain=refundChain; the others are for targetChain!=refundChain, + * where a cross chain refund is necessary + * @custom:member overridesInfo: + * - If not an override: empty bytes array + * - Otherwise: An encoded `DeliveryOverride` + */ + event Delivery( + address indexed recipientContract, + uint16 indexed sourceChain, + uint64 indexed sequence, + bytes32 deliveryVaaHash, + DeliveryStatus status, + uint256 gasUsed, + RefundStatus refundStatus, + bytes additionalStatusInfo, + bytes overridesInfo + ); + + /** + * @notice The delivery provider calls `deliver` to relay messages as described by one delivery instruction + * + * The delivery provider must pass in the specified (by VaaKeys[]) signed wormhole messages (VAAs) from the source chain + * as well as the signed wormhole message with the delivery instructions (the delivery VAA) + * + * The messages will be relayed to the target address (with the specified gas limit and receiver value) iff the following checks are met: + * - the delivery VAA has a valid signature + * - the delivery VAA's emitter is one of these WormholeRelayer contracts + * - the delivery provider passed in at least enough of this chain's currency as msg.value (enough meaning the maximum possible refund) + * - the instruction's target chain is this chain + * - the relayed signed VAAs match the descriptions in container.messages (the VAA hashes match, or the emitter address, sequence number pair matches, depending on the description given) + * + * @param encodedVMs - An array of signed wormhole messages (all from the same source chain + * transaction) + * @param encodedDeliveryVAA - Signed wormhole message from the source chain's WormholeRelayer + * contract with payload being the encoded delivery instruction container + * @param relayerRefundAddress - The address to which any refunds to the delivery provider + * should be sent + * @param deliveryOverrides - Optional overrides field which must be either an empty bytes array or + * an encoded DeliveryOverride struct + */ + function deliver( + bytes[] memory encodedVMs, + bytes memory encodedDeliveryVAA, + address payable relayerRefundAddress, + bytes memory deliveryOverrides + ) external payable; +} + +interface IWormholeRelayer is IWormholeRelayerDelivery, IWormholeRelayerSend {} + +/* + * Errors thrown by IWormholeRelayer contract + */ + +// Bound chosen by the following formula: `memoryWord * 4 + selectorSize`. +// This means that an error identifier plus four fixed size arguments should be available to developers. +// In the case of a `require` revert with error message, this should provide 2 memory word's worth of data. +uint256 constant RETURNDATA_TRUNCATION_THRESHOLD = 132; + +//When msg.value was not equal to `delivery provider's quoted delivery price` + `paymentForExtraReceiverValue` +error InvalidMsgValue(uint256 msgValue, uint256 totalFee); + +error RequestedGasLimitTooLow(); + +error DeliveryProviderDoesNotSupportTargetChain(address relayer, uint16 chainId); +error DeliveryProviderCannotReceivePayment(); + +//When calling `forward()` on the WormholeRelayer if no delivery is in progress +error NoDeliveryInProgress(); +//When calling `delivery()` a second time even though a delivery is already in progress +error ReentrantDelivery(address msgSender, address lockedBy); +//When any other contract but the delivery target calls `forward()` on the WormholeRelayer while a +// delivery is in progress +error ForwardRequestFromWrongAddress(address msgSender, address deliveryTarget); + +error InvalidPayloadId(uint8 parsed, uint8 expected); +error InvalidPayloadLength(uint256 received, uint256 expected); +error InvalidVaaKeyType(uint8 parsed); + +error InvalidDeliveryVaa(string reason); +//When the delivery VAA (signed wormhole message with delivery instructions) was not emitted by the +// registered WormholeRelayer contract +error InvalidEmitter(bytes32 emitter, bytes32 registered, uint16 chainId); +error VaaKeysLengthDoesNotMatchVaasLength(uint256 keys, uint256 vaas); +error VaaKeysDoNotMatchVaas(uint8 index); +//When someone tries to call an external function of the WormholeRelayer that is only intended to be +// called by the WormholeRelayer itself (to allow retroactive reverts for atomicity) +error RequesterNotWormholeRelayer(); + +//When trying to relay a `DeliveryInstruction` to any other chain but the one it was specified for +error TargetChainIsNotThisChain(uint16 targetChain); +error ForwardNotSufficientlyFunded(uint256 amountOfFunds, uint256 amountOfFundsNeeded); +//When a `DeliveryOverride` contains a gas limit that's less than the original +error InvalidOverrideGasLimit(); +//When a `DeliveryOverride` contains a receiver value that's less than the original +error InvalidOverrideReceiverValue(); +//When a `DeliveryOverride` contains a 'refund per unit of gas unused' that's less than the original +error InvalidOverrideRefundPerGasUnused(); + +//When the delivery provider doesn't pass in sufficient funds (i.e. msg.value does not cover the +// maximum possible refund to the user) +error InsufficientRelayerFunds(uint256 msgValue, uint256 minimum); + +//When a bytes32 field can't be converted into a 20 byte EVM address, because the 12 padding bytes +// are non-zero (duplicated from Utils.sol) +error NotAnEvmAddress(bytes32); \ No newline at end of file