diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md
new file mode 100644
index 0000000000000000000000000000000000000000..8ec440c47cecb61bb8a6cc61a52f539f04302f71
--- /dev/null
+++ b/bridges/snowbridge/docs/v2.md
@@ -0,0 +1,356 @@
+# 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.
+
+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
+
+- 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^{'}$ (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 $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
+
+$$
+\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$
+
+```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
+```
+
+### 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
+```
+
+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()
+```
+
+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.
+
+### 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.
+
+```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
+```
+
+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()
+```
+
+### 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 $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.
+
+### 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 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.
+
+```solidity
+enum Kind {
+    Index,
+    Address32,
+    Address20,
+    XCMPayload,
+}
+
+struct Beneficiary {
+    Kind kind;
+    bytes data;
+}
+
+enum AssetTransferType {
+    ReserveDeposit, ReserveWithdraw, 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....),
+    [(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
+)
+```
+
+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
+
+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 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.
+
+```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
+```
+
+```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()
+```
+
+### 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)
+*SetAssetClaimer Ethereum/Alice
+*AliasOrigin Ethereum/Alice   // origin preserved from AH
+SetAssetClaimer Bob
+DepositAsset (KLT, 100) beneficiary=Bob
+```
+
+```text
+*WithdrawAsset (KLT, 100)
+*ReserveAssetDeposited (WETH, 1)
+*PayFees (WETH, 1)
+*SetAssetClaimer Ethereum/Alice
+*AliasOrigin Ethereum/Alice   // origin preserved from AH
+SetAssetClaimer Bob
+DepositAsset (KLT, 100) beneficiary=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 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.
+
+$$
+\mathrm{claim}(o,w)
+$$
+
+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 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 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.
+
+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 and dry run apis implemented.
+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.