From 53272b6be3cedb3e51ba2eb0a5ffac8e0c3dd55c Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 2 Oct 2024 11:37:53 +0200 Subject: [PATCH 01/11] Migrate V2 design doc from Notion --- bridges/snowbridge/docs/v2.md | 306 ++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 bridges/snowbridge/docs/v2.md diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md new file mode 100644 index 000000000000..e6fab5c7f989 --- /dev/null +++ b/bridges/snowbridge/docs/v2.md @@ -0,0 +1,306 @@ +# Design #3 (Migrate to GH) + +This design evolved from [Design #1](https://www.notion.so/Design-1-56345d54e826410f9f7e64ec14dac99d?pvs=21) along with feedback from Parity at the XCM workshop. + +# 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. +- 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. + +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 + +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 +``` + +## Step 4: AH executes message x1 + +The message $x_1$ is application-specific: + +``` +ReserveAssetDeposited (KLT, 80) +PayFees (KLT, 20) +SetAssetClaimer Alice +AliasOrigin Alice +ExchangeAsset give=(KLT, 20) want=(WETH, 1) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 60) dest=Bob +``` + +``` +*ReserveAssetDeposited (KLT, 80) +*PayFees (KLT, 20) +*SetAssetClaimer Alice +*AliasOrigin Alice +ExchangeAsset give=(KLT, 20) want=(WETH, 1) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 60) dest=Bob + 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. + +## 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$. + - 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`. + - The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiplier `Transacts`. + - The Message Exporter must be able to support multiple Deposited Assets. + - 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. + +``` +!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 +``` + +``` +!WithdrawAsset(DOT, 10) +!PayFees (DOT, 10) +!ExportMessage dest=Ethereum + *ReserveAssetDeposited (KLT, 80) + *PayFees (KLT, 20) + *SetAssetClaimer Alice + *AliasOrigin Alice + DepositAsset (KLT, 60) dest=Bob + 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. +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. + +## 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$. + +# 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. + +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. + +```solidity +enum Kind { + Index, + Address32, + Address20, + XCMPayload, +} + +struct Beneficiary { + Kind kind; + bytes data; +} + +enum AssetTransferType { + LocalReserve, DestinationReserve, Teleport +} + +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) + ], + 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) + ], + 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. + +## 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. + +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 +AliasOrigin Ethereum/Alice // derived from msg.sender +InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT + DepositAsset (KLT, 100) dest=Bob +``` + +``` +WithdrawAsset (KLT, 100) +ReserveAssetDeposited(WETH, 2) +PayFees (WETH, 1) +SetAssetClaimer Ethereum/Alice // derived from beneficiary +AliasOrigin Ethereum/Alice // derived from msg.sender +InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT + DepositAsset (KLT, 100) dest=Bob + Transact Bob.hello() +``` + +## Step 4: KILT Receives XCM from AH + +The flowing XCM $x_1$ is received from BH on AH. + +``` +*WithdrawAsset (KLT, 100) +*ReserveAssetDeposited (WETH, 1) +*PayFees (WETH, 1) +*SetAssetClaimer Bob +*AliasOrigin Ethereum/Alice // origin preserved from AH +DepositAsset (KLT, 100) dest=Bob +``` + +``` +*WithdrawAsset (KLT, 100) +*ReserveAssetDeposited (WETH, 1) +*PayFees (WETH, 1) +*SetAssetClaimer Bob +*AliasOrigin Ethereum/Alice // origin preserved from AH +DepositAsset (KLT, 100) dest=Bob +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. + +$$ +\mathrm{claim}(o,w) +$$ + +For tax accounting purposes might be desirable that $o \neq w$. + +# Top-Up + +Top-up on the destination is viable to implement. + +## 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. + 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. + +`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. +3. Must accept WETH needed for fees. +4. AH as a reserve for bridged assets. +5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses. From 86d9c29a69e8919f1cbebe84184590303afd05b8 Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:05:30 +0200 Subject: [PATCH 02/11] Add V2 docs --- bridges/snowbridge/docs/v2.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index e6fab5c7f989..838bd157d54d 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -1,6 +1,8 @@ -# Design #3 (Migrate to GH) +# Snowbridge V2 -This design evolved from [Design #1](https://www.notion.so/Design-1-56345d54e826410f9f7e64ec14dac99d?pvs=21) along with feedback from Parity at the XCM workshop. +This design lowers fees and improves relayer decentralization. + +We're grateful to Adrian Catangui, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and collaboration on this design. # Summary From 6c8df9bcf68a3c9a3e67b721c23c8ab690e97854 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 2 Oct 2024 15:56:57 +0300 Subject: [PATCH 03/11] XCM Adjustments --- bridges/snowbridge/docs/v2.md | 80 ++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index 838bd157d54d..6866d52a2d88 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -1,8 +1,8 @@ # Snowbridge V2 -This design lowers fees and improves relayer decentralization. +This design lowers fees, improves UX, improves relayer decentralization and allows "transacting" over the bridge, making it a general-purpose bridge rather than just a token bridge. -We're grateful to Adrian Catangui, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and collaboration on this design. +We're grateful to Adrian Catangiu, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and collaboration on this design. # Summary @@ -26,7 +26,7 @@ The fee amounts in this message should be high enough to enable dry-running, aft ## 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. +- The native currency $P^{'}$ of the Polkadot relay chain, and $E^{'}$ of Ethereum. - 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. @@ -53,9 +53,9 @@ 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) + ExchangeAsset give=(KLT, 20) want=(WETH, 1) InitiateAssetsTransfer asset=(KLT, 40) remoteFee=(WETH, 1) dest=Ethereum - DepositAsset (KLT, 40) dest=Bob + DepositAsset (KLT, 40) beneficiary=Bob ``` ## Step 4: AH executes message x1 @@ -65,21 +65,21 @@ The message $x_1$ is application-specific: ``` ReserveAssetDeposited (KLT, 80) PayFees (KLT, 20) -SetAssetClaimer Alice -AliasOrigin Alice +SetAssetClaimer Kilt/Alice +AliasOrigin Kilt/Alice ExchangeAsset give=(KLT, 20) want=(WETH, 1) InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum - DepositAsset (KLT, 60) dest=Bob + DepositAsset (KLT, 60) beneficiary=Bob ``` - +or ``` *ReserveAssetDeposited (KLT, 80) *PayFees (KLT, 20) -*SetAssetClaimer Alice -*AliasOrigin Alice +*SetAssetClaimer Kilt/Alice +*AliasOrigin Kilt/Alice ExchangeAsset give=(KLT, 20) want=(WETH, 1) InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum - DepositAsset (KLT, 60) dest=Bob + DepositAsset (KLT, 60) beneficiary=Bob Transact Bob.hello() ``` @@ -88,7 +88,7 @@ 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. +The XCM bridge-router 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. ## Step 5: BH executes message x2 @@ -96,8 +96,8 @@ Message $x_2$ is parsed by the `SnowbridgeMessageExporter` with the following ef - A bridge command $m$ is committed to MMR structure $M$. - 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`. - - The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiplier `Transacts`. + - The original origin is preserved through the `AliasOrigin` instruction. This will allow us to resolve agents for the case of `Transact`. + - The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiple `Transacts`. - The Message Exporter must be able to support multiple Deposited Assets. - 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. @@ -109,29 +109,29 @@ Message $x_2$ is parsed by the `SnowbridgeMessageExporter` with the following ef *ReserveAssetDeposited (KLT, 60) *WithdrawAsset (WETH, 1) *PayFees (WETH, 1) - *SetAssetClaimer Alice - *AliasOrigin Alice - DepositAsset (KLT, 60) dest=Bob + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob ``` - +or ``` !WithdrawAsset(DOT, 10) !PayFees (DOT, 10) !ExportMessage dest=Ethereum *ReserveAssetDeposited (KLT, 80) *PayFees (KLT, 20) - *SetAssetClaimer Alice - *AliasOrigin Alice - DepositAsset (KLT, 60) dest=Bob + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob 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. +2. The relayer queries $m$ from $M$ and constructs the necessary proofs. 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. +4. The relayer finally delivers the message together with a relayer-controlled address $u$ on AH where the relayer reward will be lazily deposited. ## Step 7: Relayer delivers proof of delivery to BH @@ -146,11 +146,11 @@ When BH processes the proof of delivery: ## 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. +The interface that the Gateway will use to initiate transfers will be similar to the interface from `transfer_assets_using_type_and_then` extrinsic that we currently use to initiate transfers from the Polkadot to Ethereum direction. 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. +3. The same interface is used for both PNA (Polkadot Assets) 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. ```solidity enum Kind { @@ -166,7 +166,7 @@ struct Beneficiary { } enum AssetTransferType { - LocalReserve, DestinationReserve, Teleport + ReserveDeposit, ReserveWithdraw, Teleport } struct Token { @@ -189,7 +189,7 @@ send( 3022, // KILT Para Id Address32(0x0000....), [ - (DestinationReserve, KLT, 100) + (ReserveWithdraw, KLT, 100) ], 10, // WETH ) @@ -203,7 +203,7 @@ send { value: 3 }( // Send 3 Eth for fees and reward Transact Bob.hello() ), [ - (DestinationReserve, KLT, 100) + (ReserveWithdraw, KLT, 100) ], 1, // 1 ETH of 3 needs to be for the reward, the rest is for fees ) @@ -213,7 +213,7 @@ The User Agent/UX layer will need to estimate the fee required to be passed into ## 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. +On-chain 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. 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). @@ -230,7 +230,7 @@ PayFees (WETH, 1) SetAssetClaimer Bob // derived from beneficiary AliasOrigin Ethereum/Alice // derived from msg.sender InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT - DepositAsset (KLT, 100) dest=Bob + DepositAsset (KLT, 100) beneficiary=Bob ``` ``` @@ -240,30 +240,32 @@ PayFees (WETH, 1) SetAssetClaimer Ethereum/Alice // derived from beneficiary AliasOrigin Ethereum/Alice // derived from msg.sender InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT - DepositAsset (KLT, 100) dest=Bob + DepositAsset (KLT, 100) beneficiary=Bob Transact Bob.hello() ``` ## Step 4: KILT Receives XCM from AH -The flowing XCM $x_1$ is received from BH on AH. +The following XCM $x_1$ is received from BH on AH. ``` *WithdrawAsset (KLT, 100) *ReserveAssetDeposited (WETH, 1) *PayFees (WETH, 1) -*SetAssetClaimer Bob +*SetAssetClaimer Ethereum/Alice *AliasOrigin Ethereum/Alice // origin preserved from AH -DepositAsset (KLT, 100) dest=Bob +SetAssetClaimer Bob +DepositAsset (KLT, 100) beneficiary=Bob ``` ``` *WithdrawAsset (KLT, 100) *ReserveAssetDeposited (WETH, 1) *PayFees (WETH, 1) -*SetAssetClaimer Bob +*SetAssetClaimer Ethereum/Alice *AliasOrigin Ethereum/Alice // origin preserved from AH -DepositAsset (KLT, 100) dest=Bob +SetAssetClaimer Bob +DepositAsset (KLT, 100) beneficiary=Bob Transact Bob.hello() // executes with the origin from AH ``` @@ -277,11 +279,11 @@ $$ \mathrm{claim}(o,w) $$ -For tax accounting purposes might be desirable that $o \neq w$. +For tax accounting purposes it might be desirable that $o \neq w$. # Top-Up -Top-up on the destination is viable to implement. +Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub, respectively Ethereum. ## Origin Preservation From d0521bd6ae85a6f4ce2041678b19697f8a15e993 Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:01:38 +0200 Subject: [PATCH 04/11] Apply suggestions from code review Co-authored-by: Francisco Aguirre Co-authored-by: Adrian Catangiu Co-authored-by: Alistair Singh --- bridges/snowbridge/docs/v2.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index 6866d52a2d88..a8eb0fb47bb5 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -131,7 +131,7 @@ or 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 $m$ from $M$ and constructs the necessary proofs. 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 a relayer-controlled address $u$ on AH where the relayer reward will be lazily deposited. +4. The relayer finally delivers the message together with a relayer-controlled address $u$ on AH where the relayer can claim their reward after proof of delivery. ## Step 7: Relayer delivers proof of delivery to BH @@ -227,7 +227,7 @@ Submitting the message $m_0$ will cause the following XCM, $x_0$, to be built on WithdrawAsset (KLT, 100) ReserveAssetDeposited(WETH, 2) PayFees (WETH, 1) -SetAssetClaimer Bob // derived from beneficiary +SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination AliasOrigin Ethereum/Alice // derived from msg.sender InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT DepositAsset (KLT, 100) beneficiary=Bob @@ -237,7 +237,7 @@ InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT WithdrawAsset (KLT, 100) ReserveAssetDeposited(WETH, 2) PayFees (WETH, 1) -SetAssetClaimer Ethereum/Alice // derived from beneficiary +SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination AliasOrigin Ethereum/Alice // derived from msg.sender InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT DepositAsset (KLT, 100) beneficiary=Bob @@ -246,7 +246,7 @@ InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT ## Step 4: KILT Receives XCM from AH -The following XCM $x_1$ is received from BH on AH. +The following XCM $x_1$ is received from AH on KILT. ``` *WithdrawAsset (KLT, 100) @@ -283,15 +283,15 @@ For tax accounting purposes it might be desirable that $o \neq w$. # Top-Up -Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub, respectively Ethereum. +Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub and Ethereum respectively. ## 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. +1. `AliasOrigin` can behave like `DescendOrigin`. This is safe because it respects the hierarchy of multi-locations and does not allow jumping up. Meaning no escalation of privileges. 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. +2. `AliasOrigin` must allow AH to alias into bridged locations such as `{ parents: 2, interior: GlobalConsensus(Ethereum) }` and all of its internal locations so that AH can act as a proxy for the bridge on parachains. `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. @@ -304,7 +304,7 @@ RFCS: ## Parachain Requirements 1. Pallet-xcm.execute enabled. -2. XCM payment dry run apis. +2. XCM payment and dry run apis implemented. 3. Must accept WETH needed for fees. -4. AH as a reserve for bridged assets. +4. Trust AH as a reserve for bridged assets. 5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses. From b21e5be30f59590bd653a07c6ee10882801c125f Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:02:36 +0200 Subject: [PATCH 05/11] Apply suggestions from code review Co-authored-by: Francisco Aguirre --- bridges/snowbridge/docs/v2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index a8eb0fb47bb5..e59221d85e38 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -28,7 +28,7 @@ The fee amounts in this message should be high enough to enable dry-running, aft - 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. - 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. +- Suppose that the exchange rates are $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to $\beta$ to cover volatility in these rates. Apply the following sequence operations: From 495ab69b2f352a1f8af05b01dc36bd4df811eadc Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:06:16 +0200 Subject: [PATCH 06/11] currency symbols --- bridges/snowbridge/docs/v2.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index e59221d85e38..a065ff540741 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -26,16 +26,16 @@ The fee amounts in this message should be high enough to enable dry-running, aft ## 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. +- The native currency $P^{'}$ (DOT) of the Polkadot relay chain, and $E^{'}$ (ETH) of Ethereum. - Suppose that the user agent chooses relayer reward $r$ in $E^{'}$. - Suppose that the exchange rates are $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to $\beta$ to cover volatility in these rates. 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 +2. Dry-run $x_1$ on AH to receive xcm $x_2$ and cost $b$ in $P^{'}$ (DOT) +3. Dry-run $x_2$ on BH to receive command $m$ and cost $c$ in $P^{'}$ (DOT) +4. Dry-run $m$ on Ethereum to receive cost $d$ in $E^{'}$ (ETH) The final cost to the user in $S^{'}$ is given by From dc7d01a83a515b4e99545d15b8f068e696788ea9 Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:22:44 +0200 Subject: [PATCH 07/11] Make rewards claiming more clear --- bridges/snowbridge/docs/v2.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index a065ff540741..42d5a92574d4 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -83,6 +83,8 @@ InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum Transact Bob.hello() ``` +Note that the `SetAssetClaimer` instruction is placed before `AliasOrigin` in case AH fails to interpret the latter instruction. + In all cases, $x_1$ should contain the necessary instructions to: 1. Pay fees for local execution using `PaysFees` @@ -271,9 +273,9 @@ 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. +The tracking and disbursement of relayer rewards for both directions has been unified. Rewards are accumulated on BH in WETH and must be manually claimed. As part of the claims flow, an XCM instruction is sent to AH to mint the WETH into the deposit account chosen by the relayer. -To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will be paid out. +To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will be minted. $$ \mathrm{claim}(o,w) From 791aaf3583592aa36cb856fafe6eb828291b538e Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:34:30 +0200 Subject: [PATCH 08/11] note --- bridges/snowbridge/docs/v2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index 42d5a92574d4..54c1203fe739 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -307,6 +307,6 @@ RFCS: 1. Pallet-xcm.execute enabled. 2. XCM payment and dry run apis implemented. -3. Must accept WETH needed for fees. +3. Must accept WETH needed for fees. Though in future user agents can inject `ExchangeAsset` instructions to obtain WETH. 4. Trust AH as a reserve for bridged assets. 5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses. From 1c0c9f0481034ccbe1d06b9804f8fd894f270467 Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:03:55 +0200 Subject: [PATCH 09/11] Update docs --- bridges/snowbridge/docs/v2.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index 54c1203fe739..3882cd75fd79 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -96,13 +96,15 @@ The XCM bridge-router on AH will charge a small fee to prevent spamming BH with Message $x_2$ is parsed by the `SnowbridgeMessageExporter` with the following effects: -- A bridge command $m$ is committed to MMR structure $M$. +- A bridge command $m$ is committed to binary merkle tree $M_n$, where `n` is the current block number. - 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 through the `AliasOrigin` instruction. This will allow us to resolve agents for the case of `Transact`. - The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiple `Transacts`. - The Message Exporter must be able to support multiple Deposited Assets. - 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. +- Given relayer reward $r$ in WETH, set storage $P(\mathrm{hash}(m)) = r$. This is parsed from the `WithdrawAsset` and `PayFees` instruction within `ExportMessage`. + +Note that WETH on AH & BH is a wrapped derivative of the [WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) ERC20 contract on Ethereum, which is itself a wrapper over ETH, the native currency of Ethereum. For the purposes of this document you can consider them all to be of equivalent value. ``` !WithdrawAsset(DOT, 10) From b90b07d9af95816d2fb505e1e675b2dbbde99d87 Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:13:15 +0200 Subject: [PATCH 10/11] clarify per-block merkle trees --- bridges/snowbridge/docs/v2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index 3882cd75fd79..ded0afeb9e2f 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -94,9 +94,9 @@ The XCM bridge-router on AH will charge a small fee to prevent spamming BH with ## Step 5: BH executes message x2 -Message $x_2$ is parsed by the `SnowbridgeMessageExporter` with the following effects: +Message $x_2$ is parsed by the `SnowbridgeMessageExporter` in block $n$ with the following effects: -- A bridge command $m$ is committed to binary merkle tree $M_n$, where `n` is the current block number. +- A bridge command $m$ is committed to binary merkle tree $M_n$. - 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 through the `AliasOrigin` instruction. This will allow us to resolve agents for the case of `Transact`. - The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiple `Transacts`. From 7f10dd4ad395afb38cfb776d6bc6155855dd9eee Mon Sep 17 00:00:00 2001 From: Vincent Geddes <117534+vgeddes@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:07:32 +0200 Subject: [PATCH 11/11] lint/format --- bridges/snowbridge/docs/v2.md | 248 ++++++++++++++++++++-------------- 1 file changed, 145 insertions(+), 103 deletions(-) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md index ded0afeb9e2f..8ec440c47cec 100644 --- a/bridges/snowbridge/docs/v2.md +++ b/bridges/snowbridge/docs/v2.md @@ -1,10 +1,12 @@ # Snowbridge V2 -This design lowers fees, improves UX, improves relayer decentralization and allows "transacting" over the bridge, making it a general-purpose bridge rather than just a token bridge. +This design lowers fees, improves UX, improves relayer decentralization and allows "transacting" over the bridge, making +it a general-purpose bridge rather than just a token bridge. -We're grateful to Adrian Catangiu, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and collaboration on this design. +We're grateful to Adrian Catangiu, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and +collaboration on this design. -# Summary +## Summary - Unordered messaging - All messages routed through AH @@ -13,22 +15,23 @@ We're grateful to Adrian Catangiu, Francisco Aguirre, and others from the Parity - E→P Fee Asset: ETH - Relayer rewards for both directions paid out on AH in WETH -# Polkadot→Ethereum +## 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 +### 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 +### 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^{'}$ (DOT) of the Polkadot relay chain, and $E^{'}$ (ETH) of Ethereum. - Suppose that the user agent chooses relayer reward $r$ in $E^{'}$. -- Suppose that the exchange rates are $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to $\beta$ to cover volatility in these rates. +- Suppose that the exchange rates are $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to + $\beta$ to cover volatility in these rates. Apply the following sequence operations: @@ -45,116 +48,142 @@ $$ The user agent should perform a final update to xcm $x_0$, substituting the calculated fee amounts. -## Step 3: User agent initiates bridging operation +### Step 3: User agent initiates bridging operation The user agent calls `pallet_xcm::execute` with the initial xcm $x_0$ -``` +```text 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) beneficiary=Bob + ExchangeAsset give=(KLT, 20) want=(WETH, 1) + InitiateAssetsTransfer asset=(KLT, 40) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 40) beneficiary=Bob ``` -## Step 4: AH executes message x1 +### Step 4: AH executes message x1 The message $x_1$ is application-specific: -``` +```text ReserveAssetDeposited (KLT, 80) PayFees (KLT, 20) SetAssetClaimer Kilt/Alice AliasOrigin Kilt/Alice ExchangeAsset give=(KLT, 20) want=(WETH, 1) InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum - DepositAsset (KLT, 60) beneficiary=Bob + DepositAsset (KLT, 60) beneficiary=Bob ``` + or -``` + +```text *ReserveAssetDeposited (KLT, 80) *PayFees (KLT, 20) *SetAssetClaimer Kilt/Alice *AliasOrigin Kilt/Alice ExchangeAsset give=(KLT, 20) want=(WETH, 1) InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum - DepositAsset (KLT, 60) beneficiary=Bob - Transact Bob.hello() + DepositAsset (KLT, 60) beneficiary=Bob + Transact Bob.hello() ``` -Note that the `SetAssetClaimer` instruction is placed before `AliasOrigin` in case AH fails to interpret the latter instruction. +Note that the `SetAssetClaimer` instruction is placed before `AliasOrigin` in case AH fails to interpret the latter +instruction. 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 XCM bridge-router 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. +The XCM bridge-router 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. -## Step 5: BH executes message x2 +### Step 5: BH executes message x2 Message $x_2$ is parsed by the `SnowbridgeMessageExporter` in block $n$ with the following effects: - A bridge command $m$ is committed to binary merkle tree $M_n$. - - 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 through the `AliasOrigin` instruction. This will allow us to resolve agents for the case of `Transact`. - - The message exporter must be able to support multiple assets and reserve types in the same message and potentially multiple `Transacts`. - - The Message Exporter must be able to support multiple Deposited Assets. - - 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$ in WETH, set storage $P(\mathrm{hash}(m)) = r$. This is parsed from the `WithdrawAsset` and `PayFees` instruction within `ExportMessage`. - -Note that WETH on AH & BH is a wrapped derivative of the [WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) ERC20 contract on Ethereum, which is itself a wrapper over ETH, the native currency of Ethereum. For the purposes of this document you can consider them all to be of equivalent value. - -``` + - 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 through the `AliasOrigin` instruction. This will allow us to resolve agents for the + case of `Transact`. + - The message exporter must be able to support multiple assets and reserve types in the same message and potentially + multiple `Transacts`. + - The Message Exporter must be able to support multiple Deposited Assets. + - 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$ in WETH, set storage $P(\mathrm{hash}(m)) = r$. This is parsed from the `WithdrawAsset` and + `PayFees` instruction within `ExportMessage`. + +Note that WETH on AH & BH is a wrapped derivative of the +[WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) ERC20 contract on Ethereum, which is +itself a wrapper over ETH, the native currency of Ethereum. For the purposes of this document you can consider them all +to be of equivalent value. + +```text !WithdrawAsset(DOT, 10) !PayFees (DOT, 10) !ExportMessage dest=Ethereum - *ReserveAssetDeposited (KLT, 60) - *WithdrawAsset (WETH, 1) - *PayFees (WETH, 1) - *SetAssetClaimer Kilt/Alice - *AliasOrigin Kilt/Alice - DepositAsset (KLT, 60) beneficiary=Bob + *ReserveAssetDeposited (KLT, 60) + *WithdrawAsset (WETH, 1) + *PayFees (WETH, 1) + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob ``` + or -``` + +```text !WithdrawAsset(DOT, 10) !PayFees (DOT, 10) !ExportMessage dest=Ethereum - *ReserveAssetDeposited (KLT, 80) - *PayFees (KLT, 20) - *SetAssetClaimer Kilt/Alice - *AliasOrigin Kilt/Alice - DepositAsset (KLT, 60) beneficiary=Bob - Transact Bob.hello() + *ReserveAssetDeposited (KLT, 80) + *PayFees (KLT, 20) + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob + Transact Bob.hello() ``` -## Step 6: Relayer relays message to Gateway +### 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$. +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 $m$ from $M$ and constructs the necessary proofs. 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 a relayer-controlled address $u$ on AH where the relayer can claim their reward after proof of delivery. +4. The relayer finally delivers the message together with a relayer-controlled address $u$ on AH where the relayer can + claim their reward after proof of delivery. -## Step 7: Relayer delivers proof of delivery to BH +### 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$. +2. The relayer reward is tracked in storage $R$, where $R(u)$ is the accumulated rewards that can be claimed by account + $u$. -# Ethereum→Polkadot +## Ethereum→Polkadot -## Step 1: Submit send on Gateway +### Step 1: Submit send on Gateway -The interface that the Gateway will use to initiate transfers will be similar to the interface from `transfer_assets_using_type_and_then` extrinsic that we currently use to initiate transfers from the Polkadot to Ethereum direction. +The interface that the Gateway will use to initiate transfers will be similar to the interface from +`transfer_assets_using_type_and_then` extrinsic that we currently use to initiate transfers from the Polkadot to +Ethereum direction. -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 (Polkadot Assets) 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. +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 (Polkadot Assets) 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. ```solidity enum Kind { @@ -170,89 +199,91 @@ struct Beneficiary { } enum AssetTransferType { - ReserveDeposit, ReserveWithdraw, Teleport + ReserveDeposit, ReserveWithdraw, Teleport } struct Token { - AssetTransferType type; - address token; - uint128 amount; + AssetTransferType type; + address token; + uint128 amount; } function send( ParaID destinationChain, Beneficiary calldata beneficiary, - Token[] tokens, - uint128 reward) external payable; + Token[] tokens, + uint128 reward +) external payable; ``` Message enqueued $m_0$: ```solidity send( - 3022, // KILT Para Id - Address32(0x0000....), - [ - (ReserveWithdraw, KLT, 100) - ], - 10, // WETH - ) + 3022, // KILT Para Id + Address32(0x0000....), + [(ReserveWithdraw, KLT, 100)], + 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() - ), - [ - (ReserveWithdraw, KLT, 100) - ], - 1, // 1 ETH of 3 needs to be for the reward, the rest is for fees - ) + 3022, // KILT Para Id + XCMPayload( + DepositAsset (KLT, 100) dest=Bob + Transact Bob.hello() + ), + [(ReserveWithdraw, KLT, 100)], + 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. +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. -## Step 2: Relayer relays message to Bridge Hub +### Step 2: Relayer relays message to Bridge Hub -On-chain 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. +On-chain 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. -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 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. +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 +### 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. -``` +```text WithdrawAsset (KLT, 100) ReserveAssetDeposited(WETH, 2) PayFees (WETH, 1) SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination AliasOrigin Ethereum/Alice // derived from msg.sender InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT - DepositAsset (KLT, 100) beneficiary=Bob + DepositAsset (KLT, 100) beneficiary=Bob ``` -``` +```text WithdrawAsset (KLT, 100) ReserveAssetDeposited(WETH, 2) PayFees (WETH, 1) SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination AliasOrigin Ethereum/Alice // derived from msg.sender InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT - DepositAsset (KLT, 100) beneficiary=Bob - Transact Bob.hello() + DepositAsset (KLT, 100) beneficiary=Bob + Transact Bob.hello() ``` -## Step 4: KILT Receives XCM from AH +### Step 4: KILT Receives XCM from AH The following XCM $x_1$ is received from AH on KILT. -``` +```text *WithdrawAsset (KLT, 100) *ReserveAssetDeposited (WETH, 1) *PayFees (WETH, 1) @@ -262,7 +293,7 @@ SetAssetClaimer Bob DepositAsset (KLT, 100) beneficiary=Bob ``` -``` +```text *WithdrawAsset (KLT, 100) *ReserveAssetDeposited (WETH, 1) *PayFees (WETH, 1) @@ -273,11 +304,14 @@ DepositAsset (KLT, 100) beneficiary=Bob Transact Bob.hello() // executes with the origin from AH ``` -# Relayer Rewards +## Relayer Rewards -The tracking and disbursement of relayer rewards for both directions has been unified. Rewards are accumulated on BH in WETH and must be manually claimed. As part of the claims flow, an XCM instruction is sent to AH to mint the WETH into the deposit account chosen by the relayer. +The tracking and disbursement of relayer rewards for both directions has been unified. Rewards are accumulated on BH in +WETH and must be manually claimed. As part of the claims flow, an XCM instruction is sent to AH to mint the WETH into +the deposit account chosen by the relayer. -To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will be minted. +To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will +be minted. $$ \mathrm{claim}(o,w) @@ -285,19 +319,26 @@ $$ For tax accounting purposes it might be desirable that $o \neq w$. -# Top-Up +## Top-Up -Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub and Ethereum respectively. +Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub and Ethereum +respectively. ## 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: +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 safe because it respects the hierarchy of multi-locations and does not allow jumping up. Meaning no escalation of privileges. - 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) }` and all of its internal locations so that AH can act as a proxy for the bridge on parachains. +1. `AliasOrigin` can behave like `DescendOrigin`. This is safe because it respects the hierarchy of multi-locations and + does not allow jumping up. Meaning no escalation of privileges. + 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) }` and all of its internal locations so that AH can act as a proxy + for the bridge on parachains. -`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. +`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: @@ -309,6 +350,7 @@ RFCS: 1. Pallet-xcm.execute enabled. 2. XCM payment and dry run apis implemented. -3. Must accept WETH needed for fees. Though in future user agents can inject `ExchangeAsset` instructions to obtain WETH. +3. Must accept WETH needed for fees. Though in future user agents can inject `ExchangeAsset` instructions to obtain + WETH. 4. Trust AH as a reserve for bridged assets. 5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses.