2023-02-28 07:09:01 -08:00
// 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
* /
2023-02-28 07:09:01 -08:00
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-02-28 07:09:01 -08:00
2023-03-01 15:22:44 -08:00
// Add any additional funds which were passed in to the forward as msg.value
2023-02-28 07:09:01 -08:00
transactionFeeRefundAmount = transactionFeeRefundAmount + forwardInstruction . msgValue ;
2023-03-01 15:21:36 -08:00
// Checks if enough funds were passed into the forward
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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 ;
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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 )
2023-03-10 07:41:12 -08:00
* @ 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
* /
2023-02-28 07:09:01 -08:00
function _executeDelivery (
DeliveryInstruction memory internalInstruction ,
bytes [ ] memory encodedVMs ,
2023-03-10 07:41:12 -08:00
address payable relayerRefundAddress ,
DeliveryVAAInfo memory vaaInfo
2023-02-28 07:09:01 -08:00
) 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
2023-02-28 07:09:01 -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)
2023-02-28 07:09:01 -08:00
( 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)
2023-02-28 07:09:01 -08:00
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)
2023-02-28 07:09:01 -08:00
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'
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
bool forwardIsFunded = false ;
2023-03-01 15:21:36 -08:00
2023-02-28 07:09:01 -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
2023-02-28 07:09:01 -08:00
forwardIsFunded = emitForward ( transactionFeeRefundAmount , forwardingRequest ) ;
status = forwardIsFunded ? DeliveryStatus . FORWARD_REQUEST_SUCCESS : DeliveryStatus . FORWARD_REQUEST_FAILURE ;
} else {
status = callToTargetContractSucceeded ? DeliveryStatus . SUCCESS : DeliveryStatus . RECEIVER_FAILURE ;
}
2023-03-10 07:41:12 -08:00
// 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-10 07:41:12 -08:00
}
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)
2023-02-28 07:09:01 -08:00
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
2023-03-10 07:41:12 -08:00
uint256 refundToRefundAddress = receiverValueRefundAmount + ( forwardWasFunded ? 0 : transactionFeeRefundAmount ) ;
2023-02-28 07:09:01 -08:00
2023-03-01 15:21:36 -08:00
// Whether or not the refund succeeded
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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)
2023-02-28 07:09:01 -08:00
uint256 relayerRefundAmount = extraRelayerFunds
+ ( internalInstruction . maximumRefundTarget - transactionFeeRefundAmount )
2023-03-10 07:41:12 -08:00
+ ( forwardingRequestExists ? 0 : wormholeMessageFee ) + ( refundPaidToRefundAddress ? 0 : refundToRefundAddress ) ;
pay ( relayerRefundAddress , relayerRefundAmount ) ;
2023-02-28 07:09:01 -08:00
}
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 )
* /
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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 ,
2023-02-28 07:09:01 -08:00
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 ;
2023-02-28 07:09:01 -08:00
_executeDelivery (
2023-03-01 08:36:37 -08:00
originalInstruction ,
2023-02-28 07:09:01 -08:00
targetParams . sourceEncodedVMs ,
targetParams . relayerRefundAddress ,
2023-03-10 07:41:12 -08:00
DeliveryVAAInfo ( {
sourceChain : originalDeliveryVM . emitterChainId ,
sourceSequence : originalDeliveryVM . sequence ,
deliveryVaaHash : originalDeliveryVM . hash
} )
2023-02-28 07:09:01 -08:00
) ;
}
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 (
2023-02-28 07:09:01 -08:00
RedeliveryByTxHashInstruction memory redeliveryInstruction ,
DeliveryInstruction memory originalInstruction
2023-03-01 08:36:37 -08:00
) internal view returns ( bool isValid ) {
2023-02-28 07:09:01 -08:00
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 ) ;
2023-02-28 07:09:01 -08:00
}
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
&& 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
2023-02-28 07:09:01 -08:00
&& 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
2023-02-28 07:09:01 -08:00
&& 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 )
* /
2023-02-28 07:09:01 -08:00
function deliverSingle ( IDelivery . TargetDeliveryParametersSingle memory targetParams ) public payable {
IWormhole wormhole = wormhole ( ) ;
2023-03-01 15:22:44 -08:00
// Obtain the delivery VAA
2023-02-28 07:09:01 -08:00
( 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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
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
2023-02-28 07:09:01 -08:00
if ( chainId ( ) != deliveryInstruction . targetChain ) {
revert IDelivery . TargetChainIsNotThisChain ( deliveryInstruction . targetChain ) ;
}
_executeDelivery (
deliveryInstruction ,
targetParams . encodedVMs ,
targetParams . relayerRefundAddress ,
2023-03-10 07:41:12 -08:00
DeliveryVAAInfo ( {
sourceChain : deliveryVM . emitterChainId ,
sourceSequence : deliveryVM . sequence ,
deliveryVaaHash : deliveryVM . hash
} )
2023-02-28 07:09:01 -08:00
) ;
}
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 )
* /
2023-02-28 07:09:01 -08:00
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 )
* /
2023-02-28 07:09:01 -08:00
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 ;
}
}
}