Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snowbridge V2 docs #5902

Merged
merged 13 commits into from
Oct 9, 2024
308 changes: 308 additions & 0 deletions bridges/snowbridge/docs/v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
# Snowbridge V2

This design lowers fees and improves relayer decentralization.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

We're grateful to Adrian Catangui, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and collaboration on this design.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

# Summary

- Unordered messaging
- All messages routed through AH
- Off-chain fee estimation
- P→E Fee Asset: WETH
- E→P Fee Asset: ETH
- Relayer rewards for both directions paid out on AH in WETH

# Polkadot→Ethereum

Given source parachain $S$, with native token $S^{'}$ and the initial xcm $x_0$ to be executed on $S$.

## Step 1: User agent constructs initial XCM

The user agent constructs an initial XCM message $x_0$ that will be executed on S.

The fee amounts in this message should be high enough to enable dry-running, after which they will be lowered.

## Step 2: User agent estimates fees

- Given source parachain $S$, with native token $S^{'}$ and the initial xcm $x_0$ to be executed on $S$.
- The native currency $P^{'}$of the Polkadot relay chain, and $E^{'}$ of Ethereum.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
- Suppose that the user agent chooses relayer reward $r$ in $E^{'}$.
- Suppose that the exchange rates $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to $\beta$ to cover volatility in these rates.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These rates are obtained off-chain and the total fee might be too low if the rates were wrong and beta not enough to cover the difference, right?

I might add a little note here to highlight the importance of getting the correct exchange rates and the consequence of not having them.


Apply the following sequence operations:

1. Dry-run $x_0$ on $S$ to receive xcm $x_1$ and cost $a$ in $S^{'}$
2. Dry-run $x_1$ on AH to receive xcm $x_2$ and cost $b$ in DOT
3. Dry-run $x_2$ on BH to receive command $m$ and cost $c$ in DOT
4. Dry-run $m$ on Ethereum to receive cost $d$ in ETH
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that you previously stated $P^{'}$ and $E^{'}$ were the native currency of Polkadot and Ethereum respectively, should those be used here? Or should we just use DOT and ETH throughout?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mathematical notation was useful for distilling the essence of the algorithm. However I've made it more clear in 495ab69 that DOT and ETH are alternative names.


The final cost to the user in $S^{'}$ is given by

$$
\beta \left(a + \frac{b + c}{K_{P^{'}/S^{'}}} + \frac{d + r}{K_{E^{'}/S^{'}}}\right)
$$

The user agent should perform a final update to xcm $x_0$, substituting the calculated fee amounts.

## Step 3: User agent initiates bridging operation

The user agent calls `pallet_xcm::execute` with the initial xcm $x_0$

```
WithdrawAsset (KLT, 100)
PayFees (KLT, 20)
InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(KLT, 20) dest=AH
ExchangeAsset give=(KLT, 20) want=(WETH, 1)
InitiateAssetsTransfer asset=(KLT, 40) remoteFee=(WETH, 1) dest=Ethereum
DepositAsset (KLT, 40) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```

## Step 4: AH executes message x1

The message $x_1$ is application-specific:

```
ReserveAssetDeposited (KLT, 80)
PayFees (KLT, 20)
SetAssetClaimer Alice
AliasOrigin Alice
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
ExchangeAsset give=(KLT, 20) want=(WETH, 1)
InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum
DepositAsset (KLT, 60) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```

acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```
*ReserveAssetDeposited (KLT, 80)
*PayFees (KLT, 20)
*SetAssetClaimer Alice
*AliasOrigin Alice
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
ExchangeAsset give=(KLT, 20) want=(WETH, 1)
InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum
DepositAsset (KLT, 60) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
Transact Bob.hello()
```

In all cases, $x_1$ should contain the necessary instructions to:

1. Pay fees for local execution using `PaysFees`
2. Obtain WETH for remote delivery fees.

The `SovereignPaidExporter` on AH will charge a small fee to prevent spamming BH with bridge messages. This is necessary since the `ExportMessage` instruction in message $x_2$ will have no execution fee on BH. For a similar reason, we should also impose a minimum relayer reward of at least the existential deposit 0.1 DOT, which acts as a deposit to stop spamming messages with 0 rewards.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

## Step 5: BH executes message x2

Message $x_2$ is parsed by the `SnowbridgeMessageExporter` with the following effects:

- A bridge command $m$ is committed to MMR structure $M$.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
- The transferred asset is parsed from `ReserveAssetDeposited` , `WithdrawAsset` or `TeleportedAssetReceived` instructions for the local, destination and teleport asset transfer types respectively.
- The original origin is preserved in the `AliasOrigin` instruction. This will allow us to resolve agents for the case of `Transact`.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
- The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiplier `Transacts`.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
- The Message Exporter must be able to support multiple Deposited Assets.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
- The Message Exporter must be able to parse `SetAssetClaimer` and allow the provided location to claim the assets on BH in case of errors.
- Given relayer reward $r$, set storage $P(\mathrm{hash}(m)) = r$. This is parsed from the `WithdrawAsset` and `PayFees` instruction.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is m unique? In order for this to identify the message and not just a command that can repeat itself. I think there was a nonce, right?


```
!WithdrawAsset(DOT, 10)
!PayFees (DOT, 10)
!ExportMessage dest=Ethereum
*ReserveAssetDeposited (KLT, 60)
*WithdrawAsset (WETH, 1)
*PayFees (WETH, 1)
*SetAssetClaimer Alice
*AliasOrigin Alice
DepositAsset (KLT, 60) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```

acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```
!WithdrawAsset(DOT, 10)
!PayFees (DOT, 10)
!ExportMessage dest=Ethereum
*ReserveAssetDeposited (KLT, 80)
*PayFees (KLT, 20)
*SetAssetClaimer Alice
*AliasOrigin Alice
DepositAsset (KLT, 60) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
Transact Bob.hello()
```

## Step 6: Relayer relays message to Gateway

1. A relayer *Charlie* inspects storage $P$ to look for new messages to relay. Suppose it finds $\mathrm{hash}(m)$ giving reward $r$.
2. The relayer queries from m from M and constructs the necessary proofs.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
3. The relayer dry-runs m on Ethereum to decide whether the message is profitable to deliver.
4. The relayer finally delivers the message together with an relayer-controlled address $u$ on AH where the relayer reward will be lazily deposited.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

## Step 7: Relayer delivers proof of delivery to BH

The proof of delivery is essentially a merkle proof for the `InboundMessageAccepted` event log.

When BH processes the proof of delivery:

1. The command $m$ is removed from storage items $M$ and $P$.
2. The relayer reward is tracked in storage $R$, where $R(u)$ is the accumulated rewards that can be claimed by account $u$.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

# Ethereum→Polkadot

## Step 1: Submit send on Gateway

The interface that the Gateway will use to initiate transfers will copy the interface from `transfer_assets_using_type_and_then` extrinsic that we currently use to initiate transfers from the Polkadot to Ethereum direction.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

1. It must allow multiple assets to be transferred and specify the transfer type: Local, Destination or Teleport asset transfer types. It is the job of the User Agent/UX layer to fill in this information correctly.
2. It must allow specifying a destination which is `Address32` , `Address20` or a custom scale-encoded XCM payload that is executed on the destination. This is how we will support `Transact` , the User Agent/UX layer can build a scale-encoded payload with an encoded transact call.
3. The same interface is used for both PNA and ERC20 tokens. Internally we will still look up whether the token is registered as a PNA or ERC20 for the purpose of minting/locking burning/unlocking logic. The asset transfer type chosen by the UX layer will inform the XCM that is built from the message on BH.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

```solidity
enum Kind {
Index,
Address32,
Address20,
XCMPayload,
}

struct Beneficiary {
Kind kind;
bytes data;
}

enum AssetTransferType {
LocalReserve, DestinationReserve, Teleport
}
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

struct Token {
AssetTransferType type;
address token;
uint128 amount;
}

function send(
ParaID destinationChain,
Beneficiary calldata beneficiary,
Token[] tokens,
uint128 reward) external payable;
```

Message enqueued $m_0$:

```solidity
send(
3022, // KILT Para Id
Address32(0x0000....),
[
(DestinationReserve, KLT, 100)
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
],
10, // WETH
)
```

```solidity
send { value: 3 }( // Send 3 Eth for fees and reward
3022, // KILT Para Id
XCMPayload(
DepositAsset (KLT, 100) dest=Bob
Transact Bob.hello()
),
[
(DestinationReserve, KLT, 100)
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
],
1, // 1 ETH of 3 needs to be for the reward, the rest is for fees
)
```

The User Agent/UX layer will need to estimate the fee required to be passed into the `send` method. This may be an issue as we cannot Dry-Run something on Polkadot that has not even been submitted on Ethereum yet. We may need to make RPC API to DryRun and get back the xcm that would be submitted to asset hub.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

## Step 2: Relayer relays message to Bridge Hub

Exchange rate is eliminated. Users pay remote delivery costs in ETH, and this amount is sent with the message as WETH. The delivery fee can be claimed by the relayer on BH.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

The user agent applies a similar dry-running process as with [Step 2: User agent estimates fees](https://www.notion.so/Step-2-User-agent-estimates-fees-113296aaabef8159bcd0e6dd2e64c3d0?pvs=21).

The message is converted from $m_0$ to $x_0$ during message submission on BH. Dry-running submission will return $x_0$ to the relayer so that it can verify it is profitable.

## Step 3: AH receives $x_0$ from BH

Submitting the message $m_0$ will cause the following XCM, $x_0$, to be built on BH and dispatched to AH.

```
WithdrawAsset (KLT, 100)
ReserveAssetDeposited(WETH, 2)
PayFees (WETH, 1)
SetAssetClaimer Bob // derived from beneficiary
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
AliasOrigin Ethereum/Alice // derived from msg.sender
InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT
DepositAsset (KLT, 100) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```

```
WithdrawAsset (KLT, 100)
ReserveAssetDeposited(WETH, 2)
PayFees (WETH, 1)
SetAssetClaimer Ethereum/Alice // derived from beneficiary
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
AliasOrigin Ethereum/Alice // derived from msg.sender
InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT
DepositAsset (KLT, 100) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
Transact Bob.hello()
```

## Step 4: KILT Receives XCM from AH

The flowing XCM $x_1$ is received from BH on AH.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

```
*WithdrawAsset (KLT, 100)
*ReserveAssetDeposited (WETH, 1)
*PayFees (WETH, 1)
*SetAssetClaimer Bob
*AliasOrigin Ethereum/Alice // origin preserved from AH
DepositAsset (KLT, 100) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
```

```
*WithdrawAsset (KLT, 100)
*ReserveAssetDeposited (WETH, 1)
*PayFees (WETH, 1)
*SetAssetClaimer Bob
*AliasOrigin Ethereum/Alice // origin preserved from AH
DepositAsset (KLT, 100) dest=Bob
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
Transact Bob.hello() // executes with the origin from AH
```

# Relayer Rewards

The tracking and disbursement of relayer rewards for both directions has been unified. Rewards in WETH are accumulated on BH but must be manually claimed to deposit them into an account.

To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will be paid out.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This o has to be the same u as described previously, right? That way we know they're able to claim these rewards. I'd add that here if that's the case.


$$
\mathrm{claim}(o,w)
$$

For tax accounting purposes might be desirable that $o \neq w$.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

# Top-Up

Top-up on the destination is viable to implement.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

## Origin Preservation

Origins for transact will be preserved by use of the `AliasOrigin` instruction. This instruction will have the following rules that parachain runtimes will need to allow:

1. `AliasOrigin` can behave like `DescendOrigin`. This is allowed because it respects the hierarchy of multi-locations and does not allow jumping up.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
1. Example location `Ethereum` can alias into `Ethereum/Alice` because we are descending in origin and this essentially is how the `DescendOrigin` instruction works.
2. `AliasOrigin` must allow AH to alias into bridged locations such as `{ parents: 2, interior: GlobalConsensus(Ethereum) }` so that AH can act as a proxy for the bridge on parachains.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
acatangiu marked this conversation as resolved.
Show resolved Hide resolved

`AliasOrigin` will be inserted by every `InitiateAssetTransfer` instruction on the source parachain, populated with the contents of the origin register, essentially forwarding the origin of the source to the destination.

RFCS:

[https://github.com/polkadot-fellows/RFCs/pull/122](https://github.com/polkadot-fellows/RFCs/pull/122)

[https://github.com/polkadot-fellows/RFCs/blob/main/text/0100-xcm-multi-type-asset-transfer.md](https://github.com/polkadot-fellows/RFCs/blob/main/text/0100-xcm-multi-type-asset-transfer.md)

## Parachain Requirements

1. Pallet-xcm.execute enabled.
2. XCM payment dry run apis.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
3. Must accept WETH needed for fees.
acatangiu marked this conversation as resolved.
Show resolved Hide resolved
4. AH as a reserve for bridged assets.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses.
Loading