Code cleanup (#109)
* DRY: Remove duplicate structs * Move encode/decode/convert-request-to-instruction related files to CoreRelayerMessages * remove rolloverchain; now it is just the chain of the first request * forge test fix to accomdoate for removing two getters * DRY: Remove repeated error messages * Remove miscellaneous comments * DRY send and forward * replace relayprovider interface with address to match the IWormholeRelayer interface * forge fmt * Remove byteslib from CoreRelayer * Remove the encoding and decoding of the delivery request -> just store the struct itself! * forge fmt * Rewriting of checks in send/resend/forward * test passes * DRY - Emit only one event * DRY * forge fmt * Fix typescript error * using IWormholeRelayer * Consistent naming * call wormhole.messageFee() once * Remove unnecessary line * Compute the length once, not every iteration * forge tests pass
This commit is contained in:
parent
a1df44b3ee
commit
f7de3d649d
|
@ -3,15 +3,13 @@
|
|||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../libraries/external/BytesLib.sol";
|
||||
import "../interfaces/IWormholeRelayer.sol";
|
||||
import "../interfaces/IWormholeReceiver.sol";
|
||||
|
||||
import "../interfaces/IDelivery.sol";
|
||||
import "./CoreRelayerGovernance.sol";
|
||||
import "./CoreRelayerStructs.sol";
|
||||
|
||||
contract CoreRelayer is CoreRelayerGovernance {
|
||||
using BytesLib for bytes;
|
||||
|
||||
enum DeliveryStatus {
|
||||
SUCCESS,
|
||||
RECEIVER_FAILURE,
|
||||
|
@ -28,113 +26,39 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
DeliveryStatus status
|
||||
);
|
||||
|
||||
error FundsTooMuch();
|
||||
error MaxTransactionFeeNotEnough();
|
||||
error MsgValueTooLow(); // msg.value must cover the budget specified
|
||||
error NonceIsZero();
|
||||
error ForwardRequestFromWrongAddress();
|
||||
error NoDeliveryInProcess();
|
||||
error CantRequestMultipleForwards();
|
||||
error RelayProviderDoesNotSupportTargetChain();
|
||||
error RolloverChainNotIncluded(); // Rollover chain was not included in the forwarding request
|
||||
error ChainNotFoundInSends(uint16 chainId); // Required chain not found in the delivery requests
|
||||
error ReentrantCall();
|
||||
error InvalidEmitterInOriginalDeliveryVM(uint8 index);
|
||||
error InvalidRedeliveryVM(string reason);
|
||||
error InvalidEmitterInRedeliveryVM();
|
||||
error MismatchingRelayProvidersInRedelivery(); // The same relay provider must be specified when doing a single VAA redeliver
|
||||
error InvalidVaa(uint8 index);
|
||||
error InvalidEmitter();
|
||||
error SendNotSufficientlyFunded(); // This delivery request was not sufficiently funded, and must request redelivery
|
||||
error UnexpectedRelayer(); // Specified relayer is not the relayer delivering the message
|
||||
error InsufficientRelayerFunds(); // The relayer didn't pass sufficient funds (msg.value does not cover the necessary budget fees)
|
||||
error AlreadyDelivered(); // The message was already delivered.
|
||||
error TargetChainIsNotThisChain(uint16 targetChainId);
|
||||
|
||||
function send(Send memory request, uint32 nonce, IRelayProvider provider)
|
||||
function send(IWormholeRelayer.Send memory request, uint32 nonce, address relayProvider)
|
||||
public
|
||||
payable
|
||||
returns (uint64 sequence)
|
||||
{
|
||||
Send[] memory requests = new Send[](1);
|
||||
requests[0] = request;
|
||||
MultichainSend memory container = MultichainSend({relayProviderAddress: address(provider), requests: requests});
|
||||
return multichainSend(container, nonce);
|
||||
return multichainSend(multichainSendContainer(request, relayProvider), nonce);
|
||||
}
|
||||
|
||||
function forward(Send memory request, uint32 nonce, IRelayProvider provider) public payable {
|
||||
Send[] memory requests = new Send[](1);
|
||||
requests[0] = request;
|
||||
MultichainSend memory container = MultichainSend({relayProviderAddress: address(provider), requests: requests});
|
||||
return multichainForward(container, request.targetChain, nonce);
|
||||
function forward(IWormholeRelayer.Send memory request, uint32 nonce, address relayProvider) public payable {
|
||||
return multichainForward(multichainSendContainer(request, relayProvider), nonce);
|
||||
}
|
||||
|
||||
function resend(ResendByTx memory request, uint32 nonce, IRelayProvider provider)
|
||||
function resend(IWormholeRelayer.ResendByTx memory request, uint32 nonce, address relayProvider)
|
||||
public
|
||||
payable
|
||||
returns (uint64 sequence)
|
||||
{
|
||||
(uint256 requestFee, uint256 maximumRefund, uint256 receiverValueTarget, bool isSufficient, uint8 reason) =
|
||||
verifyFunding(
|
||||
VerifyFundingCalculation({
|
||||
provider: provider,
|
||||
sourceChain: chainId(),
|
||||
targetChain: request.targetChain,
|
||||
maxTransactionFeeSource: request.newMaxTransactionFee,
|
||||
receiverValueSource: request.newReceiverValue,
|
||||
isDelivery: false
|
||||
})
|
||||
);
|
||||
updateWormholeMessageFee();
|
||||
bool isSufficient = request.newMaxTransactionFee + request.newReceiverValue + wormholeMessageFee() <= msg.value;
|
||||
if (!isSufficient) {
|
||||
if (reason == 26) {
|
||||
revert MaxTransactionFeeNotEnough();
|
||||
} else {
|
||||
revert FundsTooMuch();
|
||||
}
|
||||
}
|
||||
IWormhole wormhole = wormhole();
|
||||
uint256 wormholeMessageFee = wormhole.messageFee();
|
||||
uint256 totalFee = requestFee + wormholeMessageFee;
|
||||
|
||||
//Make sure the msg.value covers the budget they specified
|
||||
if (msg.value < totalFee) {
|
||||
revert MsgValueTooLow();
|
||||
revert IWormholeRelayer.MsgValueTooLow();
|
||||
}
|
||||
|
||||
sequence = emitRedelivery(
|
||||
request,
|
||||
nonce,
|
||||
provider.getConsistencyLevel(),
|
||||
receiverValueTarget,
|
||||
maximumRefund,
|
||||
provider,
|
||||
wormhole,
|
||||
wormholeMessageFee
|
||||
IRelayProvider provider = IRelayProvider(relayProvider);
|
||||
RedeliveryByTxHashInstruction memory instruction = convertResendToRedeliveryInstruction(request, provider);
|
||||
checkRedeliveryInstruction(instruction, provider);
|
||||
|
||||
sequence = wormhole().publishMessage{value: wormholeMessageFee()}(
|
||||
nonce, encodeRedeliveryInstruction(instruction), provider.getConsistencyLevel()
|
||||
);
|
||||
|
||||
//Send the delivery fees to the specified address of the provider.
|
||||
pay(provider.getRewardAddress(), msg.value - wormholeMessageFee);
|
||||
}
|
||||
|
||||
function emitRedelivery(
|
||||
ResendByTx memory request,
|
||||
uint32 nonce,
|
||||
uint8 consistencyLevel,
|
||||
uint256 receiverValueTarget,
|
||||
uint256 maximumRefund,
|
||||
IRelayProvider provider,
|
||||
IWormhole wormhole,
|
||||
uint256 wormholeMessageFee
|
||||
) internal returns (uint64 sequence) {
|
||||
bytes memory instruction = convertToEncodedRedeliveryByTxHashInstruction(
|
||||
request,
|
||||
receiverValueTarget,
|
||||
maximumRefund,
|
||||
calculateTargetGasRedeliveryAmount(request.targetChain, request.newMaxTransactionFee, provider),
|
||||
provider
|
||||
);
|
||||
|
||||
sequence = wormhole.publishMessage{value: wormholeMessageFee}(nonce, instruction, consistencyLevel);
|
||||
pay(provider.getRewardAddress(), msg.value - wormholeMessageFee());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,37 +71,33 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
* it checks that the passed nonce is not zero (VAAs with a nonce of zero will not be batched)
|
||||
* it generates a VAA with the encoded DeliveryInstructions
|
||||
*/
|
||||
function multichainSend(MultichainSend memory deliveryRequests, uint32 nonce)
|
||||
function multichainSend(IWormholeRelayer.MultichainSend memory deliveryRequests, uint32 nonce)
|
||||
public
|
||||
payable
|
||||
returns (uint64 sequence)
|
||||
{
|
||||
(uint256 totalCost, bool isSufficient, uint8 cause) = sufficientFundsHelper(deliveryRequests, msg.value);
|
||||
if (!isSufficient) {
|
||||
if (cause == 26) {
|
||||
revert MaxTransactionFeeNotEnough();
|
||||
} else if (cause == 25) {
|
||||
revert MsgValueTooLow();
|
||||
} else {
|
||||
revert FundsTooMuch();
|
||||
}
|
||||
updateWormholeMessageFee();
|
||||
uint256 totalFee = getTotalFeeMultichainSend(deliveryRequests);
|
||||
if (totalFee > msg.value) {
|
||||
revert IWormholeRelayer.MsgValueTooLow();
|
||||
}
|
||||
if (nonce == 0) {
|
||||
revert NonceIsZero();
|
||||
revert IWormholeRelayer.NonceIsZero();
|
||||
}
|
||||
|
||||
// encode the DeliveryInstructions
|
||||
bytes memory container = convertToEncodedDeliveryInstructions(deliveryRequests, true);
|
||||
IRelayProvider relayProvider = IRelayProvider(deliveryRequests.relayProviderAddress);
|
||||
DeliveryInstructionsContainer memory container =
|
||||
convertMultichainSendToDeliveryInstructionsContainer(deliveryRequests);
|
||||
checkInstructions(container, IRelayProvider(deliveryRequests.relayProviderAddress));
|
||||
container.sufficientlyFunded = true;
|
||||
|
||||
// emit delivery message
|
||||
IWormhole wormhole = wormhole();
|
||||
IRelayProvider provider = IRelayProvider(deliveryRequests.relayProviderAddress);
|
||||
uint256 wormholeMessageFee = wormhole.messageFee();
|
||||
|
||||
sequence = wormhole.publishMessage{value: wormholeMessageFee}(nonce, container, provider.getConsistencyLevel());
|
||||
sequence = wormhole().publishMessage{value: wormholeMessageFee()}(
|
||||
nonce, encodeDeliveryInstructionsContainer(container), relayProvider.getConsistencyLevel()
|
||||
);
|
||||
|
||||
//pay fee to provider
|
||||
pay(provider.getRewardAddress(), totalCost - wormholeMessageFee);
|
||||
pay(relayProvider.getRewardAddress(), totalFee - wormholeMessageFee());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,218 +111,96 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
* it checks that the passed nonce is not zero (VAAs with a nonce of zero will not be batched)
|
||||
* it generates a VAA with the encoded DeliveryInstructions
|
||||
*/
|
||||
function multichainForward(MultichainSend memory deliveryRequests, uint16 rolloverChain, uint32 nonce)
|
||||
public
|
||||
payable
|
||||
{
|
||||
// Can only forward while a delivery is in process.
|
||||
function multichainForward(IWormholeRelayer.MultichainSend memory deliveryRequests, uint32 nonce) public payable {
|
||||
if (!isContractLocked()) {
|
||||
revert NoDeliveryInProcess();
|
||||
revert IWormholeRelayer.NoDeliveryInProgress();
|
||||
}
|
||||
if (getForwardingRequest().isValid) {
|
||||
revert CantRequestMultipleForwards();
|
||||
if (getForwardInstruction().isValid) {
|
||||
revert IWormholeRelayer.MultipleForwardsRequested();
|
||||
}
|
||||
if (nonce == 0) {
|
||||
revert IWormholeRelayer.NonceIsZero();
|
||||
}
|
||||
if (msg.sender != lockedTargetAddress()) {
|
||||
revert IWormholeRelayer.ForwardRequestFromWrongAddress();
|
||||
}
|
||||
|
||||
//We want to catch malformed requests in this function, and only underfunded requests when emitting.
|
||||
verifyForwardingRequest(deliveryRequests, rolloverChain, nonce);
|
||||
uint256 totalFee = getTotalFeeMultichainSend(deliveryRequests);
|
||||
DeliveryInstructionsContainer memory container =
|
||||
convertMultichainSendToDeliveryInstructionsContainer(deliveryRequests);
|
||||
checkInstructions(container, IRelayProvider(deliveryRequests.relayProviderAddress));
|
||||
|
||||
bytes memory encodedMultichainSend = encodeMultichainSend(deliveryRequests);
|
||||
setForwardingRequest(
|
||||
ForwardingRequest({
|
||||
deliveryRequestsContainer: encodedMultichainSend,
|
||||
rolloverChain: rolloverChain,
|
||||
setForwardInstruction(
|
||||
ForwardInstruction({
|
||||
container: container,
|
||||
nonce: nonce,
|
||||
msgValue: msg.value,
|
||||
totalFee: totalFee,
|
||||
sender: msg.sender,
|
||||
relayProvider: deliveryRequests.relayProviderAddress,
|
||||
isValid: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function emitForward(uint256 refundAmount, ForwardingRequest memory forwardingRequest)
|
||||
function emitForward(uint256 transactionFeeRefundAmount, ForwardInstruction memory forwardInstruction)
|
||||
internal
|
||||
returns (uint64, bool)
|
||||
returns (bool forwardIsFunded)
|
||||
{
|
||||
MultichainSend memory container = decodeMultichainSend(forwardingRequest.deliveryRequestsContainer);
|
||||
DeliveryInstructionsContainer memory container = forwardInstruction.container;
|
||||
|
||||
//Add any additional funds which were passed in to the refund amount
|
||||
refundAmount = refundAmount + forwardingRequest.msgValue;
|
||||
transactionFeeRefundAmount = transactionFeeRefundAmount + forwardInstruction.msgValue;
|
||||
|
||||
//make sure the refund amount covers the native gas amounts
|
||||
(uint256 totalMinimumFees, bool funded,) = sufficientFundsHelper(container, refundAmount);
|
||||
forwardIsFunded = (transactionFeeRefundAmount >= forwardInstruction.totalFee);
|
||||
container.sufficientlyFunded = forwardIsFunded;
|
||||
|
||||
//REVISE consider deducting the cost of this process from the refund amount?
|
||||
IRelayProvider relayProvider = IRelayProvider(forwardInstruction.relayProvider);
|
||||
|
||||
if (funded) {
|
||||
//find the delivery instruction for the rollover chain
|
||||
uint16 rolloverInstructionIndex = findDeliveryIndex(container, forwardingRequest.rolloverChain);
|
||||
|
||||
//calc how much budget is used by chains other than the rollover chain
|
||||
uint256 rolloverChainCostEstimate = container.requests[rolloverInstructionIndex].maxTransactionFee
|
||||
+ container.requests[rolloverInstructionIndex].receiverValue;
|
||||
//uint256 nonrolloverBudget = totalMinimumFees - rolloverChainCostEstimate; //stack too deep
|
||||
uint256 rolloverBudget = refundAmount - (totalMinimumFees - rolloverChainCostEstimate)
|
||||
- container.requests[rolloverInstructionIndex].receiverValue;
|
||||
|
||||
//overwrite the gas budget on the rollover chain to the remaining budget amount
|
||||
container.requests[rolloverInstructionIndex].maxTransactionFee = rolloverBudget;
|
||||
if (forwardIsFunded) {
|
||||
// the rollover chain is the chain in the first request
|
||||
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;
|
||||
}
|
||||
|
||||
//emit forwarding instruction
|
||||
bytes memory reencoded = convertToEncodedDeliveryInstructions(container, funded);
|
||||
IRelayProvider provider = IRelayProvider(container.relayProviderAddress);
|
||||
IWormhole wormhole = wormhole();
|
||||
uint64 sequence = wormhole.publishMessage{value: wormhole.messageFee()}(
|
||||
forwardingRequest.nonce, reencoded, provider.getConsistencyLevel()
|
||||
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 (funded) {
|
||||
pay(provider.getRewardAddress(), refundAmount);
|
||||
if (forwardIsFunded) {
|
||||
pay(relayProvider.getRewardAddress(), transactionFeeRefundAmount);
|
||||
}
|
||||
|
||||
//clear forwarding request from cache
|
||||
clearForwardingRequest();
|
||||
|
||||
return (sequence, funded);
|
||||
clearForwardInstruction();
|
||||
}
|
||||
|
||||
function verifyForwardingRequest(MultichainSend memory container, uint16 rolloverChain, uint32 nonce)
|
||||
internal
|
||||
view
|
||||
{
|
||||
if (nonce == 0) {
|
||||
revert NonceIsZero();
|
||||
}
|
||||
|
||||
if (msg.sender != lockedTargetAddress()) {
|
||||
revert ForwardRequestFromWrongAddress();
|
||||
}
|
||||
|
||||
bool foundRolloverChain = false;
|
||||
IRelayProvider selectedProvider = IRelayProvider(container.relayProviderAddress);
|
||||
|
||||
for (uint16 i = 0; i < container.requests.length; i++) {
|
||||
// TODO: Optimization opportunity here by reducing multiple calls to only one with all requested addresses.
|
||||
if (selectedProvider.getDeliveryAddress(container.requests[i].targetChain) == 0) {
|
||||
revert RelayProviderDoesNotSupportTargetChain();
|
||||
}
|
||||
if (container.requests[i].targetChain == rolloverChain) {
|
||||
foundRolloverChain = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundRolloverChain) {
|
||||
revert RolloverChainNotIncluded();
|
||||
}
|
||||
}
|
||||
|
||||
function findDeliveryIndex(MultichainSend memory container, uint16 chainId)
|
||||
function multichainSendContainer(IWormholeRelayer.Send memory request, address relayProvider)
|
||||
internal
|
||||
pure
|
||||
returns (uint16 deliveryRequestIndex)
|
||||
returns (IWormholeRelayer.MultichainSend memory container)
|
||||
{
|
||||
for (uint16 i = 0; i < container.requests.length; i++) {
|
||||
if (container.requests[i].targetChain == chainId) {
|
||||
deliveryRequestIndex = i;
|
||||
return deliveryRequestIndex;
|
||||
}
|
||||
}
|
||||
|
||||
revert ChainNotFoundInSends(chainId);
|
||||
}
|
||||
|
||||
/*
|
||||
By the time this function completes, we must be certain that the specified funds are sufficient to cover
|
||||
delivery for each one of the deliveryRequests with at least 1 gas on the target chains.
|
||||
*/
|
||||
function sufficientFundsHelper(MultichainSend memory deliveryRequests, uint256 funds)
|
||||
internal
|
||||
view
|
||||
returns (uint256 totalFees, bool isSufficient, uint8 reason)
|
||||
{
|
||||
totalFees = wormhole().messageFee();
|
||||
IRelayProvider provider = IRelayProvider(deliveryRequests.relayProviderAddress);
|
||||
|
||||
for (uint256 i = 0; i < deliveryRequests.requests.length; i++) {
|
||||
Send memory request = deliveryRequests.requests[i];
|
||||
|
||||
(uint256 requestFee, uint256 maximumRefund, uint256 receiverValueTarget, bool isSufficient, uint8 reason) =
|
||||
verifyFunding(
|
||||
VerifyFundingCalculation({
|
||||
provider: provider,
|
||||
sourceChain: chainId(),
|
||||
targetChain: request.targetChain,
|
||||
maxTransactionFeeSource: request.maxTransactionFee,
|
||||
receiverValueSource: request.receiverValue,
|
||||
isDelivery: true
|
||||
})
|
||||
);
|
||||
|
||||
if (!isSufficient) {
|
||||
return (0, false, reason);
|
||||
}
|
||||
|
||||
totalFees = totalFees + requestFee;
|
||||
if (funds < totalFees) {
|
||||
return (0, false, 25); //"Insufficient funds were provided to cover the delivery fees.");
|
||||
}
|
||||
}
|
||||
|
||||
return (totalFees, true, 0);
|
||||
}
|
||||
|
||||
struct VerifyFundingCalculation {
|
||||
IRelayProvider provider;
|
||||
uint16 sourceChain;
|
||||
uint16 targetChain;
|
||||
uint256 maxTransactionFeeSource;
|
||||
uint256 receiverValueSource;
|
||||
bool isDelivery;
|
||||
}
|
||||
|
||||
function verifyFunding(VerifyFundingCalculation memory args)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
uint256 requestFee,
|
||||
uint256 maximumRefund,
|
||||
uint256 receiverValueTarget,
|
||||
bool isSufficient,
|
||||
uint8 reason
|
||||
)
|
||||
{
|
||||
requestFee = args.maxTransactionFeeSource + args.receiverValueSource;
|
||||
receiverValueTarget = convertApplicationBudgetAmount(args.receiverValueSource, args.targetChain, args.provider);
|
||||
uint256 overheadFeeSource = args.isDelivery
|
||||
? args.provider.quoteDeliveryOverhead(args.targetChain)
|
||||
: args.provider.quoteRedeliveryOverhead(args.targetChain);
|
||||
uint256 overheadBudgetTarget =
|
||||
assetConversionHelper(args.sourceChain, overheadFeeSource, args.targetChain, 1, 1, true, args.provider);
|
||||
maximumRefund = args.isDelivery
|
||||
? calculateTargetDeliveryMaximumRefund(args.targetChain, args.maxTransactionFeeSource, args.provider)
|
||||
: calculateTargetRedeliveryMaximumRefund(args.targetChain, args.maxTransactionFeeSource, args.provider);
|
||||
|
||||
//Make sure the maxTransactionFee covers the minimum delivery cost to the targetChain
|
||||
if (args.maxTransactionFeeSource < overheadFeeSource) {
|
||||
isSufficient = false;
|
||||
reason = 26; //Insufficient msg.value to cover minimum delivery costs.";
|
||||
}
|
||||
//Make sure the budget does not exceed the maximum for the provider on that chain; //This added value is totalBudgetTarget
|
||||
else if (
|
||||
args.provider.quoteMaximumBudget(args.targetChain)
|
||||
< (maximumRefund + overheadBudgetTarget + receiverValueTarget)
|
||||
) {
|
||||
isSufficient = false;
|
||||
reason = 27; //"Specified budget exceeds the maximum allowed by the provider";
|
||||
} else {
|
||||
isSufficient = true;
|
||||
reason = 0;
|
||||
}
|
||||
IWormholeRelayer.Send[] memory requests = new IWormholeRelayer.Send[](1);
|
||||
requests[0] = request;
|
||||
container = IWormholeRelayer.MultichainSend({relayProviderAddress: relayProvider, requests: requests});
|
||||
}
|
||||
|
||||
function _executeDelivery(
|
||||
IWormhole wormhole,
|
||||
DeliveryInstruction memory internalInstruction,
|
||||
bytes[] memory encodedVMs,
|
||||
bytes32 deliveryVaaHash,
|
||||
|
@ -410,11 +208,11 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
uint16 sourceChain,
|
||||
uint64 sourceSequence
|
||||
) internal {
|
||||
//REVISE Decide whether we want to remove the DeliveryInstructionContainer from encodedVMs.
|
||||
//REVISE Decide whether we want to remove the DeliveryInstructionsContainer from encodedVMs.
|
||||
|
||||
// lock the contract to prevent reentrancy
|
||||
if (isContractLocked()) {
|
||||
revert ReentrantCall();
|
||||
revert IDelivery.ReentrantCall();
|
||||
}
|
||||
setContractLock(true);
|
||||
setLockedTargetAddress(fromWormholeFormat(internalInstruction.targetAddress));
|
||||
|
@ -422,7 +220,7 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
uint256 preGas = gasleft();
|
||||
|
||||
// call the receiveWormholeMessages endpoint on the target contract
|
||||
(bool success,) = fromWormholeFormat(internalInstruction.targetAddress).call{
|
||||
(bool callToTargetContractSucceeded,) = fromWormholeFormat(internalInstruction.targetAddress).call{
|
||||
gas: internalInstruction.executionParameters.gasLimit,
|
||||
value: internalInstruction.receiverValueTarget
|
||||
}(abi.encodeCall(IWormholeReceiver.receiveWormholeMessages, (encodedVMs, new bytes[](0))));
|
||||
|
@ -438,126 +236,49 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
: (preGas - postGas);
|
||||
|
||||
// refund unused gas budget
|
||||
uint256 weiToRefund = internalInstruction.receiverValueTarget;
|
||||
if (success) {
|
||||
weiToRefund = (internalInstruction.executionParameters.gasLimit - gasUsed)
|
||||
* internalInstruction.maximumRefundTarget / internalInstruction.executionParameters.gasLimit;
|
||||
}
|
||||
uint256 transactionFeeRefundAmount = (internalInstruction.executionParameters.gasLimit - gasUsed)
|
||||
* internalInstruction.maximumRefundTarget / internalInstruction.executionParameters.gasLimit;
|
||||
|
||||
// unlock the contract
|
||||
setContractLock(false);
|
||||
|
||||
//REVISE decide if we want to always emit a VAA, or only emit a msg when forwarding
|
||||
// // emit delivery status message
|
||||
// DeliveryStatus memory status = DeliveryStatus({
|
||||
// payloadID: 2,
|
||||
// batchHash: internalParams.batchVM.hash,
|
||||
// emitterAddress: internalParams.deliveryId.emitterAddress,
|
||||
// sequence: internalParams.deliveryId.sequence,
|
||||
// deliveryCount: uint16(stackTooDeep.attemptedDeliveryCount + 1),
|
||||
// deliverySuccess: success
|
||||
// });
|
||||
// // set the nonce to zero so a batch VAA is not created
|
||||
// sequence =
|
||||
// wormhole.publishMessage{value: wormhole.messageFee()}(0, encodeDeliveryStatus(status), consistencyLevel());
|
||||
ForwardingRequest memory forwardingRequest = getForwardingRequest();
|
||||
ForwardInstruction memory forwardingRequest = getForwardInstruction();
|
||||
DeliveryStatus status;
|
||||
bool forwardIsFunded = false;
|
||||
if (forwardingRequest.isValid) {
|
||||
(, success) = emitForward(weiToRefund, forwardingRequest);
|
||||
if (success) {
|
||||
emit Delivery({
|
||||
recipientContract: fromWormholeFormat(internalInstruction.targetAddress),
|
||||
sourceChain: sourceChain,
|
||||
sequence: sourceSequence,
|
||||
deliveryVaaHash: deliveryVaaHash,
|
||||
status: DeliveryStatus.FORWARD_REQUEST_SUCCESS
|
||||
});
|
||||
} else {
|
||||
bool sent = pay(payable(fromWormholeFormat(internalInstruction.refundAddress)), weiToRefund);
|
||||
if (!sent) {
|
||||
// if refunding fails, pay out full refund to relayer
|
||||
weiToRefund = 0;
|
||||
}
|
||||
emit Delivery({
|
||||
recipientContract: fromWormholeFormat(internalInstruction.targetAddress),
|
||||
sourceChain: sourceChain,
|
||||
sequence: sourceSequence,
|
||||
deliveryVaaHash: deliveryVaaHash,
|
||||
status: DeliveryStatus.FORWARD_REQUEST_FAILURE
|
||||
});
|
||||
}
|
||||
forwardIsFunded = emitForward(transactionFeeRefundAmount, forwardingRequest);
|
||||
status = forwardIsFunded ? DeliveryStatus.FORWARD_REQUEST_SUCCESS : DeliveryStatus.FORWARD_REQUEST_FAILURE;
|
||||
} else {
|
||||
bool sent = pay(payable(fromWormholeFormat(internalInstruction.refundAddress)), weiToRefund);
|
||||
if (!sent) {
|
||||
// if refunding fails, pay out full refund to relayer
|
||||
weiToRefund = 0;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
emit Delivery({
|
||||
recipientContract: fromWormholeFormat(internalInstruction.targetAddress),
|
||||
sourceChain: sourceChain,
|
||||
sequence: sourceSequence,
|
||||
deliveryVaaHash: deliveryVaaHash,
|
||||
status: DeliveryStatus.SUCCESS
|
||||
});
|
||||
} else {
|
||||
emit Delivery({
|
||||
recipientContract: fromWormholeFormat(internalInstruction.targetAddress),
|
||||
sourceChain: sourceChain,
|
||||
sequence: sourceSequence,
|
||||
deliveryVaaHash: deliveryVaaHash,
|
||||
status: DeliveryStatus.RECEIVER_FAILURE
|
||||
});
|
||||
}
|
||||
status = callToTargetContractSucceeded ? DeliveryStatus.SUCCESS : DeliveryStatus.RECEIVER_FAILURE;
|
||||
}
|
||||
|
||||
uint256 receiverValuePaid = (success ? internalInstruction.receiverValueTarget : 0);
|
||||
uint256 wormholeFeePaid = forwardingRequest.isValid ? wormhole.messageFee() : 0;
|
||||
uint256 relayerRefundAmount = msg.value - weiToRefund - receiverValuePaid - wormholeFeePaid;
|
||||
uint256 receiverValueRefundAmount =
|
||||
(callToTargetContractSucceeded ? 0 : internalInstruction.receiverValueTarget);
|
||||
uint256 refundToRefundAddress = receiverValueRefundAmount + (forwardIsFunded ? 0 : transactionFeeRefundAmount);
|
||||
|
||||
bool refundPaidToRefundAddress =
|
||||
pay(payable(fromWormholeFormat(internalInstruction.refundAddress)), refundToRefundAddress);
|
||||
|
||||
emit Delivery({
|
||||
recipientContract: fromWormholeFormat(internalInstruction.targetAddress),
|
||||
sourceChain: sourceChain,
|
||||
sequence: sourceSequence,
|
||||
deliveryVaaHash: deliveryVaaHash,
|
||||
status: status
|
||||
});
|
||||
|
||||
uint256 extraRelayerFunds = (
|
||||
msg.value - internalInstruction.receiverValueTarget - internalInstruction.maximumRefundTarget
|
||||
- wormholeMessageFee()
|
||||
);
|
||||
uint256 relayerRefundAmount = extraRelayerFunds
|
||||
+ (internalInstruction.maximumRefundTarget - transactionFeeRefundAmount)
|
||||
+ (forwardingRequest.isValid ? 0 : wormholeMessageFee())
|
||||
+ (refundPaidToRefundAddress ? 0 : refundToRefundAddress);
|
||||
// refund the rest to relayer
|
||||
pay(relayerRefund, relayerRefundAmount);
|
||||
}
|
||||
|
||||
//REVISE, consider implementing this system into the RelayProvider.
|
||||
// function requestRewardPayout(uint16 rewardChain, bytes32 receiver, uint32 nonce)
|
||||
// public
|
||||
// payable
|
||||
// returns (uint64 sequence)
|
||||
// {
|
||||
// uint256 amount = relayerRewards(msg.sender, rewardChain);
|
||||
|
||||
// require(amount > 0, "no current accrued rewards");
|
||||
|
||||
// resetRelayerRewards(msg.sender, rewardChain);
|
||||
|
||||
// sequence = wormhole().publishMessage{value: msg.value}(
|
||||
// nonce,
|
||||
// encodeRewardPayout(
|
||||
// RewardPayout({
|
||||
// payloadID: 100,
|
||||
// fromChain: chainId(),
|
||||
// chain: rewardChain,
|
||||
// amount: amount,
|
||||
// receiver: receiver
|
||||
// })
|
||||
// ),
|
||||
// 20 //REVISE encode finality
|
||||
// );
|
||||
// }
|
||||
|
||||
// function collectRewards(bytes memory encodedVm) public {
|
||||
// (IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
|
||||
|
||||
// require(valid, reason);
|
||||
// require(verifyRelayerVM(vm), "invalid emitter");
|
||||
|
||||
// RewardPayout memory payout = parseRewardPayout(vm.payload);
|
||||
|
||||
// require(payout.chain == chainId());
|
||||
|
||||
// payable(address(uint160(uint256(payout.receiver)))).transfer(payout.amount);
|
||||
// }
|
||||
|
||||
function verifyRelayerVM(IWormhole.VM memory vm) internal view returns (bool) {
|
||||
return registeredCoreRelayerContract(vm.emitterChainId) == vm.emitterAddress;
|
||||
}
|
||||
|
@ -566,34 +287,34 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
return defaultRelayProvider();
|
||||
}
|
||||
|
||||
function redeliverSingle(TargetRedeliveryByTxHashParamsSingle memory targetParams) public payable {
|
||||
function redeliverSingle(IDelivery.TargetRedeliveryByTxHashParamsSingle memory targetParams) public payable {
|
||||
//cache wormhole
|
||||
IWormhole wormhole = wormhole();
|
||||
updateWormholeMessageFee();
|
||||
|
||||
//validate the redelivery VM
|
||||
(IWormhole.VM memory redeliveryVM, bool valid, string memory reason) =
|
||||
wormhole.parseAndVerifyVM(targetParams.redeliveryVM);
|
||||
if (!valid) {
|
||||
revert InvalidRedeliveryVM(reason);
|
||||
revert IDelivery.InvalidRedeliveryVM(reason);
|
||||
}
|
||||
if (!verifyRelayerVM(redeliveryVM)) {
|
||||
// Redelivery VM has an invalid emitter
|
||||
revert InvalidEmitterInRedeliveryVM();
|
||||
revert IDelivery.InvalidEmitterInRedeliveryVM();
|
||||
}
|
||||
|
||||
RedeliveryByTxHashInstruction memory redeliveryInstruction =
|
||||
decodeRedeliveryByTxHashInstruction(redeliveryVM.payload);
|
||||
RedeliveryByTxHashInstruction memory redeliveryInstruction = decodeRedeliveryInstruction(redeliveryVM.payload);
|
||||
|
||||
//validate the original delivery VM
|
||||
IWormhole.VM memory originalDeliveryVM;
|
||||
(originalDeliveryVM, valid, reason) =
|
||||
wormhole.parseAndVerifyVM(targetParams.sourceEncodedVMs[redeliveryInstruction.deliveryIndex]);
|
||||
if (!valid) {
|
||||
revert InvalidVaa(redeliveryInstruction.deliveryIndex);
|
||||
revert IDelivery.InvalidVaa(redeliveryInstruction.deliveryIndex, reason);
|
||||
}
|
||||
if (!verifyRelayerVM(originalDeliveryVM)) {
|
||||
// Original Delivery VM has a invalid emitter
|
||||
revert InvalidEmitterInOriginalDeliveryVM(redeliveryInstruction.deliveryIndex);
|
||||
revert IDelivery.InvalidEmitterInOriginalDeliveryVM(redeliveryInstruction.deliveryIndex);
|
||||
}
|
||||
|
||||
DeliveryInstruction memory instruction;
|
||||
|
@ -616,7 +337,6 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
}
|
||||
|
||||
_executeDelivery(
|
||||
wormhole,
|
||||
instruction,
|
||||
targetParams.sourceEncodedVMs,
|
||||
originalDeliveryVM.hash,
|
||||
|
@ -635,16 +355,16 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
// The same relay provider must be specified when doing a single VAA redeliver.
|
||||
address providerAddress = fromWormholeFormat(redeliveryInstruction.executionParameters.providerDeliveryAddress);
|
||||
if (providerAddress != fromWormholeFormat(originalInstruction.executionParameters.providerDeliveryAddress)) {
|
||||
revert MismatchingRelayProvidersInRedelivery();
|
||||
revert IDelivery.MismatchingRelayProvidersInRedelivery();
|
||||
}
|
||||
|
||||
// relayer must have covered the necessary funds
|
||||
if (
|
||||
msg.value
|
||||
< redeliveryInstruction.newMaximumRefundTarget + redeliveryInstruction.newReceiverValueTarget
|
||||
+ wormhole().messageFee()
|
||||
+ wormholeMessageFee()
|
||||
) {
|
||||
revert InsufficientRelayerFunds();
|
||||
revert IDelivery.InsufficientRelayerFunds();
|
||||
}
|
||||
|
||||
uint16 whChainId = chainId();
|
||||
|
@ -670,24 +390,25 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
deliveryInstruction.executionParameters = redeliveryInstruction.executionParameters;
|
||||
}
|
||||
|
||||
function deliverSingle(TargetDeliveryParametersSingle memory targetParams) public payable {
|
||||
function deliverSingle(IDelivery.TargetDeliveryParametersSingle memory targetParams) public payable {
|
||||
// cache wormhole instance
|
||||
IWormhole wormhole = wormhole();
|
||||
updateWormholeMessageFee();
|
||||
|
||||
// validate the deliveryIndex
|
||||
(IWormhole.VM memory deliveryVM, bool valid, string memory reason) =
|
||||
wormhole.parseAndVerifyVM(targetParams.encodedVMs[targetParams.deliveryIndex]);
|
||||
if (!valid) {
|
||||
revert InvalidVaa(targetParams.deliveryIndex);
|
||||
revert IDelivery.InvalidVaa(targetParams.deliveryIndex, reason);
|
||||
}
|
||||
if (!verifyRelayerVM(deliveryVM)) {
|
||||
revert InvalidEmitter();
|
||||
revert IDelivery.InvalidEmitter();
|
||||
}
|
||||
|
||||
DeliveryInstructionsContainer memory container = decodeDeliveryInstructionsContainer(deliveryVM.payload);
|
||||
//ensure this is a funded delivery, not a failed forward.
|
||||
if (!container.sufficientlyFunded) {
|
||||
revert SendNotSufficientlyFunded();
|
||||
revert IDelivery.SendNotSufficientlyFunded();
|
||||
}
|
||||
|
||||
// parse the deliveryVM payload into the DeliveryInstructions struct
|
||||
|
@ -695,24 +416,23 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
|
||||
//make sure the specified relayer is the relayer delivering this message
|
||||
if (fromWormholeFormat(deliveryInstruction.executionParameters.providerDeliveryAddress) != msg.sender) {
|
||||
revert UnexpectedRelayer();
|
||||
revert IDelivery.UnexpectedRelayer();
|
||||
}
|
||||
|
||||
//make sure relayer passed in sufficient funds
|
||||
if (
|
||||
msg.value
|
||||
< deliveryInstruction.maximumRefundTarget + deliveryInstruction.receiverValueTarget + wormhole.messageFee()
|
||||
< deliveryInstruction.maximumRefundTarget + deliveryInstruction.receiverValueTarget + wormholeMessageFee()
|
||||
) {
|
||||
revert InsufficientRelayerFunds();
|
||||
revert IDelivery.InsufficientRelayerFunds();
|
||||
}
|
||||
|
||||
//make sure this delivery is intended for this chain
|
||||
if (chainId() != deliveryInstruction.targetChain) {
|
||||
revert TargetChainIsNotThisChain(deliveryInstruction.targetChain);
|
||||
revert IDelivery.TargetChainIsNotThisChain(deliveryInstruction.targetChain);
|
||||
}
|
||||
|
||||
_executeDelivery(
|
||||
wormhole,
|
||||
deliveryInstruction,
|
||||
targetParams.encodedVMs,
|
||||
deliveryVM.hash,
|
||||
|
@ -734,107 +454,6 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
return new bytes(0);
|
||||
}
|
||||
|
||||
function makeRelayerParams(IRelayProvider provider) public pure returns (bytes memory relayerParams) {
|
||||
//current version is just 1,
|
||||
relayerParams = abi.encode(1, toWormholeFormat(address(provider)));
|
||||
}
|
||||
|
||||
function getDeliveryInstructionsContainer(bytes memory encoded)
|
||||
public
|
||||
view
|
||||
returns (DeliveryInstructionsContainer memory container)
|
||||
{
|
||||
container = decodeDeliveryInstructionsContainer(encoded);
|
||||
}
|
||||
|
||||
function getRedeliveryByTxHashInstruction(bytes memory encoded)
|
||||
public
|
||||
view
|
||||
returns (RedeliveryByTxHashInstruction memory instruction)
|
||||
{
|
||||
instruction = decodeRedeliveryByTxHashInstruction(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a targetChain, maxTransactionFee, and a relay provider, this function calculates what the gas limit of the delivery transaction
|
||||
* should be.
|
||||
*/
|
||||
function calculateTargetGasDeliveryAmount(uint16 targetChain, uint256 maxTransactionFee, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (uint32 gasAmount)
|
||||
{
|
||||
gasAmount = calculateTargetGasDeliveryAmountHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteDeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
function calculateTargetDeliveryMaximumRefund(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 maximumRefund) {
|
||||
maximumRefund = calculateTargetDeliveryMaximumRefundHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteDeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a targetChain, maxTransactionFee, and a relay provider, this function calculates what the gas limit of the redelivery transaction
|
||||
* should be.
|
||||
*/
|
||||
function calculateTargetGasRedeliveryAmount(uint16 targetChain, uint256 maxTransactionFee, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (uint32 gasAmount)
|
||||
{
|
||||
gasAmount = calculateTargetGasDeliveryAmountHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteRedeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
function calculateTargetRedeliveryMaximumRefund(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 maximumRefund) {
|
||||
maximumRefund = calculateTargetDeliveryMaximumRefundHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteRedeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
function calculateTargetGasDeliveryAmountHelper(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
uint256 deliveryOverhead,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint32 gasAmount) {
|
||||
if (maxTransactionFee <= deliveryOverhead) {
|
||||
gasAmount = 0;
|
||||
} else {
|
||||
uint256 gas = (maxTransactionFee - deliveryOverhead) / provider.quoteGasPrice(targetChain);
|
||||
if (gas > type(uint32).max) {
|
||||
gasAmount = type(uint32).max;
|
||||
} else {
|
||||
gasAmount = uint32(gas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateTargetDeliveryMaximumRefundHelper(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
uint256 deliveryOverhead,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 maximumRefund) {
|
||||
if (maxTransactionFee >= deliveryOverhead) {
|
||||
uint256 remainder = maxTransactionFee - deliveryOverhead;
|
||||
maximumRefund = assetConversionHelper(chainId(), remainder, targetChain, 1, 1, false, provider);
|
||||
} else {
|
||||
maximumRefund = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function quoteGas(uint16 targetChain, uint32 gasLimit, IRelayProvider provider)
|
||||
public
|
||||
view
|
||||
|
@ -852,33 +471,6 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
provider.quoteRedeliveryOverhead(targetChain) + (gasLimit * provider.quoteGasPrice(targetChain));
|
||||
}
|
||||
|
||||
function assetConversionHelper(
|
||||
uint16 sourceChain,
|
||||
uint256 sourceAmount,
|
||||
uint16 targetChain,
|
||||
uint256 multiplier,
|
||||
uint256 multiplierDenominator,
|
||||
bool roundUp,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 targetAmount) {
|
||||
uint256 srcNativeCurrencyPrice = provider.quoteAssetPrice(sourceChain);
|
||||
if (srcNativeCurrencyPrice == 0) {
|
||||
revert RelayProviderDoesNotSupportTargetChain();
|
||||
}
|
||||
|
||||
uint256 dstNativeCurrencyPrice = provider.quoteAssetPrice(targetChain);
|
||||
if (dstNativeCurrencyPrice == 0) {
|
||||
revert RelayProviderDoesNotSupportTargetChain();
|
||||
}
|
||||
uint256 numerator = sourceAmount * srcNativeCurrencyPrice * multiplier;
|
||||
uint256 denominator = dstNativeCurrencyPrice * multiplierDenominator;
|
||||
if (roundUp) {
|
||||
targetAmount = (numerator + denominator - 1) / denominator;
|
||||
} else {
|
||||
targetAmount = numerator / denominator;
|
||||
}
|
||||
}
|
||||
|
||||
//If the integrator pays at least nativeQuote, they should receive at least targetAmount as their application budget
|
||||
function quoteReceiverValue(uint16 targetChain, uint256 targetAmount, IRelayProvider provider)
|
||||
public
|
||||
|
@ -891,81 +483,6 @@ contract CoreRelayer is CoreRelayerGovernance {
|
|||
);
|
||||
}
|
||||
|
||||
//This should invert quoteApplicationBudgetAmount, I.E when a user pays the sourceAmount, they receive at least the value of targetAmount they requested from
|
||||
//quoteReceiverValue.
|
||||
function convertApplicationBudgetAmount(uint256 sourceAmount, uint16 targetChain, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (uint256 targetAmount)
|
||||
{
|
||||
(uint16 buffer, uint16 denominator) = provider.getAssetConversionBuffer(targetChain);
|
||||
|
||||
targetAmount = assetConversionHelper(
|
||||
chainId(), sourceAmount, targetChain, denominator, uint256(0) + denominator + buffer, false, provider
|
||||
);
|
||||
}
|
||||
|
||||
function convertToEncodedRedeliveryByTxHashInstruction(
|
||||
ResendByTx memory request,
|
||||
uint256 receiverValueTarget,
|
||||
uint256 maximumRefund,
|
||||
uint32 gasLimit,
|
||||
IRelayProvider provider
|
||||
) internal view returns (bytes memory encoded) {
|
||||
encoded = abi.encodePacked(
|
||||
uint8(2), //version payload number
|
||||
uint16(request.sourceChain),
|
||||
bytes32(request.sourceTxHash),
|
||||
uint32(request.sourceNonce),
|
||||
uint16(request.targetChain),
|
||||
uint8(request.deliveryIndex),
|
||||
uint8(request.multisendIndex),
|
||||
maximumRefund,
|
||||
receiverValueTarget,
|
||||
uint8(1), //version for ExecutionParameters
|
||||
gasLimit,
|
||||
provider.getDeliveryAddress(request.targetChain)
|
||||
);
|
||||
}
|
||||
|
||||
function convertToEncodedDeliveryInstructions(MultichainSend memory container, bool isFunded)
|
||||
internal
|
||||
view
|
||||
returns (bytes memory encoded)
|
||||
{
|
||||
encoded = abi.encodePacked(
|
||||
uint8(1), //version payload number
|
||||
uint8(isFunded ? 1 : 0), // sufficiently funded
|
||||
uint8(container.requests.length) //number of requests in the array
|
||||
);
|
||||
|
||||
// TODO: this probably results in a quadratic algorithm. Further optimization can be done here.
|
||||
// Append all the messages to the array.
|
||||
for (uint256 i = 0; i < container.requests.length; i++) {
|
||||
encoded = appendDeliveryInstruction(
|
||||
encoded, container.requests[i], IRelayProvider(container.relayProviderAddress)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function appendDeliveryInstruction(bytes memory encoded, Send memory request, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (bytes memory newEncoded)
|
||||
{
|
||||
newEncoded = abi.encodePacked(
|
||||
encoded,
|
||||
request.targetChain,
|
||||
request.targetAddress,
|
||||
request.refundAddress,
|
||||
calculateTargetDeliveryMaximumRefund(request.targetChain, request.maxTransactionFee, provider),
|
||||
convertApplicationBudgetAmount(request.receiverValue, request.targetChain, provider),
|
||||
uint8(1), //version for ExecutionParameters
|
||||
calculateTargetGasDeliveryAmount(request.targetChain, request.maxTransactionFee, provider),
|
||||
provider.getDeliveryAddress(request.targetChain)
|
||||
);
|
||||
}
|
||||
|
||||
function pay(address payable receiver, uint256 amount) internal returns (bool success) {
|
||||
if (amount > 0) {
|
||||
(success,) = receiver.call{value: amount}("");
|
||||
|
|
|
@ -33,6 +33,10 @@ contract CoreRelayerGetters is CoreRelayerState {
|
|||
return IWormhole(_state.provider.wormhole);
|
||||
}
|
||||
|
||||
function wormholeMessageFee() public view returns (uint256) {
|
||||
return _state.provider.wormholeMessageFee;
|
||||
}
|
||||
|
||||
function chainId() public view returns (uint16) {
|
||||
return _state.provider.chainId;
|
||||
}
|
||||
|
@ -53,8 +57,8 @@ contract CoreRelayerGetters is CoreRelayerState {
|
|||
return IRelayProvider(_state.defaultRelayProvider);
|
||||
}
|
||||
|
||||
function getForwardingRequest() internal view returns (CoreRelayerStructs.ForwardingRequest memory) {
|
||||
return _state.forwardingRequest;
|
||||
function getForwardInstruction() internal view returns (CoreRelayerStructs.ForwardInstruction memory) {
|
||||
return _state.forwardInstruction;
|
||||
}
|
||||
|
||||
function isContractLocked() internal view returns (bool) {
|
||||
|
|
|
@ -7,22 +7,302 @@ import "../libraries/external/BytesLib.sol";
|
|||
|
||||
import "./CoreRelayerGetters.sol";
|
||||
import "./CoreRelayerStructs.sol";
|
||||
import "../interfaces/IWormholeRelayer.sol";
|
||||
|
||||
contract CoreRelayerMessages is CoreRelayerStructs, CoreRelayerGetters {
|
||||
using BytesLib for bytes;
|
||||
|
||||
error InvalidPayloadId(uint8 payloadId);
|
||||
error InvalidDeliveryInstructionsPayload(uint256 length);
|
||||
error InvalidSendsPayload(uint256 length);
|
||||
|
||||
function decodeRedeliveryByTxHashInstruction(bytes memory encoded)
|
||||
function getTotalFeeMultichainSend(IWormholeRelayer.MultichainSend memory sendContainer)
|
||||
internal
|
||||
view
|
||||
returns (uint256 totalFee)
|
||||
{
|
||||
totalFee = wormholeMessageFee();
|
||||
uint256 length = sendContainer.requests.length;
|
||||
for (uint256 i = 0; i < length; i++) {
|
||||
IWormholeRelayer.Send memory request = sendContainer.requests[i];
|
||||
totalFee += request.maxTransactionFee + request.receiverValue;
|
||||
}
|
||||
}
|
||||
|
||||
function convertMultichainSendToDeliveryInstructionsContainer(IWormholeRelayer.MultichainSend memory sendContainer)
|
||||
internal
|
||||
view
|
||||
returns (DeliveryInstructionsContainer memory instructionsContainer)
|
||||
{
|
||||
instructionsContainer.payloadId = 1;
|
||||
IRelayProvider relayProvider = IRelayProvider(sendContainer.relayProviderAddress);
|
||||
uint256 length = sendContainer.requests.length;
|
||||
instructionsContainer.instructions = new DeliveryInstruction[](length);
|
||||
for (uint256 i = 0; i < length; i++) {
|
||||
instructionsContainer.instructions[i] =
|
||||
convertSendToDeliveryInstruction(sendContainer.requests[i], relayProvider);
|
||||
}
|
||||
}
|
||||
|
||||
function convertSendToDeliveryInstruction(IWormholeRelayer.Send memory send, IRelayProvider relayProvider)
|
||||
internal
|
||||
view
|
||||
returns (DeliveryInstruction memory instruction)
|
||||
{
|
||||
instruction.targetChain = send.targetChain;
|
||||
instruction.targetAddress = send.targetAddress;
|
||||
instruction.refundAddress = send.refundAddress;
|
||||
instruction.maximumRefundTarget =
|
||||
calculateTargetDeliveryMaximumRefund(send.targetChain, send.maxTransactionFee, relayProvider);
|
||||
instruction.receiverValueTarget =
|
||||
convertReceiverValueAmount(send.receiverValue, send.targetChain, relayProvider);
|
||||
instruction.executionParameters = ExecutionParameters({
|
||||
version: 1,
|
||||
gasLimit: calculateTargetGasDeliveryAmount(send.targetChain, send.maxTransactionFee, relayProvider),
|
||||
providerDeliveryAddress: relayProvider.getDeliveryAddress(send.targetChain)
|
||||
});
|
||||
}
|
||||
|
||||
function checkInstructions(DeliveryInstructionsContainer memory container, IRelayProvider relayProvider)
|
||||
internal
|
||||
view
|
||||
{
|
||||
uint256 length = container.instructions.length;
|
||||
for (uint8 i = 0; i < length; i++) {
|
||||
DeliveryInstruction memory instruction = container.instructions[i];
|
||||
if (instruction.executionParameters.gasLimit == 0) {
|
||||
revert IWormholeRelayer.MaxTransactionFeeNotEnough(i);
|
||||
}
|
||||
if (
|
||||
instruction.maximumRefundTarget + instruction.receiverValueTarget + wormholeMessageFee()
|
||||
> relayProvider.quoteMaximumBudget(instruction.targetChain)
|
||||
) {
|
||||
revert IWormholeRelayer.FundsTooMuch(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkRedeliveryInstruction(RedeliveryByTxHashInstruction memory instruction, IRelayProvider relayProvider)
|
||||
internal
|
||||
view
|
||||
{
|
||||
if (instruction.executionParameters.gasLimit == 0) {
|
||||
revert IWormholeRelayer.MaxTransactionFeeNotEnough(0);
|
||||
}
|
||||
if (
|
||||
instruction.newMaximumRefundTarget + instruction.newReceiverValueTarget + wormholeMessageFee()
|
||||
> relayProvider.quoteMaximumBudget(instruction.targetChain)
|
||||
) {
|
||||
revert IWormholeRelayer.FundsTooMuch(0);
|
||||
}
|
||||
}
|
||||
|
||||
function convertResendToRedeliveryInstruction(IWormholeRelayer.ResendByTx memory send, IRelayProvider relayProvider)
|
||||
internal
|
||||
view
|
||||
returns (RedeliveryByTxHashInstruction memory instruction)
|
||||
{
|
||||
instruction.payloadId = 2;
|
||||
instruction.sourceChain = send.sourceChain;
|
||||
instruction.sourceTxHash = send.sourceTxHash;
|
||||
instruction.sourceNonce = send.sourceNonce;
|
||||
instruction.targetChain = send.targetChain;
|
||||
instruction.deliveryIndex = send.deliveryIndex;
|
||||
instruction.multisendIndex = send.multisendIndex;
|
||||
instruction.newMaximumRefundTarget =
|
||||
calculateTargetRedeliveryMaximumRefund(send.targetChain, send.newMaxTransactionFee, relayProvider);
|
||||
instruction.newReceiverValueTarget =
|
||||
convertReceiverValueAmount(send.newReceiverValue, send.targetChain, relayProvider);
|
||||
instruction.executionParameters = ExecutionParameters({
|
||||
version: 1,
|
||||
gasLimit: calculateTargetGasRedeliveryAmount(send.targetChain, send.newMaxTransactionFee, relayProvider),
|
||||
providerDeliveryAddress: relayProvider.getDeliveryAddress(send.targetChain)
|
||||
});
|
||||
}
|
||||
|
||||
function encodeRedeliveryInstruction(RedeliveryByTxHashInstruction memory instruction)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory encoded)
|
||||
{
|
||||
encoded = abi.encodePacked(
|
||||
instruction.payloadId,
|
||||
instruction.sourceChain,
|
||||
instruction.sourceTxHash,
|
||||
instruction.sourceNonce,
|
||||
instruction.targetChain,
|
||||
instruction.deliveryIndex,
|
||||
instruction.multisendIndex,
|
||||
instruction.newMaximumRefundTarget,
|
||||
instruction.newReceiverValueTarget,
|
||||
instruction.executionParameters.version,
|
||||
instruction.executionParameters.gasLimit,
|
||||
instruction.executionParameters.providerDeliveryAddress
|
||||
);
|
||||
}
|
||||
|
||||
function encodeDeliveryInstructionsContainer(DeliveryInstructionsContainer memory container)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory encoded)
|
||||
{
|
||||
encoded = abi.encodePacked(
|
||||
container.payloadId, uint8(container.sufficientlyFunded ? 1 : 0), uint8(container.instructions.length)
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < container.instructions.length; i++) {
|
||||
encoded = abi.encodePacked(encoded, encodeDeliveryInstruction(container.instructions[i]));
|
||||
}
|
||||
}
|
||||
|
||||
function encodeDeliveryInstruction(DeliveryInstruction memory instruction)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory encoded)
|
||||
{
|
||||
encoded = abi.encodePacked(
|
||||
instruction.targetChain,
|
||||
instruction.targetAddress,
|
||||
instruction.refundAddress,
|
||||
instruction.maximumRefundTarget,
|
||||
instruction.receiverValueTarget,
|
||||
instruction.executionParameters.version,
|
||||
instruction.executionParameters.gasLimit,
|
||||
instruction.executionParameters.providerDeliveryAddress
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a targetChain, maxTransactionFee, and a relay provider, this function calculates what the gas limit of the delivery transaction
|
||||
* should be.
|
||||
*/
|
||||
function calculateTargetGasDeliveryAmount(uint16 targetChain, uint256 maxTransactionFee, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (uint32 gasAmount)
|
||||
{
|
||||
gasAmount = calculateTargetGasDeliveryAmountHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteDeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
function calculateTargetDeliveryMaximumRefund(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 maximumRefund) {
|
||||
maximumRefund = calculateTargetDeliveryMaximumRefundHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteDeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a targetChain, maxTransactionFee, and a relay provider, this function calculates what the gas limit of the redelivery transaction
|
||||
* should be.
|
||||
*/
|
||||
function calculateTargetGasRedeliveryAmount(uint16 targetChain, uint256 maxTransactionFee, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (uint32 gasAmount)
|
||||
{
|
||||
gasAmount = calculateTargetGasDeliveryAmountHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteRedeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
function calculateTargetRedeliveryMaximumRefund(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 maximumRefund) {
|
||||
maximumRefund = calculateTargetDeliveryMaximumRefundHelper(
|
||||
targetChain, maxTransactionFee, provider.quoteRedeliveryOverhead(targetChain), provider
|
||||
);
|
||||
}
|
||||
|
||||
function calculateTargetGasDeliveryAmountHelper(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
uint256 deliveryOverhead,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint32 gasAmount) {
|
||||
if (maxTransactionFee <= deliveryOverhead) {
|
||||
gasAmount = 0;
|
||||
} else {
|
||||
uint256 gas = (maxTransactionFee - deliveryOverhead) / provider.quoteGasPrice(targetChain);
|
||||
if (gas > type(uint32).max) {
|
||||
gasAmount = type(uint32).max;
|
||||
} else {
|
||||
gasAmount = uint32(gas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateTargetDeliveryMaximumRefundHelper(
|
||||
uint16 targetChain,
|
||||
uint256 maxTransactionFee,
|
||||
uint256 deliveryOverhead,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 maximumRefund) {
|
||||
if (maxTransactionFee >= deliveryOverhead) {
|
||||
uint256 remainder = maxTransactionFee - deliveryOverhead;
|
||||
maximumRefund = assetConversionHelper(chainId(), remainder, targetChain, 1, 1, false, provider);
|
||||
} else {
|
||||
maximumRefund = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function assetConversionHelper(
|
||||
uint16 sourceChain,
|
||||
uint256 sourceAmount,
|
||||
uint16 targetChain,
|
||||
uint256 multiplier,
|
||||
uint256 multiplierDenominator,
|
||||
bool roundUp,
|
||||
IRelayProvider provider
|
||||
) internal view returns (uint256 targetAmount) {
|
||||
uint256 srcNativeCurrencyPrice = provider.quoteAssetPrice(sourceChain);
|
||||
if (srcNativeCurrencyPrice == 0) {
|
||||
revert IWormholeRelayer.RelayProviderDoesNotSupportTargetChain();
|
||||
}
|
||||
|
||||
uint256 dstNativeCurrencyPrice = provider.quoteAssetPrice(targetChain);
|
||||
if (dstNativeCurrencyPrice == 0) {
|
||||
revert IWormholeRelayer.RelayProviderDoesNotSupportTargetChain();
|
||||
}
|
||||
uint256 numerator = sourceAmount * srcNativeCurrencyPrice * multiplier;
|
||||
uint256 denominator = dstNativeCurrencyPrice * multiplierDenominator;
|
||||
if (roundUp) {
|
||||
targetAmount = (numerator + denominator - 1) / denominator;
|
||||
} else {
|
||||
targetAmount = numerator / denominator;
|
||||
}
|
||||
}
|
||||
|
||||
//This should invert quoteApplicationBudgetAmount, I.E when a user pays the sourceAmount, they receive at least the value of targetAmount they requested from
|
||||
//quoteReceiverValue.
|
||||
function convertReceiverValueAmount(uint256 sourceAmount, uint16 targetChain, IRelayProvider provider)
|
||||
internal
|
||||
view
|
||||
returns (uint256 targetAmount)
|
||||
{
|
||||
(uint16 buffer, uint16 denominator) = provider.getAssetConversionBuffer(targetChain);
|
||||
|
||||
targetAmount = assetConversionHelper(
|
||||
chainId(), sourceAmount, targetChain, denominator, uint256(0) + denominator + buffer, false, provider
|
||||
);
|
||||
}
|
||||
|
||||
function decodeRedeliveryInstruction(bytes memory encoded)
|
||||
public
|
||||
pure
|
||||
returns (RedeliveryByTxHashInstruction memory instruction)
|
||||
{
|
||||
uint256 index = 0;
|
||||
|
||||
instruction.payloadId = encoded.toUint8(index);
|
||||
if (instruction.payloadId != 2) {
|
||||
revert InvalidPayloadId(instruction.payloadId);
|
||||
}
|
||||
index += 1;
|
||||
|
||||
instruction.sourceChain = encoded.toUint16(index);
|
||||
|
@ -60,7 +340,7 @@ contract CoreRelayerMessages is CoreRelayerStructs, CoreRelayerGetters {
|
|||
}
|
||||
|
||||
function decodeDeliveryInstructionsContainer(bytes memory encoded)
|
||||
internal
|
||||
public
|
||||
pure
|
||||
returns (DeliveryInstructionsContainer memory)
|
||||
{
|
||||
|
@ -121,82 +401,4 @@ contract CoreRelayerMessages is CoreRelayerStructs, CoreRelayerGetters {
|
|||
instructions: instructionArray
|
||||
});
|
||||
}
|
||||
|
||||
function encodeMultichainSend(MultichainSend memory container) internal pure returns (bytes memory encoded) {
|
||||
encoded = abi.encodePacked(
|
||||
uint8(1), //version payload number
|
||||
address(container.relayProviderAddress),
|
||||
uint8(container.requests.length) //number of requests in the array
|
||||
);
|
||||
|
||||
//Append all the messages to the array.
|
||||
for (uint256 i = 0; i < container.requests.length; i++) {
|
||||
Send memory request = container.requests[i];
|
||||
|
||||
encoded = abi.encodePacked(
|
||||
encoded,
|
||||
request.targetChain,
|
||||
request.targetAddress,
|
||||
request.refundAddress,
|
||||
request.maxTransactionFee,
|
||||
request.receiverValue,
|
||||
uint8(request.relayParameters.length),
|
||||
request.relayParameters
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeMultichainSend(bytes memory encoded) internal pure returns (MultichainSend memory) {
|
||||
uint256 index = 0;
|
||||
|
||||
uint8 payloadId = encoded.toUint8(index);
|
||||
if (payloadId != 1) {
|
||||
revert InvalidPayloadId(payloadId);
|
||||
}
|
||||
index += 1;
|
||||
address relayProviderAddress = encoded.toAddress(index);
|
||||
index += 20;
|
||||
uint8 arrayLen = encoded.toUint8(index);
|
||||
index += 1;
|
||||
|
||||
Send[] memory requestArray = new Send[](arrayLen);
|
||||
|
||||
for (uint8 i = 0; i < arrayLen; i++) {
|
||||
Send memory request;
|
||||
|
||||
// target chain of the delivery request
|
||||
request.targetChain = encoded.toUint16(index);
|
||||
index += 2;
|
||||
|
||||
// target contract address
|
||||
request.targetAddress = encoded.toBytes32(index);
|
||||
index += 32;
|
||||
|
||||
// address to send the refund to
|
||||
request.refundAddress = encoded.toBytes32(index);
|
||||
index += 32;
|
||||
|
||||
request.maxTransactionFee = encoded.toUint256(index);
|
||||
index += 32;
|
||||
|
||||
request.receiverValue = encoded.toUint256(index);
|
||||
index += 32;
|
||||
|
||||
uint8 relayParametersLength = encoded.toUint8(index);
|
||||
|
||||
index += 1;
|
||||
|
||||
request.relayParameters = encoded.slice(index, relayParametersLength);
|
||||
|
||||
index += relayParametersLength;
|
||||
|
||||
requestArray[i] = request;
|
||||
}
|
||||
|
||||
if (index != encoded.length) {
|
||||
revert InvalidSendsPayload(encoded.length);
|
||||
}
|
||||
|
||||
return MultichainSend({relayProviderAddress: relayProviderAddress, requests: requestArray});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ pragma solidity ^0.8.0;
|
|||
import "./CoreRelayerState.sol";
|
||||
import "@openzeppelin/contracts/utils/Context.sol";
|
||||
import "./CoreRelayerStructs.sol";
|
||||
import {IWormhole} from "../interfaces/IWormhole.sol";
|
||||
|
||||
contract CoreRelayerSetters is CoreRelayerState, Context {
|
||||
error InvalidEvmChainId();
|
||||
|
@ -34,6 +35,10 @@ contract CoreRelayerSetters is CoreRelayerState, Context {
|
|||
_state.provider.wormhole = payable(wh);
|
||||
}
|
||||
|
||||
function updateWormholeMessageFee() internal {
|
||||
_state.provider.wormholeMessageFee = IWormhole(_state.provider.wormhole).messageFee();
|
||||
}
|
||||
|
||||
function setRelayProvider(address defaultRelayProvider) internal {
|
||||
_state.defaultRelayProvider = defaultRelayProvider;
|
||||
}
|
||||
|
@ -42,12 +47,12 @@ contract CoreRelayerSetters is CoreRelayerState, Context {
|
|||
_state.registeredCoreRelayerContract[chainId] = relayerAddress;
|
||||
}
|
||||
|
||||
function setForwardingRequest(CoreRelayerStructs.ForwardingRequest memory request) internal {
|
||||
_state.forwardingRequest = request;
|
||||
function setForwardInstruction(CoreRelayerStructs.ForwardInstruction memory request) internal {
|
||||
_state.forwardInstruction = request;
|
||||
}
|
||||
|
||||
function clearForwardingRequest() internal {
|
||||
delete _state.forwardingRequest; //TODO is this the best way to accomplish this?
|
||||
function clearForwardInstruction() internal {
|
||||
delete _state.forwardInstruction;
|
||||
}
|
||||
|
||||
function setContractLock(bool status) internal {
|
||||
|
|
|
@ -43,8 +43,6 @@ contract CoreRelayerSetup is CoreRelayerSetters, ERC1967Upgrade {
|
|||
setGovernanceContract(governanceContract);
|
||||
setEvmChainId(evmChainId);
|
||||
|
||||
//setRegisteredCoreRelayerContract(chainId, bytes32(uint256(uint160(address(this)))));
|
||||
|
||||
_upgradeTo(implementation);
|
||||
|
||||
// call initialize function of the new implementation
|
||||
|
|
|
@ -9,6 +9,7 @@ contract CoreRelayerStorage {
|
|||
struct Provider {
|
||||
uint16 chainId;
|
||||
address payable wormhole;
|
||||
uint256 wormholeMessageFee;
|
||||
uint16 governanceChainId;
|
||||
bytes32 governanceContract;
|
||||
}
|
||||
|
@ -26,7 +27,7 @@ contract CoreRelayerStorage {
|
|||
// address of the default relay provider on this chain
|
||||
address defaultRelayProvider;
|
||||
// Request which will be forwarded from the current delivery.
|
||||
CoreRelayerStructs.ForwardingRequest forwardingRequest;
|
||||
CoreRelayerStructs.ForwardInstruction forwardInstruction;
|
||||
// mapping of initialized implementations
|
||||
mapping(address => bool) initializedImplementations;
|
||||
// mapping of relayer contracts on other chains
|
||||
|
|
|
@ -3,74 +3,9 @@
|
|||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../interfaces/IWormhole.sol";
|
||||
import "../interfaces/IWormholeRelayer.sol";
|
||||
|
||||
abstract contract CoreRelayerStructs {
|
||||
//This first group of structs are external facing API objects,
|
||||
//which should be considered untrusted and unmodifiable
|
||||
|
||||
struct MultichainSend {
|
||||
address relayProviderAddress;
|
||||
Send[] requests;
|
||||
}
|
||||
|
||||
// struct TargetDeliveryParameters {
|
||||
// // encoded batchVM to be delivered on the target chain
|
||||
// bytes encodedVM;
|
||||
// // Index of the delivery VM in a batch
|
||||
// uint8 deliveryIndex;
|
||||
// uint8 multisendIndex;
|
||||
// //uint32 targetCallGasOverride;
|
||||
// }
|
||||
|
||||
struct TargetDeliveryParametersSingle {
|
||||
// encoded batchVM to be delivered on the target chain
|
||||
bytes[] encodedVMs;
|
||||
// Index of the delivery VM in a batch
|
||||
uint8 deliveryIndex;
|
||||
// Index of the target chain inside the delivery VM
|
||||
uint8 multisendIndex;
|
||||
// relayer refund address
|
||||
address payable relayerRefundAddress;
|
||||
}
|
||||
// Optional gasOverride which can be supplied by the relayer
|
||||
// uint32 targetCallGasOverride;
|
||||
|
||||
struct TargetRedeliveryByTxHashParamsSingle {
|
||||
bytes redeliveryVM;
|
||||
bytes[] sourceEncodedVMs;
|
||||
address payable relayerRefundAddress;
|
||||
}
|
||||
|
||||
struct Send {
|
||||
uint16 targetChain;
|
||||
bytes32 targetAddress;
|
||||
bytes32 refundAddress;
|
||||
uint256 maxTransactionFee;
|
||||
uint256 receiverValue;
|
||||
bytes relayParameters;
|
||||
}
|
||||
|
||||
struct ResendByTx {
|
||||
uint16 sourceChain;
|
||||
bytes32 sourceTxHash;
|
||||
uint32 sourceNonce;
|
||||
uint16 targetChain;
|
||||
uint8 deliveryIndex;
|
||||
uint8 multisendIndex;
|
||||
uint256 newMaxTransactionFee;
|
||||
uint256 newReceiverValue;
|
||||
bytes newRelayParameters;
|
||||
}
|
||||
|
||||
struct RelayParameters {
|
||||
uint8 version; //1
|
||||
bytes32 providerAddressOverride;
|
||||
}
|
||||
|
||||
//Below this are internal structs
|
||||
|
||||
//Wire Types
|
||||
struct DeliveryInstructionsContainer {
|
||||
uint8 payloadId; //1
|
||||
bool sufficientlyFunded;
|
||||
|
@ -83,7 +18,7 @@ abstract contract CoreRelayerStructs {
|
|||
bytes32 refundAddress;
|
||||
uint256 maximumRefundTarget;
|
||||
uint256 receiverValueTarget;
|
||||
ExecutionParameters executionParameters; //Has the gas limit to execute with
|
||||
ExecutionParameters executionParameters;
|
||||
}
|
||||
|
||||
struct ExecutionParameters {
|
||||
|
@ -105,23 +40,13 @@ abstract contract CoreRelayerStructs {
|
|||
ExecutionParameters executionParameters;
|
||||
}
|
||||
|
||||
//End Wire Types
|
||||
|
||||
//Internal usage structs
|
||||
|
||||
struct AllowedEmitterSequence {
|
||||
// wormhole emitter address
|
||||
bytes32 emitterAddress;
|
||||
// wormhole message sequence
|
||||
uint64 sequence;
|
||||
}
|
||||
|
||||
struct ForwardingRequest {
|
||||
bytes deliveryRequestsContainer;
|
||||
uint16 rolloverChain;
|
||||
struct ForwardInstruction {
|
||||
DeliveryInstructionsContainer container;
|
||||
uint32 nonce;
|
||||
address sender;
|
||||
uint256 msgValue;
|
||||
uint256 totalFee;
|
||||
address relayProvider;
|
||||
bool isValid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,10 @@ interface IDelivery {
|
|||
error InvalidEmitterInRedeliveryVM();
|
||||
error MismatchingRelayProvidersInRedelivery(); // The same relay provider must be specified when doing a single VAA redeliver
|
||||
error UnexpectedRelayer(); // msg.sender must be the provider
|
||||
error InvalidVaa(uint8 index);
|
||||
error InvalidVaa(uint8 index, string reason);
|
||||
error InvalidEmitter();
|
||||
error SendNotSufficientlyFunded(); // This delivery request was not sufficiently funded, and must request redelivery
|
||||
error InsufficientRelayerFunds(); // The relayer didn't pass sufficient funds (msg.value does not cover the necessary budget fees)
|
||||
error TargetChainIsNotThisChain(uint16 targetChainId);
|
||||
error ReentrantCall(); // A delivery cannot occur during another delivery
|
||||
}
|
||||
|
|
|
@ -263,13 +263,13 @@ interface IWormholeRelayer {
|
|||
* and let NEEDED_VALUE = (one wormhole message fee) + Sum_(i=0 -> requests.requests.length - 1) [requests.requests[i].maxTransactionFee + requests.requests[i].receiverValue].
|
||||
* The multichainForward will succeed if LEFTOVER_VALUE >= NEEDED_VALUE
|
||||
*
|
||||
* note: If LEFTOVER_VALUE > NEEDED_VALUE, then the maxTransactionFee of the first request in the array of sends will be incremented by 'LEFTOVER_VALUE - NEEDED_VALUE'
|
||||
*
|
||||
* @param requests The MultichainSend struct, containing the array of Send requests, as well as the desired relayProviderAddress
|
||||
* @param rolloverChain If LEFTOVER_VALUE > NEEDED_VALUE, then the maxTransactionFee of one of the requests in the array of sends will be incremented by 'LEFTOVER_VALUE - NEEDED_VALUE'
|
||||
* Specifically, the 'send' that will have it's maxTransactionFee incremented is the first send in the 'requests.requests' array that has targetChain equal to 'rolloverChain'
|
||||
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction that have nonce 'nonce'
|
||||
*
|
||||
*/
|
||||
function multichainForward(MultichainSend memory requests, uint16 rolloverChain, uint32 nonce) external payable;
|
||||
function multichainForward(MultichainSend memory requests, uint32 nonce) external payable;
|
||||
|
||||
/**
|
||||
* @notice quoteGas tells you how much maxTransactionFee (denominated in current (source) chain currency) must be in order to fund a call to
|
||||
|
@ -354,15 +354,13 @@ interface IWormholeRelayer {
|
|||
*/
|
||||
function getDefaultRelayParams() external pure returns (bytes memory relayParams);
|
||||
|
||||
error FundsTooMuch(); // (maxTransactionFee, converted to target chain currency) + (receiverValue, converted to target chain currency) is greater than what your chosen relay provider allows
|
||||
error MaxTransactionFeeNotEnough(); // maxTransactionFee is less than the minimum needed by your chosen relay provider
|
||||
error FundsTooMuch(uint8 multisendIndex); // (maxTransactionFee, converted to target chain currency) + (receiverValue, converted to target chain currency) is greater than what your chosen relay provider allows
|
||||
error MaxTransactionFeeNotEnough(uint8 multisendIndex); // maxTransactionFee is less than the minimum needed by your chosen relay provider
|
||||
error MsgValueTooLow(); // msg.value is too low
|
||||
// Specifically, (msg.value) + (any leftover funds if this is a forward) is less than (maxTransactionFee + receiverValue), summed over all of your requests if this is a multichainSend/multichainForward
|
||||
error NonceIsZero(); // Nonce cannot be 0
|
||||
error NoDeliveryInProcess(); // Forwards can only be requested within execution of 'receiveWormholeMessages', or when a delivery is in progress
|
||||
error NoDeliveryInProgress(); // Forwards can only be requested within execution of 'receiveWormholeMessages', or when a delivery is in progress
|
||||
error MultipleForwardsRequested(); // Only one forward can be requested in a transaction
|
||||
error ForwardRequestFromWrongAddress(); // A forward was requested from an address that is not the 'targetAddress' of the original delivery
|
||||
error RelayProviderDoesNotSupportTargetChain(); // Your relay provider does not support the target chain you specified
|
||||
error RolloverChainNotIncluded(); // None of the Send structs in your multiForward are for the target chain 'rolloverChain'
|
||||
error ChainNotFoundInSends(uint16 chainId); // This should never happen. Post a Github Issue if this occurs
|
||||
error ReentrantCall(); // A delivery cannot occur during another delivery
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ contract MockRelayerIntegration is IWormholeReceiver {
|
|||
relayProviderAddress: relayer.getDefaultRelayProvider()
|
||||
});
|
||||
|
||||
relayer.multichainForward(container, sendRequests[0].targetChain, parsed.nonce);
|
||||
relayer.multichainForward(container, parsed.nonce);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import {RelayProviderProxy} from "../contracts/relayProvider/RelayProviderProxy.
|
|||
import {RelayProviderMessages} from "../contracts/relayProvider/RelayProviderMessages.sol";
|
||||
import {RelayProviderStructs} from "../contracts/relayProvider/RelayProviderStructs.sol";
|
||||
import {IWormholeRelayer} from "../contracts/interfaces/IWormholeRelayer.sol";
|
||||
import {IDelivery} from "../contracts/interfaces/IDelivery.sol";
|
||||
import {CoreRelayer} from "../contracts/coreRelayer/CoreRelayer.sol";
|
||||
import {CoreRelayerStructs} from "../contracts/coreRelayer/CoreRelayerStructs.sol";
|
||||
import {CoreRelayerSetup} from "../contracts/coreRelayer/CoreRelayerSetup.sol";
|
||||
|
@ -404,6 +405,9 @@ contract TestCoreRelayer is Test {
|
|||
uint256 relayerProfit = uint256(feeParams.sourceNativePrice)
|
||||
* (setup.source.rewardAddress.balance - rewardAddressBalance)
|
||||
- feeParams.targetNativePrice * (relayerBalance - setup.target.relayer.balance);
|
||||
console.log(USDcost);
|
||||
console.log(relayerProfit);
|
||||
console.log((USDcost - relayerProfit));
|
||||
assertTrue(USDcost == relayerProfit, "We paid the exact amount");
|
||||
}
|
||||
|
||||
|
@ -774,8 +778,8 @@ contract TestCoreRelayer is Test {
|
|||
IWormhole.VM parsed;
|
||||
uint256 budget;
|
||||
IWormholeRelayer.ResendByTx redeliveryRequest;
|
||||
CoreRelayer.TargetDeliveryParametersSingle originalDelivery;
|
||||
CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle package;
|
||||
IDelivery.TargetDeliveryParametersSingle originalDelivery;
|
||||
IDelivery.TargetRedeliveryByTxHashParamsSingle package;
|
||||
CoreRelayer.RedeliveryByTxHashInstruction instruction;
|
||||
}
|
||||
|
||||
|
@ -871,12 +875,12 @@ contract TestCoreRelayer is Test {
|
|||
invalidateVM(fakeVM, setup.target.wormholeSimulator);
|
||||
stack.originalDelivery.encodedVMs[2] = fakeVM;
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.redeliveryVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
stack.parsed = relayerWormhole.parseVM(stack.redeliveryVM);
|
||||
stack.instruction = setup.target.coreRelayerFull.getRedeliveryByTxHashInstruction(stack.parsed.payload);
|
||||
stack.instruction = setup.target.coreRelayerFull.decodeRedeliveryInstruction(stack.parsed.payload);
|
||||
|
||||
stack.budget = stack.instruction.newMaximumRefundTarget + stack.instruction.newReceiverValueTarget
|
||||
+ setup.target.wormhole.messageFee();
|
||||
|
@ -884,12 +888,12 @@ contract TestCoreRelayer is Test {
|
|||
vm.deal(setup.target.relayer, stack.budget);
|
||||
|
||||
vm.prank(setup.target.relayer);
|
||||
vm.expectRevert(abi.encodeWithSignature("InvalidVaa(uint8)", 2));
|
||||
vm.expectRevert(abi.encodeWithSignature("InvalidVaa(uint8,string)", 2, ""));
|
||||
setup.target.coreRelayerFull.redeliverSingle{value: stack.budget}(stack.package);
|
||||
|
||||
stack.originalDelivery.encodedVMs[2] = stack.originalDelivery.encodedVMs[0];
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.redeliveryVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
|
@ -899,7 +903,7 @@ contract TestCoreRelayer is Test {
|
|||
|
||||
stack.originalDelivery.encodedVMs[2] = correctVM;
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.redeliveryVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
|
@ -907,7 +911,7 @@ contract TestCoreRelayer is Test {
|
|||
fakeVM = abi.encodePacked(correctVM);
|
||||
invalidateVM(fakeVM, setup.target.wormholeSimulator);
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
fakeVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
|
@ -918,7 +922,7 @@ contract TestCoreRelayer is Test {
|
|||
fakeVM = relayerWormholeSimulator.fetchSignedMessageFromLogs(
|
||||
stack.entries[0], setup.sourceChainId, address(setup.source.integration)
|
||||
);
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
fakeVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
|
@ -940,7 +944,7 @@ contract TestCoreRelayer is Test {
|
|||
fakeVM = relayerWormholeSimulator.fetchSignedMessageFromLogs(
|
||||
stack.entries[0], setup.sourceChainId, address(setup.source.coreRelayer)
|
||||
);
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
fakeVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
|
@ -948,7 +952,7 @@ contract TestCoreRelayer is Test {
|
|||
vm.expectRevert(abi.encodeWithSignature("MismatchingRelayProvidersInRedelivery()"));
|
||||
setup.target.coreRelayerFull.redeliverSingle{value: stack.budget}(stack.package);
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.redeliveryVM, stack.originalDelivery.encodedVMs, payable(msg.sender)
|
||||
);
|
||||
|
||||
|
@ -992,7 +996,6 @@ contract TestCoreRelayer is Test {
|
|||
newRelayParameters: setup.source.coreRelayer.getDefaultRelayParams()
|
||||
});
|
||||
setup.source.relayProvider.updatePrice(differentChainId, gasParams.targetGasPrice, feeParams.targetNativePrice);
|
||||
setup.source.relayProvider.updatePrice(differentChainId, gasParams.sourceGasPrice, feeParams.sourceNativePrice);
|
||||
setup.source.relayProvider.updateDeliveryAddress(
|
||||
differentChainId, bytes32(uint256(uint160(address(setup.target.relayer))))
|
||||
);
|
||||
|
@ -1009,12 +1012,13 @@ contract TestCoreRelayer is Test {
|
|||
fakeVM = relayerWormholeSimulator.fetchSignedMessageFromLogs(
|
||||
stack.entries[0], setup.sourceChainId, address(setup.source.coreRelayer)
|
||||
);
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle(
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle(
|
||||
fakeVM, stack.originalDelivery.encodedVMs, payable(setup.target.relayer)
|
||||
);
|
||||
|
||||
redeliveryVmHash = relayerWormhole.parseVM(fakeVM).hash;
|
||||
uint256 txValue = stack.payment + map[differentChainId].wormhole.messageFee();
|
||||
uint256 txValue = stack.payment * feeParams.sourceNativePrice / feeParams.targetNativePrice + 1
|
||||
+ map[differentChainId].wormhole.messageFee();
|
||||
vm.deal(setup.target.relayer, txValue);
|
||||
|
||||
vm.expectEmit(true, true, true, true, address(map[differentChainId].coreRelayer));
|
||||
|
@ -1028,7 +1032,7 @@ contract TestCoreRelayer is Test {
|
|||
vm.prank(setup.target.relayer);
|
||||
map[differentChainId].coreRelayerFull.redeliverSingle{value: txValue}(stack.package);
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle({
|
||||
stack.package = IDelivery.TargetRedeliveryByTxHashParamsSingle({
|
||||
redeliveryVM: correctVM,
|
||||
sourceEncodedVMs: stack.originalDelivery.encodedVMs,
|
||||
relayerRefundAddress: payable(setup.target.relayer)
|
||||
|
@ -1063,7 +1067,7 @@ contract TestCoreRelayer is Test {
|
|||
bytes[] encodedVMs;
|
||||
IWormhole.VM parsed;
|
||||
uint256 budget;
|
||||
CoreRelayer.TargetDeliveryParametersSingle package;
|
||||
IDelivery.TargetDeliveryParametersSingle package;
|
||||
CoreRelayer.DeliveryInstruction instruction;
|
||||
}
|
||||
|
||||
|
@ -1111,7 +1115,7 @@ contract TestCoreRelayer is Test {
|
|||
stack.encodedVMs[1] = stack.actualVM2;
|
||||
stack.encodedVMs[2] = stack.deliveryVM;
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetDeliveryParametersSingle({
|
||||
stack.package = IDelivery.TargetDeliveryParametersSingle({
|
||||
encodedVMs: stack.encodedVMs,
|
||||
deliveryIndex: 2,
|
||||
multisendIndex: 0,
|
||||
|
@ -1120,7 +1124,7 @@ contract TestCoreRelayer is Test {
|
|||
|
||||
stack.parsed = relayerWormhole.parseVM(stack.deliveryVM);
|
||||
stack.instruction =
|
||||
setup.target.coreRelayerFull.getDeliveryInstructionsContainer(stack.parsed.payload).instructions[0];
|
||||
setup.target.coreRelayerFull.decodeDeliveryInstructionsContainer(stack.parsed.payload).instructions[0];
|
||||
stack.budget = stack.instruction.maximumRefundTarget + stack.instruction.receiverValueTarget
|
||||
+ setup.source.wormhole.messageFee();
|
||||
|
||||
|
@ -1178,7 +1182,7 @@ contract TestCoreRelayer is Test {
|
|||
stack.encodedVMs[1] = stack.actualVM2;
|
||||
stack.encodedVMs[2] = fakeVM;
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetDeliveryParametersSingle({
|
||||
stack.package = IDelivery.TargetDeliveryParametersSingle({
|
||||
encodedVMs: stack.encodedVMs,
|
||||
deliveryIndex: 2,
|
||||
multisendIndex: 0,
|
||||
|
@ -1187,18 +1191,18 @@ contract TestCoreRelayer is Test {
|
|||
|
||||
stack.parsed = relayerWormhole.parseVM(stack.deliveryVM);
|
||||
stack.instruction =
|
||||
setup.target.coreRelayerFull.getDeliveryInstructionsContainer(stack.parsed.payload).instructions[0];
|
||||
setup.target.coreRelayerFull.decodeDeliveryInstructionsContainer(stack.parsed.payload).instructions[0];
|
||||
|
||||
stack.budget = stack.instruction.maximumRefundTarget + stack.instruction.receiverValueTarget
|
||||
+ setup.target.wormhole.messageFee();
|
||||
|
||||
vm.prank(setup.target.relayer);
|
||||
vm.expectRevert(abi.encodeWithSignature("InvalidVaa(uint8)", 2));
|
||||
vm.expectRevert(abi.encodeWithSignature("InvalidVaa(uint8,string)", 2, ""));
|
||||
setup.target.coreRelayerFull.deliverSingle{value: stack.budget}(stack.package);
|
||||
|
||||
stack.encodedVMs[2] = stack.encodedVMs[0];
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetDeliveryParametersSingle({
|
||||
stack.package = IDelivery.TargetDeliveryParametersSingle({
|
||||
encodedVMs: stack.encodedVMs,
|
||||
deliveryIndex: 2,
|
||||
multisendIndex: 0,
|
||||
|
@ -1211,7 +1215,7 @@ contract TestCoreRelayer is Test {
|
|||
|
||||
stack.encodedVMs[2] = stack.deliveryVM;
|
||||
|
||||
stack.package = CoreRelayerStructs.TargetDeliveryParametersSingle({
|
||||
stack.package = IDelivery.TargetDeliveryParametersSingle({
|
||||
encodedVMs: stack.encodedVMs,
|
||||
deliveryIndex: 2,
|
||||
multisendIndex: 0,
|
||||
|
@ -1291,8 +1295,10 @@ contract TestCoreRelayer is Test {
|
|||
relayParameters: setup.source.coreRelayer.getDefaultRelayParams()
|
||||
});
|
||||
|
||||
vm.expectRevert(abi.encodeWithSignature("MaxTransactionFeeNotEnough()"));
|
||||
setup.source.coreRelayer.send{value: stack.deliveryOverhead - 1}(
|
||||
uint256 wormholeFee = setup.source.wormhole.messageFee();
|
||||
|
||||
vm.expectRevert(abi.encodeWithSignature("MaxTransactionFeeNotEnough(uint8)", 0));
|
||||
setup.source.coreRelayer.send{value: stack.deliveryOverhead - 1 + wormholeFee}(
|
||||
stack.badSend, 1, address(setup.source.relayProvider)
|
||||
);
|
||||
|
||||
|
@ -1302,7 +1308,7 @@ contract TestCoreRelayer is Test {
|
|||
setup.targetChainId, uint256(gasParams.targetGasLimit - 1) * gasParams.targetGasPrice
|
||||
);
|
||||
|
||||
vm.expectRevert(abi.encodeWithSignature("FundsTooMuch()"));
|
||||
vm.expectRevert(abi.encodeWithSignature("FundsTooMuch(uint8)", 0));
|
||||
setup.source.coreRelayer.send{value: stack.payment}(
|
||||
stack.deliveryRequest, 1, address(setup.source.relayProvider)
|
||||
);
|
||||
|
@ -1318,7 +1324,7 @@ contract TestCoreRelayer is Test {
|
|||
|
||||
mapping(uint256 => bool) nonceCompleted;
|
||||
|
||||
mapping(bytes32 => CoreRelayer.TargetDeliveryParametersSingle) pastDeliveries;
|
||||
mapping(bytes32 => IDelivery.TargetDeliveryParametersSingle) pastDeliveries;
|
||||
|
||||
function genericRelayer(uint16 chainId, uint8 num) internal {
|
||||
Vm.Log[] memory entries = truncateRecordedLogs(chainId, num);
|
||||
|
@ -1395,20 +1401,19 @@ contract TestCoreRelayer is Test {
|
|||
function genericRelay(
|
||||
Contracts memory contracts,
|
||||
uint8 counter,
|
||||
bytes memory encodedDeliveryInstructionContainer,
|
||||
bytes memory encodedDeliveryInstructionsContainer,
|
||||
bytes[] memory encodedVMsToBeDelivered,
|
||||
IWormhole.VM memory parsedInstruction
|
||||
) internal {
|
||||
uint8 payloadId = parsedInstruction.payload.toUint8(0);
|
||||
if (payloadId == 1) {
|
||||
CoreRelayer.DeliveryInstructionsContainer memory container =
|
||||
contracts.coreRelayerFull.getDeliveryInstructionsContainer(parsedInstruction.payload);
|
||||
contracts.coreRelayerFull.decodeDeliveryInstructionsContainer(parsedInstruction.payload);
|
||||
for (uint8 k = 0; k < container.instructions.length; k++) {
|
||||
uint256 budget =
|
||||
container.instructions[k].maximumRefundTarget + container.instructions[k].receiverValueTarget;
|
||||
uint16 targetChain = container.instructions[k].targetChain;
|
||||
CoreRelayer.TargetDeliveryParametersSingle memory package = CoreRelayerStructs
|
||||
.TargetDeliveryParametersSingle({
|
||||
IDelivery.TargetDeliveryParametersSingle memory package = IDelivery.TargetDeliveryParametersSingle({
|
||||
encodedVMs: encodedVMsToBeDelivered,
|
||||
deliveryIndex: counter,
|
||||
multisendIndex: k,
|
||||
|
@ -1421,15 +1426,15 @@ contract TestCoreRelayer is Test {
|
|||
}
|
||||
} else if (payloadId == 2) {
|
||||
CoreRelayer.RedeliveryByTxHashInstruction memory instruction =
|
||||
contracts.coreRelayerFull.getRedeliveryByTxHashInstruction(parsedInstruction.payload);
|
||||
CoreRelayer.TargetDeliveryParametersSingle memory originalDelivery =
|
||||
contracts.coreRelayerFull.decodeRedeliveryInstruction(parsedInstruction.payload);
|
||||
IDelivery.TargetDeliveryParametersSingle memory originalDelivery =
|
||||
pastDeliveries[keccak256(abi.encodePacked(instruction.sourceTxHash, instruction.multisendIndex))];
|
||||
uint16 targetChain = instruction.targetChain;
|
||||
uint256 budget = instruction.newMaximumRefundTarget + instruction.newReceiverValueTarget
|
||||
+ map[targetChain].wormhole.messageFee();
|
||||
CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingle memory package = CoreRelayerStructs
|
||||
IDelivery.TargetRedeliveryByTxHashParamsSingle memory package = IDelivery
|
||||
.TargetRedeliveryByTxHashParamsSingle({
|
||||
redeliveryVM: encodedDeliveryInstructionContainer,
|
||||
redeliveryVM: encodedDeliveryInstructionsContainer,
|
||||
sourceEncodedVMs: originalDelivery.encodedVMs,
|
||||
relayerRefundAddress: payable(map[targetChain].relayer)
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
loadCoreRelayers,
|
||||
loadMockIntegrations,
|
||||
} from "../ts-scripts/helpers/env"
|
||||
import { MockRelayerIntegration, CoreRelayerStructs } from "../../sdk/src"
|
||||
import { MockRelayerIntegration, IWormholeRelayer } from "../../sdk/src"
|
||||
const ETHEREUM_ROOT = `${__dirname}/..`
|
||||
|
||||
init()
|
||||
|
@ -314,7 +314,7 @@ describe("Core Relayer Integration Test - Two Chains", () => {
|
|||
expect(message).to.not.equal(arbitraryPayload)
|
||||
|
||||
console.log("Resending the message");
|
||||
const request: CoreRelayerStructs.ResendByTxStruct = {
|
||||
const request: IWormholeRelayer.ResendByTxStruct = {
|
||||
sourceChain: sourceChain.chainId,
|
||||
sourceTxHash: tx.hash,
|
||||
sourceNonce: 1,
|
||||
|
@ -402,7 +402,7 @@ describe("Core Relayer Integration Test - Two Chains", () => {
|
|||
// RESEND THE MESSAGE SOMEHOW!
|
||||
|
||||
/*console.log("Resending the message");
|
||||
const request: CoreRelayerStructs.ResendByTxStruct = {
|
||||
const request: IWormholeRelayer.ResendByTxStruct = {
|
||||
sourceChain: sourceChain.chainId,
|
||||
sourceTxHash: tx.hash,
|
||||
sourceNonce: 1,
|
||||
|
|
|
@ -6,4 +6,6 @@ export type { IWormhole, LogMessagePublishedEvent } from "./ethers-contracts/IWo
|
|||
export { IWormhole__factory } from "./ethers-contracts/factories/IWormhole__factory"
|
||||
export type { RelayProvider } from "./ethers-contracts/RelayProvider"
|
||||
export { RelayProvider__factory } from "./ethers-contracts/factories/RelayProvider__factory"
|
||||
export type {IDelivery} from "./ethers-contracts/IDelivery"
|
||||
export type {IWormholeRelayer} from "./ethers-contracts/IWormholeRelayer"
|
||||
export * from './structs'
|
|
@ -24,7 +24,7 @@ import {
|
|||
IWormhole__factory,
|
||||
RelayProvider__factory,
|
||||
LogMessagePublishedEvent,
|
||||
CoreRelayerStructs,
|
||||
IDelivery,
|
||||
DeliveryInstructionsContainer,
|
||||
parseDeliveryInstructionsContainer,
|
||||
parseRedeliveryByTxHashInstruction,
|
||||
|
@ -545,7 +545,7 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
wallet
|
||||
)
|
||||
|
||||
const input: CoreRelayerStructs.TargetDeliveryParametersSingleStruct = {
|
||||
const input: IDelivery.TargetDeliveryParametersSingleStruct = {
|
||||
encodedVMs: payload.vaas,
|
||||
deliveryIndex: payload.deliveryVaaIndex,
|
||||
multisendIndex: i,
|
||||
|
@ -597,7 +597,7 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
|
||||
const { newReceiverValueTarget, newMaximumRefundTarget } = redelivery.ix
|
||||
const budget = newReceiverValueTarget.add(newMaximumRefundTarget).add(100)
|
||||
const input: CoreRelayerStructs.TargetRedeliveryByTxHashParamsSingleStruct = {
|
||||
const input: IDelivery.TargetRedeliveryByTxHashParamsSingleStruct = {
|
||||
sourceEncodedVMs: payload.vaas,
|
||||
redeliveryVM: redelivery.vaa.bytes,
|
||||
relayerRefundAddress: wallet.address,
|
||||
|
|
|
@ -6,4 +6,6 @@ export type { IWormhole, LogMessagePublishedEvent } from "./ethers-contracts/IWo
|
|||
export { IWormhole__factory } from "./ethers-contracts/factories/IWormhole__factory"
|
||||
export type { RelayProvider } from "./ethers-contracts/RelayProvider"
|
||||
export { RelayProvider__factory } from "./ethers-contracts/factories/RelayProvider__factory"
|
||||
export type {IDelivery} from "./ethers-contracts/IDelivery"
|
||||
export type {IWormholeRelayer} from "./ethers-contracts/IWormholeRelayer"
|
||||
export * from './structs'
|
Loading…
Reference in New Issue