trustless-generic-relayer/ethereum/contracts/coreRelayer/CoreRelayerDelivery.sol

489 lines
26 KiB
Solidity
Raw Normal View History

// contracts/Bridge.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "../interfaces/IWormholeReceiver.sol";
import "../interfaces/IDelivery.sol";
import "./CoreRelayerGovernance.sol";
import "./CoreRelayerStructs.sol";
contract CoreRelayerDelivery is CoreRelayerGovernance {
enum DeliveryStatus {
SUCCESS,
RECEIVER_FAILURE,
FORWARD_REQUEST_FAILURE,
FORWARD_REQUEST_SUCCESS,
INVALID_REDELIVERY
}
event Delivery(
address indexed recipientContract,
uint16 indexed sourceChain,
uint64 indexed sequence,
bytes32 deliveryVaaHash,
DeliveryStatus status
);
2023-03-01 15:21:36 -08:00
/**
* - Checks if enough funds were passed into a forward
2023-03-01 15:22:44 -08:00
* - Increases the maxTransactionFee of the first forward in the MultichainSend container
2023-03-01 15:21:36 -08:00
* in order to use all of the funds
* - Publishes the DeliveryInstruction, with a 'sufficientlyFunded' flag indicating whether the forward had enough funds
* - If the forward was funded, pay the relayer's reward address to deliver the forward
2023-03-01 15:22:44 -08:00
*
2023-03-01 15:21:36 -08:00
* @param transactionFeeRefundAmount amount of maxTransactionFee that was unused
* @param forwardInstruction A struct containing information about the user's forward/multichainForward request
2023-03-01 15:22:44 -08:00
*
2023-03-01 15:21:36 -08:00
* @return forwardIsFunded whether or not the funds for the forward were enough
*/
function emitForward(uint256 transactionFeeRefundAmount, ForwardInstruction memory forwardInstruction)
internal
returns (bool forwardIsFunded)
{
2023-03-09 15:13:56 -08:00
DeliveryInstructionsContainer memory container =
decodeDeliveryInstructionsContainer(forwardInstruction.container);
2023-03-01 15:22:44 -08:00
// Add any additional funds which were passed in to the forward as msg.value
transactionFeeRefundAmount = transactionFeeRefundAmount + forwardInstruction.msgValue;
2023-03-01 15:21:36 -08:00
// Checks if enough funds were passed into the forward
forwardIsFunded = (transactionFeeRefundAmount >= forwardInstruction.totalFee);
IRelayProvider relayProvider = IRelayProvider(forwardInstruction.relayProvider);
IWormhole wormhole = wormhole();
uint256 wormholeMessageFee = wormhole.messageFee();
2023-03-01 15:21:36 -08:00
2023-03-01 15:22:44 -08:00
// Increases the maxTransactionFee of the first forward in the MultichainSend container
2023-03-01 15:21:36 -08:00
// in order to use all of the funds
if (forwardIsFunded) {
uint256 amountUnderMaximum = relayProvider.quoteMaximumBudget(container.instructions[0].targetChain)
- (
wormholeMessageFee + container.instructions[0].maximumRefundTarget
+ container.instructions[0].receiverValueTarget
);
uint256 convertedExtraAmount = calculateTargetDeliveryMaximumRefund(
container.instructions[0].targetChain,
transactionFeeRefundAmount - forwardInstruction.totalFee,
relayProvider
);
container.instructions[0].maximumRefundTarget +=
(amountUnderMaximum > convertedExtraAmount) ? convertedExtraAmount : amountUnderMaximum;
}
2023-03-01 15:21:36 -08:00
// Publishes the DeliveryInstruction, with a 'sufficientlyFunded' flag indicating whether the forward had enough funds
container.sufficientlyFunded = forwardIsFunded;
wormhole.publishMessage{value: wormholeMessageFee}(
forwardInstruction.nonce,
encodeDeliveryInstructionsContainer(container),
relayProvider.getConsistencyLevel()
);
// if funded, pay out reward to provider. Otherwise, the delivery code will handle sending a refund.
if (forwardIsFunded) {
pay(relayProvider.getRewardAddress(), transactionFeeRefundAmount);
}
2023-03-01 15:21:36 -08:00
//clear forwarding request from storage
clearForwardInstruction();
}
2023-03-01 15:21:36 -08:00
/**
* Performs the following actions:
* - Calls the 'receiveWormholeMessages' endpoint on the contract 'internalInstruction.targetAddress'
* (with the gas limit and value specified in internalInstruction, and 'encodedVMs' as the input)
2023-03-01 15:22:44 -08:00
*
2023-03-01 15:21:36 -08:00
* - Calculates how much of 'maxTransactionFee' is left
* - If the call succeeded and during execution of 'receiveWormholeMessages' there was a forward/multichainForward, then:
* if there is enough 'maxTransactionFee' left to execute the forward, then execute the forward
* else emit the forward instruction but with a flag (sufficientlyFunded = false) indicating that it wasn't paid for
2023-03-01 15:22:44 -08:00
* - else:
2023-03-01 15:21:36 -08:00
* refund any of the 'maxTransactionFee' not used to internalInstruction.refundAddress
* if the call reverted, refund the 'receiverValue' to internalInstruction.refundAddress
* - refund anything leftover to the relayer
2023-03-01 15:22:44 -08:00
*
2023-03-01 15:21:36 -08:00
* @param internalInstruction instruction to execute
* @param encodedVMs list of signed wormhole messages (VAAs)
* @param relayerRefundAddress address to send the relayer's refund to
* @param vaaInfo struct specifying:
* - sourceChain chain id that the delivery originated from
* - sourceSequence sequence number of the delivery VAA on the source chain
* - deliveryVaaHash hash of delivery VAA
2023-03-01 15:21:36 -08:00
*/
function _executeDelivery(
DeliveryInstruction memory internalInstruction,
bytes[] memory encodedVMs,
address payable relayerRefundAddress,
DeliveryVAAInfo memory vaaInfo
) internal {
// lock the contract to prevent reentrancy
if (isContractLocked()) {
revert IDelivery.ReentrantCall();
}
setContractLock(true);
setLockedTargetAddress(fromWormholeFormat(internalInstruction.targetAddress));
2023-03-01 15:21:36 -08:00
uint256 preGas = gasleft();
2023-03-01 15:21:36 -08:00
// Calls the 'receiveWormholeMessages' endpoint on the contract 'internalInstruction.targetAddress'
// (with the gas limit and value specified in internalInstruction, and 'encodedVMs' as the input)
(bool callToTargetContractSucceeded,) = fromWormholeFormat(internalInstruction.targetAddress).call{
gas: internalInstruction.executionParameters.gasLimit,
value: internalInstruction.receiverValueTarget
}(abi.encodeCall(IWormholeReceiver.receiveWormholeMessages, (encodedVMs, new bytes[](0))));
uint256 postGas = gasleft();
2023-03-01 15:21:36 -08:00
// Calculate the amount of gas used in the call (upperbounding at the gas limit, which shouldn't have been exceeded)
uint256 gasUsed = (preGas - postGas) > internalInstruction.executionParameters.gasLimit
? internalInstruction.executionParameters.gasLimit
: (preGas - postGas);
2023-03-01 15:21:36 -08:00
// Calculate the amount of maxTransactionFee to refund (multiply the maximum refund by the fraction of gas unused)
uint256 transactionFeeRefundAmount = (internalInstruction.executionParameters.gasLimit - gasUsed)
* internalInstruction.maximumRefundTarget / internalInstruction.executionParameters.gasLimit;
// unlock the contract
setContractLock(false);
2023-03-01 15:21:36 -08:00
// Retrieve the forward instruction created during execution of 'receiveWormholeMessages'
ForwardInstruction memory forwardingRequest = getForwardInstruction();
DeliveryStatus status;
2023-03-01 15:21:36 -08:00
// Represents whether or not (amount user passed into forward as msg.value) + (remaining maxTransactionFee) is enough to fund the forward
bool forwardIsFunded = false;
2023-03-01 15:21:36 -08:00
if (forwardingRequest.isValid) {
2023-03-01 15:21:36 -08:00
// If the user made a forward/multichainForward request, then try to execute it
forwardIsFunded = emitForward(transactionFeeRefundAmount, forwardingRequest);
status = forwardIsFunded ? DeliveryStatus.FORWARD_REQUEST_SUCCESS : DeliveryStatus.FORWARD_REQUEST_FAILURE;
} else {
status = callToTargetContractSucceeded ? DeliveryStatus.SUCCESS : DeliveryStatus.RECEIVER_FAILURE;
}
// Emit a status update that can be read by a SDK
emit Delivery({
recipientContract: fromWormholeFormat(internalInstruction.targetAddress),
sourceChain: vaaInfo.sourceChain,
sequence: vaaInfo.sourceSequence,
deliveryVaaHash: vaaInfo.deliveryVaaHash,
status: status
});
2023-03-09 15:13:56 -08:00
payRefunds(
internalInstruction,
relayerRefundAddress,
transactionFeeRefundAmount,
callToTargetContractSucceeded,
forwardingRequest.isValid,
forwardIsFunded
);
}
2023-03-09 15:13:56 -08:00
function payRefunds(
DeliveryInstruction memory internalInstruction,
address payable relayerRefundAddress,
uint256 transactionFeeRefundAmount,
bool callToTargetContractSucceeded,
bool forwardingRequestExists,
bool forwardWasFunded
) internal {
2023-03-01 15:21:36 -08:00
// Amount of receiverValue that is refunded to the user (0 if the call to 'receiveWormholeMessages' did not revert, or the full receiverValue otherwise)
uint256 receiverValueRefundAmount =
(callToTargetContractSucceeded ? 0 : internalInstruction.receiverValueTarget);
2023-03-09 15:13:56 -08:00
2023-03-01 15:21:36 -08:00
// Total refund to the user
uint256 refundToRefundAddress = receiverValueRefundAmount + (forwardWasFunded ? 0 : transactionFeeRefundAmount);
2023-03-01 15:21:36 -08:00
// Whether or not the refund succeeded
bool refundPaidToRefundAddress =
pay(payable(fromWormholeFormat(internalInstruction.refundAddress)), refundToRefundAddress);
uint256 wormholeMessageFee = wormhole().messageFee();
2023-03-01 15:21:36 -08:00
// Funds that the relayer passed as msg.value over what they needed
uint256 extraRelayerFunds = (
msg.value - internalInstruction.receiverValueTarget - internalInstruction.maximumRefundTarget
- wormholeMessageFee
);
2023-03-01 15:21:36 -08:00
// Refund the relayer (their extra funds) + (the amount that the relayer spent on gas) + (the wormhole message fee if no forward was sent)
// + (the users refund if that refund didn't succeed)
uint256 relayerRefundAmount = extraRelayerFunds
+ (internalInstruction.maximumRefundTarget - transactionFeeRefundAmount)
+ (forwardingRequestExists ? 0 : wormholeMessageFee) + (refundPaidToRefundAddress ? 0 : refundToRefundAddress);
pay(relayerRefundAddress, relayerRefundAmount);
}
function verifyRelayerVM(IWormhole.VM memory vm) internal view returns (bool) {
return registeredCoreRelayerContract(vm.emitterChainId) == vm.emitterAddress;
}
2023-03-01 08:36:37 -08:00
/**
* @notice The relay provider calls 'redeliverSingle' to relay messages as described by one redelivery instruction
2023-03-01 15:22:44 -08:00
*
2023-03-01 08:36:37 -08:00
* The instruction specifies, among other things, the target chain (must be this chain), refund address, new maximum refund (in this chain's currency),
* new receiverValue (in this chain's currency), new upper bound on gas
2023-03-01 15:22:44 -08:00
*
2023-03-01 08:36:37 -08:00
* The relay provider must pass in the original signed wormhole messages from the source chain of the same nonce
* (the wormhole message with the original delivery instructions (the delivery VAA) must be one of these messages)
* as well as the wormhole message with the new redelivery instruction (the redelivery VAA)
2023-03-01 15:22:44 -08:00
*
2023-03-01 08:36:37 -08:00
* The messages will be relayed to the target address (with the specified gas limit and receiver value) iff the following checks are met:
* - the redelivery VAA (targetParams.redeliveryVM) has a valid signature
* - the redelivery VAA's emitter is one of these CoreRelayer contracts
* - the original delivery VAA has a valid signature
* - the original delivery VAA's emitter is one of these CoreRelayer contracts
* - the new redelivery instruction's upper bound on gas >= the original instruction's upper bound on gas
* - the new redelivery instruction's 'receiver value' amount >= the original instruction's 'receiver value' amount
* - the redelivery instruction's target chain = this chain
* - the original instruction's target chain = this chain
2023-03-01 15:22:44 -08:00
* - for the redelivery instruction, the relay provider passed in at least [(one wormhole message fee) + instruction.newMaximumRefundTarget + instruction.newReceiverValueTarget] of this chain's currency as msg.value
2023-03-01 08:36:37 -08:00
* - msg.sender is the permissioned address allowed to execute this redelivery instruction
2023-03-01 15:22:44 -08:00
* - the permissioned address allowed to execute this redelivery instruction is the permissioned address allowed to execute the old instruction
*
2023-03-01 08:36:37 -08:00
* @param targetParams struct containing the signed wormhole messages and encoded redelivery instruction (and other information)
*/
function redeliverSingle(IDelivery.TargetRedeliveryByTxHashParamsSingle memory targetParams) public payable {
IWormhole wormhole = wormhole();
(IWormhole.VM memory redeliveryVM, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(targetParams.redeliveryVM);
2023-03-01 08:36:37 -08:00
// Check that the redelivery VAA (targetParams.redeliveryVM) has a valid signature
if (!valid) {
revert IDelivery.InvalidRedeliveryVM(reason);
}
2023-03-01 08:36:37 -08:00
// Check that the redelivery VAA's emitter is one of these CoreRelayer contracts
if (!verifyRelayerVM(redeliveryVM)) {
revert IDelivery.InvalidEmitterInRedeliveryVM();
}
RedeliveryByTxHashInstruction memory redeliveryInstruction = decodeRedeliveryInstruction(redeliveryVM.payload);
2023-03-01 15:22:44 -08:00
// Obtain the original delivery VAA
IWormhole.VM memory originalDeliveryVM;
(originalDeliveryVM, valid, reason) =
wormhole.parseAndVerifyVM(targetParams.sourceEncodedVMs[redeliveryInstruction.deliveryIndex]);
2023-03-01 08:36:37 -08:00
// Check that the original delivery VAA has a valid signature
if (!valid) {
revert IDelivery.InvalidVaa(redeliveryInstruction.deliveryIndex, reason);
}
2023-03-01 08:36:37 -08:00
// Check that the original delivery VAA's emitter is one of these CoreRelayer contracts
if (!verifyRelayerVM(originalDeliveryVM)) {
revert IDelivery.InvalidEmitterInOriginalDeliveryVM(redeliveryInstruction.deliveryIndex);
}
2023-03-01 08:36:37 -08:00
// Obtain the specific old instruction that was originally executed (and is meant to be re-executed with new parameters)
// specifying the the target chain (must be this chain), target address, refund address, old maximum refund (in this chain's currency),
// old receiverValue (in this chain's currency), old upper bound on gas, and the permissioned address allowed to execute this instruction
2023-03-01 15:22:44 -08:00
DeliveryInstruction memory originalInstruction = decodeDeliveryInstructionsContainer(originalDeliveryVM.payload)
.instructions[redeliveryInstruction.multisendIndex];
2023-03-01 08:36:37 -08:00
// Perform the following checks:
// - the new redelivery instruction's upper bound on gas >= the original instruction's upper bound on gas
// - the new redelivery instruction's 'receiver value' amount >= the original instruction's 'receiver value' amount
// - the redelivery instruction's target chain = this chain
// - the original instruction's target chain = this chain
2023-03-01 15:22:44 -08:00
// - for the redelivery instruction, the relay provider passed in at least [(one wormhole message fee) + instruction.newMaximumRefundTarget + instruction.newReceiverValueTarget] of this chain's currency as msg.value
2023-03-01 08:36:37 -08:00
// - msg.sender is the permissioned address allowed to execute this redelivery instruction
2023-03-01 15:22:44 -08:00
// - the permissioned address allowed to execute this redelivery instruction is the permissioned address allowed to execute the old instruction
valid = checkRedeliveryInstructionTarget(redeliveryInstruction, originalInstruction);
2023-03-02 13:51:21 -08:00
// Emit an 'Invalid Redelivery' event if one of the following four checks failed:
// - the permissioned address allowed to execute this redelivery instruction is the permissioned address allowed to execute the old instruction
2023-03-01 08:36:37 -08:00
// - the original instruction's target chain = this chain
// - the new redelivery instruction's 'receiver value' amount >= the original instruction's 'receiver value' amount
// - the new redelivery instruction's upper bound on gas >= the original instruction's upper bound on gas
if (!valid) {
emit Delivery({
2023-03-01 08:36:37 -08:00
recipientContract: fromWormholeFormat(originalInstruction.targetAddress),
sourceChain: originalDeliveryVM.emitterChainId,
sequence: originalDeliveryVM.sequence,
deliveryVaaHash: originalDeliveryVM.hash,
status: DeliveryStatus.INVALID_REDELIVERY
});
pay(targetParams.relayerRefundAddress, msg.value);
return;
}
2023-03-01 15:22:44 -08:00
// Replace maximumRefund, receiverValue, and the gasLimit on the original request
2023-03-01 08:36:37 -08:00
originalInstruction.maximumRefundTarget = redeliveryInstruction.newMaximumRefundTarget;
originalInstruction.receiverValueTarget = redeliveryInstruction.newReceiverValueTarget;
originalInstruction.executionParameters = redeliveryInstruction.executionParameters;
_executeDelivery(
2023-03-01 08:36:37 -08:00
originalInstruction,
targetParams.sourceEncodedVMs,
targetParams.relayerRefundAddress,
DeliveryVAAInfo({
sourceChain: originalDeliveryVM.emitterChainId,
sourceSequence: originalDeliveryVM.sequence,
deliveryVaaHash: originalDeliveryVM.hash
})
);
}
2023-03-01 08:36:37 -08:00
/**
* Check that:
* - the new redelivery instruction's upper bound on gas >= the original instruction's upper bound on gas
* - the new redelivery instruction's 'receiver value' amount >= the original instruction's 'receiver value' amount
* - the redelivery instruction's target chain = this chain
* - the original instruction's target chain = this chain
2023-03-01 15:22:44 -08:00
* - for the redelivery instruction, the relay provider passed in at least [(one wormhole message fee) + instruction.newMaximumRefundTarget + instruction.newReceiverValueTarget] of this chain's currency as msg.value
2023-03-01 08:36:37 -08:00
* - msg.sender is the permissioned address allowed to execute this redelivery instruction
2023-03-01 15:22:44 -08:00
* - the permissioned address allowed to execute this redelivery instruction is the permissioned address allowed to execute the old instruction
2023-03-01 08:36:37 -08:00
* @param redeliveryInstruction redelivery instruction
* @param originalInstruction old instruction
*/
function checkRedeliveryInstructionTarget(
RedeliveryByTxHashInstruction memory redeliveryInstruction,
DeliveryInstruction memory originalInstruction
2023-03-01 08:36:37 -08:00
) internal view returns (bool isValid) {
address providerAddress = fromWormholeFormat(redeliveryInstruction.executionParameters.providerDeliveryAddress);
2023-03-01 08:36:37 -08:00
2023-03-02 13:51:21 -08:00
// Check that msg.sender is the permissioned address allowed to execute this redelivery instruction
if (providerAddress != msg.sender) {
revert IDelivery.UnexpectedRelayer();
}
uint16 whChainId = chainId();
// Check that the redelivery instruction's target chain = this chain
if (whChainId != redeliveryInstruction.targetChain) {
revert IDelivery.TargetChainIsNotThisChain(redeliveryInstruction.targetChain);
}
uint256 wormholeMessageFee = wormhole().messageFee();
2023-03-01 08:36:37 -08:00
2023-03-01 15:22:44 -08:00
// Check that for the redelivery instruction, the relay provider passed in at least [(one wormhole message fee) + instruction.newMaximumRefundTarget + instruction.newReceiverValueTarget] of this chain's currency as msg.value
if (
msg.value
< redeliveryInstruction.newMaximumRefundTarget + redeliveryInstruction.newReceiverValueTarget
+ wormholeMessageFee
) {
revert IDelivery.InsufficientRelayerFunds();
}
2023-03-02 13:51:21 -08:00
// Check that the permissioned address allowed to execute this redelivery instruction is the permissioned address allowed to execute the old instruction
2023-03-02 15:22:48 -08:00
isValid = (
providerAddress == fromWormholeFormat(originalInstruction.executionParameters.providerDeliveryAddress)
)
2023-03-01 08:36:37 -08:00
// Check that the original instruction's target chain = this chain
&& whChainId == originalInstruction.targetChain
2023-03-01 08:36:37 -08:00
// Check that the new redelivery instruction's 'receiver value' amount >= the original instruction's 'receiver value' amount
&& originalInstruction.receiverValueTarget <= redeliveryInstruction.newReceiverValueTarget
2023-03-01 08:36:37 -08:00
// Check that the new redelivery instruction's upper bound on gas >= the original instruction's upper bound on gas
&& originalInstruction.executionParameters.gasLimit <= redeliveryInstruction.executionParameters.gasLimit;
}
2023-02-28 13:45:43 -08:00
/**
* @notice The relay provider calls 'deliverSingle' to relay messages as described by one delivery instruction
2023-03-01 15:22:44 -08:00
*
2023-02-28 13:45:43 -08:00
* The instruction specifies the target chain (must be this chain), target address, refund address, maximum refund (in this chain's currency),
2023-03-01 08:36:37 -08:00
* receiver value (in this chain's currency), upper bound on gas, and the permissioned address allowed to execute this instruction
2023-03-01 15:22:44 -08:00
*
2023-03-01 08:36:37 -08:00
* The relay provider must pass in the signed wormhole messages (VAAs) from the source chain of the same nonce
2023-02-28 13:45:43 -08:00
* (the wormhole message with the delivery instructions (the delivery VAA) must be one of these messages)
2023-03-01 15:22:44 -08:00
* as well as identify which of these messages is the delivery VAA and which of the many instructions in the multichainSend container is meant to be executed
*
2023-03-01 08:36:37 -08:00
* 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 CoreRelayer contracts
* - the delivery instruction container in the delivery VAA was fully funded
* - the instruction's target chain is this chain
2023-03-01 15:22:44 -08:00
* - the relay provider passed in at least [(one wormhole message fee) + instruction.maximumRefundTarget + instruction.receiverValueTarget] of this chain's currency as msg.value
2023-03-01 08:36:37 -08:00
* - msg.sender is the permissioned address allowed to execute this instruction
2023-03-01 15:22:44 -08:00
*
2023-02-28 13:45:43 -08:00
* @param targetParams struct containing the signed wormhole messages and encoded delivery instruction container (and other information)
*/
function deliverSingle(IDelivery.TargetDeliveryParametersSingle memory targetParams) public payable {
IWormhole wormhole = wormhole();
2023-03-01 15:22:44 -08:00
// Obtain the delivery VAA
(IWormhole.VM memory deliveryVM, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(targetParams.encodedVMs[targetParams.deliveryIndex]);
2023-03-01 08:36:37 -08:00
// Check that the delivery VAA has a valid signature
if (!valid) {
revert IDelivery.InvalidVaa(targetParams.deliveryIndex, reason);
}
2023-03-01 08:36:37 -08:00
// Check that the delivery VAA's emitter is one of these CoreRelayer contracts
if (!verifyRelayerVM(deliveryVM)) {
revert IDelivery.InvalidEmitter();
}
DeliveryInstructionsContainer memory container = decodeDeliveryInstructionsContainer(deliveryVM.payload);
2023-02-28 13:45:43 -08:00
2023-03-01 08:36:37 -08:00
// Check that the delivery instruction container in the delivery VAA was fully funded
if (!container.sufficientlyFunded) {
revert IDelivery.SendNotSufficientlyFunded();
}
2023-02-28 13:45:43 -08:00
// Obtain the specific instruction that is intended to be executed in this function
// specifying the the target chain (must be this chain), target address, refund address, maximum refund (in this chain's currency),
// receiverValue (in this chain's currency), upper bound on gas, and the permissioned address allowed to execute this instruction
DeliveryInstruction memory deliveryInstruction = container.instructions[targetParams.multisendIndex];
2023-03-01 08:36:37 -08:00
// Check that msg.sender is the permissioned address allowed to execute this instruction
if (fromWormholeFormat(deliveryInstruction.executionParameters.providerDeliveryAddress) != msg.sender) {
revert IDelivery.UnexpectedRelayer();
}
uint256 wormholeMessageFee = wormhole.messageFee();
2023-02-28 13:45:43 -08:00
2023-03-01 08:36:37 -08:00
// Check that the relay provider passed in at least [(one wormhole message fee) + instruction.maximumRefund + instruction.receiverValue] of this chain's currency as msg.value
if (
msg.value
< deliveryInstruction.maximumRefundTarget + deliveryInstruction.receiverValueTarget + wormholeMessageFee
) {
revert IDelivery.InsufficientRelayerFunds();
}
2023-03-01 08:36:37 -08:00
// Check that the instruction's target chain is this chain
if (chainId() != deliveryInstruction.targetChain) {
revert IDelivery.TargetChainIsNotThisChain(deliveryInstruction.targetChain);
}
_executeDelivery(
deliveryInstruction,
targetParams.encodedVMs,
targetParams.relayerRefundAddress,
DeliveryVAAInfo({
sourceChain: deliveryVM.emitterChainId,
sourceSequence: deliveryVM.sequence,
deliveryVaaHash: deliveryVM.hash
})
);
}
2023-02-28 13:45:43 -08:00
/**
* @notice Helper function that converts an EVM address to wormhole format
* @param addr (EVM 20-byte address)
* @return whFormat (32-byte address in Wormhole format)
*/
function toWormholeFormat(address addr) public pure returns (bytes32 whFormat) {
return bytes32(uint256(uint160(addr)));
}
2023-02-28 13:45:43 -08:00
/**
* @notice Helper function that converts an Wormhole format (32-byte) address to the EVM 'address' 20-byte format
* @param whFormatAddress (32-byte address in Wormhole format)
* @return addr (EVM 20-byte address)
*/
function fromWormholeFormat(bytes32 whFormatAddress) public pure returns (address addr) {
return address(uint160(uint256(whFormatAddress)));
}
function pay(address payable receiver, uint256 amount) internal returns (bool success) {
if (amount > 0) {
(success,) = receiver.call{value: amount}("");
} else {
success = true;
}
}
}