wormhole/ethereum/contracts/relayer/wormholeRelayer/WormholeRelayerSend.sol

572 lines
20 KiB
Solidity
Raw Normal View History

Relayer: Ethereum folder Changes for Merging into Main (#3038) * gRelayer: surrounding files * modification to get compilation * restore devnet * remove generic relayer docker * remove wait for relayer engine * keep build time 20 * sh -> bash * sh -> bash * Remove comment * bash -> sh * Revert "bash -> sh" This reverts commit 5c37e92fa19bbdbefc79c8ee0dbceeb127c53373. * bash->sh * gRelayer: ethereum folder changes for generic-relayer-merge * add eth-devnet * Adds .github because workflow needs to install forge * sdk-ci-tests need to install forge * don't wait for nonexistent relayer engine * update package.json and package-lock.json * Remove unnecessary types from package.json * ts-node * gRelayer: ethereum folder changes for generic-relayer-merge * sdk-ci-tests need to install forge * don't wait for nonexistent relayer engine * update package.json and package-lock.json * remove these changes * Relayer: Natspec documentation in IWormholeRelayer (#3032) * WIP * Fixes * Updated interfaces * remove bash * Forward uses same refund chain id and refund address (#3034) * WIP * Fixes * Forward uses same refund chain id and refund address * Updated interfaces * Remove forge build warnings * Add note to interface for resend * via-ir on unless in Tilt * Correct IWormholeReceiver interface * Wormhole message fee now part of quoteDeliveryPrice (#3043) * Fix to PR 3043 * Remove compiler warning * Relayer/address drew review (#3060) * Fix typo in Create2Factory * Add event for contract upgrades * Prevent registering contract if it is already registered * Prevent allowing unset chainId for default delivery provider governance VAA * memory to calldata for external functions in WormholeRelayerSend * continue memory to calldata for external functions * Fix pricing in delivery provider * Sanity check new default delivery provider isn't 0 address * Don't save vaaKey as local variable * cache the length of array rather than iterate every time for vaaKeys * Replacing memory with calldata in few locations * Remove stale file DeliveryProviderMessages * Remove batch VAA sender script * Remove batch VAA from WormholeSimulator * Wait for a confirmation in deploy scripts * remove unnecessary comments * Fix Delivery Provider Pricing and add a test * remove console logs * Revert "continue memory to calldata for external functions" This reverts commit f322afb6c0bbd09e3d04ab42a90e592ff752f6bf. * Revert "memory to calldata for external functions in WormholeRelayerSend" This reverts commit 42fcaad8842d0c81506c9586d8d0fd98f6bb6ae1. * Revert "Don't save vaaKey as local variable" This reverts commit a9172379c564fd430a083645c1c42c78e014d68d. * Revert "cache the length of array rather than iterate every time for vaaKeys" This reverts commit d61380a9b0c0671e67e3bd5d874ae339e180dd34. * Revert "Replacing memory with calldata in few locations" This reverts commit 94e47b6e72eaaa52ac0ba2980c439180401fafd7. * Revert "Fix typo in Create2Factory" This reverts commit a9f7bdf461945c8abf020007d16bbc6b4301d051. * Update contract addresses for via-ir * Slight improvements to delivery provider implementation * typed errors for delivery provider * enable VIA-IR in CI and not in Tilt * correct contract address for via ir * WormholeRelayerSend and WormholeRelayerDelivery (#3082)
2023-06-13 14:01:43 -07:00
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;
import {
DeliveryProviderDoesNotSupportTargetChain,
InvalidMsgValue,
DeliveryProviderCannotReceivePayment,
VaaKey,
IWormholeRelayerSend
} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";
import {IDeliveryProvider} from "../../interfaces/relayer/IDeliveryProviderTyped.sol";
import {toWormholeFormat, fromWormholeFormat} from "../../libraries/relayer/Utils.sol";
import {
DeliveryInstruction,
RedeliveryInstruction
} from "../../libraries/relayer/RelayerInternalStructs.sol";
import {WormholeRelayerSerde} from "./WormholeRelayerSerde.sol";
import {ForwardInstruction, getDefaultDeliveryProviderState} from "./WormholeRelayerStorage.sol";
import {WormholeRelayerBase} from "./WormholeRelayerBase.sol";
import "../../interfaces/relayer/TypedUnits.sol";
import "../../libraries/relayer/ExecutionParameters.sol";
abstract contract WormholeRelayerSend is WormholeRelayerBase, IWormholeRelayerSend {
using WormholeRelayerSerde for *;
using WeiLib for Wei;
using GasLib for Gas;
using TargetNativeLib for TargetNative;
using LocalNativeLib for LocalNative;
/*
* Public convenience overloads
*/
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
Gas gasLimit
) external payable returns (uint64 sequence) {
return sendToEvm(
targetChain,
targetAddress,
payload,
receiverValue,
LocalNative.wrap(0),
gasLimit,
targetChain,
getDefaultDeliveryProviderOnChain(targetChain),
getDefaultDeliveryProvider(),
new VaaKey[](0),
CONSISTENCY_LEVEL_FINALIZED
);
}
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
Gas gasLimit,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence) {
return sendToEvm(
targetChain,
targetAddress,
payload,
receiverValue,
LocalNative.wrap(0),
gasLimit,
refundChain,
refundAddress,
getDefaultDeliveryProvider(),
new VaaKey[](0),
CONSISTENCY_LEVEL_FINALIZED
);
}
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
Gas gasLimit,
VaaKey[] memory vaaKeys
) external payable returns (uint64 sequence) {
return sendToEvm(
targetChain,
targetAddress,
payload,
receiverValue,
LocalNative.wrap(0),
gasLimit,
targetChain,
getDefaultDeliveryProviderOnChain(targetChain),
getDefaultDeliveryProvider(),
vaaKeys,
CONSISTENCY_LEVEL_FINALIZED
);
}
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
Gas gasLimit,
VaaKey[] memory vaaKeys,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence) {
return sendToEvm(
targetChain,
targetAddress,
payload,
receiverValue,
LocalNative.wrap(0),
gasLimit,
refundChain,
refundAddress,
getDefaultDeliveryProvider(),
vaaKeys,
CONSISTENCY_LEVEL_FINALIZED
);
}
function sendToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
LocalNative paymentForExtraReceiverValue,
Gas gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) public payable returns (uint64 sequence) {
sequence = send(
targetChain,
toWormholeFormat(targetAddress),
payload,
receiverValue,
paymentForExtraReceiverValue,
encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
refundChain,
toWormholeFormat(refundAddress),
deliveryProviderAddress,
vaaKeys,
consistencyLevel
);
}
function forwardPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
Gas gasLimit
) external payable {
(address deliveryProvider,) =
getOriginalOrDefaultDeliveryProvider(targetChain);
forward(
targetChain,
toWormholeFormat(targetAddress),
payload,
receiverValue,
LocalNative.wrap(0),
encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
getCurrentRefundChain(),
getCurrentRefundAddress(),
deliveryProvider,
new VaaKey[](0),
CONSISTENCY_LEVEL_FINALIZED
);
}
function forwardVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
Gas gasLimit,
VaaKey[] memory vaaKeys
) external payable {
(address deliveryProvider,) =
getOriginalOrDefaultDeliveryProvider(targetChain);
forward(
targetChain,
toWormholeFormat(targetAddress),
payload,
receiverValue,
LocalNative.wrap(0),
encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
getCurrentRefundChain(),
getCurrentRefundAddress(),
deliveryProvider,
vaaKeys,
CONSISTENCY_LEVEL_FINALIZED
);
}
function forwardToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
TargetNative receiverValue,
LocalNative paymentForExtraReceiverValue,
Gas gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) public payable {
// provide ability to use original relay provider
if (deliveryProviderAddress == address(0)) {
deliveryProviderAddress = getOriginalDeliveryProvider();
}
forward(
targetChain,
toWormholeFormat(targetAddress),
payload,
receiverValue,
paymentForExtraReceiverValue,
encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
refundChain,
toWormholeFormat(refundAddress),
deliveryProviderAddress,
vaaKeys,
consistencyLevel
);
}
function resendToEvm(
VaaKey memory deliveryVaaKey,
uint16 targetChain,
TargetNative newReceiverValue,
Gas newGasLimit,
address newDeliveryProviderAddress
) public payable returns (uint64 sequence) {
sequence = resend(
deliveryVaaKey,
targetChain,
newReceiverValue,
encodeEvmExecutionParamsV1(EvmExecutionParamsV1(newGasLimit)),
newDeliveryProviderAddress
);
}
function send(
uint16 targetChain,
bytes32 targetAddress,
bytes memory payload,
TargetNative receiverValue,
LocalNative paymentForExtraReceiverValue,
bytes memory encodedExecutionParameters,
uint16 refundChain,
bytes32 refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) public payable returns (uint64 sequence) {
sequence = send(
Send(
targetChain,
targetAddress,
payload,
receiverValue,
paymentForExtraReceiverValue,
encodedExecutionParameters,
refundChain,
refundAddress,
deliveryProviderAddress,
vaaKeys,
consistencyLevel
)
);
}
function forward(
uint16 targetChain,
bytes32 targetAddress,
bytes memory payload,
TargetNative receiverValue,
LocalNative paymentForExtraReceiverValue,
bytes memory encodedExecutionParameters,
uint16 refundChain,
bytes32 refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) public payable {
forward(
Send(
targetChain,
targetAddress,
payload,
receiverValue,
paymentForExtraReceiverValue,
encodedExecutionParameters,
refundChain,
refundAddress,
deliveryProviderAddress,
vaaKeys,
consistencyLevel
)
);
}
/*
* Non overload logic
*/
struct Send {
uint16 targetChain;
bytes32 targetAddress;
bytes payload;
TargetNative receiverValue;
LocalNative paymentForExtraReceiverValue;
bytes encodedExecutionParameters;
uint16 refundChain;
bytes32 refundAddress;
address deliveryProviderAddress;
VaaKey[] vaaKeys;
uint8 consistencyLevel;
}
function send(Send memory sendParams) internal returns (uint64 sequence) {
IDeliveryProvider provider = IDeliveryProvider(sendParams.deliveryProviderAddress);
// Revert if delivery provider does not support the target chain
if (!provider.isChainSupported(sendParams.targetChain)) {
revert DeliveryProviderDoesNotSupportTargetChain(
sendParams.deliveryProviderAddress, sendParams.targetChain
);
}
// Obtain the delivery provider's fee for this delivery, as well as some encoded info (e.g. refund per unit of gas unused)
(LocalNative deliveryPrice, bytes memory encodedExecutionInfo) = provider.quoteDeliveryPrice(
sendParams.targetChain, sendParams.receiverValue, sendParams.encodedExecutionParameters
);
// Check if user passed in 'one wormhole message fee' + 'delivery provider's fee'
LocalNative wormholeMessageFee = getWormholeMessageFee();
checkMsgValue(wormholeMessageFee, deliveryPrice, sendParams.paymentForExtraReceiverValue);
// Encode all relevant info the delivery provider needs to perform the delivery as requested
bytes memory encodedInstruction = DeliveryInstruction({
targetChain: sendParams.targetChain,
targetAddress: sendParams.targetAddress,
payload: sendParams.payload,
requestedReceiverValue: sendParams.receiverValue,
extraReceiverValue: provider.quoteAssetConversion(
sendParams.targetChain, sendParams.paymentForExtraReceiverValue
),
encodedExecutionInfo: encodedExecutionInfo,
refundChain: sendParams.refundChain,
refundAddress: sendParams.refundAddress,
refundDeliveryProvider: provider.getTargetChainAddress(sendParams.targetChain),
sourceDeliveryProvider: toWormholeFormat(sendParams.deliveryProviderAddress),
senderAddress: toWormholeFormat(msg.sender),
vaaKeys: sendParams.vaaKeys
}).encode();
// Publish the encoded delivery instruction as a wormhole message
// and pay the delivery provider their fee
bool paymentSucceeded;
(sequence, paymentSucceeded) = publishAndPay(
wormholeMessageFee,
deliveryPrice,
sendParams.paymentForExtraReceiverValue,
encodedInstruction,
sendParams.consistencyLevel,
provider.getRewardAddress()
);
if(!paymentSucceeded)
revert DeliveryProviderCannotReceivePayment();
}
function forward(Send memory sendParams) internal {
// Revert if a delivery with targetAddress == msg.sender is not currently in progress
checkMsgSenderInDelivery();
IDeliveryProvider provider = IDeliveryProvider(sendParams.deliveryProviderAddress);
// Revert if delivery provider does not support the target chain
if (!provider.isChainSupported(sendParams.targetChain)) {
revert DeliveryProviderDoesNotSupportTargetChain(
sendParams.deliveryProviderAddress, sendParams.targetChain
);
}
// Obtain the delivery provider's fee for this delivery, as well as some encoded info (e.g. refund per unit of gas unused)
(LocalNative deliveryPrice, bytes memory encodedExecutionInfo) = provider.quoteDeliveryPrice(
sendParams.targetChain, sendParams.receiverValue, sendParams.encodedExecutionParameters
);
// Encode all relevant info the delivery provider needs to perform this delivery as requested
bytes memory encodedInstruction = DeliveryInstruction({
targetChain: sendParams.targetChain,
targetAddress: sendParams.targetAddress,
payload: sendParams.payload,
requestedReceiverValue: sendParams.receiverValue,
extraReceiverValue: provider.quoteAssetConversion(
sendParams.targetChain, sendParams.paymentForExtraReceiverValue
),
encodedExecutionInfo: encodedExecutionInfo,
refundChain: sendParams.refundChain,
refundAddress: sendParams.refundAddress,
refundDeliveryProvider: provider.getTargetChainAddress(sendParams.targetChain),
sourceDeliveryProvider: toWormholeFormat(sendParams.deliveryProviderAddress),
senderAddress: toWormholeFormat(msg.sender),
vaaKeys: sendParams.vaaKeys
}).encode();
// Store information about this delivery in state
// so that it can be performed after the execution of the current delivery,
// when the 'refund' available to use for this delivery is known
appendForwardInstruction(
ForwardInstruction({
encodedInstruction: encodedInstruction,
msgValue: LocalNative.wrap(msg.value),
deliveryPrice: deliveryPrice,
paymentForExtraReceiverValue: sendParams.paymentForExtraReceiverValue,
consistencyLevel: sendParams.consistencyLevel,
rewardAddress: provider.getRewardAddress()
})
);
}
function resend(
VaaKey memory deliveryVaaKey,
uint16 targetChain,
TargetNative newReceiverValue,
bytes memory newEncodedExecutionParameters,
address newDeliveryProviderAddress
) public payable returns (uint64 sequence) {
IDeliveryProvider provider = IDeliveryProvider(newDeliveryProviderAddress);
// Revert if delivery provider does not support the target chain
if (!provider.isChainSupported(targetChain)) {
revert DeliveryProviderDoesNotSupportTargetChain(
newDeliveryProviderAddress, targetChain
);
}
// Obtain the delivery provider's fee for this delivery, as well as some encoded info (e.g. refund per unit of gas unused)
(LocalNative deliveryPrice, bytes memory encodedExecutionInfo) = provider.quoteDeliveryPrice(
targetChain, newReceiverValue, newEncodedExecutionParameters
);
// Check if user passed in 'one wormhole message fee' + 'delivery provider's fee'
LocalNative wormholeMessageFee = getWormholeMessageFee();
checkMsgValue(wormholeMessageFee, deliveryPrice, LocalNative.wrap(0));
// Encode all relevant info the delivery provider needs to perform this redelivery as requested
bytes memory encodedInstruction = RedeliveryInstruction({
deliveryVaaKey: deliveryVaaKey,
targetChain: targetChain,
newRequestedReceiverValue: newReceiverValue,
newEncodedExecutionInfo: encodedExecutionInfo,
newSourceDeliveryProvider: toWormholeFormat(newDeliveryProviderAddress),
newSenderAddress: toWormholeFormat(msg.sender)
}).encode();
// Publish the encoded redelivery instruction as a wormhole message
// and pay the delivery provider their fee
bool paymentSucceeded;
(sequence, paymentSucceeded) = publishAndPay(
wormholeMessageFee,
deliveryPrice,
LocalNative.wrap(0),
encodedInstruction,
CONSISTENCY_LEVEL_INSTANT,
provider.getRewardAddress()
);
if (!paymentSucceeded)
revert DeliveryProviderCannotReceivePayment();
}
function getDefaultDeliveryProvider() public view returns (address deliveryProvider) {
deliveryProvider = getDefaultDeliveryProviderState().defaultDeliveryProvider;
}
// Get the delivery provider's contract address on chain 'targetChain'
function getDefaultDeliveryProviderOnChain(uint16 targetChain)
public
view
returns (address deliveryProvider)
{
deliveryProvider = fromWormholeFormat(
IDeliveryProvider(getDefaultDeliveryProviderState().defaultDeliveryProvider)
.getTargetChainAddress(targetChain)
);
}
function getOriginalOrDefaultDeliveryProvider(uint16 targetChain)
public
view
returns (address deliveryProvider, address deliveryProviderOnTarget)
{
deliveryProvider = getOriginalDeliveryProvider();
if (
deliveryProvider == address(0)
|| !IDeliveryProvider(deliveryProvider).isChainSupported(targetChain)
) {
deliveryProvider = getDefaultDeliveryProvider();
}
deliveryProviderOnTarget = fromWormholeFormat(
IDeliveryProvider(deliveryProvider).getTargetChainAddress(targetChain)
);
}
function quoteEVMDeliveryPrice(
uint16 targetChain,
TargetNative receiverValue,
Gas gasLimit,
address deliveryProviderAddress
) public view returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerGasUnused) {
(LocalNative quote, bytes memory encodedExecutionInfo) = quoteDeliveryPrice(
targetChain,
receiverValue,
encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
deliveryProviderAddress
);
nativePriceQuote = quote;
targetChainRefundPerGasUnused = decodeEvmExecutionInfoV1(encodedExecutionInfo).targetChainRefundPerGasUnused;
}
function quoteEVMDeliveryPrice(
uint16 targetChain,
TargetNative receiverValue,
Gas gasLimit
) public view returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerGasUnused) {
return quoteEVMDeliveryPrice(
targetChain, receiverValue, gasLimit, getDefaultDeliveryProvider()
);
}
function quoteDeliveryPrice(
uint16 targetChain,
TargetNative receiverValue,
bytes memory encodedExecutionParameters,
address deliveryProviderAddress
) public view returns (LocalNative nativePriceQuote, bytes memory encodedExecutionInfo) {
IDeliveryProvider provider = IDeliveryProvider(deliveryProviderAddress);
(LocalNative deliveryPrice, bytes memory _encodedExecutionInfo) = provider
.quoteDeliveryPrice(
targetChain, receiverValue, encodedExecutionParameters
);
encodedExecutionInfo = _encodedExecutionInfo;
nativePriceQuote = deliveryPrice + getWormholeMessageFee();
}
function quoteNativeForChain(
uint16 targetChain,
LocalNative currentChainAmount,
address deliveryProviderAddress
) public view returns (TargetNative targetChainAmount) {
return IDeliveryProvider(deliveryProviderAddress).quoteAssetConversion(targetChain, currentChainAmount);
}
}