Updates post contract freeze (#125)

This commit is contained in:
derpy-duck 2023-06-01 12:25:41 -04:00 committed by GitHub
parent d3b30d4e35
commit 204421a8ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 92 additions and 165 deletions

View File

@ -160,21 +160,21 @@ These chains can _verify_ Wormhole messages submitted to them, but cannot _emit_
| Chain Name | Wormhole Chain ID | Network ID | Address |
| :------------------ | :---------------- | :--------- | :----------------------------------------- |
| Binance Smart Chain | 4 | 97 | 0xda2592C43f2e10cBBA101464326fb132eFD8cB09 |
| Polygon (Mumbai) | 5 | 80001 | 0xFAd28FcD3B05B73bBf52A3c4d8b638dFf1c5605c |
| Avalanche (Fuji) | 6 | 43113 | 0xDDe6b89B7d0AD383FafDe6477f0d300eC4d4033e |
| Celo | 14 | 44787 | 0xA92aa4f8CBE1c2d7321F1575ad85bE396e2bbE0D |
| Moonbase | 16 | 1287 | 0x57523648FB5345CF510c1F12D346A18e55Aec5f5 |
| Binance Smart Chain | 4 | 97 | 0x80aC94316391752A193C1c47E27D382b507c93F3 |
| Polygon (Mumbai) | 5 | 80001 | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 |
| Avalanche (Fuji) | 6 | 43113 | 0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB |
| Celo | 14 | 44787 | 0x306B68267Deb7c5DfCDa3619E22E9Ca39C374f84 |
| Moonbase | 16 | 1287 | 0x0591C25ebd0580E0d4F27A82Fc2e24E7489CB5e0 |
### Default Relay Providers
| Chain Name | Wormhole Chain ID | Network ID | Address |
| :------------------ | :---------------- | :--------- | :----------------------------------------- |
| Binance Smart Chain | 4 | 97 | 0xFAEd45351a0ddC272dc89c29c17e228278d2A24F |
| Polygon (Mumbai) | 5 | 80001 | 0x27196D91bD67C437a806Be3d824794C0260e7f4c |
| Avalanche (Fuji) | 6 | 43113 | 0x61CAE64b05Cb1fBfc9e810683c5C52F2C886640C |
| Celo | 14 | 44787 | 0xc5156B6635DC04b692e4298332eab136e1B2055C |
| Moonbase | 16 | 1287 | 0x8b5315217858B2feD71fcD7677DcC2a546C28C1B |
| Binance Smart Chain | 4 | 97 | 0x813AB43ab264362c55BF35A1448d0fd8135049a6 |
| Polygon (Mumbai) | 5 | 80001 | 0xBF684878906629E72079D4f07D75Ef7165238092 |
| Avalanche (Fuji) | 6 | 43113 | 0xd5903a063f604D4615E5c2760b7b80D491564BBe |
| Celo | 14 | 44787 | 0x93d56f29542c156B3e36f10dE41124B499664ff7 |
| Moonbase | 16 | 1287 | 0xBF684878906629E72079D4f07D75Ef7165238092 |
### NFT Bridge

View File

@ -2,36 +2,36 @@
**_Disclaimer: This module is only available in testnet._**
The WormholeRelayer module allows developers to deliver their VAAs via an untrusted **RelayProvider**, rather than needing to develop and host their own relay infrastructure.
The WormholeRelayer module allows developers to deliver their VAAs via an untrusted **DeliveryProvider**, rather than needing to develop and host their own relay infrastructure.
<br/>
<br/>
## Interacting with the Module
There are four relevant interfaces to discuss when utilizing the WormholeRelayer module:
There are two relevant interfaces to discuss when utilizing the WormholeRelayer module:
- [IWormholeRelayer](https://github.com/wormhole-foundation/trustless-generic-relayer/blob/main/ethereum/contracts/interfaces/IWormholeRelayer.sol) - the primary interface by which you interact with the module. It allows you to request deliveries from a given RelayProvider.
- [IRelayProvider](https://github.com/wormhole-foundation/trustless-generic-relayer/blob/main/ethereum/contracts/interfaces/IRelayProvider.sol) - this interface represents the delivery pricing information for a given relayer network.
- [IWormholeReceiver](https://github.com/wormhole-foundation/trustless-generic-relayer/blob/main/ethereum/contracts/interfaces/IWormholeReceiver.sol) - this is the interface you are responsible for implementing. It allows the selected RelayProvider to deliver messages to your contract.
- [IWormhole](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol) - this is simply the Wormhole Core Messaging interface, used for emitting and verifying VAAs.
- [IWormholeRelayer](https://github.com/wormhole-foundation/wormhole/blob/generic-relayer-merge/ethereum/contracts/interfaces/relayer/IWormholeRelayer.sol) - the primary interface by which you interact with the module. It allows you to request deliveries from a given DeliveryProvider.
- [IWormholeReceiver](https://github.com/wormhole-foundation/wormhole/blob/generic-relayer-merge/ethereum/contracts/interfaces/relayer/IWormholeReceiver.sol) - this is the interface you are responsible for implementing. It allows the selected Delivery Provider to deliver messages to your contract.
Check the [deployed contracts page](../../reference/contracts.md) for contract addresses on each supported blockchain.
A minimal setup looks something like this:
A minimal setup that can receive messages looks something like this:
```solidity
import "../IWormholeRelayer.sol";
import "../IRelayProvider.sol";
import "../IWormholeReceiver.sol";
import "../IWormhole.sol";
contract HelloWorld is IWormholeReceiver {
IWormholeRelayer relayer = IWormholeRelayer(WORMHOLE_RELAYER_CONTRACT_ADDRESS);
IWormhole wormhole = IWormhole(WORMHOLE_CORE_CONTRACT_ADDRESS);
function receiveWormholeMessages(bytes[] memory whMessages, bytes[] memory otherData)
public payable override onlyRelayerContract {
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory additionalVaas,
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 deliveryHash
) public payable override onlyRelayerContract {
}
modifier onlyRelayerContract() {
@ -48,61 +48,38 @@ contract HelloWorld is IWormholeReceiver {
# Sending Messages
The WormholeRelayer contract does not directly send messages. Rather, the WormholeRelayer contract allows you to deliver **any or all messages which originate from the current transaction**, including those which don't originate directly from the current contract.
This allows you to easily combine basic messaging along with other modules of the Wormhole ecosystem, such as the Token Bridge or NFT modules. It even allows for other Wormhole integrators to easily compose with your application! (See [best practices](./bestPractices.md) for more info.)
We'll discuss more complex usage later. For now let's just cover how to send a "Hello World" message. The basic mechanism to request delivery of your VAAs is to call the `send` function on the IWormholeRelayer interface. Here's its basic usage:
Let's cover how to send a "Hello World" message. The basic mechanism to call the `sendPayloadToEvm` function on the IWormholeRelayer interface. Here's its basic usage:
```solidity
function sendHelloWorldMessage() public payable {
//spell out some constants
bytes memory helloWorld = abi.encode("Hello World");
uint64 nonce = 1;
uint8 consistencyLevel = 200; //instant
uint32 gasLimit = 500000;
bytes32 TARGET_CONTRACT = relayer.toWormholeFormat(MY_OTHER_DEPLOYED_CONTRACT);
uint256 gasLimit = 500000;
uint256 receiverValue = 0; // don't deliver any 'msg.value' along with the message
//publish the Hello World message
wormhole.publishMessage{value: wormhole.messageFee()}(nonce, helloWorld, consistencyLevel);
//calculate cost to deliver this message
uint256 maxTransactionFee = relayer.quoteGas(
TARGET_CHAIN,
gasLimit,
relayer.getDefaultRelayProvider());
//calculate cost to cover receiver value of 100 wei on the targetChain.
//if you don't need 'receiver value', feel free to skip this and just pass 0 to the send
uint256 receiverValue = relayer.quoteReceiverValue(
//calculate cost to deliver message
(uint256 deliveryCost,) = relayer.quoteEVMDeliveryPrice(
targetChain,
100,
relayer.getDefaultRelayProvider());
receiverValue,
gasLimit
);
// publish delivery request
// the fields, in order, are:
// targetChain, targetAddress, refundAddress, maxTransactionFee, receiverValue, nonce
relayer.send{value: deliveryCost + receiverValue}(
TARGET_CHAIN, TARGET_CONTRACT, TARGET_CONTRACT, maxTransactionFee, receiverValue, nonce
relayer.sendPayloadToEvm{value: deliveryCost}(
TARGET_CHAIN, TARGET_CONTRACT, helloWorld, receiverValue, gasLimit
);
}
```
In this code, we first emit a "Hello World" message via the Wormhole Core Layer the same way it's always done. We then request from the default RelayProvider that they deliver all messages emitted from this transaction with nonce 1 to the TARGET_CONTRACT on the TARGET_CHAIN.
In this code, we first emit a "Hello World" message via the Wormhole Core Layer the same way it's always done. We then request from the default DeliveryProvider that they deliver all messages emitted from this transaction with nonce 1 to the TARGET_CONTRACT on the TARGET_CHAIN.
Let's break down all the things happening in this code.
- `nonce` - Core Contract nonce. All messages with this nonce will be delivered. Messages without this nonce won't be delivered!
- `consistencyLevel` - here we use 200 (instant) for the message emission on our "Hello World" message. Deliveries must wait for the _slowest_ message, because the delivery can't take place until there are signed VAAs for every message.
- `deliveryCost` - this calculates the necessary price for the selected RelayProvider to perform a delivery with 500,000 gas on the target chain. Thus, by paying this `deliveryCost`, you can be sure that your `receiveWormholeMessages` function will be invoked with a gas limit of 500,000. There's more info on the how these deliveries work in a later section.
- `relayProvider` - The relayer network which will deliver the request. Here we use the default provider.
- `deliveryCost` - this calculates the necessary price for the selected DeliveryProvider to perform a delivery with 500,000 gas on the target chain. Thus, by paying this `deliveryCost`, you can be sure that your `receiveWormholeMessages` function will be invoked with a gas limit of 500,000. There's more info on the how these deliveries work in a later section.
- `targetChain` - Wormhole chainId where the messages should be sent. This is not the same as the EVM Network ID!
- `targetContract` - Contract address on targetChain where the messages should be sent. This is in the 32-byte Wormhole address format.
- `refundAddress` - Address (in Wormhole format) on **targetChain** where any remaining maxTransactionFee should be sent once execution of receiveWormholeMessages is complete.
- `maxTransactionFee` - this specifies the maximum amount of funds (in sourceChain wei) that should be utilized to execute receiveWormholeMessages on the targetChain. If the maxTransactionFee is exceeded during contract execution you will enter a **delivery failure** state. Any unused budget is sent to the refundAddress.
- `receiverValue` - this amount (in sourceChain wei) is converted to targetChain native funds at the rate specified by the RelayProvider and passed to `receiveWormholeMessages` on the target chain when the delivery happens. This is useful for covering small fees encountered during execution on the target chain.
- `targetContract` - Contract address on targetChain where the messages should be sent.
- `gasLimit` - this specifies the maximum units of targetChain gas that can be used to execute receiveWormholeMessages on the targetChain. If the gasLimit is exceeded during contract execution you will enter a **receiver failure** state. Note: If you have a wallet on the targetChain (or any chain) that you wish to collect refunds to (i.e. if your contract takes less than `gasLimit` units of gas to execute), there is an option in IWormholeRelayer to have this happen.
- `receiverValue` - this amount (in targetChain wei) is passed to `receiveWormholeMessages` on the target chain when the delivery happens. This is useful for covering small fees encountered during execution on the target chain.
<br/>
<br/>
@ -111,18 +88,18 @@ Let's break down all the things happening in this code.
## Receiving Messages
Receiving messages through the relayer module is quite straightforward. Simply implement the `IWormholeReceiver` interface.
To receive messages through the relayer module, simply implement the `IWormholeReceiver` interface.
```solidity
function receiveWormholeMessages(bytes[] memory whMessages, bytes[] memory otherData)
public payable override onlyRelayerContract {
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory additionalVaas,
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 deliveryHash
) public payable override onlyRelayerContract {
(IWormhole.VM memory whMessage, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(whMessages[0]);
require(valid, reason);
//Parse whMessage.payload and do whatever you need to do
//Do whatever you need to do with 'payload'
}
modifier onlyRelayerContract() {
@ -133,21 +110,19 @@ modifier onlyRelayerContract() {
Breaking down everything happening in this code snippet:
- `receiveWormholeMessages` - this is the function which will be invoked by the WormholeRelayer contract when the RelayProvider completes the delivery. It will be executed with a gas limit equal to the amount which was covered by the `maxTransactionFee` that was specified in the deliveryRequest.
- `whMessages` - These are all the messages that were requested for delivery, in the order they were emitted. This includes the deliveryVAA used by the WormholeRelayer, which should generally be ignored.
- `otherData` - Non-Wormhole data which was requested for delivery. Currently not used, but included for future compatibility.
- `receiveWormholeMessages` - this is the function which will be invoked by the WormholeRelayer contract when the DeliveryProvider completes the delivery. It will be executed with a gas limit that was specified in the deliveryRequest.
- `payload` - This is the payload that was sent in the delivery request
- `additionalVaas` - In the example shown above, this will be empty. This will contain any additional VAAs that were requested to be relayed through the 'vaaKeys' field. These should not be considered trusted until you call `core_bridge.parseAndVerifyVM` or otherwise verify them against the Core Contract! (More on this in [Best Practices](./bestPractices.md))
- `sourceAddress` - Address that requested this delivery (in Wormhole bytes32 format; i.e. if this is originally an EVM address, it will be left-padded with 12 zeros)
- `sourceChain` - Chain (in Wormhole Chain ID format) that this delivery was requested from
- `deliveryHash` - Unique identifier of this delivery request. Specifically, this is the hash of the delivery VAA.
- `onlyRelayerContract` - this prevents contracts other than the WormholeRelayer contract from calling this entrypoint. The WormholeRelayer contract handles the invocation of `receiveWormholeMessages`, and ensures that relayers can't improperly call it.
Here are a few other important points to note:
- `receiveWormholeMessages` function should generally not throw an exception or revert during execution. If an exception is thrown, or a 'require' statement is violated, you will enter a delivery failure. When a delivery failure occurs, the execution of `receiveWormholeMessages` is reverted, but the entire transaction is not.
- `receiveWormholeMessages` function should generally not throw an exception or revert during execution. If an exception is thrown, or a 'require' statement is violated, you will enter a receiver failure. When a receiver failure occurs, the execution of `receiveWormholeMessages` is reverted.
- `receiveWormholeMessages` will only be called with as much gas as was specified by the maxTransactionFee specified when the message delivery was requested. If you exceed this gas amount, you will enter a delivery failure. Ther are more details on maxTransactionFee in a later section.
- `whMessages` is the array of VAAs which were requested for delivery, in the order they were emitted during the requesting transaction. These VAAs are not verified, and should not be considered trusted until you call `core_bridge.parseAndVerifyVM` or otherwise verify them against the Core Contract! (More on this in [Best Practices](./bestPractices.md))
- The delivery VAA will be included in the array you receive. This is generally best ignored.
- `receiveWormholeMessages` will only be called with as much gas as was specified by the gasLimit specified when the message delivery was requested. If you exceed this gas amount, you will enter a delivery failure.
<br/>
<br/>
@ -156,32 +131,32 @@ Here are a few other important points to note:
# Delivery Guarantees & Delivery Failures
The WormholeRelayer protocol is intended to create a service interface whereby mutually distrustful integrators and RelayProviders can work together to provide a seamless Dapp experience. You don't trust the relay providers with your data, and the relay providers don't trust your smart contract. The primary agreement which is made between integrators and relayers is that:
The WormholeRelayer protocol is intended to create a service interface whereby mutually distrustful integrators and DeliveryProviders can work together to provide a seamless Dapp experience. You don't trust the delivery providers with your data, and the delivery providers don't trust your smart contract. The primary agreement which is made between integrators and delivery providers is that:
**When a delivery is requested, the relay provider will attempt to deliver the VAA within the provider's stated delivery timeframe.**
**When a delivery is requested, the delivery provider will attempt to deliver the VAA within the provider's stated delivery timeframe.**
As a baseline, RelayProviders should aim to perform deliveries **within 5 minutes of the VAA creation, assuming blockchain liveness**.
As a baseline, DeliveryProviders should aim to perform deliveries **within 5 minutes of the VAA creation, assuming blockchain liveness**.
This creates a marketplace whereby providers can set different price levels and service guarantees. Relay providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages **even if they have to do so at a loss**.
This creates a marketplace whereby providers can set different price levels and service guarantees. Delivery providers effectively accept the slippage risk premium of delivering your VAAs in exchange for a set fee rate. Thus, the providers agree to deliver your messages **even if they have to do so at a loss**.
Relay providers should set their prices such that they turn a profit on average, but not necessarily on every single transfer. Thus, some providers may choose to set higher rates for tighter guarantees, or lower rates for less stringent guarantees.
<br/>
### Delivery Failures
### Receiver Failures
All deliveries should result in one of following four outcomes prior to the delivery timeframe of the relay provider. These outcomes are emitted as EVM events from the WormholeRelayer contract when they occur.
All deliveries should result in one of following four outcomes prior to the delivery timeframe of the delivery provider. These outcomes are emitted as EVM events from the WormholeRelayer contract when they occur.
- Delivery Success
- Delivery Failure
- Forward Request (More on forwarding in a later section)
- Forward Failure
- Receiver Failure
- Forward Request Success (More on forwarding in a later section)
- Forward Request Failure
Delivery Failures are not a nebulous 'something went wrong' term in the Wormhole Core Relayer protocol. A delivery failure is a well-defined term which means that the selected provider **performed the delivery, but the delivery was not able to be completed.** There are only three causes for a delivery failure:
Receiver Failures are not a nebulous 'something went wrong' term in the Wormhole Core Relayer protocol. A delivery failure is a well-defined term which means that the selected provider **performed the delivery, but the delivery was not able to be completed.** There are only three causes for a delivery failure:
- the target contract does not implement the `IWormholeReceiver` interface
- the target contract threw an exception or reverted during execution of `receiveWormholeMessages`
- the target contract exceeded the specified `maxTransactionFee` while executing `receiveWormholeMessages`
- the target contract exceeded the specified `gasLimit` while executing `receiveWormholeMessages`
All three of these scenarios should generally be avoidable by the integrator, and thus it is up to integrator to resolve them.
@ -196,67 +171,32 @@ What happens in the case of a delivery failure is up to you as the integrator. I
However, in the scenario where you need to reattempt the delivery, there is a function specifically for this.
```solidity
function redeliveryExample() public payable {
function resendExample() public payable {
//spelling out consts
bytes memory deliveryTxHash = ORIGINATING_TX_HASH
uint16 sourceChain = SOURCE_CHAIN
uint16 targetChain = TARGET_CHAIN
uint16 nonce = SOURCE_NONCE
uint32 gasLimit = 1000000
IWormholeRelayer.VaaKey memory deliveryVaaKey = IWormholeRelayer.VaaKey({
chainId: SOURCE_CHAIN,
emitterAddress: EMITTER_ADDRESS, // address which requested the delivery, in Wormhole bytes32 format (for EVM addresses, left-padded with 12 zeros)
sequence: DELIVERY_SEQUENCE_NUMBER // return value from the send
});
uint16 targetChain = TARGET_CHAIN;
uint256 newReceiverValue = 0;
uint256 newGasLimit = 1000000;
//Note, call quoteGasResend instead of quoteGas.
//The overheads for the two processes differ, so the quotes differ as well.
const newMaxTransactionFee = relayer.quoteGasResend(
TARGET_CHAIN,
gasLimit,
relayer.getDefaultRelayProvider());
//Receiver value calculations do not differ
const receiverValue = relayer.quoteReceiverValue(
(uint256 deliveryCost,) = relayer.quoteEVMDeliveryPrice(
targetChain,
0,
relayer.getDefaultRelayProvider());
IWormholeRelayer.ResendByTx memory redeliveryRequest = IWormholeRelayer.ResendByTx(
sourceChain,
deliveryTxHash,
nonce, //sourceNonce
targetChain,
newMaxTransactionFee, //newMaxTransactionFee
receiverValue, //newReceiverValue
relayer.getDefaultRelayParams() //newRelayParams
newReceiverValue,
newGasLimit
);
relayer.resend{value: newMaxTransactionFee + receiverValue}(
redeliveryRequest, nonce, relayer.getDefaultRelayProvider()
relayer.resendToEvm{value: deliveryCost}(
deliveryVaaKey, targetChain, newReceiverValue, newGasLimit, relayer.getDefaultDeliveryProvider()
);
}
```
The relayer has already paid for the first attempted delivery, so it would not be fair to have them need to pay for the redelivery out-of-pocket. As such, **the requester must pay a second time in order to initiate the redelivery**.
Note: **the requester must pay a second time in order to initiate the redelivery**.
Any delivery or forwarding request can be requested for redelivery, potentially even deliveries which succeeded. The key pieces of information needed for a redelivery are the sourceChain, sourceTxHash, and sourceNonce for the original delivery request, which means you can **request redeliveries from chains other than the chain where the request originated**. This can be useful when performing multi-hop deliveries with forwarding. When requesting a redelivery for a Forward Failure, the transaction hash of the Forwarding transaction should be specified, not the original delivery request.
<br/>
<br/>
<br/>
<br/>
## Max Transaction Fee and Refunds
When you request delivery to an EVM chain, there are effectively three factors which go into the delivery fee.
- A fixed `deliveryOverhead` provided by the RelayProvider, which covers the overhead fees associated with any delivery.
- A predetermined rate at which gas can be pre-purchased on the target chain.
- An exchange rate for `receiverValue`.
On every delivery there is a `refundAddress` specified on the `targetChain`. If the entire `maxTransactionFee` is not exhausted during the execution of `receiveWormholeMessages`, the remaining unused budget will be sent to the `refundAddress`.
For example, let's say that the `maxTransactionFee` for a 500k gas execution on FooChain is equal to 13 fooCoins. If the `deliveryOverhead` is 3 fooCoins, and `receiveWormholeMessages` only uses 250k gas during its execution, then we can expect 5 fooCoins to be sent to the `refundAddress`.
Notably, this means that there is not a penalty for specifying a `maxTransactionFee` which is too large, so long as the RelayProvider has reasonably accurate price quotes. You should generally err on the side of caution when specifying a `maxTransactionFee`, as undershooting results in a Delivery Failure, whereas overshooting just results in a larger refund.
Contrary to `maxTransactionFee`, when specifying a `receiverValue` the RelayProvider will take a percentage of the exchange as specified by the provider. RelayProviders also specify a maximum budget that they will support.
Also note: **Redeliveries must not decrease the original gasLimit, receiverValue, or targetChainRefundPerGasUnused**
<br/>
<br/>
@ -271,11 +211,10 @@ Forwarding is quite similar to a normal 'send' action, however it has a couple s
- Instead of calling `send`, you should call `forward`.
- `forward` can only be called while a delivery is being executed (I.E, during execution of receiveWormholMessages), and can only be called by the contract which is receiving the delivery.
- When a forward is requested, the `refundAddress` of the delivery is ignored, and the refund is instead used to pay for the `maxTransactionFee` and `receiverValue` of the next delivery.
- When a forward is requested, the `refundAddress` of the delivery is ignored, and the refund is instead used to pay for the next delivery.
- You can add supplemental funds to cover the forwarding costs by passing additional tokens in msg.value.
- If the refund amount + supplemental funds do not cover the cost of the delivery, you will encounter a Forward Failure.
- Forward Failures do not revert the previous delivery, but the next delivery is not guaranteed to be performed.
- Forward Failures can be redelivered via the normal redelivery process, however the transaction hash which requested the forward should be used instead of the original delivery transaction hash.
- Forward Failures, just like Receiver Failures, revert the previous delivery
<br/>
<br/>
@ -286,19 +225,15 @@ Forwarding is quite similar to a normal 'send' action, however it has a couple s
### Validating Received Messages
The array of `whMessages` which is passed to `receiveWormholeMessages` are non-validated VAAs. This means _you are responsible for validating these messages_. This is most commonly done by either calling `parseAndVerifyVM` on the Wormhole Core Contract, or by passing the VAA into another contract which will do its own verification. However, this design benefits you quite a few desireable security properties:
The array of `additionalVaas` which is passed to `receiveWormholeMessages` are non-validated VAAs. This means _you are responsible for validating these messages_. This is most commonly done by either calling `parseAndVerifyVM` on the Wormhole Core Contract, or by passing the VAA into another contract which will do its own verification. However, this design benefits you quite a few desireable security properties:
- Relayers are not trusted with message content! If they were to modify the content of a VAA during delivery, it would invalidate the signatures and fail to be verified by the Core Contract. This means relayers are only trusted for **liveness**.
- Relayers are not trusted with payload content! If they were to modify the content of a payload during delivery, it would invalidate the signatures on the delivery VAA, which the WormholeRelayer contract checks before delivering the message. This means, as long as you restrict the receiveWormholeMessage to only be called by the WormholeRelayer contract, relayers are only trusted for **liveness**.
- There are also very few trust assumptions placed on the WormholeRelayer contract. The WormholeRelayer contract only enforces a few protections, such as that refunds are correctly paid out, and that non Batch-VAAs are not handed into the contract.
- There are also very few trust assumptions placed on the WormholeRelayer contract. The WormholeRelayer contract only enforces a few protections, such as that refunds are correctly paid out
However, as always with smart contract development, there are some things you should be aware of:
- The Relay Module is technically in **beta** until Batch VAAs are live in mainnet. While in beta, the selected RelayProvider can potentially reorder, omit, or mix-and-match VAAs if they were to behave maliciously. As such, you will either have to trust your RelayProvider to not do this, or code some relatively straightforward checks to detect this scenario.
- Never trust the content of VAAs which haven't been verified by the Core Contract! Your first line of code should essentially always be a verify statement which ensures the VAA originates from a trusted contract.
- Deliveries can potentially be performed multiple times, and redeliveries for any delivery can be requested by anyone. If you need replay protection on your deliveries, you will have to enforce it yourself. One common methodology for replay protection is simply to compose with `transferWithPayload` from the Token Bridge module. Because this function enforces replay protection, you can often passively leverage this protection for your own application.
- Deliveries can potentially be performed multiple times, and redeliveries for any delivery can be requested by anyone. If you need replay protection on your deliveries, you will have to enforce it yourself. One common methodology for replay protection is simply to store a map of 'deliveryHash' to boolean in your contract state, and check that 'deliveryHash' doesn't already exist in this map.
<br/>
<br/>
@ -309,25 +244,17 @@ However, as always with smart contract development, there are some things you sh
<br />
### Drop a user off with native gas
The most common way to accomplish this is to simply specify a large `maxTransactionFee` with the user's wallet as the `refundAddress`. This can also be done via the `receiverValue`, however the `receiverValue` rates are always equal to or worse than the `maxTransactionFee` rates.
### Safe Round-Trips
A very common scenario for Hub-and-Spoke style applications is to want to round-trip a delivery from a Spoke chain to the Hub chain and then back. In this case, it's generally a good idea to capture a large `maxTransactionFee` and then perform a `forward` from the Hub chain with the end-user's wallet set to the `refundAddress`. Thus the end user is ultimately returned all unused funds.
A very common scenario for Hub-and-Spoke style applications is to want to round-trip a delivery from a Spoke chain to the Hub chain and then back. In this case, it's generally a good idea to set `receiverValue` to be what you expect the price of the second leg of the delivery will be (in Hub-chain currency) and then perform a `forward`, passing in receiverValue as msg.value, from the Hub chain with the end-user's wallet set to the `refundAddress`. Thus the end user is ultimately returned all unused funds.
### Bridging Multiple Tokens
Because the WormholeRelayer can handle delivery of multiple messages, you can call the Token Bridge module multiple times in the same transaction using the same nonce and all the VAAs will be included in the delivery array. This is great for scenarios where an action results in tokens being sent to two different locations, or multiple tokens needing to be sent atomically.
### Broadcasting and Multidelivery
You can request delivery to many chains at once by calling `multichainSend` or `multichainForward`. This is great for accomplishing actions like the delivery of a governance event or any other piece of data which has to be sent to all your contracts. This also allows you to send tokens to multiple addresses on multiple chains from a single transaction.
Because the WormholeRelayer can handle delivery of multiple messages, you can call the Token Bridge module multiple times and have 'vaaKeys' identify the resulting VAAs, and then these VAAs will be included in the delivery array. This is great for scenarios where an action results in tokens being sent to two different locations, or multiple tokens needing to be sent atomically.
### Faster-than-finality transfers
One of the primary features of the WormholeRelayer protocol is that messages can be delivered faster than finality so long as the RelayProvider supports it. Normally the Token Bridge module can only transfer tokens once finality has been reached on a chain. However, with the WormholeRelayer protocol, you could potentially initiate two transfers in the same transaction.
One of the primary features of the WormholeRelayer protocol is that messages can be delivered faster than finality so long as the DeliveryProvider supports it. Normally the Token Bridge module can only transfer tokens once finality has been reached on a chain. However, with the WormholeRelayer protocol, you could potentially initiate two transfers in the same transaction.
- The first transfer sends funds instantly from a liqudity source, so that the end user receives their funds quickly.
- The second transfer sends funds via the Token Bridge to reimburse the liquidity source on the `targetChain`
@ -341,7 +268,7 @@ Beware, the second transfer may never arrive if there is a rollback on the `sour
## Examples
Checkout this [Hello World contract](https://github.com/wormhole-foundation/trustless-generic-relayer/blob/main/ethereum/contracts/mock/MockRelayerIntegration.sol)
Checkout this [Hello World contract](https://github.com/wormhole-foundation/wormhole/blob/generic-relayer-merge/ethereum/contracts/mock/relayer/MockRelayerIntegration.sol)
<br/>