Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
Contract changes (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
derpy-duck authored Mar 23, 2023
1 parent 2a204b8 commit 7b71615
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 102 deletions.
67 changes: 33 additions & 34 deletions ethereum/contracts/coreRelayer/CoreRelayer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract CoreRelayer is CoreRelayerDelivery {
* If maxTransactionFee >= quoteGas(targetChain, gasLimit, getDefaultRelayProvider()), then as long as 'targetAddress''s receiveWormholeMessage function uses at most 'gasLimit' units of gas (and doesn't revert), the delivery will succeed
* @param receiverValue The amount (denominated in source chain currency) that will be converted to target chain currency and passed into the receiveWormholeMessage endpoint as value.
* If receiverValue >= quoteReceiverValue(targetChain, targetAmount, getDefaultRelayProvider()), then at least 'targetAmount' of targetChain currency will be passed into the 'receiveWormholeFunction' as value.
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction that have nonce 'nonce'.
* @param messages Array of (emitterAddress, sequence, hash) structs identifying each message to be relayed. For each entry in this array, either the (emitterAddress, sequence) pair must be provided, or the hash must be provided.
*
* This function must be called with a payment of at least maxTransactionFee + receiverValue + one wormhole message fee.
*
Expand All @@ -40,13 +40,13 @@ contract CoreRelayer is CoreRelayerDelivery {
bytes32 refundAddress,
uint256 maxTransactionFee,
uint256 receiverValue,
uint32 nonce
IWormholeRelayer.MessageInfo[] memory messages
) external payable returns (uint64 sequence) {
sequence = send(
IWormholeRelayer.Send(
targetChain, targetAddress, refundAddress, maxTransactionFee, receiverValue, getDefaultRelayParams()
),
nonce,
messages,
getDefaultRelayProvider()
);
}
Expand All @@ -61,7 +61,7 @@ contract CoreRelayer is CoreRelayerDelivery {
*
*
* @param request The Send request containing info about the targetChain, targetAddress, refundAddress, maxTransactionFee, receiverValue, and relayParameters
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction that have nonce 'nonce'.
* @param messages Array of (emitterAddress, sequence, hash) structs identifying each message to be relayed. For each entry in this array, either the (emitterAddress, sequence) pair must be provided, or the hash must be provided.
* @param relayProvider The address of (the relay provider you wish to deliver the messages)'s contract on this source chain. This must be a contract that implements IRelayProvider.
* If request.maxTransactionFee >= quoteGas(request.targetChain, gasLimit, relayProvider),
* then as long as 'request.targetAddress''s receiveWormholeMessage function uses at most 'gasLimit' units of gas (and doesn't revert), the delivery will succeed
Expand All @@ -73,13 +73,13 @@ contract CoreRelayer is CoreRelayerDelivery {
* @return sequence The sequence number for the emitted wormhole message, which contains encoded delivery instructions meant for your specified relay provider.
* The relay provider will listen for these messages, and then execute the delivery as described.
*/
function send(IWormholeRelayer.Send memory request, uint32 nonce, address relayProvider)
public
payable
returns (uint64 sequence)
{
function send(
IWormholeRelayer.Send memory request,
IWormholeRelayer.MessageInfo[] memory messages,
address relayProvider
) public payable returns (uint64 sequence) {
// call multichainSend with one 'Send' in the requests array
sequence = multichainSend(multichainSendContainer(request, relayProvider), nonce);
sequence = multichainSend(multichainSendContainer(request, relayProvider, messages));
}

/**
Expand Down Expand Up @@ -112,7 +112,7 @@ contract CoreRelayer is CoreRelayerDelivery {
* If maxTransactionFee >= quoteGas(targetChain, gasLimit, getDefaultRelayProvider()), then as long as 'targetAddress''s receiveWormholeMessage function uses at most 'gasLimit' units of gas (and doesn't revert), the delivery will succeed
* @param receiverValue The amount (denominated in source chain currency) that will be converted to target chain currency and passed into the receiveWormholeMessage endpoint as value.
* If receiverValue >= quoteReceiverValue(targetChain, targetAmount, getDefaultRelayProvider()), then at least 'targetAmount' of targetChain currency will be passed into the 'receiveWormholeFunction' as value.
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction that have nonce 'nonce'.
* @param messages Array of (emitterAddress, sequence, hash) structs identifying each message to be relayed. For each entry in this array, either the (emitterAddress, sequence) pair must be provided, or the hash must be provided.
*
* This forward will succeed if (leftover funds from the current delivery that would have been refunded) + (any extra msg.value passed into forward) is at least maxTransactionFee + receiverValue + one wormhole message fee.
*/
Expand All @@ -122,13 +122,13 @@ contract CoreRelayer is CoreRelayerDelivery {
bytes32 refundAddress,
uint256 maxTransactionFee,
uint256 receiverValue,
uint32 nonce
IWormholeRelayer.MessageInfo[] memory messages
) external payable {
forward(
IWormholeRelayer.Send(
targetChain, targetAddress, refundAddress, maxTransactionFee, receiverValue, getDefaultRelayParams()
),
nonce,
messages,
getDefaultRelayProvider()
);
}
Expand Down Expand Up @@ -156,7 +156,7 @@ contract CoreRelayer is CoreRelayerDelivery {
* @param request The Send request containing info about the targetChain, targetAddress, refundAddress, maxTransactionFee, receiverValue, and relayParameters
* (specifically, the send info that will be used to deliver all of the wormhole messages emitted during the execution of oldTargetAddress's receiveWormholeMessages)
* This forward will succeed if (leftover funds from the current delivery that would have been refunded) + (any extra msg.value passed into forward) is at least maxTransactionFee + receiverValue + one wormhole message fee.
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction (during execution of oldTargetAddress's receiveWormholeMessages) that have nonce 'nonce'.
* @param messages Array of (emitterAddress, sequence, hash) structs identifying each message to be relayed. For each entry in this array, either the (emitterAddress, sequence) pair must be provided, or the hash must be provided.
* @param relayProvider The address of (the relay provider you wish to deliver the messages)'s contract on this source chain. This must be a contract that implements IRelayProvider.
* If request.maxTransactionFee >= quoteGas(request.targetChain, gasLimit, relayProvider),
* then as long as 'request.targetAddress''s receiveWormholeMessage function uses at most 'gasLimit' units of gas (and doesn't revert), the delivery will succeed
Expand All @@ -165,24 +165,27 @@ contract CoreRelayer is CoreRelayerDelivery {
*
* This function must be called with a payment of at least request.maxTransactionFee + request.receiverValue + one wormhole message fee.
*/
function forward(IWormholeRelayer.Send memory request, uint32 nonce, address relayProvider) public payable {
function forward(
IWormholeRelayer.Send memory request,
IWormholeRelayer.MessageInfo[] memory messages,
address relayProvider
) public payable {
// call multichainForward with one 'Send' in the requests array
multichainForward(multichainSendContainer(request, relayProvider), nonce);
multichainForward(multichainSendContainer(request, relayProvider, messages));
}

/**
* @notice The multichainSend function delivers all wormhole messages in the current transaction of nonce 'nonce' to many destinations,
* with each destination specified in a Send struct, describing the desired targetAddress, targetChain, maxTransactionFee, receiverValue, refundAddress, and relayParameters
*
* @param sendContainer The MultichainSend struct, containing the array of Send requests, as well as the desired relayProviderAddress
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction that have nonce 'nonce'
*
* This function must be called with a payment of at least (one wormhole message fee) + Sum_(i=0 -> sendContainer.requests.length - 1) [sendContainer.requests[i].maxTransactionFee + sendContainer.requests[i].receiverValue].
*
* @return sequence The sequence number for the emitted wormhole message, which contains encoded delivery instructions meant for the default wormhole relay provider.
* The relay provider will listen for these messages, and then execute the delivery as described
*/
function multichainSend(IWormholeRelayer.MultichainSend memory sendContainer, uint32 nonce)
function multichainSend(IWormholeRelayer.MultichainSend memory sendContainer)
public
payable
returns (uint64 sequence)
Expand All @@ -193,9 +196,6 @@ contract CoreRelayer is CoreRelayerDelivery {
if (totalFee > msg.value) {
revert IWormholeRelayer.MsgValueTooLow();
}
if (nonce == 0) {
revert IWormholeRelayer.NonceIsZero();
}
if (sendContainer.requests.length == 0) {
revert IWormholeRelayer.MultichainSendEmpty();
}
Expand All @@ -219,7 +219,7 @@ contract CoreRelayer is CoreRelayerDelivery {
// Publish a wormhole message indicating to the relay provider (who is watching wormhole messages from this contract)
// to relay the messages from this transaction (of nonce 'nonce') to the specified chains, each with the calculated amount of gas and receiverValue
sequence = wormhole.publishMessage{value: wormholeMessageFee}(
nonce, encodeDeliveryInstructionsContainer(instructionsContainer), relayProvider.getConsistencyLevel()
0, encodeDeliveryInstructionsContainer(instructionsContainer), relayProvider.getConsistencyLevel()
);

// Pay the relay provider
Expand All @@ -239,19 +239,15 @@ contract CoreRelayer is CoreRelayerDelivery {
* 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 sendContainer The MultichainSend struct, containing the array of Send requests, as well as the desired relayProviderAddress
* @param nonce The messages to be relayed are all of the emitted wormhole messages in the current transaction that have nonce 'nonce'
*
*/
function multichainForward(IWormholeRelayer.MultichainSend memory sendContainer, uint32 nonce) public payable {
function multichainForward(IWormholeRelayer.MultichainSend memory sendContainer) public payable {
if (!isContractLocked()) {
revert IWormholeRelayer.NoDeliveryInProgress();
}
if (getForwardInstruction().isValid) {
revert IWormholeRelayer.MultipleForwardsRequested();
}
if (nonce == 0) {
revert IWormholeRelayer.NonceIsZero();
}
if (msg.sender != lockedTargetAddress()) {
revert IWormholeRelayer.ForwardRequestFromWrongAddress();
}
Expand All @@ -278,7 +274,6 @@ contract CoreRelayer is CoreRelayerDelivery {
setForwardInstruction(
ForwardInstruction({
container: encodeDeliveryInstructionsContainer(instructionsContainer),
nonce: nonce,
msgValue: msg.value,
totalFee: totalFee,
sender: msg.sender,
Expand Down Expand Up @@ -431,13 +426,17 @@ contract CoreRelayer is CoreRelayerDelivery {
}

// Helper to put one Send struct into a MultichainSend struct
function multichainSendContainer(IWormholeRelayer.Send memory request, address relayProvider)
internal
pure
returns (IWormholeRelayer.MultichainSend memory container)
{
function multichainSendContainer(
IWormholeRelayer.Send memory request,
address relayProvider,
IWormholeRelayer.MessageInfo[] memory messages
) internal pure returns (IWormholeRelayer.MultichainSend memory container) {
IWormholeRelayer.Send[] memory requests = new IWormholeRelayer.Send[](1);
requests[0] = request;
container = IWormholeRelayer.MultichainSend({relayProviderAddress: relayProvider, requests: requests});
container = IWormholeRelayer.MultichainSend({
relayProviderAddress: relayProvider,
requests: requests,
messages: messages
});
}
}
50 changes: 41 additions & 9 deletions ethereum/contracts/coreRelayer/CoreRelayerDelivery.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ contract CoreRelayerDelivery is CoreRelayerGovernance {
// Publishes the DeliveryInstruction, with a 'sufficientlyFunded' flag indicating whether the forward had enough funds
container.sufficientlyFunded = forwardIsFunded;
wormhole.publishMessage{value: wormholeMessageFee}(
forwardInstruction.nonce,
encodeDeliveryInstructionsContainer(container),
relayProvider.getConsistencyLevel()
0, encodeDeliveryInstructionsContainer(container), relayProvider.getConsistencyLevel()
);

// if funded, pay out reward to provider. Otherwise, the delivery code will handle sending a refund.
Expand Down Expand Up @@ -120,6 +118,7 @@ contract CoreRelayerDelivery is CoreRelayerGovernance {
if (isContractLocked()) {
revert IDelivery.ReentrantCall();
}

setContractLock(true);
setLockedTargetAddress(fromWormholeFormat(internalInstruction.targetAddress));

Expand Down Expand Up @@ -263,19 +262,20 @@ contract CoreRelayerDelivery is CoreRelayerGovernance {

// Obtain the original delivery VAA
IWormhole.VM memory originalDeliveryVM;
(originalDeliveryVM, valid, reason) =
wormhole.parseAndVerifyVM(targetParams.sourceEncodedVMs[redeliveryInstruction.deliveryIndex]);
(originalDeliveryVM, valid, reason) = wormhole.parseAndVerifyVM(targetParams.originalEncodedDeliveryVAA);

// Check that the original delivery VAA has a valid signature
if (!valid) {
revert IDelivery.InvalidVaa(redeliveryInstruction.deliveryIndex, reason);
revert IDelivery.InvalidDeliveryVaa(reason);
}

// Check that the original delivery VAA's emitter is one of these CoreRelayer contracts
if (!verifyRelayerVM(originalDeliveryVM)) {
revert IDelivery.InvalidEmitterInOriginalDeliveryVM(redeliveryInstruction.deliveryIndex);
revert IDelivery.InvalidEmitterInOriginalDeliveryVM();
}

checkMessageInfosWithVAAs(redeliveryInstruction.messages, targetParams.sourceEncodedVMs);

// 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
Expand Down Expand Up @@ -400,11 +400,11 @@ contract CoreRelayerDelivery is CoreRelayerGovernance {

// Obtain the delivery VAA
(IWormhole.VM memory deliveryVM, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(targetParams.encodedVMs[targetParams.deliveryIndex]);
wormhole.parseAndVerifyVM(targetParams.encodedDeliveryVAA);

// Check that the delivery VAA has a valid signature
if (!valid) {
revert IDelivery.InvalidVaa(targetParams.deliveryIndex, reason);
revert IDelivery.InvalidDeliveryVaa(reason);
}

// Check that the delivery VAA's emitter is one of these CoreRelayer contracts
Expand Down Expand Up @@ -444,6 +444,8 @@ contract CoreRelayerDelivery is CoreRelayerGovernance {
revert IDelivery.TargetChainIsNotThisChain(deliveryInstruction.targetChain);
}

checkMessageInfosWithVAAs(container.messages, targetParams.encodedVMs);

_executeDelivery(
deliveryInstruction,
targetParams.encodedVMs,
Expand All @@ -456,6 +458,36 @@ contract CoreRelayerDelivery is CoreRelayerGovernance {
);
}

function checkMessageInfosWithVAAs(IWormholeRelayer.MessageInfo[] memory messageInfos, bytes[] memory vaas)
internal
view
{
if (messageInfos.length != vaas.length) {
revert IDelivery.MessageInfosLengthDoesNotMatchVaasLength();
}
for (uint8 i = 0; i < messageInfos.length; i++) {
if (!messageInfoMatchesVAA(messageInfos[i], vaas[i])) {
revert IDelivery.MessageInfosDoNotMatchVaas(i);
}
}
}

function messageInfoMatchesVAA(IWormholeRelayer.MessageInfo memory messageInfo, bytes memory vaa)
internal
view
returns (bool)
{
IWormhole.VM memory parsedVaa = wormhole().parseVM(vaa);
bool emitterAddressMatch = messageInfo.emitterAddress == parsedVaa.emitterAddress;
bool sequenceMatch = (messageInfo.sequence == parsedVaa.sequence);
bool emitterAddressAndSequenceEmpty =
(messageInfo.emitterAddress == bytes32(0x0)) && (messageInfo.sequence == 0);
bool vaaHashMatch = (messageInfo.vaaHash == parsedVaa.hash);
bool vaaHashEmpty = messageInfo.vaaHash == bytes32(0x0);
return (emitterAddressMatch && sequenceMatch && (vaaHashEmpty || vaaHashMatch))
|| (emitterAddressAndSequenceEmpty && vaaHashMatch);
}

/**
* @notice Helper function that converts an EVM address to wormhole format
* @param addr (EVM 20-byte address)
Expand Down
Loading

0 comments on commit 7b71615

Please sign in to comment.