From c138ff31ccc949e81dcd7696ba7af80ddb7fa851 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Wed, 8 May 2024 14:34:22 +0200 Subject: [PATCH 01/15] prepare hydradx atomic swap filter --- runtime/battery-station/src/lib.rs | 3 ++ .../src/xcm_config/hydra_atomic_swap.rs | 37 +++++++++++++++++++ runtime/battery-station/src/xcm_config/mod.rs | 1 + runtime/common/src/lib.rs | 2 +- runtime/zeitgeist/src/lib.rs | 3 ++ .../src/xcm_config/hydra_atomic_swap.rs | 37 +++++++++++++++++++ runtime/zeitgeist/src/xcm_config/mod.rs | 1 + 7 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs create mode 100644 runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs diff --git a/runtime/battery-station/src/lib.rs b/runtime/battery-station/src/lib.rs index 2393a7634..507581fa6 100644 --- a/runtime/battery-station/src/lib.rs +++ b/runtime/battery-station/src/lib.rs @@ -92,6 +92,9 @@ use sp_runtime::{ use nimbus_primitives::CanAuthor; use sp_version::RuntimeVersion; +#[cfg(feature = "parachain")] +use crate::xcm_config::hydra_atomic_swap::AllowHydraDxAtomicSwap; + #[cfg(test)] pub mod integration_tests; #[cfg(feature = "parachain")] diff --git a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs new file mode 100644 index 000000000..f82d4a1b0 --- /dev/null +++ b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs @@ -0,0 +1,37 @@ +// Copyright 2024 Forecasting Technologies LTD. +// +// This file is part of Zeitgeist. +// +// Zeitgeist is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// Zeitgeist is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Zeitgeist. If not, see . +#![cfg(feature = "parachain")] + +use crate::RuntimeCall; +use cumulus_primitives_core::Xcm; +use frame_support::traits::Contains; +use xcm::latest::{prelude::AccountId32, Junctions, MultiLocation}; + +pub struct AllowHydraDxAtomicSwap; + +impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { + fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { + match origin { + MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { + // TODO if msg matches HydraDX atomic swap messages then true, otherwise false + + false + } + _ => false, + } + } +} diff --git a/runtime/battery-station/src/xcm_config/mod.rs b/runtime/battery-station/src/xcm_config/mod.rs index 448000ebe..c4762cba5 100644 --- a/runtime/battery-station/src/xcm_config/mod.rs +++ b/runtime/battery-station/src/xcm_config/mod.rs @@ -20,3 +20,4 @@ pub mod asset_registry; pub mod config; pub mod fees; +pub mod hydra_atomic_swap; diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index eff5c92c0..0892322e8 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -516,7 +516,7 @@ macro_rules! impl_config_traits { type SendXcmOrigin = EnsureXcmOrigin; type UniversalLocation = UniversalLocation; type Weigher = FixedWeightBounds; - type XcmExecuteFilter = Nothing; + type XcmExecuteFilter = AllowHydraDxAtomicSwap; // ^ Disable dispatchable execute on the XCM pallet. // Needs to be `Everything` for local testing. type XcmExecutor = xcm_executor::XcmExecutor; diff --git a/runtime/zeitgeist/src/lib.rs b/runtime/zeitgeist/src/lib.rs index 4fcde1f80..b15b1a095 100644 --- a/runtime/zeitgeist/src/lib.rs +++ b/runtime/zeitgeist/src/lib.rs @@ -81,6 +81,9 @@ use sp_runtime::{ use nimbus_primitives::CanAuthor; use sp_version::RuntimeVersion; +#[cfg(feature = "parachain")] +use crate::xcm_config::hydra_atomic_swap::AllowHydraDxAtomicSwap; + #[cfg(test)] pub mod integration_tests; #[cfg(feature = "parachain")] diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs new file mode 100644 index 000000000..f82d4a1b0 --- /dev/null +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -0,0 +1,37 @@ +// Copyright 2024 Forecasting Technologies LTD. +// +// This file is part of Zeitgeist. +// +// Zeitgeist is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// Zeitgeist is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Zeitgeist. If not, see . +#![cfg(feature = "parachain")] + +use crate::RuntimeCall; +use cumulus_primitives_core::Xcm; +use frame_support::traits::Contains; +use xcm::latest::{prelude::AccountId32, Junctions, MultiLocation}; + +pub struct AllowHydraDxAtomicSwap; + +impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { + fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { + match origin { + MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { + // TODO if msg matches HydraDX atomic swap messages then true, otherwise false + + false + } + _ => false, + } + } +} diff --git a/runtime/zeitgeist/src/xcm_config/mod.rs b/runtime/zeitgeist/src/xcm_config/mod.rs index 448000ebe..c4762cba5 100644 --- a/runtime/zeitgeist/src/xcm_config/mod.rs +++ b/runtime/zeitgeist/src/xcm_config/mod.rs @@ -20,3 +20,4 @@ pub mod asset_registry; pub mod config; pub mod fees; +pub mod hydra_atomic_swap; From a052d95009e35d01e5cc566ea5d0a9c349fca8d0 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Wed, 8 May 2024 15:45:28 +0200 Subject: [PATCH 02/15] add xcm contains filter --- .../src/xcm_config/hydra_atomic_swap.rs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index f82d4a1b0..3c3d36ca3 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -17,9 +17,10 @@ #![cfg(feature = "parachain")] use crate::RuntimeCall; -use cumulus_primitives_core::Xcm; use frame_support::traits::Contains; -use xcm::latest::{prelude::AccountId32, Junctions, MultiLocation}; +use xcm::prelude::*; + +pub const HYDRA_PARA_ID: u32 = 2034; pub struct AllowHydraDxAtomicSwap; @@ -28,6 +29,29 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { match origin { MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { // TODO if msg matches HydraDX atomic swap messages then true, otherwise false + // TODO figure out which stablecoin pairs to swap atomically with HydraDX + let mut it = msg.inner().iter(); + match (it.next(), it.next(), it.next()) { + ( + Some(SetFeesMode { jit_withdraw: true }), + Some(TransferReserveAsset { assets, dest, xcm }), + None, + ) => { + let mut xit = xcm.inner().iter(); + let valid_xcm = match (xit.next(), xit.next(), xit.next(), xit.next()) { + ( + Some(BuyExecution { .. }), + Some(ExchangeAsset { .. }), + Some(DepositAsset { .. }), + None, + ) => true, + _ => false, + }; + let valid_dest = *dest == MultiLocation::new(1, X1(Parachain(HYDRA_PARA_ID))); + // TODO Do we want to check the assets from TransferReserveAsset? + } + _ => return false, + } false } From 2d951b5c8a8d5213fa82c946ad306e99daa8ca40 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Fri, 10 May 2024 13:04:10 +0200 Subject: [PATCH 03/15] add four hop xcms --- .../src/xcm_config/hydra_atomic_swap.rs | 1 + .../src/xcm_config/hydra_atomic_swap.rs | 78 +++++++++++++++++-- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs index f82d4a1b0..18313edf6 100644 --- a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs @@ -21,6 +21,7 @@ use cumulus_primitives_core::Xcm; use frame_support::traits::Contains; use xcm::latest::{prelude::AccountId32, Junctions, MultiLocation}; +// TODO: Maybe name it AllowBasiliskAtomicSwap and ask HydraDX if we can test atomic swaps on Basilisk pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index 3c3d36ca3..d55351a29 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -20,21 +20,64 @@ use crate::RuntimeCall; use frame_support::traits::Contains; use xcm::prelude::*; -pub const HYDRA_PARA_ID: u32 = 2034; +pub const HYDRA_DX_PARA_ID: u32 = 2034; pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { + // TODO outsource this into parameter_types! + let hydra_dx_loc: MultiLocation = MultiLocation::new(1, X1(Parachain(HYDRA_DX_PARA_ID))); + let matches_inner_0 = |xcm: Xcm<()>| -> bool { + let mut xit = xcm.inner().iter(); + match (xit.next(), xit.next(), xit.next()) { + (Some(BuyExecution { .. }), Some(DepositAsset { .. }), None) => true, + _ => false, + } + }; + let matches_inner_1 = |xcm: Xcm<()>| -> Option> { + let mut xit = xcm.inner().iter(); + match (xit.next(), xit.next(), xit.next()) { + ( + Some(BuyExecution { .. }), + // TODO maybe dest verification? + Some(DepositReserveAsset { assets: _, dest: _, xcm }), + None, + ) => Some(xcm.clone()), + _ => None, + } + }; + let matches_inner_2 = |xcm: Xcm<()>| -> Option> { + let mut xit = xcm.inner().iter(); + match (xit.next(), xit.next(), xit.next(), xit.next()) { + ( + Some(BuyExecution { .. }), + Some(ExchangeAsset { .. }), + Some(InitiateReserveWithdraw { assets: _, reserve: _, xcm }), + None, + ) => Some(xcm.clone()), + _ => None, + } + }; + let matches_inner_3 = |xcm: &Xcm<()>| -> Option> { + let mut xit = xcm.inner().iter(); + match (xit.next(), xit.next(), xit.next()) { + ( + Some(BuyExecution { .. }), + Some(DepositReserveAsset { assets: _, dest, xcm }), + None, + ) if *dest == hydra_dx_loc => Some(xcm.clone()), + _ => None, + } + }; match origin { MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { - // TODO if msg matches HydraDX atomic swap messages then true, otherwise false // TODO figure out which stablecoin pairs to swap atomically with HydraDX let mut it = msg.inner().iter(); match (it.next(), it.next(), it.next()) { ( Some(SetFeesMode { jit_withdraw: true }), - Some(TransferReserveAsset { assets, dest, xcm }), + Some(TransferReserveAsset { assets: _, dest, xcm }), None, ) => { let mut xit = xcm.inner().iter(); @@ -47,13 +90,34 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { ) => true, _ => false, }; - let valid_dest = *dest == MultiLocation::new(1, X1(Parachain(HYDRA_PARA_ID))); - // TODO Do we want to check the assets from TransferReserveAsset? + let valid_dest = *dest == hydra_dx_loc; + // TODO Do we want to check the assets from TransferReserveAsset? If yes, we could check this here too! + return valid_xcm && valid_dest; + } + ( + Some(WithdrawAsset(_)), + Some(InitiateReserveWithdraw { assets: _, reserve: _, xcm }), + None, + ) => { + let xcm_3_opt = matches_inner_3(xcm); + let xcm_3 = match xcm_3_opt { + None => return false, + Some(xcm_3) => xcm_3, + }; + let xcm_2_opt = matches_inner_2(xcm_3); + let xcm_2 = match xcm_2_opt { + None => return false, + Some(xcm_2) => xcm_2, + }; + let xcm_1_opt = matches_inner_1(xcm_2); + let xcm_1 = match xcm_1_opt { + None => return false, + Some(xcm_1) => xcm_1, + }; + return matches_inner_0(xcm_1); } _ => return false, } - - false } _ => false, } From c855201d90d12d11fcc8f6aecfd537a51c9cd042 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Fri, 10 May 2024 15:42:01 +0200 Subject: [PATCH 04/15] simplify xcm pattern matching --- .../src/xcm_config/hydra_atomic_swap.rs | 121 ++++++------------ 1 file changed, 41 insertions(+), 80 deletions(-) diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index d55351a29..3b6a397af 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -17,104 +17,65 @@ #![cfg(feature = "parachain")] use crate::RuntimeCall; -use frame_support::traits::Contains; +use frame_support::{parameter_types, traits::Contains}; use xcm::prelude::*; -pub const HYDRA_DX_PARA_ID: u32 = 2034; +parameter_types! { + pub const HydraDxParachainId: u32 = 2034; + pub HydraDxMultiLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(HydraDxParachainId::get()))); +} pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { - // TODO outsource this into parameter_types! - let hydra_dx_loc: MultiLocation = MultiLocation::new(1, X1(Parachain(HYDRA_DX_PARA_ID))); - let matches_inner_0 = |xcm: Xcm<()>| -> bool { - let mut xit = xcm.inner().iter(); - match (xit.next(), xit.next(), xit.next()) { - (Some(BuyExecution { .. }), Some(DepositAsset { .. }), None) => true, - _ => false, - } - }; - let matches_inner_1 = |xcm: Xcm<()>| -> Option> { - let mut xit = xcm.inner().iter(); - match (xit.next(), xit.next(), xit.next()) { - ( - Some(BuyExecution { .. }), - // TODO maybe dest verification? - Some(DepositReserveAsset { assets: _, dest: _, xcm }), - None, - ) => Some(xcm.clone()), - _ => None, - } - }; - let matches_inner_2 = |xcm: Xcm<()>| -> Option> { - let mut xit = xcm.inner().iter(); - match (xit.next(), xit.next(), xit.next(), xit.next()) { - ( - Some(BuyExecution { .. }), - Some(ExchangeAsset { .. }), - Some(InitiateReserveWithdraw { assets: _, reserve: _, xcm }), - None, - ) => Some(xcm.clone()), - _ => None, - } - }; - let matches_inner_3 = |xcm: &Xcm<()>| -> Option> { - let mut xit = xcm.inner().iter(); - match (xit.next(), xit.next(), xit.next()) { - ( - Some(BuyExecution { .. }), - Some(DepositReserveAsset { assets: _, dest, xcm }), - None, - ) if *dest == hydra_dx_loc => Some(xcm.clone()), - _ => None, - } - }; match origin { MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { // TODO figure out which stablecoin pairs to swap atomically with HydraDX - let mut it = msg.inner().iter(); - match (it.next(), it.next(), it.next()) { - ( - Some(SetFeesMode { jit_withdraw: true }), - Some(TransferReserveAsset { assets: _, dest, xcm }), - None, - ) => { - let mut xit = xcm.inner().iter(); - let valid_xcm = match (xit.next(), xit.next(), xit.next(), xit.next()) { - ( - Some(BuyExecution { .. }), - Some(ExchangeAsset { .. }), - Some(DepositAsset { .. }), - None, - ) => true, + match msg.inner() { + [ + SetFeesMode { jit_withdraw: true }, + TransferReserveAsset { assets: _, dest, xcm }, + ] => { + let valid_xcm = match xcm.inner() { + [BuyExecution { .. }, ExchangeAsset { .. }, DepositAsset { .. }] => { + true + } _ => false, }; - let valid_dest = *dest == hydra_dx_loc; + let valid_dest = *dest == HydraDxMultiLocation::get(); // TODO Do we want to check the assets from TransferReserveAsset? If yes, we could check this here too! return valid_xcm && valid_dest; } - ( - Some(WithdrawAsset(_)), - Some(InitiateReserveWithdraw { assets: _, reserve: _, xcm }), - None, - ) => { - let xcm_3_opt = matches_inner_3(xcm); - let xcm_3 = match xcm_3_opt { - None => return false, - Some(xcm_3) => xcm_3, + [WithdrawAsset(_), InitiateReserveWithdraw { assets: _, reserve: _, xcm }] => { + let xcm_3 = match xcm.inner() { + [BuyExecution { .. }, DepositReserveAsset { assets: _, dest, xcm }] + if *dest == HydraDxMultiLocation::get() => + { + xcm + } + _ => return false, + }; + let xcm_2 = match xcm_3.inner() { + [ + BuyExecution { .. }, + ExchangeAsset { .. }, + InitiateReserveWithdraw { assets: _, reserve: _, xcm }, + ] => xcm, + _ => return false, }; - let xcm_2_opt = matches_inner_2(xcm_3); - let xcm_2 = match xcm_2_opt { - None => return false, - Some(xcm_2) => xcm_2, + let xcm_1 = match xcm_2.inner() { + // TODO maybe dest verification? + [ + BuyExecution { .. }, + DepositReserveAsset { assets: _, dest: _, xcm }, + ] => xcm, + _ => return false, }; - let xcm_1_opt = matches_inner_1(xcm_2); - let xcm_1 = match xcm_1_opt { - None => return false, - Some(xcm_1) => xcm_1, + return match xcm_1.inner() { + [BuyExecution { .. }, DepositAsset { .. }] => true, + _ => false, }; - return matches_inner_0(xcm_1); } _ => return false, } From 12153dfed1b5c9b46f74ba77f9ce24df5b39af36 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Tue, 14 May 2024 12:24:25 +0200 Subject: [PATCH 05/15] prepare integration test --- integration-tests/moonwall.config.json | 47 ++++++- integration-tests/tests/common-tests.ts | 121 ++++++++++++++++++ ...eitgeist-chopsticks-hydradx-atomic-swap.ts | 77 +++++++++++ 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 integration-tests/tests/zeitgeist-hydradx-atomic-swap-chopsticks/test-zeitgeist-chopsticks-hydradx-atomic-swap.ts diff --git a/integration-tests/moonwall.config.json b/integration-tests/moonwall.config.json index 18cec7399..5b5e4e0db 100644 --- a/integration-tests/moonwall.config.json +++ b/integration-tests/moonwall.config.json @@ -125,6 +125,51 @@ "endpoints": ["ws://127.0.0.1:8002"] } ] - } + }, + { + "name": "chopsticks_zeitgeist_hydradx_atomic_swap", + "testFileDir": ["tests/zeitgeist-hydradx-atomic-swap-chopsticks"], + "runScripts": ["build-node.sh"], + "foundation": { + "type": "chopsticks", + "rtUpgradePath": "../target/release/wbuild/zeitgeist-runtime/zeitgeist_runtime.compact.compressed.wasm", + "launchSpec": [ + { + "name": "ZeitgeistDB", + "type": "parachain", + "configPath": "./configs/zeitgeist.yml" + }, + { + "name": "HydraDXDB", + "type": "parachain", + "configPath": "./configs/hydradx.yml" + }, + { + "name": "PolkadotDB", + "type": "relaychain", + "configPath": "polkadot" + } + ] + }, + "envVars": ["LOG_LEVEL=debug", "VERBOSE_LOG"], + "buildBlockMode": "manual", + "connections": [ + { + "name": "ZeitgeistPara", + "type": "polkadotJs", + "endpoints": ["ws://127.0.0.1:8000"] + }, + { + "name": "HydraDXPara", + "type": "polkadotJs", + "endpoints": ["ws://127.0.0.1:8001"] + }, + { + "name": "PolkadotRelay", + "type": "polkadotJs", + "endpoints": ["ws://127.0.0.1:8002"] + } + ] + }, ] } diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts index 6d60dadae..79e90766e 100644 --- a/integration-tests/tests/common-tests.ts +++ b/integration-tests/tests/common-tests.ts @@ -1,4 +1,20 @@ // Copyright (C) Moondance Labs Ltd. +// Copyright 2024 Forecasting Technologies LTD. +// +// This file is part of Zeitgeist. +// +// Zeitgeist is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// Zeitgeist is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Zeitgeist. If not, see . import { expect, ChopsticksContext } from "@moonwall/cli"; import { generateKeyringPair } from "@moonwall/util"; @@ -205,3 +221,108 @@ export async function canSendXcmTransfer( "Unexpected xcm transfer balance diff" ).toBe(amount - xcmFee); } + +export async function canExecuteAtomicSwap( + context: ChopsticksContext, + log: Debugger, + senderProviderName: string, + senderParaApi: ApiPromise, + hydradxParaApi: ApiPromise, + hydradxParaId: number +) { + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice", { name: "Alice default" }); + const bob = keyring.addFromUri("//Bob", { name: "Bob default" }); + + const senderBalanceBefore = ( + (await senderParaApi.query.system.account( + alice.address + )) as unknown as AccountInfo + ).data.free.toBigInt(); + const tokensIndex = 0; + const receiverBalanceBefore = ( + (await hydradxParaApi.query.tokens.accounts( + bob.address, + tokensIndex + )) as AccountData + ).free.toBigInt(); + + const ztg = { Ztg: null }; + const amount: bigint = BigInt("192913122185847181"); + const bobAccountId = senderParaApi + .createType("AccountId32", bob.address) + .toHex(); + const destination = { + V3: { + parents: 1, + interior: { + X2: [ + { Parachain: hydradxParaId }, + { AccountId32: { id: bobAccountId, network: null } }, + ], + }, + }, + }; + const destWeightLimit = { Unlimited: null }; + + const xcmTransfer = senderParaApi.tx.xTokens.transfer( + ztg, + amount, + destination, + destWeightLimit + ); + + const { partialFee, weight } = await xcmTransfer.paymentInfo(alice.address); + const transferFee: bigint = partialFee.toBigInt(); + + await xcmTransfer.signAndSend(alice, { nonce: -1 }); + + await context.createBlock({ + providerName: senderProviderName, + count: 1, + allowFailures: false, + }); + + const senderBalanceAfter = ( + (await senderParaApi.query.system.account( + alice.address + )) as unknown as AccountInfo + ).data.free.toBigInt(); + expect( + senderBalanceBefore - senderBalanceAfter, + "Unexpected balance diff" + ).toBe(amount + transferFee); + + // RpcError: 1: Block 0x... not found, if using this `await context.createBlock({ providerName: "ReceiverPara", count: 1 });` + // Reported Bug here https://github.com/Moonsong-Labs/moonwall/issues/343 + + // use a workaround for creating a block + const newBlockPromise = new Promise((resolve, reject) => { + // ws://127.0.0.1:8001 represents the receiver chain endpoint + const ws = new WebSocket("ws://127.0.0.1:8001"); + + ws.on("open", function open() { + const message = { + jsonrpc: "2.0", + id: 1, + method: "dev_newBlock", + params: [{ count: 1 }], + }; + + ws.send(JSON.stringify(message)); + }); + + ws.on("message", async function message(data) { + const dataObj = JSON.parse(data.toString()); + log("Received message:", dataObj); + resolve(dataObj.result); + }); + + ws.on("error", function error(error) { + log("Error:", error.toString()); + reject(error); + }); + }); + + await newBlockPromise; +} diff --git a/integration-tests/tests/zeitgeist-hydradx-atomic-swap-chopsticks/test-zeitgeist-chopsticks-hydradx-atomic-swap.ts b/integration-tests/tests/zeitgeist-hydradx-atomic-swap-chopsticks/test-zeitgeist-chopsticks-hydradx-atomic-swap.ts new file mode 100644 index 000000000..0760e468a --- /dev/null +++ b/integration-tests/tests/zeitgeist-hydradx-atomic-swap-chopsticks/test-zeitgeist-chopsticks-hydradx-atomic-swap.ts @@ -0,0 +1,77 @@ +// Copyright (C) Moondance Labs Ltd. +// Copyright 2024 Forecasting Technologies LTD. +// +// This file is part of Zeitgeist. +// +// Zeitgeist is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// Zeitgeist is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Zeitgeist. If not, see . + +import { beforeAll, describeSuite, expect } from "@moonwall/cli"; +import { KeyringPair } from "@moonwall/util"; +import { ApiPromise, Keyring } from "@polkadot/api"; +import { canExecuteAtomicSwap } from "tests/common-tests"; +import { RuntimeVersion } from "@polkadot/types/interfaces"; + +const HYDRADX_PARA_ID = 2034; +describeSuite({ + id: "CZH", + title: "Chopsticks Zeitgeist HydraDX Atomic Swap Tests", + foundationMethods: "chopsticks", + testCases: function ({ it, context, log }) { + let zeitgeistParaApi: ApiPromise; + let relayApi: ApiPromise; + let hydradxParaApi: ApiPromise; + let alice: KeyringPair; + + beforeAll(async () => { + const keyring = new Keyring({ type: "sr25519" }); + alice = keyring.addFromUri("//Alice", { name: "Alice default" }); + zeitgeistParaApi = context.polkadotJs("ZeitgeistPara"); + relayApi = context.polkadotJs("PolkadotRelay"); + hydradxParaApi = context.polkadotJs("HydraDXPara"); + + const paraZeitgeistNetwork = ( + zeitgeistParaApi.consts.system.version as unknown as RuntimeVersion + ).specName.toString(); + expect(paraZeitgeistNetwork, "Para API incorrect").to.contain( + "zeitgeist" + ); + + const relayNetwork = ( + relayApi.consts.system.version as unknown as RuntimeVersion + ).specName.toString(); + expect(relayNetwork, "Relay API incorrect").to.contain("polkadot"); + + const paraHydraDXNetwork = ( + hydradxParaApi.consts.system.version as unknown as RuntimeVersion + ).specName.toString(); + expect(paraHydraDXNetwork, "Para API incorrect").to.contain("hydradx"); + }, 120000); + + it({ + id: "T1", + timeout: 60000, + title: "Can execute atomic swap on HydraDX", + test: async () => { + await canExecuteAtomicSwap( + context, + log, + "ZeitgeistPara", + zeitgeistParaApi, + hydradxParaApi, + HYDRADX_PARA_ID + ); + }, + }); + }, +}); From f91bec5786bd7bafe7c01b2c4a8891e9c7296085 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Tue, 14 May 2024 16:04:28 +0200 Subject: [PATCH 06/15] add todo --- runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index 3b6a397af..e3c348670 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -29,6 +29,7 @@ pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { + // TODO incoming xcm from HyrdaDX should be allowed here match origin { MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { // TODO figure out which stablecoin pairs to swap atomically with HydraDX From 4bfc06bc886835ff5ef6388246faa9d989ac2530 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Wed, 15 May 2024 04:59:02 +0200 Subject: [PATCH 07/15] prepare basilisk xcm filter --- .../src/xcm_config/hydra_atomic_swap.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs index 18313edf6..967695c18 100644 --- a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs @@ -21,18 +21,16 @@ use cumulus_primitives_core::Xcm; use frame_support::traits::Contains; use xcm::latest::{prelude::AccountId32, Junctions, MultiLocation}; -// TODO: Maybe name it AllowBasiliskAtomicSwap and ask HydraDX if we can test atomic swaps on Basilisk +parameter_types! { + pub const BasiliskParachainId: u32 = 2090; + pub BasiliskMultiLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(BasiliskParachainId::get()))); +} + pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { - match origin { - MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { - // TODO if msg matches HydraDX atomic swap messages then true, otherwise false - - false - } - _ => false, - } + // TODO just copy the same code as for the hydra dx main net filter since the basilisk node uses the same code as the mainnet here https://github.com/galacticcouncil/Basilisk-node/blob/24ffc88d5cbc75e2f00f43c95f7d48db2d3a618f/Cargo.toml#L30 + false } } From a125668fdd0e1d44325aa64a3d8d34362a03f270 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Wed, 15 May 2024 05:20:05 +0200 Subject: [PATCH 08/15] allow root to execute any xcm --- .../battery-station/src/xcm_config/hydra_atomic_swap.rs | 9 +++++++-- runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs index 967695c18..2231ec542 100644 --- a/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/battery-station/src/xcm_config/hydra_atomic_swap.rs @@ -18,8 +18,8 @@ use crate::RuntimeCall; use cumulus_primitives_core::Xcm; -use frame_support::traits::Contains; -use xcm::latest::{prelude::AccountId32, Junctions, MultiLocation}; +use frame_support::{parameter_types, traits::Contains}; +use xcm::prelude::*; parameter_types! { pub const BasiliskParachainId: u32 = 2090; @@ -30,6 +30,11 @@ pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { + // allow root to execute XCM + if origin == &MultiLocation::here() { + return true; + } + // TODO just copy the same code as for the hydra dx main net filter since the basilisk node uses the same code as the mainnet here https://github.com/galacticcouncil/Basilisk-node/blob/24ffc88d5cbc75e2f00f43c95f7d48db2d3a618f/Cargo.toml#L30 false } diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index e3c348670..c0baee275 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -29,6 +29,11 @@ pub struct AllowHydraDxAtomicSwap; impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { fn contains((ref origin, ref msg): &(MultiLocation, Xcm)) -> bool { + // allow root to execute XCM + if origin == &MultiLocation::here() { + return true; + } + // TODO incoming xcm from HyrdaDX should be allowed here match origin { MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { From 6ad6205bf91b7563e02b0d16d8fc91962c0f67ba Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Wed, 15 May 2024 07:50:23 +0200 Subject: [PATCH 09/15] handle incoming xcm message --- .../src/xcm_config/hydra_atomic_swap.rs | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index c0baee275..8efb7415c 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -16,7 +16,7 @@ // along with Zeitgeist. If not, see . #![cfg(feature = "parachain")] -use crate::RuntimeCall; +use crate::{ParachainInfo, RuntimeCall}; use frame_support::{parameter_types, traits::Contains}; use xcm::prelude::*; @@ -34,10 +34,9 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { return true; } - // TODO incoming xcm from HyrdaDX should be allowed here match origin { + // the outgoing XCMs to HydraDX MultiLocation { parents: 0, interior: Junctions::X1(AccountId32 { .. }) } => { - // TODO figure out which stablecoin pairs to swap atomically with HydraDX match msg.inner() { [ SetFeesMode { jit_withdraw: true }, @@ -50,7 +49,8 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { _ => false, }; let valid_dest = *dest == HydraDxMultiLocation::get(); - // TODO Do we want to check the assets from TransferReserveAsset? If yes, we could check this here too! + // TODO Do we want to check the multi assets and fees from TransferReserveAsset and ExchangeAsset and BuyExecution and DepositAsset? If yes, we could check this here too! + // TODO I suggest a pattern matching to only allow our stablecoin assets here. On the other hand this would require us to change this pattern if we change the configuration of stablecoins we have return valid_xcm && valid_dest; } [WithdrawAsset(_), InitiateReserveWithdraw { assets: _, reserve: _, xcm }] => { @@ -86,7 +86,25 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { _ => return false, } } - _ => false, + // the incoming XCMs from HydraDX + MultiLocation { parents: 1, interior: Junctions::X1(Parachain(para_id)) } => { + if para_id != ParachainInfo::parachain_id().into() { + return false; + } + + match msg.inner() { + [BuyExecution { .. }, DepositAsset { assets: _, beneficiary }] => { + match beneficiary { + Junction::AccountId32 { .. } => { + return true; + } + _ => return false, + } + } + _ => return false, + } + } + _ => return false, } } } From 3f653b1c704d313f6db78065d2fd8964d52ac3fa Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Wed, 15 May 2024 09:15:55 +0200 Subject: [PATCH 10/15] make code compile --- runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index 8efb7415c..14ba70f37 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -88,14 +88,19 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { } // the incoming XCMs from HydraDX MultiLocation { parents: 1, interior: Junctions::X1(Parachain(para_id)) } => { - if para_id != ParachainInfo::parachain_id().into() { + if *para_id != u32::from(ParachainInfo::parachain_id()) { return false; } match msg.inner() { [BuyExecution { .. }, DepositAsset { assets: _, beneficiary }] => { match beneficiary { - Junction::AccountId32 { .. } => { + // TODO or is it parents: 1 ? + // TODO or is it interior: Junctions::X2(Parachain(zeitgeist_parachain_id), AccountId32 { .. }) ? + MultiLocation { + parents: 0, + interior: Junctions::X1(AccountId32 { .. }), + } => { return true; } _ => return false, From 7387f446ba1a252dde0744117cc5d5dee1e749fa Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Thu, 16 May 2024 05:42:22 +0200 Subject: [PATCH 11/15] fix clippy --- .../src/xcm_config/hydra_atomic_swap.rs | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs index 14ba70f37..0abe4ab37 100644 --- a/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs +++ b/runtime/zeitgeist/src/xcm_config/hydra_atomic_swap.rs @@ -42,16 +42,14 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { SetFeesMode { jit_withdraw: true }, TransferReserveAsset { assets: _, dest, xcm }, ] => { - let valid_xcm = match xcm.inner() { - [BuyExecution { .. }, ExchangeAsset { .. }, DepositAsset { .. }] => { - true - } - _ => false, - }; + let valid_xcm = matches!( + xcm.inner(), + [BuyExecution { .. }, ExchangeAsset { .. }, DepositAsset { .. }] + ); let valid_dest = *dest == HydraDxMultiLocation::get(); // TODO Do we want to check the multi assets and fees from TransferReserveAsset and ExchangeAsset and BuyExecution and DepositAsset? If yes, we could check this here too! // TODO I suggest a pattern matching to only allow our stablecoin assets here. On the other hand this would require us to change this pattern if we change the configuration of stablecoins we have - return valid_xcm && valid_dest; + valid_xcm && valid_dest } [WithdrawAsset(_), InitiateReserveWithdraw { assets: _, reserve: _, xcm }] => { let xcm_3 = match xcm.inner() { @@ -78,12 +76,10 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { ] => xcm, _ => return false, }; - return match xcm_1.inner() { - [BuyExecution { .. }, DepositAsset { .. }] => true, - _ => false, - }; + + return matches!(xcm_1.inner(), [BuyExecution { .. }, DepositAsset { .. }]); } - _ => return false, + _ => false, } } // the incoming XCMs from HydraDX @@ -93,23 +89,24 @@ impl Contains<(MultiLocation, Xcm)> for AllowHydraDxAtomicSwap { } match msg.inner() { - [BuyExecution { .. }, DepositAsset { assets: _, beneficiary }] => { - match beneficiary { - // TODO or is it parents: 1 ? - // TODO or is it interior: Junctions::X2(Parachain(zeitgeist_parachain_id), AccountId32 { .. }) ? - MultiLocation { - parents: 0, - interior: Junctions::X1(AccountId32 { .. }), - } => { - return true; - } - _ => return false, - } - } - _ => return false, + // TODO maybe check the assets here? + // TODO or is it parents: 1 ? + // TODO or is it interior: Junctions::X2(Parachain(zeitgeist_parachain_id), AccountId32 { .. }) ? + [ + BuyExecution { .. }, + DepositAsset { + assets: _, + beneficiary: + MultiLocation { + parents: 0, + interior: Junctions::X1(AccountId32 { .. }), + }, + }, + ] => true, + _ => false, } } - _ => return false, + _ => false, } } } From 9ca2f0ee1869891d98f13f85013dd43d4e20039f Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Thu, 16 May 2024 10:26:11 +0200 Subject: [PATCH 12/15] prepare swap xcm --- integration-tests/tests/common-tests.ts | 150 ++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 7 deletions(-) diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts index 79e90766e..27b1b020c 100644 --- a/integration-tests/tests/common-tests.ts +++ b/integration-tests/tests/common-tests.ts @@ -227,6 +227,7 @@ export async function canExecuteAtomicSwap( log: Debugger, senderProviderName: string, senderParaApi: ApiPromise, + senderParaId: number, hydradxParaApi: ApiPromise, hydradxParaId: number ) { @@ -252,18 +253,153 @@ export async function canExecuteAtomicSwap( const bobAccountId = senderParaApi .createType("AccountId32", bob.address) .toHex(); + + // TODO: fill in bobs AccountId32 address in beneficiary of DepositAsset for the polkadot js org reference below + console.log("bobAccountId", bobAccountId); + + // TODO: register HDX token on Zeitgeist chain first in order to swap ZTG for HDX on HydraDX chain + + const dest = { + parents: 1, + interior: { + X1: { Parachain: hydradxParaId }, + }, + }; + const destination = { - V3: { - parents: 1, - interior: { - X2: [ - { Parachain: hydradxParaId }, - { AccountId32: { id: bobAccountId, network: null } }, + V3: dest, + }; + + // taken from here https://github.com/galacticcouncil/HydraDX-node/blob/e3821e078bdb72a0416f8aebca21ba4a7a599f64/runtime/hydradx/src/xcm.rs#L312-L315 + const localHDX = { + parents: 0, + interior: { + X1: { GeneralIndex: 0 }, + }, + }; + + // TODO: mint HDX token on HydraDX for the swap executor to pay for the XCM execution + const buyExecution = { + BuyExecution: { + fees: { + id: { + Concrete: localHDX, + }, + fun: { + // 100 HDX (12 decimals base) + Fungible: 100_000_000_000_000n, + }, + }, + weightLimit: { + Unlimited: null, + }, + }, + }; + + const ztgOnHydraDX = { + parents: 1, + interior: { + X2: [ + { Parachain: senderParaId }, + { + GeneralKey: { + length: 2, + data: "0x0001000000000000000000000000000000000000000000000000000000000000", + }, + }, + ], + }, + }; + + const exchangeAsset = { + ExchangeAsset: { + give: { + Definite: [ + { + id: { + Concrete: ztgOnHydraDX, + }, + fun: { + // 100 ZTG (10 decimals base) + Fungible: 1_000_000_000_000n, + }, + }, ], }, + want: { + id: { + Concrete: localHDX, + }, + fun: { + // 50 HDX (12 decimals base) + Fungible: 50_000_000_000_000n, + }, + }, + // Reference: https://github.com/paritytech/polkadot-sdk/blob/289f5bbf7a45dc0380904a435464b15ec711ed03/polkadot/xcm/src/v3/mod.rs#L722-L724 + // give as little ZTG as possible to receive at least 50 HDX + maximal: false, }, }; - const destWeightLimit = { Unlimited: null }; + + const depositAsset = { + DepositAsset: { + assets: { Wild: { AllCounted: 2 } }, + beneficiary: { + parents: 0, + interior: { + X1: { AccountId32: { id: bobAccountId, network: null } }, + }, + }, + }, + }; + + // executed on HydraDX + const hydradxXcm = { + V3: [buyExecution, exchangeAsset, depositAsset], + }; + + const setFeesMode = { + SetFeesMode: { + jitWithdraw: true, + }, + }; + + const localZTG = { + parents: 0, + interior: { + X1: { + GeneralKey: { + length: 2, + data: "0x0001000000000000000000000000000000000000000000000000000000000000", + }, + }, + }, + }; + + const assets = [ + { + id: { + Concrete: localZTG, + }, + fun: { + // 100 ZTG (10 decimals base) + Fungible: 1_000_000_000_000n, + }, + }, + ]; + + const transferReserveAsset = { + TransferReserveAsset: { + assets: assets, + dest: dest, + xcm: hydradxXcm, + }, + }; + + // Reference: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fzeitgeist-rpc.dwellir.com#/extrinsics/decode/0x7a0003010100c91f03082b0105040000010602000100000000000000000000000000000000000000000000000000000000000000070010a5d4e8010100c91f0c130000010500000b00407a10f35a000f000400010200b1200602000100000000000000000000000000000000000000000000000000000000000000070010a5d4e8040000010500000b00203d88792d000d0102080001010032324422424000000000f3230040020423040032003000f0302f30300f000323 + const xcmMessage = { + V3: [setFeesMode, transferReserveAsset], + }; const xcmTransfer = senderParaApi.tx.xTokens.transfer( ztg, From 50bb086171016c5cba90b5b6c9cfb655f3882ef6 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Thu, 16 May 2024 10:38:49 +0200 Subject: [PATCH 13/15] wip --- integration-tests/tests/common-tests.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts index 27b1b020c..c44eaa309 100644 --- a/integration-tests/tests/common-tests.ts +++ b/integration-tests/tests/common-tests.ts @@ -222,6 +222,7 @@ export async function canSendXcmTransfer( ).toBe(amount - xcmFee); } +// tests this https://github.com/galacticcouncil/HydraDX-node/blob/7402f8ef84bb4a2ba71d54eb19f2e36742b8f655/integration-tests/src/exchange_asset.rs#L530-L597 export async function canExecuteAtomicSwap( context: ChopsticksContext, log: Debugger, @@ -396,7 +397,7 @@ export async function canExecuteAtomicSwap( }, }; - // Reference: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fzeitgeist-rpc.dwellir.com#/extrinsics/decode/0x7a0003010100c91f03082b0105040000010602000100000000000000000000000000000000000000000000000000000000000000070010a5d4e8010100c91f0c130000010500000b00407a10f35a000f000400010200b1200602000100000000000000000000000000000000000000000000000000000000000000070010a5d4e8040000010500000b00203d88792d000d0102080001010032324422424000000000f3230040020423040032003000f0302f30300f000323 + // Reference: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fzeitgeist-rpc.dwellir.com#/extrinsics/decode/0x7a0003010100c91f03082b0105040000010602000100000000000000000000000000000000000000000000000000000000000000070010a5d4e8010100c91f0c130000010500000b00407a10f35a000f000400010200b1200602000100000000000000000000000000000000000000000000000000000000000000070010a5d4e8040000010500000b00203d88792d000d01020800010100d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d const xcmMessage = { V3: [setFeesMode, transferReserveAsset], }; From de77c33fbbb88a50b97b7dcb34550abe0d848134 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Thu, 16 May 2024 11:09:12 +0200 Subject: [PATCH 14/15] wip --- integration-tests/tests/common-tests.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts index c44eaa309..f15c8bc51 100644 --- a/integration-tests/tests/common-tests.ts +++ b/integration-tests/tests/common-tests.ts @@ -234,7 +234,6 @@ export async function canExecuteAtomicSwap( ) { const keyring = new Keyring({ type: "sr25519" }); const alice = keyring.addFromUri("//Alice", { name: "Alice default" }); - const bob = keyring.addFromUri("//Bob", { name: "Bob default" }); const senderBalanceBefore = ( (await senderParaApi.query.system.account( @@ -242,22 +241,12 @@ export async function canExecuteAtomicSwap( )) as unknown as AccountInfo ).data.free.toBigInt(); const tokensIndex = 0; - const receiverBalanceBefore = ( - (await hydradxParaApi.query.tokens.accounts( - bob.address, - tokensIndex - )) as AccountData - ).free.toBigInt(); const ztg = { Ztg: null }; - const amount: bigint = BigInt("192913122185847181"); - const bobAccountId = senderParaApi - .createType("AccountId32", bob.address) + const aliceAccountId = senderParaApi + .createType("AccountId32", alice.address) .toHex(); - // TODO: fill in bobs AccountId32 address in beneficiary of DepositAsset for the polkadot js org reference below - console.log("bobAccountId", bobAccountId); - // TODO: register HDX token on Zeitgeist chain first in order to swap ZTG for HDX on HydraDX chain const dest = { @@ -348,7 +337,7 @@ export async function canExecuteAtomicSwap( beneficiary: { parents: 0, interior: { - X1: { AccountId32: { id: bobAccountId, network: null } }, + X1: { AccountId32: { id: aliceAccountId, network: null } }, }, }, }, From 721dd71e0de15e7dc15029616ab3528c8f2059b9 Mon Sep 17 00:00:00 2001 From: Chralt98 Date: Mon, 24 Jun 2024 11:22:32 +0200 Subject: [PATCH 15/15] wip --- integration-tests/tests/common-tests.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts index f15c8bc51..71ad4397b 100644 --- a/integration-tests/tests/common-tests.ts +++ b/integration-tests/tests/common-tests.ts @@ -240,7 +240,6 @@ export async function canExecuteAtomicSwap( alice.address )) as unknown as AccountInfo ).data.free.toBigInt(); - const tokensIndex = 0; const ztg = { Ztg: null }; const aliceAccountId = senderParaApi @@ -366,14 +365,16 @@ export async function canExecuteAtomicSwap( }, }; + // 100 ZTG (10 decimals base) + const ztgAmount = 1_000_000_000_000n; + const assets = [ { id: { Concrete: localZTG, }, fun: { - // 100 ZTG (10 decimals base) - Fungible: 1_000_000_000_000n, + Fungible: ztgAmount, }, }, ]; @@ -391,17 +392,15 @@ export async function canExecuteAtomicSwap( V3: [setFeesMode, transferReserveAsset], }; - const xcmTransfer = senderParaApi.tx.xTokens.transfer( - ztg, - amount, + const xcmAtomicSwap = senderParaApi.tx.polkadotXcm.send( destination, - destWeightLimit + xcmMessage ); - const { partialFee, weight } = await xcmTransfer.paymentInfo(alice.address); + const { partialFee, weight } = await xcmAtomicSwap.paymentInfo(alice.address); const transferFee: bigint = partialFee.toBigInt(); - await xcmTransfer.signAndSend(alice, { nonce: -1 }); + await xcmAtomicSwap.signAndSend(alice, { nonce: -1 }); await context.createBlock({ providerName: senderProviderName, @@ -417,7 +416,7 @@ export async function canExecuteAtomicSwap( expect( senderBalanceBefore - senderBalanceAfter, "Unexpected balance diff" - ).toBe(amount + transferFee); + ).toBe(ztgAmount + transferFee); // RpcError: 1: Block 0x... not found, if using this `await context.createBlock({ providerName: "ReceiverPara", count: 1 });` // Reported Bug here https://github.com/Moonsong-Labs/moonwall/issues/343