From 85e0eb27831aeb06a73ee1c23469a039bccc604e Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Sun, 22 Dec 2024 16:16:02 +0800 Subject: [PATCH] Initialization Signed-off-by: Xavier Lau --- .cargo/config.toml | 33 - .config/taplo.toml | 29 - .config/zepter.yaml | 39 - .github/changelog-processor.py | 117 - .github/env | 3 - .github/pull_request_template.md | 6 - .github/review-bot.yml | 39 - .github/scripts/cmd/_help.py | 26 - .github/scripts/cmd/cmd.py | 188 - .github/scripts/cmd/file_header.txt | 15 - .github/workflows/auto-merge.yml | 31 - .github/workflows/changelog.yml | 60 - .github/workflows/check-features.yml | 39 - .github/workflows/check-migrations.yml | 143 - .github/workflows/clippy.yml | 43 - .github/workflows/cmd.yml | 412 -- .github/workflows/fmt.yml | 35 - .../workflows/integration-tests-matrix.json | 30 - .github/workflows/override.yml | 71 + .github/workflows/release.yml | 271 +- .github/workflows/review-bot.yml | 34 - .github/workflows/review-trigger.yml | 74 - .github/workflows/runtimes-matrix.json | 106 - .github/workflows/test.yml | 283 -- .github/workflows/try-runtime.yml | 56 + .github/workflows/up-to-date.yml | 23 - .rustfmt.toml | 24 - CHANGELOG.md | 482 -- Cargo.lock | 4279 +++-------------- Cargo.toml | 27 - README.md | 122 +- chain-spec-generator/Cargo.toml | 64 - chain-spec-generator/src/common.rs | 69 - chain-spec-generator/src/main.rs | 122 - chain-spec-generator/src/relay_chain_specs.rs | 108 - .../src/system_parachains_specs.rs | 346 -- docs/on-chain-identity-process.png | Bin 365121 -> 0 bytes docs/on-chain-identity.md | 15 - docs/pull_request_template.md | 22 - docs/removing-migrations.md | 25 - docs/running-commands.md | 32 - docs/weight-generation.md | 43 - integration-tests/bridges/README.md | 40 - .../bridge_hub_kusama_local_network.toml | 75 - .../bridge_hub_polkadot_local_network.toml | 73 - .../bridges_polkadot_kusama.sh | 385 -- .../polkadot-kusama/generate_bhk_spec.sh | 13 - .../polkadot-kusama/generate_bhp_spec.sh | 13 - .../environments/polkadot-kusama/helper.sh | 3 - .../polkadot-kusama/kusama-bridge.zndsl | 5 - .../polkadot-kusama/kusama-init.zndsl | 6 - .../polkadot-kusama/polkadot-bridge.zndsl | 5 - .../polkadot-kusama/polkadot-init.zndsl | 7 - .../environments/polkadot-kusama/spawn.sh | 49 - .../polkadot-kusama/start_relayer.sh | 23 - integration-tests/bridges/run-test.sh | 44 - integration-tests/bridges/sudo-relay.patch | 136 - .../dot-reaches-kusama.zndsl | 12 - .../ksm-reaches-polkadot.zndsl | 12 - .../run.sh | 28 - .../wdot-reaches-polkadot.zndsl | 10 - .../wksm-reaches-kusama.zndsl | 10 - .../assets/asset-hub-kusama/Cargo.toml | 26 - .../assets/asset-hub-kusama/src/genesis.rs | 107 - .../assets/asset-hub-kusama/src/lib.rs | 61 - .../assets/asset-hub-polkadot/Cargo.toml | 26 - .../assets/asset-hub-polkadot/src/genesis.rs | 140 - .../assets/asset-hub-polkadot/src/lib.rs | 61 - .../bridges/bridge-hub-kusama/Cargo.toml | 26 - .../bridges/bridge-hub-kusama/src/genesis.rs | 89 - .../bridges/bridge-hub-kusama/src/lib.rs | 51 - .../bridges/bridge-hub-polkadot/Cargo.toml | 26 - .../bridge-hub-polkadot/src/genesis.rs | 94 - .../bridges/bridge-hub-polkadot/src/lib.rs | 54 - .../collectives-polkadot/Cargo.toml | 22 - .../collectives-polkadot/src/genesis.rs | 68 - .../collectives-polkadot/src/lib.rs | 52 - .../coretime/coretime-kusama/Cargo.toml | 22 - .../coretime/coretime-kusama/src/genesis.rs | 67 - .../coretime/coretime-kusama/src/lib.rs | 51 - .../coretime/coretime-polkadot/Cargo.toml | 22 - .../coretime/coretime-polkadot/src/genesis.rs | 69 - .../coretime/coretime-polkadot/src/lib.rs | 52 - .../people/people-kusama/Cargo.toml | 26 - .../people/people-kusama/src/genesis.rs | 70 - .../people/people-kusama/src/lib.rs | 51 - .../people/people-polkadot/Cargo.toml | 26 - .../people/people-polkadot/src/genesis.rs | 70 - .../people/people-polkadot/src/lib.rs | 51 - .../parachains/testing/penpal/Cargo.toml | 25 - .../parachains/testing/penpal/src/genesis.rs | 98 - .../parachains/testing/penpal/src/lib.rs | 102 - .../emulated/chains/relays/kusama/Cargo.toml | 28 - .../chains/relays/kusama/src/genesis.rs | 123 - .../emulated/chains/relays/kusama/src/lib.rs | 49 - .../chains/relays/polkadot/Cargo.toml | 30 - .../chains/relays/polkadot/src/genesis.rs | 133 - .../chains/relays/polkadot/src/lib.rs | 49 - integration-tests/emulated/helpers/Cargo.toml | 24 - integration-tests/emulated/helpers/src/lib.rs | 406 -- .../kusama-polkadot-system/Cargo.toml | 22 - .../kusama-polkadot-system/src/lib.rs | 102 - .../networks/kusama-system/Cargo.toml | 21 - .../networks/kusama-system/src/lib.rs | 59 - .../networks/polkadot-system/Cargo.toml | 22 - .../networks/polkadot-system/src/lib.rs | 63 - .../tests/assets/asset-hub-kusama/Cargo.toml | 43 - .../tests/assets/asset-hub-kusama/src/lib.rs | 85 - .../src/tests/claim_assets.rs | 30 - .../src/tests/hybrid_transfers.rs | 790 --- .../assets/asset-hub-kusama/src/tests/mod.rs | 24 - .../src/tests/reserve_transfer.rs | 1112 ----- .../assets/asset-hub-kusama/src/tests/send.rs | 187 - .../src/tests/set_xcm_versions.rs | 82 - .../assets/asset-hub-kusama/src/tests/swap.rs | 395 -- .../asset-hub-kusama/src/tests/teleport.rs | 537 --- .../asset-hub-kusama/src/tests/treasury.rs | 266 - .../src/tests/xcm_fee_estimation.rs | 304 -- .../assets/asset-hub-polkadot/Cargo.toml | 43 - .../assets/asset-hub-polkadot/src/lib.rs | 94 - .../src/tests/claim_assets.rs | 36 - .../src/tests/fellowship_treasury.rs | 133 - .../src/tests/hybrid_transfers.rs | 793 --- .../asset-hub-polkadot/src/tests/mod.rs | 25 - .../src/tests/reserve_transfer.rs | 1053 ---- .../asset-hub-polkadot/src/tests/send.rs | 187 - .../src/tests/set_xcm_versions.rs | 86 - .../asset-hub-polkadot/src/tests/swap.rs | 416 -- .../asset-hub-polkadot/src/tests/teleport.rs | 536 --- .../asset-hub-polkadot/src/tests/treasury.rs | 123 - .../src/tests/xcm_fee_estimation.rs | 305 -- .../bridges/bridge-hub-kusama/Cargo.toml | 54 - .../bridges/bridge-hub-kusama/src/lib.rs | 83 - .../src/tests/asset_transfers.rs | 555 --- .../src/tests/claim_assets.rs | 30 - .../bridge-hub-kusama/src/tests/mod.rs | 231 - .../src/tests/register_bridged_assets.rs | 107 - .../bridge-hub-kusama/src/tests/send_xcm.rs | 143 - .../bridge-hub-kusama/src/tests/teleport.rs | 60 - .../bridges/bridge-hub-polkadot/Cargo.toml | 54 - .../bridges/bridge-hub-polkadot/src/lib.rs | 85 - .../src/tests/asset_transfers.rs | 539 --- .../src/tests/claim_assets.rs | 36 - .../bridge-hub-polkadot/src/tests/mod.rs | 227 - .../src/tests/register_bridged_assets.rs | 128 - .../bridge-hub-polkadot/src/tests/send_xcm.rs | 143 - .../src/tests/snowbridge.rs | 1286 ----- .../bridge-hub-polkadot/src/tests/teleport.rs | 60 - .../collectives-polkadot/Cargo.toml | 48 - .../collectives-polkadot/src/lib.rs | 44 - .../src/tests/fellowship.rs | 72 - .../src/tests/fellowship_salary.rs | 68 - .../src/tests/fellowship_treasury.rs | 235 - .../collectives-polkadot/src/tests/mod.rs | 19 - .../src/tests/teleport.rs | 74 - .../tests/coretime/coretime-kusama/Cargo.toml | 40 - .../tests/coretime/coretime-kusama/src/lib.rs | 55 - .../src/tests/coretime_interface.rs | 223 - .../coretime/coretime-kusama/src/tests/mod.rs | 17 - .../coretime-kusama/src/tests/teleport.rs | 46 - .../coretime/coretime-polkadot/Cargo.toml | 39 - .../coretime/coretime-polkadot/src/lib.rs | 57 - .../src/tests/coretime_interface.rs | 223 - .../coretime-polkadot/src/tests/mod.rs | 18 - .../coretime-polkadot/src/tests/teleport.rs | 47 - .../tests/people/people-kusama/Cargo.toml | 38 - .../tests/people/people-kusama/src/lib.rs | 61 - .../people-kusama/src/tests/claim_assets.rs | 29 - .../people-kusama/src/tests/governance.rs | 535 --- .../people/people-kusama/src/tests/mod.rs | 18 - .../people-kusama/src/tests/teleport.rs | 134 - .../tests/people/people-polkadot/Cargo.toml | 38 - .../tests/people/people-polkadot/src/lib.rs | 62 - .../people-polkadot/src/tests/claim_assets.rs | 29 - .../people-polkadot/src/tests/governance.rs | 533 -- .../people/people-polkadot/src/tests/mod.rs | 18 - .../people-polkadot/src/tests/teleport.rs | 134 - integration-tests/zombienet/Cargo.toml | 12 - .../zombienet/src/environment.rs | 51 - integration-tests/zombienet/src/lib.rs | 70 - integration-tests/zombienet/tests/smoke.rs | 39 - 181 files changed, 995 insertions(+), 25408 deletions(-) delete mode 100644 .cargo/config.toml delete mode 100644 .config/taplo.toml delete mode 100644 .config/zepter.yaml delete mode 100755 .github/changelog-processor.py delete mode 100644 .github/env delete mode 100644 .github/pull_request_template.md delete mode 100644 .github/review-bot.yml delete mode 100644 .github/scripts/cmd/_help.py delete mode 100755 .github/scripts/cmd/cmd.py delete mode 100644 .github/scripts/cmd/file_header.txt delete mode 100644 .github/workflows/auto-merge.yml delete mode 100644 .github/workflows/changelog.yml delete mode 100644 .github/workflows/check-features.yml delete mode 100644 .github/workflows/check-migrations.yml delete mode 100644 .github/workflows/clippy.yml delete mode 100644 .github/workflows/cmd.yml delete mode 100644 .github/workflows/fmt.yml delete mode 100644 .github/workflows/integration-tests-matrix.json create mode 100644 .github/workflows/override.yml delete mode 100644 .github/workflows/review-bot.yml delete mode 100644 .github/workflows/review-trigger.yml delete mode 100644 .github/workflows/runtimes-matrix.json delete mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/try-runtime.yml delete mode 100644 .github/workflows/up-to-date.yml delete mode 100644 .rustfmt.toml delete mode 100644 CHANGELOG.md delete mode 100644 chain-spec-generator/Cargo.toml delete mode 100644 chain-spec-generator/src/common.rs delete mode 100644 chain-spec-generator/src/main.rs delete mode 100644 chain-spec-generator/src/relay_chain_specs.rs delete mode 100644 chain-spec-generator/src/system_parachains_specs.rs delete mode 100644 docs/on-chain-identity-process.png delete mode 100644 docs/on-chain-identity.md delete mode 100644 docs/pull_request_template.md delete mode 100644 docs/removing-migrations.md delete mode 100644 docs/running-commands.md delete mode 100644 docs/weight-generation.md delete mode 100644 integration-tests/bridges/README.md delete mode 100644 integration-tests/bridges/environments/polkadot-kusama/bridge_hub_kusama_local_network.toml delete mode 100644 integration-tests/bridges/environments/polkadot-kusama/bridge_hub_polkadot_local_network.toml delete mode 100755 integration-tests/bridges/environments/polkadot-kusama/bridges_polkadot_kusama.sh delete mode 100755 integration-tests/bridges/environments/polkadot-kusama/generate_bhk_spec.sh delete mode 100755 integration-tests/bridges/environments/polkadot-kusama/generate_bhp_spec.sh delete mode 100755 integration-tests/bridges/environments/polkadot-kusama/helper.sh delete mode 100644 integration-tests/bridges/environments/polkadot-kusama/kusama-bridge.zndsl delete mode 100644 integration-tests/bridges/environments/polkadot-kusama/kusama-init.zndsl delete mode 100644 integration-tests/bridges/environments/polkadot-kusama/polkadot-bridge.zndsl delete mode 100644 integration-tests/bridges/environments/polkadot-kusama/polkadot-init.zndsl delete mode 100755 integration-tests/bridges/environments/polkadot-kusama/spawn.sh delete mode 100755 integration-tests/bridges/environments/polkadot-kusama/start_relayer.sh delete mode 100755 integration-tests/bridges/run-test.sh delete mode 100644 integration-tests/bridges/sudo-relay.patch delete mode 100644 integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/dot-reaches-kusama.zndsl delete mode 100644 integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/ksm-reaches-polkadot.zndsl delete mode 100755 integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/run.sh delete mode 100644 integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wdot-reaches-polkadot.zndsl delete mode 100644 integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl delete mode 100644 integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/people/people-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/people/people-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml delete mode 100644 integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs delete mode 100644 integration-tests/emulated/chains/relays/kusama/Cargo.toml delete mode 100644 integration-tests/emulated/chains/relays/kusama/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/relays/kusama/src/lib.rs delete mode 100644 integration-tests/emulated/chains/relays/polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/chains/relays/polkadot/src/genesis.rs delete mode 100644 integration-tests/emulated/chains/relays/polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/helpers/Cargo.toml delete mode 100644 integration-tests/emulated/helpers/src/lib.rs delete mode 100644 integration-tests/emulated/networks/kusama-polkadot-system/Cargo.toml delete mode 100644 integration-tests/emulated/networks/kusama-polkadot-system/src/lib.rs delete mode 100644 integration-tests/emulated/networks/kusama-system/Cargo.toml delete mode 100644 integration-tests/emulated/networks/kusama-system/src/lib.rs delete mode 100644 integration-tests/emulated/networks/polkadot-system/Cargo.toml delete mode 100644 integration-tests/emulated/networks/polkadot-system/src/lib.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/claim_assets.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/send.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/treasury.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/claim_assets.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/fellowship_treasury.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/send.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/treasury.rs delete mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/claim_assets.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/register_bridged_assets.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/send_xcm.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/asset_transfers.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/claim_assets.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/register_bridged_assets.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/send_xcm.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs delete mode 100644 integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship.rs delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_salary.rs delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_treasury.rs delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/coretime_interface.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/tests/coretime/coretime-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/coretime_interface.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/people/people-kusama/Cargo.toml delete mode 100644 integration-tests/emulated/tests/people/people-kusama/src/lib.rs delete mode 100644 integration-tests/emulated/tests/people/people-kusama/src/tests/claim_assets.rs delete mode 100644 integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs delete mode 100644 integration-tests/emulated/tests/people/people-kusama/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs delete mode 100644 integration-tests/emulated/tests/people/people-polkadot/Cargo.toml delete mode 100644 integration-tests/emulated/tests/people/people-polkadot/src/lib.rs delete mode 100644 integration-tests/emulated/tests/people/people-polkadot/src/tests/claim_assets.rs delete mode 100644 integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs delete mode 100644 integration-tests/emulated/tests/people/people-polkadot/src/tests/mod.rs delete mode 100644 integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs delete mode 100644 integration-tests/zombienet/Cargo.toml delete mode 100644 integration-tests/zombienet/src/environment.rs delete mode 100644 integration-tests/zombienet/src/lib.rs delete mode 100644 integration-tests/zombienet/tests/smoke.rs diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index df126cfef6..0000000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,33 +0,0 @@ -# -# An auto defined `clippy` feature was introduced, -# but it was found to clash with user defined features, -# so was renamed to `cargo-clippy`. -# -# If you want standard clippy run: -# RUSTFLAGS= cargo clippy -[target.'cfg(feature = "cargo-clippy")'] -rustflags = [ - "-Aclippy::all", - "-Aclippy::bind_instead_of_map", # stylistic - "-Aclippy::borrowed-box", # Reasonable to fix this one - "-Aclippy::derivable_impls", # false positives - "-Aclippy::eq_op", # In tests we test equality. - "-Aclippy::erasing_op", # E.g. 0 * DOLLARS - "-Aclippy::extra-unused-type-parameters", # stylistic - "-Aclippy::identity-op", # One case where we do 0 + - "-Aclippy::if-same-then-else", - "-Aclippy::needless_option_as_deref", # false positives - "-Aclippy::nonminimal-bool", # maybe - "-Aclippy::option-map-unit-fn", # stylistic - "-Aclippy::stable_sort_primitive", # prefer stable sort - "-Aclippy::too-many-arguments", # (Turning this on would lead to) - "-Aclippy::type_complexity", # raison d'etre - "-Aclippy::unit_arg", # stylistic - "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::useless_conversion", # Types may change - "-Aclippy::while_immutable_condition", # false positives - "-Aclippy::zero-prefixed-literal", # 00_1000_000 - "-Asuspicious_double_ref_op", - "-Dclippy::complexity", - "-Dclippy::correctness", -] diff --git a/.config/taplo.toml b/.config/taplo.toml deleted file mode 100644 index fb2fe64824..0000000000 --- a/.config/taplo.toml +++ /dev/null @@ -1,29 +0,0 @@ -# all options https://taplo.tamasfe.dev/configuration/formatter-options.html - -exclude = [ - "target/**", -] - -# global rules -[formatting] -reorder_arrays = true -inline_table_expand = false -array_auto_expand = false -array_auto_collapse = false -indent_string = " " # tab - -# don't re-order order-dependent deb package metadata -[[rule]] -include = ["polkadot/Cargo.toml"] -keys = ["package.metadata.deb"] - -[rule.formatting] -reorder_arrays = false - -# don't re-order order-dependent rustflags -[[rule]] -include = [".cargo/config.toml"] -keys = ["build"] - -[rule.formatting] -reorder_arrays = false diff --git a/.config/zepter.yaml b/.config/zepter.yaml deleted file mode 100644 index 8699c80134..0000000000 --- a/.config/zepter.yaml +++ /dev/null @@ -1,39 +0,0 @@ -version: - format: 1 - # Minimum version of the binary that is expected to work. This is just for printing a nice error - # message when someone tries to use an older version. - binary: 0.13.2 - -# The examples in this file assume crate `A` to have a dependency on crate `B`. -workflows: - check: - - [ - 'lint', - # Check that `A` activates the features of `B`. - 'propagate-feature', - # These are the features to check: - '--features=try-runtime,runtime-benchmarks,std', - # Do not try to add a new section into `[features]` of `A` only because `B` expose that feature. There are edge-cases where this is still needed, but we can add them manually. - '--left-side-feature-missing=ignore', - # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. - '--left-side-outside-workspace=ignore', - # Some features imply that they activate a specific dependency as non-optional. Otherwise the default behaviour with a `?` is used. - '--feature-enables-dep=try-runtime:frame-try-runtime,runtime-benchmarks:frame-benchmarking', - # Auxillary flags: - '--offline', - '--locked', - '--show-path', - '--quiet', - ] - # Same as `check`, but with the `--fix` flag. - default: - - [ $check.0, '--fix' ] - -# Will be displayed when any workflow fails: -help: - text: | - This repo uses the Zepter CLI to detect abnormalities in the feature configuration. - It looks like one more more checks failed; please check the console output. You can try to automatically address them by running `zepter`. - Otherwise please ask directly in the Merge Request, GitHub Discussions or on Matrix Chat, thank you. - links: - - "https://github.com/ggwpez/zepter" diff --git a/.github/changelog-processor.py b/.github/changelog-processor.py deleted file mode 100755 index 43ad132fed..0000000000 --- a/.github/changelog-processor.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import argparse - -parser = argparse.ArgumentParser(description="Process the CHANGELOG.md") -parser.add_argument( - "changelog", - metavar="CHANGELOG", - help="Path to the CHANGELOG.md file", - default="CHANGELOG.md", - nargs='?' -) - -group = parser.add_mutually_exclusive_group() -group.add_argument( - "--print-latest-version", - dest="print_latest_version", - help="Print the latest version (first in the file) found in the CHANGELOG.md", - action="store_true" -) -group.add_argument( - "--should-release", - dest="should_release", - help="Should a release be made? Prints `1` or `0`.", - action="store_true" -) -group.add_argument( - "--print-changelog-from-last-release", - dest="changelog_last_release", - help="Print the changelog from the last release.", - action="store_true" -) -group.add_argument( - "--validate-changelog", - dest="validate_changelog", - help="Validates that the changelog uses the correct syntax", - action="store_true" -) - -args = parser.parse_args() - -with open(args.changelog, "r") as changelog: - lines = changelog.readlines() - - if args.validate_changelog: - versions = set() - - for line in lines: - if line.startswith("##"): - if line.startswith("###"): - continue - elif not line.startswith("## ["): - print("Line starting with `##` needs to be followed by ` [`, e.g.: `## [Unreleased]`, `## [400.2.1]`") - print(line) - sys.exit(-1) - elif line.strip().removeprefix("## [").split("]")[0].count(".") != 2 and not "unreleased" in line.lower(): - print("Only Major.Minor.Patch are supported as versioning") - print(line) - sys.exit(-1) - else: - version = line.strip().removeprefix("## [").split("]")[0] - if version in versions: - print("Found version '" + version + "' more than once") - sys.exit(-1) - else: - versions.add(version) - elif line.startswith("#"): - if line.strip() != "# Changelog": - print("Line starting with `#` is only allowed for `# Changelog`") - print(line) - sys.exit(-1) - - sys.exit(0) - - changelog_last_release = "" - found_last_version = False - - # Find the latest version - for line in lines: - if not line.startswith("## ["): - changelog_last_release += line - continue - elif not found_last_version: - changelog_last_release += line - found_last_version = True - version = line.strip().removeprefix("## [").split("]")[0] - else: - break - - if args.changelog_last_release: - print(changelog_last_release, end = "") - sys.exit(0) - elif args.print_latest_version: - print(version, end = "") - sys.exit(0) - elif args.should_release: - if version.lower() == "unreleased": - print("0", end = "") - sys.exit(0) - elif version.count(".") != 2: - print("0", end = "") - sys.exit(-1) - - stream = os.popen("git tag -l v" + version) - output = stream.read() - - # Empty output means that the tag doesn't exist and that we should release. - if output.strip() == "": - print("1", end = "") - else: - print("0", end = "") - - sys.exit(0) - else: - parser.print_help() diff --git a/.github/env b/.github/env deleted file mode 100644 index 14bcafb097..0000000000 --- a/.github/env +++ /dev/null @@ -1,3 +0,0 @@ -RUST_STABLE_VERSION=1.81.0 -RUST_NIGHTLY_VERSION=2024-09-11 -TAPLO_VERSION=0.9.3 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 9984a58df6..0000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,6 +0,0 @@ - - - - -- [ ] Does not require a CHANGELOG entry diff --git a/.github/review-bot.yml b/.github/review-bot.yml deleted file mode 100644 index 418efcaac2..0000000000 --- a/.github/review-bot.yml +++ /dev/null @@ -1,39 +0,0 @@ -rules: - - name: CI Files - condition: - include: - - ^\.github/.* - type: fellows - minRank: 3 - minApprovals: 2 - - name: Relay and system files - condition: - include: - - ^relay\/.* - - ^system-parachains\/.* - - ^CHANGELOG.md$ - type: fellows - minRank: 2 - minApprovals: 2 - minTotalScore: 6 - - name: General Files - condition: - include: - - '.*' - exclude: - - ^relay\/.* - - ^system-parachains\/.* - - ^\.github/.* - - ^CHANGELOG.md$ - type: fellows - minRank: 1 -scores: - dan1: 1 - dan2: 2 - dan3: 5 - dan4: 9 - dan5: 10 - dan6: 15 - dan7: 20 - dan8: 25 - dan9: 30 diff --git a/.github/scripts/cmd/_help.py b/.github/scripts/cmd/_help.py deleted file mode 100644 index 8ad49dad84..0000000000 --- a/.github/scripts/cmd/_help.py +++ /dev/null @@ -1,26 +0,0 @@ -import argparse - -""" - -Custom help action for argparse, it prints the help message for the main parser and all subparsers. - -""" - - -class _HelpAction(argparse._HelpAction): - def __call__(self, parser, namespace, values, option_string=None): - parser.print_help() - - # retrieve subparsers from parser - subparsers_actions = [ - action for action in parser._actions - if isinstance(action, argparse._SubParsersAction)] - # there will probably only be one subparser_action, - # but better save than sorry - for subparsers_action in subparsers_actions: - # get all subparsers and print help - for choice, subparser in subparsers_action.choices.items(): - print("\n### Command '{}'".format(choice)) - print(subparser.format_help()) - - parser.exit() diff --git a/.github/scripts/cmd/cmd.py b/.github/scripts/cmd/cmd.py deleted file mode 100755 index 589ce7e173..0000000000 --- a/.github/scripts/cmd/cmd.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import json -import argparse -import tempfile -import _help - -_HelpAction = _help._HelpAction - -f = open('.github/workflows/runtimes-matrix.json', 'r') -runtimesMatrix = json.load(f) - -runtimeNames = list(map(lambda x: x['name'], runtimesMatrix)) - -common_args = { - '--continue-on-fail': {"action": "store_true", "help": "Won't exit(1) on failed command and continue with next " - "steps. Helpful when you want to push at least successful " - "pallets, and then run failed ones separately"}, - '--quiet': {"action": "store_true", "help": "Won't print start/end/failed messages in Pull Request"}, - '--clean': {"action": "store_true", "help": "Clean up the previous bot's & author's comments in Pull Request " - "which triggered /cmd"}, -} - -parser = argparse.ArgumentParser(prog="/cmd ", description='A command runner for polkadot runtimes repo', add_help=False) -parser.add_argument('--help', action=_HelpAction, help='help for help if you need some help') # help for help - -subparsers = parser.add_subparsers(help='a command to run', dest='command') - -""" -BENCH -""" - -bench_example = '''**Examples**: - - > runs all benchmarks - - %(prog)s - - > runs benchmarks for pallet_balances and pallet_multisig for all runtimes which have these pallets - > --quiet makes it to output nothing to PR but reactions - - %(prog)s --pallet pallet_balances pallet_xcm_benchmarks::generic --quiet - - > runs bench for all pallets for polkadot runtime and continues even if some benchmarks fail - - %(prog)s --runtime polkadot --continue-on-fail - - > does not output anything and cleans up the previous bot's & author command triggering comments in PR - - %(prog)s --runtime polkadot kusama --pallet pallet_balances pallet_multisig --quiet --clean - - ''' - -parser_bench = subparsers.add_parser('bench', help='Runs benchmarks', epilog=bench_example, formatter_class=argparse.RawDescriptionHelpFormatter) - -for arg, config in common_args.items(): - parser_bench.add_argument(arg, **config) - -parser_bench.add_argument('--runtime', help='Runtime(s) space separated', choices=runtimeNames, nargs='*', default=runtimeNames) -parser_bench.add_argument('--pallet', help='Pallet(s) space separated', nargs='*', default=[]) - -""" -FMT -""" -parser_fmt = subparsers.add_parser('fmt', help='Formats code') -for arg, config in common_args.items(): - parser_fmt.add_argument(arg, **config) - -args, unknown = parser.parse_known_args() - -print(f'args: {args}') - -if args.command == 'bench': - tempdir = tempfile.TemporaryDirectory() - print(f'Created temp dir: {tempdir.name}') - runtime_pallets_map = {} - failed_benchmarks = {} - successful_benchmarks = {} - - profile = "release" - - print(f'Provided runtimes: {args.runtime}') - # convert to mapped dict - runtimesMatrix = list(filter(lambda x: x['name'] in args.runtime, runtimesMatrix)) - runtimesMatrix = {x['name']: x for x in runtimesMatrix} - print(f'Filtered out runtimes: {runtimesMatrix}') - - # loop over remaining runtimes to collect available pallets - for runtime in runtimesMatrix.values(): - os.system(f"cargo build -p {runtime['package']} --profile {profile} --features runtime-benchmarks") - print(f'-- listing pallets for benchmark for {runtime["name"]}') - wasm_file = f"target/{profile}/wbuild/{runtime['package']}/{runtime['package'].replace('-', '_')}.wasm" - output = os.popen( - f"frame-omni-bencher v1 benchmark pallet --no-csv-header --all --list --runtime={wasm_file}").read() - raw_pallets = output.split('\n') - - all_pallets = set() - for pallet in raw_pallets: - if pallet: - all_pallets.add(pallet.split(',')[0].strip()) - - pallets = list(all_pallets) - print(f'Pallets in {runtime}: {pallets}') - runtime_pallets_map[runtime['name']] = pallets - - # filter out only the specified pallets from collected runtimes/pallets - if args.pallet: - print(f'Pallet: {args.pallet}') - new_pallets_map = {} - # keep only specified pallets if they exist in the runtime - for runtime in runtime_pallets_map: - if set(args.pallet).issubset(set(runtime_pallets_map[runtime])): - new_pallets_map[runtime] = args.pallet - - runtime_pallets_map = new_pallets_map - - print(f'Filtered out runtimes & pallets: {runtime_pallets_map}') - - if not runtime_pallets_map: - if args.pallet and not args.runtime: - print(f"No pallets [{args.pallet}] found in any runtime") - elif args.runtime and not args.pallet: - print(f"{args.runtime} runtime does not have any pallets") - elif args.runtime and args.pallet: - print(f"No pallets [{args.pallet}] found in {args.runtime}") - else: - print('No runtimes found') - sys.exit(0) - - header_path = os.path.abspath('./.github/scripts/cmd/file_header.txt') - - for runtime in runtime_pallets_map: - for pallet in runtime_pallets_map[runtime]: - config = runtimesMatrix[runtime] - print(f'-- config: {config}') - default_path = f"./{config['path']}/src/weights" - xcm_path = f"./{config['path']}/src/weights/xcm" - output_path = default_path if not pallet.startswith("pallet_xcm_benchmarks") else xcm_path - print(f'-- benchmarking {pallet} in {runtime} into {output_path}') - - status = os.system(f"frame-omni-bencher v1 benchmark pallet " - f"--extrinsic=* " - f"--runtime=target/{profile}/wbuild/{config['package']}/{config['package'].replace('-', '_')}.wasm " - f"--pallet={pallet} " - f"--header={header_path} " - f"--output={output_path} " - f"--wasm-execution=compiled " - f"--steps=50 " - f"--repeat=20 " - f"--heap-pages=4096 " - ) - if status != 0 and not args.continue_on_fail: - print(f'Failed to benchmark {pallet} in {runtime}') - sys.exit(1) - - # Otherwise collect failed benchmarks and print them at the end - # push failed pallets to failed_benchmarks - if status != 0: - failed_benchmarks[f'{runtime}'] = failed_benchmarks.get(f'{runtime}', []) + [pallet] - else: - successful_benchmarks[f'{runtime}'] = successful_benchmarks.get(f'{runtime}', []) + [pallet] - - if failed_benchmarks: - print('❌ Failed benchmarks of runtimes/pallets:') - for runtime, pallets in failed_benchmarks.items(): - print(f'-- {runtime}: {pallets}') - - if successful_benchmarks: - print('✅ Successful benchmarks of runtimes/pallets:') - for runtime, pallets in successful_benchmarks.items(): - print(f'-- {runtime}: {pallets}') - - tempdir.cleanup() - -elif args.command == 'fmt': - nightly_version = os.getenv('RUST_NIGHTLY_VERSION') - command = f"cargo +nightly-{nightly_version} fmt" - print('Formatting with `{command}`') - nightly_status = os.system(f'{command}') - taplo_status = os.system('taplo format --config .config/taplo.toml') - - if (nightly_status != 0 or taplo_status != 0) and not args.continue_on_fail: - print('❌ Failed to format code') - sys.exit(1) - -print('🚀 Done') diff --git a/.github/scripts/cmd/file_header.txt b/.github/scripts/cmd/file_header.txt deleted file mode 100644 index 9fc718fdc0..0000000000 --- a/.github/scripts/cmd/file_header.txt +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml deleted file mode 100644 index 3427f2619d..0000000000 --- a/.github/workflows/auto-merge.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Auto Merge Bot - -on: - # GitHub considers PRs as issues - issue_comment: - types: [created] - -jobs: - set-auto-merge: - runs-on: ubuntu-latest - environment: master - timeout-minutes: 10 - # Important! This forces the job to run only on comments on Pull Requests that starts with '/merge' - if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/merge') }} - steps: - - name: Get the GitHub handle of the fellows - uses: paritytech/get-fellows-action@v1.2.0 - id: fellows - - name: Generate a token - id: merge_token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.MERGE_APP_ID }} - private-key: ${{ secrets.MERGE_APP_KEY }} - - name: Set auto merge - uses: paritytech/auto-merge-bot@v1.1.0 - with: - GITHUB_TOKEN: ${{ steps.merge_token.outputs.token }} - MERGE_METHOD: "SQUASH" - ALLOWLIST: ${{ steps.fellows.outputs.github-handles }} - UPDATE_BEFORE_MERGE: true diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml deleted file mode 100644 index 52b6801f9b..0000000000 --- a/.github/workflows/changelog.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Verify Changelog - -# If you modify more test jobs, ensure that you add them as required to the job "confirmChangelogChecksPassed" -# which is located at the end of this file (more info in the job) - -on: - push: - branches: ["main", "release-*"] - pull_request: - types: [opened, reopened, synchronize, edited] - workflow_dispatch: - -# cancel previous runs -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - # Job required by "confirmChangelogChecksPassed" - verify-changelog-updated: - name: Verify that Changelog is Updated - runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ github.token }} - steps: - - name: Get Changed Files - id: changed - uses: foodee/pr-includes-file-change@master - with: - paths: ^CHANGELOG.md - - name: Set error - if: steps.changed.outputs.matched != 'true' && !contains(github.event.pull_request.body, '[x] Does not require a CHANGELOG entry') - run: echo "::error::CHANGELOG.md has not been modified. Either modify the file or check the checkbox in the body" && exit 1 - - # Job required by "confirmChangelogChecksPassed" - verify-changelog-valid: - name: Verify that Changelog is valid - runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ github.token }} - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Verify - run: .github/changelog-processor.py CHANGELOG.md --validate-changelog - - # This will only run if all the tests in its "needs" array passed. - # Add this as your required job, becuase if the matrix changes size (new things get added) - # it will still require all the steps to succeed. - # If you add more jobs, remember to add them to the "needs" array. - confirmChangelogChecksPassed: - runs-on: ubuntu-latest - name: All changelog checks passed - # If any new job gets added, be sure to add it to this list - needs: - - verify-changelog-updated - - verify-changelog-valid - steps: - - run: echo '### Good job! All the changelog checks passed 🚀' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/check-features.yml b/.github/workflows/check-features.yml deleted file mode 100644 index 6b67389ca7..0000000000 --- a/.github/workflows/check-features.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Various checks to verify the cargo workspace and its crates are correctly configured. -name: "Workspace features" - -on: - push: - branches: ["main", "release-*"] - pull_request: - workflow_dispatch: - -# cancel previous runs -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - check: - name: Check workspace features - runs-on: ubuntu-22.04 - - steps: - - name: Install stable Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - - - name: Install Zepter - run: cargo install --locked -q zepter && zepter --version - - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Dont clone historic commits. - - - name: Check features - run: | - zepter run check - # We will add this to the config file once its stabilized. Just run it in the CI for now. - zepter transpose dep lift-to-workspace 'regex:.*' diff --git a/.github/workflows/check-migrations.yml b/.github/workflows/check-migrations.yml deleted file mode 100644 index 968ff80c00..0000000000 --- a/.github/workflows/check-migrations.yml +++ /dev/null @@ -1,143 +0,0 @@ -name: Check Migrations - -# If you modify more jobs, ensure that you add them as required to the job "confirmMigrationsPassed" -# which is located at the end of this file (more info in the job) - -on: - push: - branches: ["main", "release-*"] - pull_request: - workflow_dispatch: - -# Cancel a currently running workflow from the same PR, branch or tag when a new workflow is -# triggered (ref https://stackoverflow.com/a/72408109) -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -# drop permissions for default token -permissions: {} - -jobs: - # This generates a matrix with all the required jobs which will be run in the next step - runtime-matrix: - runs-on: ubuntu-latest - outputs: - runtime: ${{ steps.runtime.outputs.runtime }} - name: Extract tasks from matrix - steps: - - uses: actions/checkout@v4 - - id: runtime - run: | - # Filter out runtimes that don't have a URI - TASKS=$(jq '[.[] | select(.uri != null)]' .github/workflows/runtimes-matrix.json) - SKIPPED_TASKS=$(jq '[.[] | select(.uri == null)]' .github/workflows/runtimes-matrix.json) - echo --- Running the following tasks --- - echo $TASKS - echo --- Skipping the following tasks due to not having a uri field --- - echo $SKIPPED_TASKS - # Strip whitespace from Tasks now that we've logged it - TASKS=$(echo $TASKS | jq -c .) - echo "runtime=$TASKS" >> $GITHUB_OUTPUT - - # This runs all the jobs in the matrix. It is required by the "confirmMigrationsPassed" job, so - # if they all pass, that job will pass too. - check-migrations: - needs: [runtime-matrix] - continue-on-error: true - runs-on: ubuntu-latest - strategy: - matrix: - runtime: ${{ fromJSON(needs.runtime-matrix.outputs.runtime) }} - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Build EXTRA_FLAGS - run: | - # When running on relay, we don't need weight checks. - EXTRA_FLAGS="${{ matrix.runtime.extra_args }}" - if [[ "${{ matrix.runtime.is_relay }}" == "true" ]]; then - EXTRA_FLAGS+="--no-weight-warnings" - echo "Disabling weight checks since we are on a relay" - - echo "Disabling try-state checks on the relay" - CHECKS="pre-and-post" - else - echo "Enabling weight checks since we are not on a relay" - - echo "Enabling try-state checks on the non-relay" - CHECKS="all" - fi - - EXTRA_FLAGS+=" --blocktime ${{ matrix.runtime.blocktime }} " - - # Disable the spec version check when we dont want to release. - # The program prints either `1` or `0`. - if [ "$(.github/changelog-processor.py CHANGELOG.md --should-release)" = "0" ]; then - EXTRA_FLAGS+=" --disable-spec-version-check" - echo "Disabling the spec version check since we are not releasing" - else - echo "Enabling the spec version check since we are releasing" - fi - - echo "Flags: $EXTRA_FLAGS" - echo "Checks: $CHECKS" - - echo "EXTRA_FLAGS=$EXTRA_FLAGS" >> $GITHUB_ENV - echo "CHECKS=$CHECKS" >> $GITHUB_ENV - - - name: Install Protoc - uses: arduino/setup-protoc@v1.3.0 - with: - version: "3.6.1" - - - name: Add wasm32-unknown-unknown target - run: rustup target add wasm32-unknown-unknown - shell: bash - - - name: Add rust-src component - run: rustup component add rust-src - shell: bash - - - name: Run ${{ matrix.runtime.name }} Runtime Checks - #uses: "paritytech/try-runtime-gha@v0.2.0" - env: - EXTRA_FLAGS: ${{ env.EXTRA_FLAGS }} - CHECKS: ${{ env.CHECKS }} - run: | - cargo install -q --git https://github.com/paritytech/try-runtime-cli --tag v0.8.0 --locked && try-runtime --version - - cargo build --profile production -p ${{ matrix.runtime.package }} --features try-runtime -q --locked - - PACKAGE_NAME=${{ matrix.runtime.package }} - RUNTIME_BLOB_NAME=$(echo $PACKAGE_NAME | sed 's/-/_/g').compact.compressed.wasm - RUNTIME_BLOB_PATH=./target/production/wbuild/$PACKAGE_NAME/$RUNTIME_BLOB_NAME - export RUST_LOG=remote-ext=debug,runtime=debug - - echo "Extra args: $EXTRA_FLAGS" - - # Store the command in a variable so we can log it - COMMAND="try-runtime \ - --runtime $RUNTIME_BLOB_PATH \ - on-runtime-upgrade --checks=$CHECKS \ - $EXTRA_FLAGS \ - live --uri ${{ matrix.runtime.uri }}" - - # Echo the command before running it, for debugging purposes - echo "Running command:" - echo "$COMMAND" - eval "$COMMAND" - - - # This will only run if all the tests in its "needs" array passed. - # Add this as your required job, becuase if the matrix changes size (new things get added) - # it will still require all the steps to succeed. - # If you add more jobs, remember to add them to the "needs" array. - confirmMigrationsPassed: - runs-on: ubuntu-latest - name: All migrations passed - # If any new job gets added, be sure to add it to this array - needs: [check-migrations] - steps: - - run: echo '### Good job! All the migrations passed 🚀' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml deleted file mode 100644 index a5dc42a6eb..0000000000 --- a/.github/workflows/clippy.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: "Clippy" - -on: - push: - branches: ["main", "release-*"] - pull_request: - workflow_dispatch: - -# cancel previous runs -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - clippy: - runs-on: ubuntu-22.04 - - steps: - - name: Install updates and protobuf-compiler - run: sudo apt update && sudo apt install --assume-yes cmake protobuf-compiler - - - name: Checkout - uses: actions/checkout@v4 - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install stable toolchain - run: | - rustup toolchain install $RUST_STABLE_VERSION --profile minimal --component clippy - cargo --version - cargo clippy --version - - - name: Fetch cache - uses: Swatinem/rust-cache@a95ba195448af2da9b00fb742d14ffaaf3c21f43 # v2.7.0 - with: - shared-key: "fellowship-cache-clippy" - - - name: Clippy - run: cargo clippy --all-targets --locked -q - env: - RUSTFLAGS: "-D warnings" - SKIP_WASM_BUILD: 1 diff --git a/.github/workflows/cmd.yml b/.github/workflows/cmd.yml deleted file mode 100644 index e30982abee..0000000000 --- a/.github/workflows/cmd.yml +++ /dev/null @@ -1,412 +0,0 @@ -name: Command - -on: - issue_comment: # listen for comments on issues - types: [created] - -permissions: # allow the action to comment on the PR - contents: write - issues: write - pull-requests: write - actions: read - -jobs: - fellows: - runs-on: ubuntu-latest - outputs: - github-handles: ${{ steps.load-fellows.outputs.github-handles }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Load fellows - id: load-fellows - uses: paritytech/get-fellows-action@v1.2.0 - - reject-non-fellows: - needs: fellows - if: ${{ startsWith(github.event.comment.body, '/cmd') && !contains(needs.fellows.outputs.github-handles, github.event.sender.login) }} - runs-on: ubuntu-latest - steps: - - name: Add reaction to rejected comment - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.reactions.createForIssueComment({ - comment_id: ${{ github.event.comment.id }}, - owner: context.repo.owner, - repo: context.repo.repo, - content: 'confused' - }) - - - name: Comment PR (Rejected) - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `Sorry, only fellows can run commands.` - }) - - acknowledge: - needs: fellows - if: ${{ startsWith(github.event.comment.body, '/cmd') && contains(needs.fellows.outputs.github-handles, github.event.sender.login) }} - runs-on: ubuntu-latest - steps: - - name: Add reaction to triggered comment - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.reactions.createForIssueComment({ - comment_id: ${{ github.event.comment.id }}, - owner: context.repo.owner, - repo: context.repo.repo, - content: 'eyes' - }) - - clean: - needs: fellows - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Clean previous comments - if: ${{ startsWith(github.event.comment.body, '/cmd') && contains(github.event.comment.body, '--clean') && contains(needs.fellows.outputs.github-handles, github.event.sender.login) }} - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.issues.listComments({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo - }).then(comments => { - for (let comment of comments.data) { - console.log(comment) - if ( - ${{ github.event.comment.id }} !== comment.id && - ( - ((comment.body.startsWith('Command') || comment.body.startsWith('
Command')) && comment.user.type === 'Bot') || - (comment.body.startsWith('/cmd') && comment.user.login === context.actor) - ) - ) { - github.rest.issues.deleteComment({ - comment_id: comment.id, - owner: context.repo.owner, - repo: context.repo.repo - }) - } - } - }) - help: - needs: [clean, fellows] - if: ${{ startsWith(github.event.comment.body, '/cmd') && contains(github.event.comment.body, '--help') && contains(needs.fellows.outputs.github-handles, github.event.sender.login) }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Get command - uses: actions-ecosystem/action-regex-match@v2 - id: get-pr-comment - with: - text: ${{ github.event.comment.body }} - regex: '^(\/cmd )([\s\w-]+)$' - - - name: Save output of help - id: help - env: - CMD: ${{ steps.get-pr-comment.outputs.group2 }} # to avoid "" around the command - run: | - echo 'help<> $GITHUB_OUTPUT - python3 .github/scripts/cmd/cmd.py $CMD >> $GITHUB_OUTPUT - echo 'EOF' >> $GITHUB_OUTPUT - - - name: Comment PR (Help) - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `
Command help: - - \`\`\` - ${{ steps.help.outputs.help }} - \`\`\` - -
` - }) - - - name: Add confused reaction on failure - uses: actions/github-script@v7 - if: ${{ failure() }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.reactions.createForIssueComment({ - comment_id: ${{ github.event.comment.id }}, - owner: context.repo.owner, - repo: context.repo.repo, - content: 'confused' - }) - - - name: Add 👍 reaction on success - uses: actions/github-script@v7 - if: ${{ !failure() }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.reactions.createForIssueComment({ - comment_id: ${{ github.event.comment.id }}, - owner: context.repo.owner, - repo: context.repo.repo, - content: '+1' - }) - - # Get PR branch name, because the issue_comment event does not contain the PR branch name - get-pr-branch: - needs: [clean, fellows] - runs-on: ubuntu-latest - outputs: - pr-branch: ${{ steps.get-pr.outputs.pr_branch }} - repo: ${{ steps.get-pr.outputs.repo }} - steps: - - name: Check if the issue is a PR - id: check-pr - run: | - if [ -n "${{ github.event.issue.pull_request.url }}" ]; then - echo "This is a pull request comment" - else - echo "This is not a pull request comment" - exit 1 - fi - - - name: Get PR Branch Name and Repo - if: steps.check-pr.outcome == 'success' - id: get-pr - uses: actions/github-script@v7 - with: - script: | - const pr = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - }); - const prBranch = pr.data.head.ref; - const repo = pr.data.head.repo.full_name; - core.setOutput('pr_branch', prBranch); - core.setOutput('repo', repo); - - - name: Use PR Branch Name and Repo - run: | - echo "The PR branch is ${{ steps.get-pr.outputs.pr_branch }}" - echo "The repository is ${{ steps.get-pr.outputs.repo }}" - - - cmd: - needs: [get-pr-branch, fellows] - env: - JOB_NAME: 'cmd' - if: ${{ startsWith(github.event.comment.body, '/cmd') && !contains(github.event.comment.body, '--help') && contains(needs.fellows.outputs.github-handles, github.event.sender.login) }} - runs-on: ${{ startsWith(github.event.comment.body, '/cmd bench') && 'gitrun-001' || 'ubuntu-22.04' }} - steps: - - name: Install updates and protobuf-compiler - if: startsWith(github.event.comment.body, '/cmd bench') - run: | - sudo apt update && sudo apt install --assume-yes \ - openssl pkg-config g++ make cmake protobuf-compiler curl libssl-dev libclang-dev libudev-dev git jq - - - name: Get command - uses: actions-ecosystem/action-regex-match@v2 - id: get-pr-comment - with: - text: ${{ github.event.comment.body }} - regex: '^(\/cmd )([\s\w-]+)$' - - - name: Build workflow link - if: ${{ !contains(github.event.comment.body, '--quiet') }} - id: build-link - run: | - # Get exactly the CMD job link, filtering out the other jobs - jobLink=$(curl -s \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/jobs | jq '.jobs[] | select(.name | contains("${{ env.JOB_NAME }}")) | .html_url') - - runLink=$(curl -s \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }} | jq '.html_url') - - echo "job_url=${jobLink}" - echo "run_url=${runLink}" - echo "job_url=$jobLink" >> $GITHUB_OUTPUT - echo "run_url=$runLink" >> $GITHUB_OUTPUT - - - - name: Comment PR (Start) - if: ${{ !contains(github.event.comment.body, '--quiet') }} - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - let job_url = ${{ steps.build-link.outputs.job_url }} - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has started 🚀 [See logs here](${job_url})` - }) - - - name: Checkout - uses: actions/checkout@v4 - with: - repository: ${{ needs.get-pr-branch.outputs.repo }} - ref: ${{ needs.get-pr-branch.outputs.pr-branch }} - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install Rust - uses: dtolnay/rust-toolchain@master - with: - targets: "wasm32-unknown-unknown,x86_64-unknown-linux-musl" - components: "rust-src rustfmt clippy" - toolchain: "nightly-${{env.RUST_NIGHTLY_VERSION}}" - - - name: Install dependencies for bench - if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') - run: cargo install subweight frame-omni-bencher --locked - - - name: Install dependencies for fmt - if: startsWith(steps.get-pr-comment.outputs.group2, 'fmt') - run: cargo install taplo-cli --version ${{ env.TAPLO_VERSION }} - - - name: Setup Cache - if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') - uses: Swatinem/rust-cache@a95ba195448af2da9b00fb742d14ffaaf3c21f43 # v2.7.0 - with: - shared-key: "fellowship-cmd" - - - name: Run cmd - id: cmd - env: - CMD: ${{ steps.get-pr-comment.outputs.group2 }} # to avoid "" around the command - run: | - echo "github.ref: ${{ github.ref }}" - echo "Running command: $CMD on branch ${{ needs.get-pr-branch.outputs.pr-branch }}" - git remote -v - python3 .github/scripts/cmd/cmd.py $CMD - git status - git diff - - - name: Commit changes - run: | - if [ -n "$(git status --porcelain)" ]; then - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - - git pull origin ${{ needs.get-pr-branch.outputs.pr-branch }} - git add . - git restore --staged Cargo.lock # ignore changes in Cargo.lock - git commit -m "Update from ${{ github.actor }} running command '${{ steps.get-pr-comment.outputs.group2 }}'" || true - git push origin ${{ needs.get-pr-branch.outputs.pr-branch }} - else - echo "Nothing to commit"; - fi - - - name: Run Subweight - id: subweight - if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') - shell: bash - run: | - git fetch - result=$(subweight compare commits \ - --path-pattern "./**/weights/**/*.rs" \ - --method asymptotic \ - --format markdown \ - --no-color \ - --change added changed \ - --ignore-errors \ - refs/remotes/origin/main refs/heads/${{ needs.get-pr-branch.outputs.pr-branch }}) - - # Save the multiline result to the output - { - echo "result<> $GITHUB_OUTPUT - - - name: Comment PR (End) - if: ${{ !failure() && !contains(github.event.comment.body, '--quiet') }} - uses: actions/github-script@v7 - env: - SUBWEIGHT: '${{ steps.subweight.outputs.result }}' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - let runUrl = ${{ steps.build-link.outputs.run_url }} - let subweight = process.env.SUBWEIGHT; - - let subweightCollapsed = subweight - ? `
\n\nSubweight results:\n\n${subweight}\n\n
` - : ''; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has finished ✅ [See logs here](${runUrl})${subweightCollapsed}` - }) - - - name: Comment PR (Failure) - if: ${{ failure() && !contains(github.event.comment.body, '--quiet') }} - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - let jobUrl = ${{ steps.build-link.outputs.job_url }} - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has failed ❌! [See logs here](${jobUrl})` - }) - - - name: Add 😕 reaction on failure - uses: actions/github-script@v7 - if: ${{ failure() }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.reactions.createForIssueComment({ - comment_id: ${{ github.event.comment.id }}, - owner: context.repo.owner, - repo: context.repo.repo, - content: 'confused' - }) - - - name: Add 👍 reaction on success - uses: actions/github-script@v7 - if: ${{ !failure() }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.reactions.createForIssueComment({ - comment_id: ${{ github.event.comment.id }}, - owner: context.repo.owner, - repo: context.repo.repo, - content: '+1' - }) - - diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml deleted file mode 100644 index 2b115bd863..0000000000 --- a/.github/workflows/fmt.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "Rustfmt (check)" - -on: - push: - branches: ["main", "release-*"] - pull_request: - workflow_dispatch: - -# Cancel a currently running workflow from the same PR, branch or tag when a new workflow is -# triggered (ref https://stackoverflow.com/a/72408109) -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - rustfmt: - runs-on: ubuntu-22.04 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install nightly toolchain - run: | - rustup toolchain install "nightly-$RUST_NIGHTLY_VERSION" --profile minimal --component rustfmt - cargo install taplo-cli --version $TAPLO_VERSION - - - name: Rustfmt (check) - run: cargo +nightly-$RUST_NIGHTLY_VERSION fmt --all -- --check - - - name: Taplo (check) - run: taplo format --check --config .config/taplo.toml diff --git a/.github/workflows/integration-tests-matrix.json b/.github/workflows/integration-tests-matrix.json deleted file mode 100644 index 48ce7e5681..0000000000 --- a/.github/workflows/integration-tests-matrix.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "name": "asset-hub-kusama", - "package": "asset-hub-kusama-integration-tests" - }, - { - "name": "asset-hub-polkadot", - "package": "asset-hub-polkadot-integration-tests" - }, - { - "name": "bridge-hub-kusama", - "package": "bridge-hub-kusama-integration-tests" - }, - { - "name": "bridge-hub-polkadot", - "package": "bridge-hub-polkadot-integration-tests" - }, - { - "name": "people-kusama", - "package": "people-kusama-integration-tests" - }, - { - "name": "people-polkadot", - "package": "people-polkadot-integration-tests" - }, - { - "name": "collectives-polkadot", - "package": "collectives-polkadot-integration-tests" - } -] diff --git a/.github/workflows/override.yml b/.github/workflows/override.yml new file mode 100644 index 0000000000..1cb0f51e38 --- /dev/null +++ b/.github/workflows/override.yml @@ -0,0 +1,71 @@ +name: Override +on: + workflow_dispatch: + inputs: + # The target runtime to build. + # + # For example, `polkadot-runtime` or `staging-kusama-runtime`. + runtime: + description: > + Target runtime crate to build. + required: true + type: choice + # Add the runtime crate name here that you want to build its override. + # + # These will be used as the target branch names for the override. + # Make sure these branches exist in the runtime repository. + options: [polkadot-runtime, staging-kusama-runtime] + # The branch, tag, or commit of the runtime repository to fetch. + # + # Generally, this would be the tag `vX.Y.Z` or `runtime-XYZ`. + ref: + description: > + Branch, tag, or commit of the runtime repository to fetch. + type: string + +permissions: + # Needed to commit the overrides. + contents: write + +env: + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + CARGO_TERM_COLOR: always + + RUST_BACKTRACE: full + +jobs: + mainnet: + name: Override + runs-on: ubuntu-latest + strategy: + matrix: + features: [force-debug, runtime-metrics] + steps: + - name: Override + # It is recommended to use a specific version of the action in production. + # + # For example: + # uses: hack-ink/polkadot-runtime-releaser/action/override@vX.Y.Z + uses: hack-ink/polkadot-runtime-releaser/action/override@main + with: + # The runtime repository. + # For demonstration purposes, we use the same repository. + # + # In production, + # current repository should be `x-network/runtime-overrides`, + # the runtime repository should be `x-network/polkadot-runtime`. + repository: hack-ink/polkadot-runtime-releaser-workshop + # The branch, tag, or commit of the runtime repository to fetch. + # + # Generally, this would be the tag `vX.Y.Z` or `runtime-XYZ`. + ref: ${{ inputs.ref }} + # The target runtime to build. + # + # For example, `polkadot-runtime` or `staging-kusama-runtime`. + runtime: ${{ inputs.runtime }} + # The features to enable for the override. + # + # For example, `force-debug`, `runtime-metrics` or `force-debug,runtime-metrics`. + features: ${{ matrix.features }} + # Use a Personal Access Token (PAT) if `GITHUB_TOKEN` does not have enough permissions to commit the overrides. + # token: .. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9d5deb9e7f..d0caf7ddae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,195 +1,128 @@ -name: Create Release +name: Release on: push: - branches: [ "main" ] - paths: [ "CHANGELOG.md" ] - workflow_dispatch: + tags: + - "v*" + +permissions: + # Necessary to trigger the override workflow. + actions: write + # Necessary to publish the release. + contents: write + +env: + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + CARGO_TERM_COLOR: always + + RUST_BACKTRACE: full jobs: - collect-release-information: - runs-on: ubuntu-latest - outputs: - should-release: ${{ steps.run.outputs.should-release }} - version: ${{ steps.run.outputs.version }} - steps: - - uses: actions/checkout@v4 - - id: run - run: | - echo "should-release=$(.github/changelog-processor.py CHANGELOG.md --should-release)" >> $GITHUB_OUTPUT - echo "version=$(.github/changelog-processor.py CHANGELOG.md --print-latest-version)" >> $GITHUB_OUTPUT - cat $GITHUB_OUTPUT - runtime-matrix: - needs: [ collect-release-information ] - if: needs.collect-release-information.outputs.should-release == '1' + # This job triggers the override workflow for the target runtime. + trigger-override: + name: Trigger override runs-on: ubuntu-latest - outputs: - runtime: ${{ steps.runtime.outputs.runtime }} + strategy: + matrix: + # Add the runtime here that you want to build its override. + # + # The possible values are defined in the `override.yml` workflow. + runtime: [polkadot-runtime, staging-kusama-runtime] steps: - - uses: actions/checkout@v4 - - id: runtime - run: | - TASKS=$(echo $(cat .github/workflows/runtimes-matrix.json) | sed 's/ //g' ) - echo $TASKS - echo "runtime=$TASKS" >> $GITHUB_OUTPUT - build-runtimes: - needs: [ runtime-matrix ] - continue-on-error: true + - name: Trigger override + env: + # Use a Personal Access Token (PAT) if `GITHUB_TOKEN` does not have enough permissions to trigger the override workflow. + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # It is recommended to put the override workflow in the main branch in the runtime-overrides repository. + # So, we dispatch it from main branch to build for other `RUNTIME` branches by `--ref main`. + run: gh workflow run override.yml + --repo hack-ink/polkadot-runtime-releaser-workshop + --ref main + -f runtime="${{ matrix.runtime }}" + -f ref="${{ github.ref_name }}" + build-runtime: + name: Build runtime runs-on: ubuntu-latest strategy: matrix: - runtime: ${{ fromJSON(needs.runtime-matrix.outputs.runtime) }} + # Add the runtime here that you want to release. + runtime: [polkadot-runtime, staging-kusama-runtime] steps: - - name: Checkout sources + - name: Fetch latest code uses: actions/checkout@v4 - - - name: Cache target dir - uses: actions/cache@v4 + - name: Build runtime + # It is recommended to use a specific version of the action in production. + # + # For example: + # uses: hack-ink/polkadot-runtime-releaser/action/build@vX.Y.Z + uses: hack-ink/polkadot-runtime-releaser/action/build@main with: - path: "${{ github.workspace }}/${{ matrix.runtime.path }}/target" - key: srtool-target-${{ matrix.runtime.path }}-${{ matrix.runtime.name }}-${{ github.sha }} - restore-keys: | - srtool-target-${{ matrix.runtime.path }}-${{ matrix.runtime.name }}- - srtool-target-${{ matrix.runtime.path }}- - - - name: Build ${{ matrix.runtime.name }} - id: srtool_build - uses: chevdor/srtool-actions@v0.8.0 - env: - BUILD_OPTS: "--features on-chain-release-build" - with: - chain: ${{ matrix.runtime.name }} - package: ${{ matrix.runtime.package }} - runtime_dir: ${{ matrix.runtime.path }} - profile: "production" - - - name: Store ${{ matrix.runtime.name }} srtool digest to disk + # The target runtime to build. + # + # For example, `polkadot-runtime` or `staging-kusama-runtime`. + runtime: ${{ matrix.runtime }} + # The features to enable for this release build. + # + # Generally, this would be `on-chain-release-build` in order to disable the logging to shrink the WASM binary size. + features: on-chain-release-build + # Rust toolchain version to build the runtime. + toolchain-ver: 1.81.0 + # The workdir to build the runtime. + # + # By default, it is current directory. + # workdir: . + # The output directory of the WASM binary. + output-dir: . + - name: Construct runtime info + id: construction run: | - echo '${{ steps.srtool_build.outputs.json }}' | jq > ${{ matrix.runtime.name }}_srtool_output.json + RUNTIME="$(echo "${{ matrix.runtime }}" | sed 's/-/_/g')" + echo "RUNTIME=$RUNTIME" + echo "runtime=$RUNTIME" >> "$GITHUB_OUTPUT" - - name: Upload ${{ matrix.runtime.name }} srtool json - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.runtime.name }}-srtool-json - path: ${{ matrix.runtime.name }}_srtool_output.json + WASM=$(ls "${RUNTIME}"-*.compact.compressed.wasm) + JSON=$(ls "${RUNTIME}"-*.json) - - name: Upload ${{ matrix.runtime.name }} + cat "$JSON" | jq '.' > tmp.json + mv tmp.json "$JSON" + - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: ${{ matrix.runtime.name }} + name: ${{ matrix.runtime }}-artifact path: | - ${{ steps.srtool_build.outputs.wasm_compressed }} - - publish-release: + ${{ steps.construction.outputs.runtime }}-*.compact.compressed.wasm + ${{ steps.construction.outputs.runtime }}-*.json + release: + name: Release runs-on: ubuntu-latest - needs: [ build-runtimes, collect-release-information ] - outputs: - release_url: ${{ steps.create-release.outputs.html_url }} - asset_upload_url: ${{ steps.create-release.outputs.upload_url }} + needs: build-runtime steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Download srtool json output + - name: Download artifact uses: actions/download-artifact@v4 - - - name: Archive context output - uses: actions/upload-artifact@v4 with: - name: release-notes-context - path: | - **/*_srtool_output.json - - - name: Add runtime info to changelog + path: download + - name: Construct release notes run: | - CONTEXT=$(find . -name '*_srtool_output.json') - SRTOOL() { <$(<<<$CONTEXT head -n1) jq -r .$1; } - WASM() { <${JSON} jq -r ".runtimes.compressed.subwasm.$1"; } - - # Copy the relevant parts of the changelog - .github/changelog-processor.py CHANGELOG.md --print-changelog-from-last-release > DRAFT - - tee -a DRAFT <<-EOF - # Runtime info - *These runtimes were built with **$(SRTOOL rustc)** using **[$(SRTOOL gen)](https://github.com/paritytech/srtool)*** - - To replicate the build, use the following command: - \`\`\`sh - srtool build - --root --profile production - --package CRATE_NAME --runtime-dir PATH_TO_CRATE - --build-opts="--features=on-chain-release-build" - \`\`\` - EOF - - for JSON in $(<<<$CONTEXT sort -sr) - do - SPEC_NAME=$(WASM 'core_version.specName') - # Check for spec names and adjust the heading accordingly - if [[ "$SPEC_NAME" == "statemint" ]]; then - HEADING="Asset Hub Polkadot (previously Statemint)" - elif [[ "$SPEC_NAME" == "statemine" ]]; then - HEADING="Asset Hub Kusama (previously Statemine)" - else - HEADING=$(WASM 'core_version.specName / "-" | map(. / "" | first |= ascii_upcase | add) | join(" ")') - fi - - tee -a DRAFT <<-EOF - - ## $HEADING - ~~~ - 🏋️ Runtime Size: $(numfmt --to iec-i --format "%.2f" $(WASM size)) ($(WASM size) bytes) - 🗜 Compressed: $(WASM 'compression | if .compressed then "Yes: \(1 - .size_compressed / .size_decompressed | . * 10000 | round / 100)%" else "No" end') - 🔥 Core Version: $(WASM 'core_version | "\(.specName)-\(.specVersion) \(.implName)-\(.implVersion).tx\(.transactionVersion).au\(.authoringVersion)"') - 🎁 Metadata version: V$(WASM metadata_version) - 🗳️ Blake2-256 hash: $(WASM blake2_256) - 📦 IPFS: $(WASM ipfs_hash) - ~~~ - EOF + for artifact_dir in download/*-artifact; do + if [ -d "$artifact_dir" ]; then + for json_file in "$artifact_dir"/*.json; do + [ -f "$json_file" ] || continue + + BASE_NAME="$(basename "$json_file")" + NAME_NO_EXT="${BASE_NAME%.json}" + NAME="${NAME_NO_EXT//_/-}" + + echo "## $NAME" >> release_note.md + echo "\`\`\`json" >> release_note.md + cat "$json_file" >> release_note.md + echo "\`\`\`" >> release_note.md + echo "" >> release_note.md + done + fi done - - - name: Create release - id: create-release - # TODO: Replace as it has been deprecated - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ format('v{0}', needs.collect-release-information.outputs.version) }} - release_name: Runtimes ${{ needs.collect-release-information.outputs.version }} - body_path: DRAFT - draft: false - - publish-runtimes: - needs: [ runtime-matrix, publish-release ] - continue-on-error: true - runs-on: ubuntu-latest - env: - RUNTIME_DIR: runtime - strategy: - matrix: - runtime: ${{ fromJSON(needs.runtime-matrix.outputs.runtime) }} - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Download artifacts - uses: actions/download-artifact@v4 - - - name: Get runtime info - env: - JSON: release-notes-context/${{ matrix.runtime.name }}-srtool-json/${{ matrix.runtime.name }}_srtool_output.json - run: | - >>$GITHUB_ENV echo ASSET=$(find ${{ matrix.runtime.name }} -name '*.compact.compressed.wasm') - >>$GITHUB_ENV echo SPEC=$(<${JSON} jq -r .runtimes.compact.subwasm.core_version.specVersion) - - - name: Upload compressed ${{ matrix.runtime.name }} v${{ env.SPEC }} wasm - # TODO: Replace as it has been deprecated - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Publish release + uses: softprops/action-gh-release@v2 with: - upload_url: ${{ needs.publish-release.outputs.asset_upload_url }} - asset_path: ${{ env.ASSET }} - asset_name: ${{ matrix.runtime.name }}_runtime-v${{ env.SPEC }}.compact.compressed.wasm - asset_content_type: application/wasm + body_path: release_note.md + files: | + download/**/*.wasm diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml deleted file mode 100644 index ffb6763014..0000000000 --- a/.github/workflows/review-bot.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Review Bot - -on: - workflow_run: - workflows: - - Review-Trigger - types: - - completed - -permissions: - contents: read - -jobs: - review-approvals: - runs-on: ubuntu-latest - steps: - - name: Extract content of artifact - id: number - uses: Bullrich/extract-text-from-artifact@v1.0.1 - with: - artifact-name: pr_number - - name: Generate token - id: team_token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.REVIEW_APP_ID }} - private-key: ${{ secrets.REVIEW_APP_KEY }} - - name: "Evaluates PR reviews and assigns reviewers" - uses: paritytech/review-bot@v2.6.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - team-token: ${{ steps.team_token.outputs.token }} - checks-token: ${{ steps.team_token.outputs.token }} - pr-number: ${{ steps.number.outputs.content }} diff --git a/.github/workflows/review-trigger.yml b/.github/workflows/review-trigger.yml deleted file mode 100644 index 82570a0e46..0000000000 --- a/.github/workflows/review-trigger.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Review-Trigger - -on: - pull_request_target: - types: - - opened - - reopened - - synchronize - - review_requested - - review_request_removed - - ready_for_review - pull_request_review: - pull_request: - workflow_dispatch: - -jobs: - trigger-review-bot: - # (It is not a draft) && (it is not a review || it is an approving review) - if: ${{ github.event.pull_request.draft != true && (github.event_name != 'pull_request_review' || (github.event.review && github.event.review.state == 'APPROVED')) }} - runs-on: ubuntu-latest - name: trigger review bot - steps: - - name: Get PR data - id: comments - run: | - echo "bodies=$(gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json comments --jq '[.comments[].body]')" >> "$GITHUB_OUTPUT" - echo "reviews=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews --jq '[.[].state]')" >> "$GITHUB_OUTPUT" - env: - GH_TOKEN: ${{ github.token }} - - name: Get the GitHub handle of the fellows - uses: paritytech/get-fellows-action@v1.2.0 - id: fellows - # Require new reviews when the author is pushing and he is not a fellow - - name: Fail when author pushes new code - # if (contains approved reviews && it's a synchronize event && was triggered by the author (who is not a fellow)) - if: | - contains(fromJson(steps.comments.outputs.reviews), 'APPROVED') && - github.event_name == 'pull_request_target' && - github.event.action == 'synchronize' && - github.event.sender.login == github.event.pull_request.user.login && - !contains(steps.fellows.outputs.github-handles, github.event.pull_request.user.login) - run: | - # We get the list of reviewers who approved the PR - REVIEWERS=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews \ - --jq '{reviewers: [.[] | select(.state == "APPROVED") | .user.login]}') - - # We request them to review again - echo $REVIEWERS | gh api --method POST repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/requested_reviewers --input - - - echo "::error::Project needs to be reviewed again" - exit 1 - env: - GH_TOKEN: ${{ github.token }} - - name: Comment requirements - # If the previous step failed and github-actions hasn't commented yet we comment instructions - if: failure() && !contains(fromJson(steps.comments.outputs.bodies), 'Review required! Latest push from author must always be reviewed') - run: | - gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "Review required! Latest push from author must always be reviewed" - env: - GH_TOKEN: ${{ github.token }} - COMMENTS: ${{ steps.comments.outputs.users }} - - name: Get PR number - env: - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - echo "Saving PR number: $PR_NUMBER" - mkdir -p ./pr - echo $PR_NUMBER > ./pr/pr_number - - uses: actions/upload-artifact@v4 - name: Save PR number - with: - name: pr_number - path: pr/ - retention-days: 5 diff --git a/.github/workflows/runtimes-matrix.json b/.github/workflows/runtimes-matrix.json deleted file mode 100644 index 172c53929c..0000000000 --- a/.github/workflows/runtimes-matrix.json +++ /dev/null @@ -1,106 +0,0 @@ -[ - { - "name": "polkadot", - "package": "polkadot-runtime", - "path": "relay/polkadot", - "uri": "wss://try-runtime.polkadot.io:443", - "is_relay": true, - "blocktime": 6000 - }, - { - "name": "kusama", - "package": "staging-kusama-runtime", - "path": "relay/kusama", - "uri": "wss://try-runtime-kusama.polkadot.io:443", - "is_relay": true, - "blocktime": 6000 - }, - { - "name": "glutton-kusama", - "package": "glutton-kusama-runtime", - "path": "system-parachains/gluttons/glutton-kusama", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "asset-hub-kusama", - "package": "asset-hub-kusama-runtime", - "path": "system-parachains/asset-hubs/asset-hub-kusama", - "uri": "wss://kusama-asset-hub-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "asset-hub-polkadot", - "package": "asset-hub-polkadot-runtime", - "path": "system-parachains/asset-hubs/asset-hub-polkadot", - "uri": "wss://polkadot-asset-hub-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "bridge-hub-kusama", - "package": "bridge-hub-kusama-runtime", - "path": "system-parachains/bridge-hubs/bridge-hub-kusama", - "uri": "wss://kusama-bridge-hub-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "bridge-hub-polkadot", - "package": "bridge-hub-polkadot-runtime", - "path": "system-parachains/bridge-hubs/bridge-hub-polkadot", - "uri": "wss://polkadot-bridge-hub-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "collectives-polkadot", - "package": "collectives-polkadot-runtime", - "path": "system-parachains/collectives/collectives-polkadot", - "uri": "wss://polkadot-collectives-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "coretime-kusama", - "package": "coretime-kusama-runtime", - "path": "system-parachains/coretime/coretime-kusama", - "uri": "wss://kusama-coretime-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "coretime-polkadot", - "package": "coretime-polkadot-runtime", - "path": "system-parachains/coretime/coretime-polkadot", - "is_relay": false, - "blocktime": 12000, - "uri": "wss://polkadot-coretime-rpc.polkadot.io:443" - }, - { - "name": "people-kusama", - "package": "people-kusama-runtime", - "path": "system-parachains/people/people-kusama", - "uri": "wss://kusama-people-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 6000 - }, - { - "name": "people-polkadot", - "package": "people-polkadot-runtime", - "path": "system-parachains/people/people-polkadot", - "uri": "wss://polkadot-people-rpc.polkadot.io:443", - "is_relay": false, - "blocktime": 12000 - }, - { - "name": "encointer-kusama", - "package": "encointer-kusama-runtime", - "path": "system-parachains/encointer", - "uri": "wss://kusama.api.encointer.org:443", - "is_relay": false, - "blocktime": 12000, - "extra_args": "--disable-mbm-checks" - } -] diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 31fce66445..0000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,283 +0,0 @@ -name: "Test all features" - -# If you modify more test jobs, ensure that you add them as required to the job "confirmTestPassed" -# which is located at the end of this file (more info in the job) - -on: - push: - branches: ["main", "release-*"] - pull_request: - workflow_dispatch: - -env: - FRAME_OMNI_BENCHER_RELEASE_VERSION: polkadot-stable2409 - -# cancel previous runs -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - # This generates a matrix with all the required jobs which will be run in the next step - runtime-matrix: - runs-on: ubuntu-latest - outputs: - runtime: ${{ steps.runtime.outputs.runtime }} - name: Extract runtimes from matrix - steps: - - uses: actions/checkout@v4 - - id: runtime - run: | - TASKS=$(echo $(cat .github/workflows/runtimes-matrix.json) | sed 's/ //g' ) - echo $TASKS - echo "runtime=$TASKS" >> $GITHUB_OUTPUT - - integration-test-matrix: - runs-on: ubuntu-latest - outputs: - itest: ${{ steps.itest.outputs.itest }} - name: Extract integration tests from matrix - steps: - - uses: actions/checkout@v4 - - id: itest - run: | - TASKS=$(echo $(cat .github/workflows/integration-tests-matrix.json) | sed 's/ //g' ) - echo $TASKS - echo "itest=$TASKS" >> $GITHUB_OUTPUT - - # Job required by "confirmTestPassed" - runtime-test: - needs: [runtime-matrix] - runs-on: ubuntu-22.04 - strategy: - matrix: - runtime: ${{ fromJSON(needs.runtime-matrix.outputs.runtime) }} - steps: - - name: Install updates and protobuf-compiler - run: sudo apt update && sudo apt install --assume-yes cmake protobuf-compiler - - - name: Free space on the runner - run: | - df -h - sudo apt -y autoremove --purge - sudo apt -y autoclean - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - df -h - - - name: Checkout - uses: actions/checkout@v4 - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install stable toolchain - run: | - rustup install $RUST_STABLE_VERSION - rustup default $RUST_STABLE_VERSION - rustup target add wasm32-unknown-unknown - rustup component add rust-src - - - name: Fetch cache - uses: Swatinem/rust-cache@a95ba195448af2da9b00fb742d14ffaaf3c21f43 # v2.7.0 - with: - shared-key: "fellowship-cache-tests" - - - name: Download frame-omni-bencher - run: | - curl -sL https://github.com/paritytech/polkadot-sdk/releases/download/$FRAME_OMNI_BENCHER_RELEASE_VERSION/frame-omni-bencher -o frame-omni-bencher - chmod +x ./frame-omni-bencher - ./frame-omni-bencher --version - shell: bash - - - name: Test ${{ matrix.runtime.name }} - run: cargo test -p ${{ matrix.runtime.package }} --release --locked -q - env: - RUSTFLAGS: "-C debug-assertions -D warnings" - - - name: Test all features ${{ matrix.runtime.name }} - run: cargo test -p ${{ matrix.runtime.package }} --release --locked -q --all-features - env: - RUSTFLAGS: "-C debug-assertions -D warnings" - SKIP_WASM_BUILD: 1 - - - name: Test benchmarks ${{ matrix.runtime.name }} - run: | - PACKAGE_NAME=${{ matrix.runtime.package }} - RUNTIME_BLOB_NAME=$(echo $PACKAGE_NAME | sed 's/-/_/g').compact.compressed.wasm - RUNTIME_BLOB_PATH=./target/production/wbuild/$PACKAGE_NAME/$RUNTIME_BLOB_NAME - # build wasm - echo "Preparing wasm for benchmarking RUNTIME_BLOB_PATH=$RUNTIME_BLOB_PATH" - cargo build --profile production -p ${{ matrix.runtime.package }} --features=runtime-benchmarks -q --locked - # run benchmarking - echo "Running benchmarking for RUNTIME_BLOB_PATH=$RUNTIME_BLOB_PATH" - ./frame-omni-bencher v1 benchmark pallet --runtime $RUNTIME_BLOB_PATH --all --steps 2 --repeat 1 - env: - RUSTFLAGS: "-C debug-assertions -D warnings" - - # Job required by "confirmTestPassed" - integration-test: - needs: [integration-test-matrix] - runs-on: ubuntu-22.04 - strategy: - matrix: - itest: ${{ fromJSON(needs.integration-test-matrix.outputs.itest) }} - steps: - - name: Cancel previous runs - uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # v0.11.0 - with: - access_token: ${{ github.token }} - - - name: Install updates and protobuf-compiler - run: sudo apt update && sudo apt install --assume-yes cmake protobuf-compiler - - - name: Free space on the runner - run: | - df -h - sudo apt -y autoremove --purge - sudo apt -y autoclean - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - df -h - - - name: Checkout - uses: actions/checkout@v4 - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install stable toolchain - run: | - rustup install $RUST_STABLE_VERSION - rustup default $RUST_STABLE_VERSION - rustup target add wasm32-unknown-unknown - rustup component add rust-src - - - name: Fetch cache - uses: Swatinem/rust-cache@a95ba195448af2da9b00fb742d14ffaaf3c21f43 # v2.7.0 - with: - shared-key: "fellowship-cache-tests" - - - name: Test ${{ matrix.itest.name }} - run: cargo test -p ${{ matrix.itest.package }} --release --locked -q - env: - RUSTFLAGS: "-C debug-assertions -D warnings" - - # Job required by "confirmTestPassed" - build-chain-spec-generator: - runs-on: ubuntu-latest - steps: - - name: Cancel previous runs - uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # v0.11.0 - with: - access_token: ${{ github.token }} - - - name: Install updates and protobuf-compiler - run: sudo apt update && sudo apt install --assume-yes cmake protobuf-compiler - - - name: Free space on the runner - run: | - df -h - sudo apt -y autoremove --purge - sudo apt -y autoclean - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - df -h - - - name: Checkout - uses: actions/checkout@v4 - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install stable toolchain - run: | - rustup install $RUST_STABLE_VERSION - rustup default $RUST_STABLE_VERSION - rustup target add wasm32-unknown-unknown - rustup component add rust-src - - - name: Fetch cache - uses: Swatinem/rust-cache@a95ba195448af2da9b00fb742d14ffaaf3c21f43 # v2.7.0 - with: - shared-key: "fellowship-cache-tests" - - - name: Build - run: cargo test -p chain-spec-generator --release --locked -q --features=runtime-benchmarks - env: - RUSTFLAGS: "-C debug-assertions -D warnings" - SKIP_WASM_BUILD: 1 - - # Job required by "confirmTestPassed" - zombienet-smoke: - needs: [build-chain-spec-generator] - runs-on: ubuntu-latest - steps: - - name: Cancel previous runs - uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # v0.11.0 - with: - access_token: ${{ github.token }} - - - name: Install updates and protobuf-compiler - run: sudo apt update && sudo apt install --assume-yes cmake protobuf-compiler - - - name: Free space on the runner - run: | - df -h - sudo apt -y autoremove --purge - sudo apt -y autoclean - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - df -h - - - name: Checkout - uses: actions/checkout@v4 - - - name: Set rust version via common env file - run: cat .github/env >> $GITHUB_ENV - - - name: Install stable toolchain - run: | - rustup install $RUST_STABLE_VERSION - rustup default $RUST_STABLE_VERSION - rustup target add wasm32-unknown-unknown - rustup component add rust-src - - - name: Fetch cache - uses: Swatinem/rust-cache@a95ba195448af2da9b00fb742d14ffaaf3c21f43 # v2.7.0 - with: - shared-key: "fellowship-cache-integration-tests" - - - name: Build - run: | - cargo build -p chain-spec-generator --features fast-runtime --release --locked - - - name: Zombienet smoke test - timeout-minutes: 20 - run: | - export PATH=$(pwd)/target/release:$PATH - cargo test --manifest-path integration-tests/zombienet/Cargo.toml - - # This will only run if all the tests in its "needs" array passed. - # Add this as your required job, becuase if the matrix changes size (new things get added) - # it will still require all the steps to succeed. - # If you add more jobs, remember to add them to the "needs" array. - confirmTestPassed: - runs-on: ubuntu-latest - name: All tests passed - # If any new job gets added, be sure to add it to this list - needs: - - runtime-test - - integration-test - - build-chain-spec-generator - - zombienet-smoke - steps: - - run: echo '### Good job! All the tests passed 🚀' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml new file mode 100644 index 0000000000..54e4ebf10a --- /dev/null +++ b/.github/workflows/try-runtime.yml @@ -0,0 +1,56 @@ +name: Try Runtime + +on: + issue_comment: + types: [created] + +permissions: + # Necessary to comment on the pull requests. + pull-requests: write + +env: + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + CARGO_TERM_COLOR: always + + RUST_BACKTRACE: full + +jobs: + try-runtime: + if: > + github.event.issue.pull_request && + contains(github.event.comment.body, '/bot try-runtime') + runs-on: ubuntu-latest + strategy: + matrix: + # Add the runtime name and URI here. + runtime: + - name: polkadot-runtime + uri: wss://polkadot.dotters.network + - name: staging-kusama-runtime + uri: wss://kusama.dotters.network + steps: + - name: Fetch latest code + uses: actions/checkout@v4 + - name: Try-Runtime + # It is recommended to use a specific version of the action in production. + # + # For example: + # uses: hack-ink/polkadot-runtime-releaser/action/try-runtime@vX.Y.Z + uses: hack-ink/polkadot-runtime-releaser/action/try-runtime@main + with: + # The target runtime to build. + # + # For example, `polkadot-runtime` or `staging-kusama-runtime`. + runtime: ${{ matrix.runtime.name }} + # The features to enable for this try-runtime build. + features: try-runtime + # Rust toolchain version to build the runtime. + toolchain-ver: 1.81.0 + # Try-Runtime CLI version. + try-runtime-ver: 0.8.0 + # Whether to skip enforcing that the new runtime `spec_version` is greater or equal to the existing `spec_version`. + disable-spec-version-check: ${{ contains(github.event.comment.body, '--disable-spec-version-check') }} + # Whether to disable migration idempotency checks. + disable-idempotency-checks: ${{ contains(github.event.comment.body, '--disable-idempotency-checks') }} + # The URI of the node to connect to fetch the state. + uri: ${{ matrix.runtime.uri }} diff --git a/.github/workflows/up-to-date.yml b/.github/workflows/up-to-date.yml deleted file mode 100644 index a660979a8a..0000000000 --- a/.github/workflows/up-to-date.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Keep PR up to date - -on: - push: - branches: - - main - -jobs: - updatePullRequests: - name: Keep PRs up to date - runs-on: ubuntu-latest - environment: master - steps: - - name: Generate token - id: generate_token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.MERGE_APP_ID }} - private-key: ${{ secrets.MERGE_APP_KEY }} - - name: Update all the PRs - uses: paritytech/up-to-date-action@v0.2.1 - with: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index c342153912..0000000000 --- a/.rustfmt.toml +++ /dev/null @@ -1,24 +0,0 @@ -# Basic -edition = "2021" -hard_tabs = true -max_width = 100 -use_small_heuristics = "Max" -# Imports -imports_granularity = "Crate" -reorder_imports = true -# Consistency -newline_style = "Unix" -# Misc -chain_width = 80 -spaces_around_ranges = false -binop_separator = "Back" -reorder_impl_items = false -match_arm_leading_pipes = "Preserve" -match_arm_blocks = false -match_block_trailing_comma = true -trailing_comma = "Vertical" -trailing_semicolon = false -use_field_init_shorthand = true -# Format comments -comment_width = 100 -wrap_comments = true diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 6fe06d9544..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,482 +0,0 @@ -# Changelog - -Changelog for the runtimes governed by the Polkadot Fellowship. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## [Unreleased] - -- Fix missing Encointer democracy pallet hook needed for enactment ([polkadot-fellows/runtimes/pull/508](https://github.com/polkadot-fellows/runtimes/pull/508)) - -### Added - -- Location conversion tests for relays and parachains ([polkadot-fellows/runtimes#487](https://github.com/polkadot-fellows/runtimes/pull/487)) - -### Changed - -- Kusama Treasury: remove funding to the Kappa Sigma Mu Society and disable burn ([polkadot-fellows/runtimes#507](https://github.com/polkadot-fellows/runtimes/pull/507)) -- Remove Snowbridge create agent and channel extrinsics. ([polkadot-fellows/runtimes#506](https://github.com/polkadot-fellows/runtimes/pull/506)) - -#### From [#490](https://github.com/polkadot-fellows/runtimes/pull/490) - -- Transfer Polkadot-native assets to Ethereum ([SDK `stable2409` #5710](https://github.com/paritytech/polkadot-sdk/pull/5710), [SDK #5546](https://github.com/paritytech/polkadot-sdk/pull/5546)) -- Add possibility to inject non-authorities session-keys in genesis ([SDK `stable2409` #5078](https://github.com/paritytech/polkadot-sdk/pull/5078)) -- \[bridges-v2\] Permissionless lanes ([SDK `stable2409` #4949](https://github.com/paritytech/polkadot-sdk/pull/4949)) -- \[Assets\] Call implementation for `transfer_all` ([SDK `stable2409` #4527](https://github.com/paritytech/polkadot-sdk/pull/4527)) -- Tx Payment: drop ED requirements for tx payments with exchangeable asset ([SDK `stable2409` #4488](https://github.com/paritytech/polkadot-sdk/pull/4488)) -- Coretime auto-renew ([SDK `stable2409` #4424](https://github.com/paritytech/polkadot-sdk/pull/4424)) -- Initialises pallet-delegated-staking ([SDK `v1.12.0` #3904](https://github.com/paritytech/polkadot-sdk/pull/3904)) - -### Changed - -#### From [#490](https://github.com/polkadot-fellows/runtimes/pull/490) - -- Polkadot Primitives v8 ([SDK v1.16 #5525](https://github.com/paritytech/polkadot-sdk/pull/5525)). -- Relax `XcmFeeToAccount` trait bound on `AccountId` ([SDK v1.16 #4959](https://github.com/paritytech/polkadot-sdk/pull/4959)) -- Bridges V2 refactoring backport and `pallet_bridge_messages` simplifications ([SDK `stable2407` #4935](https://github.com/paritytech/polkadot-sdk/pull/4935)) -- Renamed `assigner_on_demand` to `on_demand` ([SDK `stable2409` #4706](https://github.com/paritytech/polkadot-sdk/pull/4706)). -- \[BEEFY\] Add runtime support for reporting fork voting ([SDK `stable2407` #4522](https://github.com/paritytech/polkadot-sdk/pull/4522)). -- Migrates Nomination Pool to use delegated staking: i.e. allowing delegated funds to be held in member's own account - instead of the pool account. This would enable pool member funds to be used for voting in opengov. - ([SDK `v1.13.0` #3905](https://github.com/paritytech/polkadot-sdk/pull/3905)) - -## [1.3.4] 01.11.2024 - -### Changed - -- Change Polkadot inflation to 120M DOT per year ([polkadot-fellows/runtimes#471](https://github.com/polkadot-fellows/runtimes/pull/471)) -- Update foreign asset ids in Asset Hub Polkadot and Asset Hub Kusama from v3 to v4 locations ([polkadot-fellows/runtimes#472](https://github.com/polkadot-fellows/runtimes/pull/472)) -- Lower Parachain and Data Deposits to Encourage Experimentation on Kusama ([polkadot-fellows/runtimes#501](https://github.com/polkadot-fellows/runtimes/pull/501)) - -### Fixed - -- Fix `experimental_inflation_info` in Polkadot and remove unused code (https://github.com/polkadot-fellows/runtimes/pull/497) - -## [1.3.3] 01.10.2024 - -### Changed - -- Allow signed origins to send arbitrary XCMs from some system chains ([polkadot-fellows/runtimes#407](https://github.com/polkadot-fellows/runtimes/pull/407)) -- Include the Core and Salary pallets into the Fellowship proxy ([polkadot-fellows/runtimes#454](https://github.com/polkadot-fellows/runtimes/pull/454)) -- Add new community democracy and treasuries pallets to Encointer ([polkadot-fellows/runtimes#456](https://github.com/polkadot-fellows/runtimes/pull/456)) -- Change target block time for Encointer to 6s ([polkadot-fellows/runtimes#462](https://github.com/polkadot-fellows/runtimes/pull/462)) -- Asset Hubs: allow Polkadot, Kusama and Ethereum assets across P<>K bridge ([polkadot-fellows/runtimes#421](https://github.com/polkadot-fellows/runtimes/pull/421)). - -### Fixed - -- Chain-spec generator: propagate the `on_chain_release_build` feature to the chain-spec generator. Without this the live/genesis chain-specs contain a wrongly-configured WASM blob ([polkadot-fellows/runtimes#450](https://github.com/polkadot-fellows/runtimes/pull/450)). -- Adds a migration to the Polkadot Coretime chain to fix an issue from the initial Coretime migration. ([polkadot-fellows/runtimes#458](https://github.com/polkadot-fellows/runtimes/pull/458)) -- Adds migrations to restore currupted staking ledgers in Polkadot and Kusama ([polkadot-fellows/runtimes#447](https://github.com/polkadot-fellows/runtimes/pull/447)) - -### Added - -- Polkadot: Make the current inflation formula adjustable ([polkadot-fellows/runtimes#443](https://github.com/polkadot-fellows/runtimes/pull/443)) - -## [1.3.2] 27.08.2024 - -### Fixed - -- Kusama: Revert accidental changes to inflation formula ([polkadot-fellows/runtimes#445](https://github.com/polkadot-fellows/runtimes/pull/445)). - -## [1.3.1] 23.08.2024 - -### Fixed - -- [🚨 Breaking Change] Polkadot Collectives: enable transaction payment ([polkadot-fellows/runtimes#442](https://github.com/polkadot-fellows/runtimes/pull/442)) - -## [1.3.0] 20.08.2024 - -### Added - -- Kusama: Relay General Admin Origin mapping to xcm Location ([polkadot-fellows/runtimes#383](https://github.com/polkadot-fellows/runtimes/pull/383)) -- Encointer, PeopleKusama, PeoplePolkadot: Configure delivery fees for UMP ([polkadot-fellows/runtimes#390](https://github.com/polkadot-fellows/runtimes/pull/390)) -- Introduce a new dispatchable function `set_partial_params` in `pallet-core-fellowship` ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #3843](https://github.com/paritytech/polkadot-sdk/pull/3843)). -- RFC-5: Add request revenue info ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #3940](https://github.com/paritytech/polkadot-sdk/pull/3940)). -- Core-Fellowship: new `promote_fast` call ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #4877](https://github.com/paritytech/polkadot-sdk/pull/4877)). -- Pallet ranked collective: max member count per rank ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #4807](https://github.com/paritytech/polkadot-sdk/pull/4807)). -- All runtimes: XcmPaymentApi and DryRunApi ([polkadot-fellows/runtimes#380](https://github.com/polkadot-fellows/runtimes/pull/380)) -- Fast promotion tracks for the Fellowship ranks I-III ([polkadot-fellows/runtimes#356](https://github.com/polkadot-fellows/runtimes/pull/356)). -- All runtimes: add `LocationToAccountApi` ([polkadot-fellows/runtimes#413](https://github.com/polkadot-fellows/runtimes/pull/413)) -- Enable Agile Coretime on Polkadot ([polkadot-fellows/runtimes#401](https://github.com/polkadot-fellows/runtimes/pull/401)) -- Add the Polkadot Coretime Chain runtime ([polkadot-fellows/runtimes#410](https://github.com/polkadot-fellows/runtimes/pull/410)) -- Kusama: Add a "Spokesperson" proxy type only allowed to send remarks ([polkadot-fellows/runtimes#430](https://github.com/polkadot-fellows/runtimes/pull/430)) -- Add the Polkadot and Kusama Coretime Chain specs ([polkadot-fellows/runtimes#432](https://github.com/polkadot-fellows/runtimes/pull/432)) -- Migration to remove all but the 21 first elected Head Ambassador members from the Program ([polkadot-fellows/runtimes#422](https://github.com/polkadot-fellows/runtimes/pull/422)). -- Kusama: Make the current inflation formula adjustable ([polkadot-fellows/runtimes#364](https://github.com/polkadot-fellows/runtimes/pull/364)) -- Port Agile Coretime migration from polkadot-sdk in order to fix leases with gaps handling([polkadot-fellows/runtimes#426](https://github.com/polkadot-fellows/runtimes/pull/426)) - -#### From [#322](https://github.com/polkadot-fellows/runtimes/pull/322) - -- Add `claim_assets` extrinsic to `pallet-xcm` ([SDK v1.9 #3403](https://github.com/paritytech/polkadot-sdk/pull/3403)). -- Add `Deposited`/`Withdrawn` events for `pallet-assets` ([SDK v1.12 #4312](https://github.com/paritytech/polkadot-sdk/pull/4312)). -- Add `MaxRank` Config to `pallet-core-fellowship` ([SDK v1.13 #3393](https://github.com/paritytech/polkadot-sdk/pull/3393)). -- Add Extra Check in Primary Username Setter ([SDK v1.13 #4534](https://github.com/paritytech/polkadot-sdk/pull/4534)). -- Add HRMP notification handlers to the xcm-executor ([SDK v1.10 #3696](https://github.com/paritytech/polkadot-sdk/pull/3696)). -- Add retry mechanics to `pallet-scheduler` ([SDK v1.8 #3060](https://github.com/paritytech/polkadot-sdk/pull/3060)). -- Add support for versioned notification for HRMP pallet ([SDK v1.12 #4281](https://github.com/paritytech/polkadot-sdk/pull/4281)). -- Adds ability to trigger tasks via unsigned transactions ([SDK v1.11 #4075](https://github.com/paritytech/polkadot-sdk/pull/4075)). -- Asset Conversion: Pool Account ID derivation with additional Pallet ID seed ([SDK v1.11 #3250](https://github.com/paritytech/polkadot-sdk/pull/3250)). -- Asset Conversion: Pool Touch Call ([SDK v1.11 #3251](https://github.com/paritytech/polkadot-sdk/pull/3251)). -- Balances: add failsafe for consumer ref underflow ([SDK v1.12 #3865](https://github.com/paritytech/polkadot-sdk/pull/3865)). -- Bridge: added force_set_pallet-state call to pallet-bridge-grandpa ([SDK v1.13 #4465](https://github.com/paritytech/polkadot-sdk/pull/4465)). -- Burn extrinsic call and `fn burn_from` `Preservation` argument ([SDK v1.12 #3964](https://github.com/paritytech/polkadot-sdk/pull/3964)). -- GenesisConfig presets for runtime ([SDK v1.11 #2714](https://github.com/paritytech/polkadot-sdk/pull/2714)). -- Im-online pallet offchain storage cleanup ([SDK v1.8 #2290](https://github.com/paritytech/polkadot-sdk/pull/2290)). -- Implements a percentage cap on staking rewards from era inflation ([SDK v1.8 #1660](https://github.com/paritytech/polkadot-sdk/pull/1660)). -- Introduce submit_finality_proof_ex call to bridges GRANDPA pallet ([SDK v1.8 #3225](https://github.com/paritytech/polkadot-sdk/pull/3225)). -- New call `hrmp.establish_channel_with_system` to allow parachains to establish a channel with a system parachain ([SDK v1.11 #3721](https://github.com/paritytech/polkadot-sdk/pull/3721)). -- New runtime api to check if a validator has pending pages of rewards for an era ([SDK v1.12 #4301](https://github.com/paritytech/polkadot-sdk/pull/4301)). -- Pallet-xcm: add new extrinsic for asset transfers using explicit reserve ([SDK v1.11 #3695](https://github.com/paritytech/polkadot-sdk/pull/3695)). -- Ranked collective introduce `Add` and `Remove` origins ([SDK v1.8 #3212](https://github.com/paritytech/polkadot-sdk/pull/3212)). -- Runtime apis to help with delegate-stake based Nomination Pools ([SDK v1.13 #4537](https://github.com/paritytech/polkadot-sdk/pull/4537)). - -### Changed - -- Polkadot chains: allow arbitrary XCM execution ([polkadot-fellows/runtimes#345](https://github.com/polkadot-fellows/runtimes/pull/345)). -- Bounties: Remove payout delay ([polkadot-fellows/runtimes#386](https://github.com/polkadot-fellows/runtimes/pull/386)). -- Polkadot System Chains: Reduce the base transaction fee by half ([polkadot-fellows/runtimes#398](https://github.com/polkadot-fellows/runtimes/pull/398)). -- Asset Hubs: setup auto incremented asset id to 50_000_000 for trust backed assets ([polkadot-fellows/runtimes#414](https://github.com/polkadot-fellows/runtimes/pull/414)). -- Upgrade dependencies to the [polkadot-sdk@1.13.0](https://github.com/paritytech/polkadot-sdk/releases/tag/polkadot-v1.13.0) release ([polkadot-fellows/runtimes#332](https://github.com/polkadot-fellows/runtimes/pull/332)). -- Filter `interlace` calls on the Polkadot Coretime Chain until the Relay chain implementation is more mature ([polkadot-fellows/runtimes#438](https://github.com/polkadot-fellows/runtimes/pull/438)). - -#### From [#322](https://github.com/polkadot-fellows/runtimes/pull/322) - -- The `MessageQueue` also runs "on idle", this causes `MessageQueue::Processed` events to be emitted in other phases than just initialization ([SDK v1.13 #3844](https://github.com/paritytech/polkadot-sdk/pull/3844)). -- AdaptPrice trait is now price controlled ([SDK v1.13 #4521](https://github.com/paritytech/polkadot-sdk/pull/4521)). -- Allow StakingAdmin to manage nomination pool configurations ([SDK v1.11 #3959](https://github.com/paritytech/polkadot-sdk/pull/3959)). -- Bridge: make some headers submissions free ([SDK v1.12 #4102](https://github.com/paritytech/polkadot-sdk/pull/4102)). -- Improving on_demand_assigner emitted events ([SDK v1.13 #4339](https://github.com/paritytech/polkadot-sdk/pull/4339)). -- `pallet-broker::start_sales`: Take `extra_cores` and not total cores ([SDK v1.11 #4221](https://github.com/paritytech/polkadot-sdk/pull/4221)). -- Pallet-nomination-pools: `chill` is permissionless if depositor's stake is less than `min_nominator_bond` ([SDK v1.9 #3453](https://github.com/paritytech/polkadot-sdk/pull/3453)). -- `polkadot_runtime_parachains::coretime`: Expose `MaxXcmTransactWeight` ([SDK v1.11 #4189](https://github.com/paritytech/polkadot-sdk/pull/4189)). -- Pools: Make PermissionlessWithdraw the default claim permission ([SDK v1.10 #3438](https://github.com/paritytech/polkadot-sdk/pull/3438)). -- Prevents staking controllers from becoming stashes of different ledgers; Ensures that no ledger in bad state is mutated ([SDK v1.9 #3639](https://github.com/paritytech/polkadot-sdk/pull/3639)). -- Snowbridge: deposit extra fee to beneficiary on Asset Hub ([SDK v1.12 #4175](https://github.com/paritytech/polkadot-sdk/pull/4175)). -- Storage bound the XCMP queue pallet ([SDK v1.13 #3952](https://github.com/paritytech/polkadot-sdk/pull/3952)). -- Validator disabling strategy in runtime ([SDK v1.12 #2226](https://github.com/paritytech/polkadot-sdk/pull/2226)). - -### Fixed - -- Fix claim queue size ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #4691](https://github.com/paritytech/polkadot-sdk/pull/4691)). -- `pallet-referenda`: Ensure to schedule referenda earliest at the next block ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #4823](https://github.com/paritytech/polkadot-sdk/pull/4823)). -- Don't partially modify HRMP pages ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #4710](https://github.com/paritytech/polkadot-sdk/pull/4710)). -- Coretime Chain: mitigate behaviour with many assignments on one core ([runtimes#434](https://github.com/polkadot-fellows/runtimes/pull/434)). -- Port Agile Coretime migration from polkadot-sdk in order to fix leases with gaps handling([polkadot-fellows/runtimes#426](https://github.com/polkadot-fellows/runtimes/pull/426)) - -#### From [#322](https://github.com/polkadot-fellows/runtimes/pull/322) - -- CheckWeight checks for combined extrinsic length and proof size ([SDK v1.12 #4326](https://github.com/paritytech/polkadot-sdk/pull/4326)). -- Decrement total_deposit when clearing collection metadata ([SDK v1.11 #3976](https://github.com/paritytech/polkadot-sdk/pull/3976)). -- Detect incorrect pre-image length when submitting a referenda ([SDK v1.10 #3850](https://github.com/paritytech/polkadot-sdk/pull/3850)). -- Fix `schedule_code_upgrade` when called by the owner/root ([SDK v1.10 #3341](https://github.com/paritytech/polkadot-sdk/pull/3341)). -- Fix algorithmic complexity of the on-demand scheduler ([SDK v1.10 #3190](https://github.com/paritytech/polkadot-sdk/pull/3190)). -- Fix call enum's metadata regression ([SDK v1.9 #3513](https://github.com/paritytech/polkadot-sdk/pull/3513)). -- Fix dust unbonded for zero existential deposit ([SDK v1.12 #4364](https://github.com/paritytech/polkadot-sdk/pull/4364)). -- Fix extrinsics count logging in frame-system ([SDK v1.12 #4461](https://github.com/paritytech/polkadot-sdk/pull/4461)). -- Fix kusama 0 backing rewards when entering active set ([SDK v1.10 #3722](https://github.com/paritytech/polkadot-sdk/pull/3722)). -- Fix Stuck Collator Funds ([SDK v1.11 #4229](https://github.com/paritytech/polkadot-sdk/pull/4229)). -- Fix weight calculation and event emission in pallet-membership ([SDK v1.9 #3324](https://github.com/paritytech/polkadot-sdk/pull/3324)). -- Fix weight refund for `pallet-collator-selection::set_candidacy_bond` ([SDK v1.9 #3643](https://github.com/paritytech/polkadot-sdk/pull/3643)). -- Fixed `GrandpaConsensusLogReader::find_scheduled_change` ([SDK v1.11 #4208](https://github.com/paritytech/polkadot-sdk/pull/4208)). -- Fixes a scenario where a nomination pool's `TotalValueLocked` is out of sync due to staking's implicit withdraw ([SDK v1.8 #3052](https://github.com/paritytech/polkadot-sdk/pull/3052)). -- Handle legacy lease swaps on coretime ([SDK v1.10 #3714](https://github.com/paritytech/polkadot-sdk/pull/3714)). -- Ignore mandatory extrinsics in total PoV size check ([SDK v1.13 #4571](https://github.com/paritytech/polkadot-sdk/pull/4571)). -- Pallet assets: minor improvement on errors returned for some calls ([SDK v1.11 #4118](https://github.com/paritytech/polkadot-sdk/pull/4118)). -- Pallet-broker: Fix `Linear::adapt_price` behavior at zero ([SDK v1.9 #3636](https://github.com/paritytech/polkadot-sdk/pull/3636)). -- Pallet-broker: Fix claim revenue behaviour for zero timeslices ([SDK v1.11 #3997](https://github.com/paritytech/polkadot-sdk/pull/3997)). -- Pallet-broker: Support renewing leases expired in a previous period ([SDK v1.11 #4089](https://github.com/paritytech/polkadot-sdk/pull/4089)). -- Pallet-broker: Use saturating math in input validation ([SDK v1.11 #4151](https://github.com/paritytech/polkadot-sdk/pull/4151)). -- Pallet-xcm: fix transport fees for remote reserve transfers ([SDK v1.10 #3792](https://github.com/paritytech/polkadot-sdk/pull/3792)). -- Patch pool to handle extra consumer ref when destroying ([SDK v1.13 #4503](https://github.com/paritytech/polkadot-sdk/pull/4503)). -- Region reserve transfers fix ([SDK v1.11 #3455](https://github.com/paritytech/polkadot-sdk/pull/3455)). -- Snowbridge - Ethereum Client - Reject finalized updates without a sync committee in next store period ([SDK v1.13 #4478](https://github.com/paritytech/polkadot-sdk/pull/4478)). -- Treat XCM ExceedsStackLimit errors as transient in the MQ pallet ([SDK v1.12 #4202](https://github.com/paritytech/polkadot-sdk/pull/4202)). -- Unrequest a pre-image when it failed to execute ([SDK v1.10 #3849](https://github.com/paritytech/polkadot-sdk/pull/3849)). -- Validate code when scheduling uprades ([SDK v1.8 #3232](https://github.com/paritytech/polkadot-sdk/pull/3232)). -- XCMP: Use the number of 'ready' pages in XCMP suspend logic ([SDK v1.9 #2393](https://github.com/paritytech/polkadot-sdk/pull/2393)). - -### Removed - -- Remove deprecated calls from treasury pallet ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #3820](https://github.com/paritytech/polkadot-sdk/pull/3820)). -- Treasury pallet: - remove unused config parameters ([runtimes#381](https://github.com/polkadot-fellows/runtimes/pull/381), [SDK v1.14 #4831](https://github.com/paritytech/polkadot-sdk/pull/4831)). -- Remove Identity from Polkadot Relay Chain ([runtimes#415](https://github.com/polkadot-fellows/runtimes/pull/415)) -- Kusama: Remove unused Snowbridge code and configs ([polkadot-fellows/runtimes#411](https://github.com/polkadot-fellows/runtimes/pull/411)). -- Remove the identity ops pallet after the invalid judgments have been cleared ([polkadot-fellows/runtimes#408](https://github.com/polkadot-fellows/runtimes/pull/408)). - -#### From [#322](https://github.com/polkadot-fellows/runtimes/pull/322) - -- Deprecate dmp-queue pallet ([SDK v1.13 #4475](https://github.com/paritytech/polkadot-sdk/pull/4475)). -- Deprecate XCMv2 ([SDK v1.13 #4131](https://github.com/paritytech/polkadot-sdk/pull/4131)). -- Identity: Remove double encoding username signature payload ([SDK v1.13 #4646](https://github.com/paritytech/polkadot-sdk/pull/4646)). -- Pallet-xcm: deprecate execute and send in favor of execute_blob and send_blob ([SDK v1.10 #3749](https://github.com/paritytech/polkadot-sdk/pull/3749)). -- Pallet-xcm: deprecate transfer extrinsics without weight limit ([SDK v1.10 #3927](https://github.com/paritytech/polkadot-sdk/pull/3927)). -- Remove `parametrized-consensus-hook` feature ([SDK v1.13 #4380](https://github.com/paritytech/polkadot-sdk/pull/4380)). - -## [1.2.8] 03.07.2024 - -### Changed - -- Snowbridge: Sync headers on demand ([polkadot-fellows/runtimes#365](https://github.com/polkadot-fellows/runtimes/pull/365)) -- Polkadot chains: allow arbitrary XCM execution ([polkadot-fellows/runtimes#345](https://github.com/polkadot-fellows/runtimes/pull/345)). - -Note: This release only affects the following runtimes and is not a full system release: - -- Polkadot Relay Chain -- Polkadot Asset Hub -- Polkadot Bridge Hub -- Polkadot Collectives -- Kusama Relay Chain -- Kusama Bridge Hub - -### Fixed - -- Kusama People: Build the metadata hash at build time, so that `CheckMetadata` can use it at runtime ([polkadot-fellows/runtimes#371](https://github.com/polkadot-fellows/runtimes/pull/371)) - -## [1.2.7] 14.06.2024 - -Note: This release only affects the following runtimes and is not a full system release: - -- Polkadot Relay Chain -- Polkadot People - -### Changed - -- Updated Relay and People configurations to complete launch ([polkadot-fellows/runtimes#350](https://github.com/polkadot-fellows/runtimes/pull/350)) - -## [1.2.6] 13.06.2024 - -Note: This release only affects the following runtimes and is not a full system release: - -- Polkadot Relay Chain -- Polkadot Asset Hub -- Polkadot People -- Kusama Relay Chain -- Kusama Asset Hub -- Kusama People - -### Added - -- Add the Polkadot People Chain ([polkadot-fellows/runtimes#319](https://github.com/polkadot-fellows/runtimes/pull/319)) - -### Changed - -- Set max asset ID restriction for the creation of trusted assets ([polkadot-fellows/runtimes#346](https://github.com/polkadot-fellows/runtimes/pull/346)) - -### Fixed - -- Kusama People: clear requested judgements that do not have corresponding deposits reserved ([polkadot-fellows/runtimes#339](https://github.com/polkadot-fellows/runtimes/pull/339)) - -### Changed - -- People chain now uses 6-second block times ([polkadot-fellows/runtimes#308](https://github.com/polkadot-fellows/runtimes/pull/308)) - -### Removed - -- Removed Identity-related code from Kusama Relay Chain ([polkadot-fellows/runtimes#315](https://github.com/polkadot-fellows/runtimes/pull/315)) - -## [1.2.5] 06.06.2024 - -### Added - -- Staking runtime api to check if reward is pending for an era ([polkadot-fellows/runtimes#318](https://github.com/polkadot-fellows/runtimes/pull/318)) -- Allow any parachain to have bidirectional channel with any system parachains ([polkadot-fellows/runtimes#329](https://github.com/polkadot-fellows/runtimes/pull/329)) -- Update price controller of broker pallet to use higher leadin, without adjusting the minimum price too much ([polkadot-fellows/runtimes#334](https://github.com/polkadot-fellows/runtimes/pull/334)) -- Enable support for new hardware signers like the generic ledger app ([polkadot-fellows/runtimes#337](https://github.com/polkadot-fellows/runtimes/pull/337)) - -### Changed - -- Transaction payments work via new `fungible` trait implementation ([polkadot-fellows/runtimes#332](https://github.com/polkadot-fellows/runtimes/pull/332)) -- Block `request_judgement` calls on the Relay Chain ([polkadot-fellows/runtimes#338](https://github.com/polkadot-fellows/runtimes/pull/338)) - -### Fixed - -- Handle extra erroneous consumer reference when a nomination pool is destroying ([polkadot-fellows/runtimes#318](https://github.com/polkadot-fellows/runtimes/pull/318)) -- Introduce [Encointer](https://encointer.org) collator selection and send fees to authors instead of treasury ([polkadot-fellows/runtimes#270](https://github.com/polkadot-fellows/runtimes/pull/270)) - -## [1.2.4] 20.05.2024 - -### Changed - -- Kusama chains: allow arbitrary XCM execution ([polkadot-fellows/runtimes#261](https://github.com/polkadot-fellows/runtimes/pull/261)) -- Allow everything through XCM SafeCallFilter ([polkadot-fellows/runtimes#285](https://github.com/polkadot-fellows/runtimes/pull/285)) -- Disable Coretime credit purchasing until we have the credit system implemented ([polkadot-fellows/runtimes#312](https://github.com/polkadot-fellows/runtimes/pull/312)) - -### Added - -- Add `pallet-vesting` to Asset Hubs ([polkadot-fellows/runtimes#269](https://github.com/polkadot-fellows/runtimes/pull/269)) -- Add Pay Salary Collectives test ([polkadot-fellows/runtimes#260](https://github.com/polkadot-fellows/runtimes/pull/260)) -- Add `pallet-xcm::transfer_assets_using_type_and_then()` for complex asset transfers ([polkadot-fellows/runtimes#311](https://github.com/polkadot-fellows/runtimes/pull/311)) -- The Ambassador Program ([polkadot-fellows/runtimes#291](https://github.com/polkadot-fellows/runtimes/pull/291)) - -### Removed - -- Remove one-shot migrations from Kusama Coretime ([polkadot-fellows/runtimes#300](https://github.com/polkadot-fellows/runtimes/pull/300)) -- Remove DMP queue and allow `system::authorize_upgrade` in XCM's call filter ([polkadot-fellows/runtimes#280](https://github.com/polkadot-fellows/runtimes/pull/280)) -- Allow Sending XCM messages using a Signed origin on Kusama ([polkadot-fellows/runtimes#290](https://github.com/polkadot-fellows/runtimes/pull/290)) - -### Fixed - -- Include patch to release stuck collator bonds ([polkadot-fellows/runtimes#289](https://github.com/polkadot-fellows/runtimes/pull/289)) -- Safeguard pallet-balances against consumer ref underflow ([polkadot-fellows/runtimes#309](https://github.com/polkadot-fellows/runtimes/pull/309)) -- Polkadot Bridge Hub: Unstuck Snowbridge ([polkadot-fellows/runtimes#313](https://github.com/polkadot-fellows/runtimes/pull/313)) - -## [1.2.3] 29.04.2024 - -### Added - -- Add migration to Kusama Coretime to onboard People Chain without long delay ([polkadot-fellows/runtimes#286](https://github.com/polkadot-fellows/runtimes/pull/286)) - -### Fixed - -- Clean up outdated assignment in Kusama Coretime Chain state ([polkadot-fellows/runtimes#286](https://github.com/polkadot-fellows/runtimes/pull/286)) - -## [1.2.2] 20.04.2024 - -### Fixed - -- Polkadot Bridge Hub: Unstuck bridge with Kusama ([polkadot-fellows/runtimes#277](https://github.com/polkadot-fellows/runtimes/pull/277)). -- Fix Kusama Coretime launch issues: import leases and fix renewals for short leases ([polkadot-fellows/runtimes#276](https://github.com/polkadot-fellows/runtimes/pull/276)) - -## [1.2.1] 09.04.2024 - -### Changed - -- Modify runtimes for phase two of People Chain launch (Kusama) ([polkadot-fellows/runtimes#246](https://github.com/polkadot-fellows/runtimes/pull/246)) - -## [1.2.0] 28.03.2024 - -### Added - -- Remove state-trie-migration pallet from kusama, add state trie migration to V1 on polkadot ([polkadot-fellows/runtimes#170](https://github.com/polkadot-fellows/runtimes/pull/170)) -- Introduce chain spec generator ([polkadot-fellows/runtimes#127](https://github.com/polkadot-fellows/runtimes/pull/127)) -- Add [Encointer](https://encointer.org) system parachain runtime, completing [RFC22](https://github.com/polkadot-fellows/RFCs/blob/main/text/0022-adopt-encointer-runtime.md) ([polkadot-fellows/runtimes#80](https://github.com/polkadot-fellows/runtimes/pull/80)) -- Feature for enabling debug prints in the Polkadot and Kusama runtime ([polkadot-fellows/runtimes#85](https://github.com/polkadot-fellows/runtimes/pull/85)) -- Added new "Wish for Change" track ([polkadot-fellows/runtimes#184](https://github.com/polkadot-fellows/runtimes/pull/184)) -- Enable Coretime and on-demand on Kusama ([polkadot-fellows/runtimes#159](https://github.com/polkadot-fellows/runtimes/pull/159)) -- Refund any leases that are not migrated to Coretime (have holes in them/have not yet started) ([polkadot-fellows/runtimes#206](https://github.com/polkadot-fellows/runtimes/pull/206)) -- Enable Elastic Scaling node side feature for Kusama ([polkadot-fellows/runtimes#205](https://github.com/polkadot-fellows/runtimes/pull/205)) -- Cancel Parachain Auctions ([polkadot-fellows/runtimes#215](https://github.com/polkadot-fellows/runtimes/pull/215)) -- Upgrade encointer protocol to 6.1.0 ([polkadot-fellows/runtimes#236](https://github.com/polkadot-fellows/runtimes/pull/236)) -- Update NFT deposits according to RFC-45 ([polkadot-fellows/runtimes#237](https://github.com/polkadot-fellows/runtimes/pull/237)) -- Add Kusama People Chain ([polkadot-fellows/runtimes#217](https://github.com/polkadot-fellows/runtimes/pull/217)) -- Asset Conversion setup for Polkadot Asset Hub, and XCM Swap Weight Trader for both Asset Hubs ([polkadot-fellows/runtimes#218](https://github.com/polkadot-fellows/runtimes/pull/218)) -- Adds Snowbridge to Kusama and Polkadot ([polkadot-fellows/runtimes#130](https://github.com/polkadot-fellows/runtimes/pull/130)) -- Add the Kusama Coretime Chain ([polkadot-fellows/runtimes#212](https://github.com/polkadot-fellows/runtimes/pull/212)) - -### Changed - -- Upgrade parachains runtime API from v7 to v8 in Kusama ([context](https://paritytech.github.io/polkadot-sdk/book/protocol-validator-disabling.html), [polkadot-fellows/runtimes#148](https://github.com/polkadot-fellows/runtimes/pull/148)). -- Fixed the lowering of Asset Hub existential deposits. -- MMR leaves generated by `pallet_mmr` point to the next-authority-set of the current block instead of the prior block [polkadot-fellows/runtimes#169](https://github.com/polkadot-fellows/runtimes/pull/169) -- Deprecate the `xcm::body::TREASURER_INDEX` constant and use the standard `Treasury` variant from the `xcm::BodyId` type instead ([polkadot-fellows/runtimes#149](https://github.com/polkadot-fellows/runtimes/pull/149)) -- Bump parachains runtime API to v9 in Kusama to enable the `node_features` function [polkadot-fellows/runtimes#194](https://github.com/polkadot-fellows/runtimes/pull/194) -- Bump parachains runtime API to v10 in Kusama to enable the `approval-voting-params` function [polkadot-fellows/runtimes#204](https://github.com/polkadot-fellows/runtimes/pull/204) -- Use Relay Chain's Treasury Pallet account as a destination for XCM fees on System Parachain ([polkadot-fellows/runtimes#191](https://github.com/polkadot-fellows/runtimes/pull/191)) -- Bump parachains runtime API to v10 in Polkadot to enable async-backing subsystems(still in backwards compatible mode) [polkadot-fellows/runtimes#222](https://github.com/polkadot-fellows/runtimes/pull/222) -- Prepared system parachain runtimes for async backing enabling ([polkadot-fellows/runtimes#228](https://github.com/polkadot-fellows/runtimes/pull/228)) -- Update runtime weights [polkadot-fellows/runtimes#223](https://github.com/polkadot-fellows/runtimes/pull/223) -- Treasury Spend detects relative locations of the native asset ([polkadot-fellows/runtimes#233](https://github.com/polkadot-fellows/runtimes/pull/233)) -- Increase consumer reference limits for Asset Hubs ([polkadot-fellows/runtimes#258](https://github.com/polkadot-fellows/runtimes/pull/258)) -- Updated Asset Hub asset class creation deposit to use `system_para_deposit()` ([polkadot-fellows/runtimes#259](https://github.com/polkadot-fellows/runtimes/pull/259)) - -### Removed - -- Removed the `SafeCallFilter` from the Relay Chain XCM config ([polkadot-fellows/runtimes#172](https://github.com/polkadot-fellows/runtimes/pull/172)). -- Removed the `ImOnline` pallet ([polkadot-fellows/runtimes#178](https://github.com/polkadot-fellows/runtimes/pull/178)) - -### Fixed - -- Fixed the cost of a single byte, sent over bridge to use the `TransactionByteFee` constant of the bridged chain [polkadot-fellows/runtimes#174](https://github.com/polkadot-fellows/runtimes/pull/174). - -### Based on Polkadot-SDK - -- Upgrade dependencies to the [polkadot-sdk@1.5.0](https://github.com/paritytech/polkadot-sdk/releases/tag/polkadot-v1.5.0) release ([polkadot-fellows/runtimes#137](https://github.com/polkadot-fellows/runtimes/pull/137)) -- Upgrade dependencies to the [polkadot-sdk@1.6.0](https://github.com/paritytech/polkadot-sdk/releases/tag/polkadot-v1.6.0) release ([polkadot-fellows/runtimes#159](https://github.com/polkadot-fellows/runtimes/pull/159)) -- Upgrade dependencies to the [polkadot-sdk@1.7.0](https://github.com/paritytech/polkadot-sdk/releases/tag/polkadot-v1.7.0) release ([polkadot-fellows/runtimes#187](https://github.com/polkadot-fellows/runtimes/pull/187)) - -## [1.1.1] 25.01.2024 - -### Fixed - -- Fixed the lowering of Asset Hub existential deposits ([polkadot-fellows/runtimes#158](https://github.com/polkadot-fellows/runtimes/pull/158)). - -## [1.1.0] 10.01.2024 - -### Changed - -- Upgrade parachains runtime API from v5 to v7 in Polkadot and Kusama ([polkadot-fellows/runtimes#56](https://github.com/polkadot-fellows/runtimes/pull/56)) -- Upgrade Preimage pallet's config implementations to adapt the new `Consideration` API ([polkadot-fellows/runtimes#56](https://github.com/polkadot-fellows/runtimes/pull/56)) -- Remove `experimental` feature flag for `pallet-society`, `pallet-xcm`, and `runtime-common` crates imports ([polkadot-fellows/runtimes#56](https://github.com/polkadot-fellows/runtimes/pull/56)) -- Election provider: use a geometric deposit base calculation for EPM signed submissions in Polkadot and Kusama ([polkadot-fellows/runtimes#56](https://github.com/polkadot-fellows/runtimes/pull/56)) -- Make `IdentityInfo` generic in `pallet-identity` ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: -- Whitelist `force_default_xcm_version` in XCM call filter ([polkadot-fellows/runtimes#45](https://github.com/polkadot-fellows/runtimes/pull/45)) -- Update the fellowship salary budget amount in alignment with the Fellowship Salary [RFC](https://github.com/polkadot-fellows/RFCs/pull/50) ([polkadot-fellows/runtimes#121](https://github.com/polkadot-fellows/runtimes/pull/121)) -- Set up an account ID for the local root location on Polkadot Collectives ([polkadot-fellows/runtimes#125](https://github.com/polkadot-fellows/runtimes/pull/125)) -- Increase confirmation period for treasury spend tracks on Polkadot & Kusama ([polkadot-fellows/runtimes#119](https://github.com/polkadot-fellows/runtimes/pull/119)) -- Drop ED requirement for transaction payments with an exchangeable asset ([polkadot-fellows/runtimes#310](https://github.com/polkadot-fellows/runtimes/pull/310)) - -### Added - -- Enable async backing on Kusama ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: -- Implemented GenesisBuilder API for all runtimes ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: -- XCM transport fees are now exponential and are sent to a treasury account ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: -- System parachains are now trusted teleporters of each other ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: -- Treasury is able to spend various asset kinds ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)) -- Add BEEFY to Polkadot ([polkadot-fellows/runtimes#65](https://github.com/polkadot-fellows/runtimes/pull/65)) -- Fellowship Treasury pallet on Polkadot Collectives ([polkadot-fellows/runtimes#109](https://github.com/polkadot-fellows/runtimes/pull/109)) -- Added Polkadot <> Kusama bridge to support asset transfers between Asset Hubs ([polkadot-fellows/runtimes#108](https://github.com/polkadot-fellows/runtimes/pull/108)) - -### Fixed - -- Add missing weight functions for `runtime_parachains_hrmp` and `preimage` pallets ([polkadot-fellows/runtimes#56](https://github.com/polkadot-fellows/runtimes/pull/56)) -- Fix for Reward Deficit in the pool ([polkadot-fellows/runtimes#87](https://github.com/polkadot-fellows/runtimes/pull/87)). Context: - -## [1.0.1] 14.11.2023 - -### Changed - -- Restore governance lock periods to 7 days in Polkadot ([polkadot-fellows/runtimes#86](https://github.com/polkadot-fellows/runtimes/pull/86)) - -## [1.0.0] 22.10.2023 - -### Changed - -- Update Polkadot ideal staking rate ([polkadot-fellows/runtimes#26](https://github.com/polkadot-fellows/runtimes/pull/26)) -- Treasury deprecate `propose_spend` dispatchable ([paritytech/substrate#14538](https://github.com/paritytech/substrate/pull/14538)) -- Use benchmarked weights for `XCM` ([paritytech/polkadot#7077](https://github.com/paritytech/polkadot/pull/7077)) -- Put HRMP Channel Management on General Admin Track ([paritytech/polkadot#7477](https://github.com/paritytech/polkadot/pull/7477)) -- Improve locking mechanism for parachains ([paritytech/polkadot-sdk#1290](https://github.com/paritytech/polkadot-sdk/pull/1290)) -- Allow Root to initiate auctions ([paritytech/polkadot#7449](https://github.com/paritytech/polkadot/pull/7449)) -- Remark: Allow any kind of origin ([paritytech/substrate#14260](https://github.com/paritytech/substrate/pull/14260)) -- Im-Online: Remove network state from heartbeats ([paritytech/substrate#14251](https://github.com/paritytech/substrate/pull/14251)) -- Nomination pools: disallow setting above global max commission ([paritytech/substrate#14496](https://github.com/paritytech/substrate/pull/14496)) -- Rename Statemint/Statemine to Asset Hub ([paritytech/cumulus#2633](https://github.com/paritytech/cumulus/pull/2633)) -- Fellowship: Voters can initiate proposals on their votable tracks ([paritytech/cumulus#2725](https://github.com/paritytech/cumulus/pull/2725)) -- Root can promote on Polkadot Collectives ([paritytech/cumulus#2781](https://github.com/paritytech/cumulus/pull/2781)) -- Add New Assets Privileged Functions to Appropriate Proxy Types ([paritytech/cumulus#2839](https://github.com/paritytech/cumulus/pull/2839)) -- Better Handling of Candidates Who Become Invulnerable ([paritytech/cumulus#2801](https://github.com/paritytech/cumulus/pull/2801)) - -### Added - -- Implement dynamic number of nominators ([paritytech/substrate#12970](https://github.com/paritytech/substrate/pull/12970) & [paritytech/polkadot#6807](https://github.com/paritytech/polkadot/pull/6807)) -- Upgrade Kusama to Society V2 ([paritytech/polkadot#7356](https://github.com/paritytech/polkadot/pull/7356)) -- Kusama state version switch and migration ([paritytech/polkadot#7015](https://github.com/paritytech/polkadot/pull/7015)) -- Add Nomination Pools and Voters List to Staking Proxy ([paritytech/polkadot#7448](https://github.com/paritytech/polkadot/pull/7448)) -- Add minting price to the pre-signed mint object ([paritytech/substrate#14242](https://github.com/paritytech/substrate/pull/14242)) -- Add mint price to the witness object on mint and confirm it ([paritytech/substrate#14257](https://github.com/paritytech/substrate/pull/14257)) -- Stabilize Metadata V15 ([paritytech/substrate#14481](https://github.com/paritytech/substrate/pull/14481)) -- Add Ability to Add/Remove Invulnerable Collators ([paritytech/cumulus#2596](https://github.com/paritytech/cumulus/pull/2596)) -- Polkadot Fellowship promotion/demotion periods, members activity and salaries ([paritytech/cumulus#2607](https://github.com/paritytech/cumulus/pull/2607)) -- Add asset conversion to asset hub Kusama ([paritytech/cumulus#2935](https://github.com/paritytech/cumulus/pull/2935)) - -### Fixed - -- Unlock/unreserve Gov v1 balances and remove kvs ([paritytech/polkadot#7314](https://github.com/paritytech/polkadot/pull/7314)) -- Polkadot 28 days as conviction voting period ([paritytech/polkadot#7595](https://github.com/paritytech/polkadot/pull/7595)) -- XCM: Fix issue with RequestUnlock ([paritytech/polkadot#7278](https://github.com/paritytech/polkadot/pull/7278)) -- Clear Existing HRMP Channel Request When Force Opening ([paritytech/polkadot#7389](https://github.com/paritytech/polkadot/pull/7389)) -- Prune upgrade cooldowns ([paritytech/polkadot#7470](https://github.com/paritytech/polkadot/pull/7470)) -- Assets `destroy_accounts` releases the deposit - ([paritytech/substrate#14443](https://github.com/paritytech/substrate/pull/14443)) -- Update Polkadot Collectives to use `limited_teleport_assets` for automatic slash handling, as - `teleport_assets` is deprecated and caused a failing integration test. ([polkadot-fellows/runtimes#46](https://github.com/polkadot-fellows/runtimes/pull/46)) diff --git a/Cargo.lock b/Cargo.lock index 02c6d0e8ec..41c3ed75f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,7 +136,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bytes", ] @@ -184,63 +184,12 @@ dependencies = [ "libc", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anstream" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - [[package]] name = "anstyle" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "anyhow" version = "1.0.83" @@ -471,15 +420,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - [[package]] name = "arrayvec" version = "0.7.4" @@ -570,53 +510,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[package]] -name = "asset-hub-kusama-emulated-chain" -version = "1.0.0" -dependencies = [ - "asset-hub-kusama-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "kusama-emulated-chain", - "parachains-common", - "penpal-emulated-chain", - "polkadot-parachain-primitives", - "sp-core 34.0.0", - "staging-xcm", -] - -[[package]] -name = "asset-hub-kusama-integration-tests" -version = "1.0.0" -dependencies = [ - "assert_matches", - "asset-hub-kusama-runtime", - "asset-test-utils", - "cumulus-pallet-parachain-system", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "kusama-runtime-constants", - "kusama-system-emulated-network", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-treasury", - "pallet-utility", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "sp-runtime 39.0.2", - "staging-kusama-runtime", - "staging-xcm", - "staging-xcm-executor", - "system-parachains-constants", - "xcm-runtime-apis", -] - [[package]] name = "asset-hub-kusama-runtime" version = "1.0.0" @@ -684,18 +577,18 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", - "sp-weights 31.0.0", + "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -705,53 +598,6 @@ dependencies = [ "xcm-runtime-apis", ] -[[package]] -name = "asset-hub-polkadot-emulated-chain" -version = "1.0.0" -dependencies = [ - "asset-hub-polkadot-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "penpal-emulated-chain", - "polkadot-emulated-chain", - "polkadot-parachain-primitives", - "sp-core 34.0.0", - "staging-xcm", -] - -[[package]] -name = "asset-hub-polkadot-integration-tests" -version = "1.0.0" -dependencies = [ - "assert_matches", - "asset-hub-polkadot-runtime", - "asset-test-utils", - "collectives-polkadot-runtime-constants", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-treasury", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime", - "polkadot-runtime-common", - "polkadot-system-emulated-network", - "sp-runtime 39.0.2", - "staging-xcm", - "staging-xcm-executor", - "system-parachains-constants", - "xcm-runtime-apis", -] - [[package]] name = "asset-hub-polkadot-runtime" version = "1.0.0" @@ -818,18 +664,18 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", - "sp-weights 31.0.0", + "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -860,8 +706,8 @@ dependencies = [ "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -886,7 +732,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -904,50 +750,13 @@ dependencies = [ "futures-core", ] -[[package]] -name = "async-channel" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" -dependencies = [ - "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", - "futures-core", - "pin-project-lite 0.2.13", -] - -[[package]] -name = "async-executor" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock 3.2.0", - "blocking", - "futures-lite", -] - [[package]] name = "async-io" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" dependencies = [ - "async-lock 3.2.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", @@ -960,15 +769,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.2.0" @@ -976,65 +776,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c" dependencies = [ "event-listener 4.0.0", - "event-listener-strategy 0.4.0", + "event-listener-strategy", "pin-project-lite 0.2.13", ] -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-process" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d" -dependencies = [ - "async-channel 2.3.0", - "async-io", - "async-lock 3.2.0", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener 5.3.0", - "futures-lite", - "rustix 0.38.31", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-signal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" -dependencies = [ - "async-io", - "async-lock 2.8.0", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.31", - "signal-hook-registry", - "slab", - "windows-sys 0.48.0", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.80" @@ -1059,12 +804,6 @@ dependencies = [ "pin-project-lite 0.2.13", ] -[[package]] -name = "atomic-take" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" - [[package]] name = "atomic-waker" version = "1.1.2" @@ -1099,17 +838,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "backoff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" -dependencies = [ - "getrandom", - "instant", - "rand", -] - [[package]] name = "backtrace" version = "0.3.69" @@ -1137,12 +865,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base58" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" - [[package]] name = "base64" version = "0.13.1" @@ -1167,15 +889,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] - [[package]] name = "binary-merkle-tree" version = "15.0.1" @@ -1195,17 +908,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bip39" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" -dependencies = [ - "bitcoin_hashes 0.11.0", - "serde", - "unicode-normalization", -] - [[package]] name = "bit-set" version = "0.5.3" @@ -1227,12 +929,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" -[[package]] -name = "bitcoin_hashes" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" - [[package]] name = "bitcoin_hashes" version = "0.13.0" @@ -1289,16 +985,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -dependencies = [ - "arrayvec 0.4.12", - "constant_time_eq 0.1.5", -] - [[package]] name = "blake2b_simd" version = "1.0.2" @@ -1306,8 +992,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", - "arrayvec 0.7.4", - "constant_time_eq 0.3.0", + "arrayvec", + "constant_time_eq", ] [[package]] @@ -1317,8 +1003,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" dependencies = [ "arrayref", - "arrayvec 0.7.4", - "constant_time_eq 0.3.0", + "arrayvec", + "constant_time_eq", ] [[package]] @@ -1328,10 +1014,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "cc", "cfg-if", - "constant_time_eq 0.3.0", + "constant_time_eq", ] [[package]] @@ -1352,20 +1038,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "blocking" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" -dependencies = [ - "async-channel 2.3.0", - "async-lock 3.2.0", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - [[package]] name = "bounded-collections" version = "0.2.0" @@ -1431,7 +1103,7 @@ dependencies = [ "kusama-runtime-constants", "polkadot-runtime-constants", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", "system-parachains-constants", ] @@ -1449,7 +1121,7 @@ dependencies = [ "polkadot-runtime-constants", "snowbridge-core", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", "staging-xcm", "system-parachains-constants", @@ -1468,8 +1140,8 @@ dependencies = [ "scale-info", "serde", "sp-consensus-grandpa", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", ] @@ -1499,8 +1171,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-std", ] @@ -1517,8 +1189,8 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", ] @@ -1551,7 +1223,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -1569,8 +1241,8 @@ dependencies = [ "parity-util-mem", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", ] @@ -1589,7 +1261,7 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -1608,13 +1280,13 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", "sp-std", - "sp-trie 37.0.0", - "trie-db 0.29.1", + "sp-trie", + "trie-db", ] [[package]] @@ -1630,12 +1302,12 @@ dependencies = [ "ed25519-dalek", "finality-grandpa", "parity-scale-codec", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-grandpa", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", - "sp-trie 37.0.0", + "sp-trie", ] [[package]] @@ -1650,8 +1322,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-std", "staging-xcm", ] @@ -1664,8 +1336,8 @@ checksum = "9284820ca704f5c065563cad77d2e3d069a23cc9cb3a29db9c0de8dd3b173a87" dependencies = [ "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "staging-xcm", ] @@ -1681,96 +1353,44 @@ dependencies = [ "parity-scale-codec", "scale-info", "snowbridge-core", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", "staging-xcm", ] [[package]] -name = "bridge-hub-kusama-emulated-chain" +name = "bridge-hub-kusama-runtime" version = "1.0.0" dependencies = [ + "bp-asset-hub-kusama", + "bp-asset-hub-polkadot", + "bp-bridge-hub-kusama", + "bp-bridge-hub-polkadot", + "bp-header-chain", + "bp-kusama", "bp-messages", + "bp-parachains", + "bp-polkadot", + "bp-polkadot-core", + "bp-relayers", + "bp-runtime", + "bp-xcm-bridge-hub", + "bp-xcm-bridge-hub-router", "bridge-hub-common", - "bridge-hub-kusama-runtime", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "sp-core 34.0.0", - "staging-xcm", -] - -[[package]] -name = "bridge-hub-kusama-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-hub-kusama-runtime", - "bp-bridge-hub-kusama", - "bp-messages", - "bridge-hub-kusama-runtime", - "cumulus-pallet-xcmp-queue", - "emulated-integration-tests-common", - "frame-support", - "hex-literal", - "integration-tests-helpers", - "kusama-polkadot-system-emulated-network", - "kusama-system-emulated-network", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "scale-info", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "staging-xcm", - "staging-xcm-executor", - "system-parachains-constants", - "xcm-runtime-apis", -] - -[[package]] -name = "bridge-hub-kusama-runtime" -version = "1.0.0" -dependencies = [ - "bp-asset-hub-kusama", - "bp-asset-hub-polkadot", - "bp-bridge-hub-kusama", - "bp-bridge-hub-polkadot", - "bp-header-chain", - "bp-kusama", - "bp-messages", - "bp-parachains", - "bp-polkadot", - "bp-polkadot-core", - "bp-relayers", - "bp-runtime", - "bp-xcm-bridge-hub", - "bp-xcm-bridge-hub-router", - "bridge-hub-common", - "bridge-hub-test-utils", - "bridge-runtime-common", - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", + "bridge-hub-test-utils", + "bridge-runtime-common", + "cumulus-pallet-aura-ext", + "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-aura", + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-benchmarking", + "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -1810,16 +1430,16 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-keyring", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -1833,58 +1453,6 @@ dependencies = [ "xcm-runtime-apis", ] -[[package]] -name = "bridge-hub-polkadot-emulated-chain" -version = "1.0.0" -dependencies = [ - "bp-messages", - "bridge-hub-common", - "bridge-hub-polkadot-runtime", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "sp-core 34.0.0", - "staging-xcm", -] - -[[package]] -name = "bridge-hub-polkadot-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-hub-polkadot-runtime", - "bp-bridge-hub-polkadot", - "bp-messages", - "bridge-hub-polkadot-runtime", - "cumulus-pallet-xcmp-queue", - "emulated-integration-tests-common", - "frame-support", - "hex-literal", - "integration-tests-helpers", - "kusama-polkadot-system-emulated-network", - "pallet-asset-conversion", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-system-emulated-network", - "scale-info", - "snowbridge-beacon-primitives", - "snowbridge-core", - "snowbridge-pallet-inbound-queue-fixtures", - "snowbridge-pallet-outbound-queue", - "snowbridge-pallet-system", - "snowbridge-router-primitives", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "staging-xcm", - "staging-xcm-executor", - "system-parachains-constants", - "xcm-runtime-apis", -] - [[package]] name = "bridge-hub-polkadot-runtime" version = "1.0.0" @@ -1968,16 +1536,16 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-keyring", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2025,11 +1593,11 @@ dependencies = [ "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-keyring", - "sp-runtime 39.0.2", - "sp-tracing 17.0.1", + "sp-runtime", + "sp-tracing", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2059,10 +1627,10 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "sp-std", - "sp-trie 37.0.0", + "sp-trie", "staging-xcm", "static_assertions", "tuplex", @@ -2235,30 +1803,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "chain-spec-generator" -version = "1.0.0" -dependencies = [ - "asset-hub-kusama-runtime", - "asset-hub-polkadot-runtime", - "bridge-hub-kusama-runtime", - "bridge-hub-polkadot-runtime", - "clap", - "collectives-polkadot-runtime", - "coretime-kusama-runtime", - "coretime-polkadot-runtime", - "encointer-kusama-runtime", - "glutton-kusama-runtime", - "people-kusama-runtime", - "people-polkadot-runtime", - "polkadot-runtime", - "sc-chain-spec", - "sc-network", - "serde", - "serde_json", - "staging-kusama-runtime", -] - [[package]] name = "chrono" version = "0.4.31" @@ -2269,7 +1813,6 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", - "serde", "wasm-bindgen", "windows-targets 0.48.5", ] @@ -2320,46 +1863,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "clap" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim 0.11.0", -] - -[[package]] -name = "clap_derive" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -2370,54 +1873,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "collectives-polkadot-emulated-chain" -version = "0.0.0" -dependencies = [ - "collectives-polkadot-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "sp-core 34.0.0", -] - -[[package]] -name = "collectives-polkadot-integration-tests" -version = "1.0.0" -dependencies = [ - "assert_matches", - "asset-hub-polkadot-runtime", - "asset-test-utils", - "collectives-polkadot-runtime", - "collectives-polkadot-runtime-constants", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "pallet-asset-rate", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-treasury", - "pallet-utility", - "pallet-whitelist", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime", - "polkadot-runtime-common", - "polkadot-runtime-constants", - "polkadot-system-emulated-network", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "staging-xcm", - "staging-xcm-executor", - "system-parachains-constants", - "xcm-runtime-apis", -] - [[package]] name = "collectives-polkadot-runtime" version = "1.0.0" @@ -2473,18 +1928,18 @@ dependencies = [ "scale-info", "serde_json", "sp-api", - "sp-arithmetic 26.0.0", + "sp-arithmetic", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2500,12 +1955,6 @@ dependencies = [ name = "collectives-polkadot-runtime-constants" version = "1.0.0" -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - [[package]] name = "combine" version = "4.6.7" @@ -2583,12 +2032,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.3.0" @@ -2632,46 +2075,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "coretime-kusama-emulated-chain" -version = "1.0.0" -dependencies = [ - "coretime-kusama-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "sp-core 34.0.0", -] - -[[package]] -name = "coretime-kusama-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-test-utils", - "coretime-kusama-runtime", - "cumulus-pallet-parachain-system", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "kusama-runtime-constants", - "kusama-system-emulated-network", - "pallet-balances", - "pallet-broker", - "pallet-identity", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime-common", - "polkadot-runtime-parachains", - "sp-runtime 39.0.2", - "staging-kusama-runtime", - "staging-xcm", - "staging-xcm-executor", - "xcm-runtime-apis", -] - [[package]] name = "coretime-kusama-runtime" version = "1.0.0" @@ -2722,14 +2125,14 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -2741,45 +2144,6 @@ dependencies = [ "xcm-runtime-apis", ] -[[package]] -name = "coretime-polkadot-emulated-chain" -version = "1.0.0" -dependencies = [ - "coretime-polkadot-runtime", - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "sp-core 34.0.0", -] - -[[package]] -name = "coretime-polkadot-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-test-utils", - "coretime-polkadot-runtime", - "cumulus-pallet-parachain-system", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "pallet-balances", - "pallet-broker", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "polkadot-runtime", - "polkadot-runtime-common", - "polkadot-runtime-constants", - "polkadot-runtime-parachains", - "polkadot-system-emulated-network", - "sp-runtime 39.0.2", - "staging-xcm", - "staging-xcm-executor", - "xcm-runtime-apis", -] - [[package]] name = "coretime-polkadot-runtime" version = "1.0.0" @@ -2828,17 +2192,17 @@ dependencies = [ "serde", "serde_json", "sp-api", - "sp-arithmetic 26.0.0", + "sp-arithmetic", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -3009,15 +2373,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -3037,7 +2392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", "zeroize", ] @@ -3049,7 +2404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.7", - "rand_core 0.6.4", + "rand_core", "typenum", ] @@ -3095,9 +2450,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-aura", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -3123,18 +2478,18 @@ dependencies = [ "polkadot-runtime-common", "polkadot-runtime-parachains", "scale-info", - "sp-core 34.0.0", - "sp-externalities 0.29.0", + "sp-core", + "sp-externalities", "sp-inherents", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-io", + "sp-runtime", + "sp-state-machine", "sp-std", - "sp-trie 37.0.0", + "sp-trie", "sp-version", "staging-xcm", "staging-xcm-builder", - "trie-db 0.29.1", + "trie-db", ] [[package]] @@ -3160,7 +2515,7 @@ dependencies = [ "frame-system", "pallet-session", "parity-scale-codec", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -3174,8 +2529,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "staging-xcm", ] @@ -3197,9 +2552,9 @@ dependencies = [ "polkadot-runtime-common", "polkadot-runtime-parachains", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -3216,7 +2571,7 @@ dependencies = [ "polkadot-primitives 15.0.0", "sp-api", "sp-consensus-aura", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -3231,8 +2586,8 @@ dependencies = [ "polkadot-primitives 16.0.0", "scale-info", "sp-api", - "sp-runtime 39.0.2", - "sp-trie 37.0.0", + "sp-runtime", + "sp-trie", "staging-xcm", ] @@ -3246,9 +2601,9 @@ dependencies = [ "cumulus-primitives-core", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-trie 37.0.0", + "sp-trie", ] [[package]] @@ -3257,9 +2612,9 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "421f03af054aac7c89e87a49e47964886e53a8d7395990eab27b6f201d42524f" dependencies = [ - "sp-externalities 0.29.0", - "sp-runtime-interface 28.0.0", - "sp-trie 37.0.0", + "sp-externalities", + "sp-runtime-interface", + "sp-trie", ] [[package]] @@ -3274,7 +2629,7 @@ dependencies = [ "pallet-asset-conversion", "parity-scale-codec", "polkadot-runtime-common", - "sp-runtime 39.0.2", + "sp-runtime", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -3289,22 +2644,9 @@ dependencies = [ "cumulus-primitives-core", "parity-scale-codec", "polkadot-primitives 16.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", - "sp-trie 37.0.0", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle 2.5.0", - "zeroize", + "sp-runtime", + "sp-state-machine", + "sp-trie", ] [[package]] @@ -3378,76 +2720,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core 0.14.4", - "darling_macro 0.14.4", -] - -[[package]] -name = "darling" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" -dependencies = [ - "darling_core 0.20.8", - "darling_macro 0.20.8", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", -] - -[[package]] -name = "darling_core" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 2.0.65", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core 0.14.4", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" -dependencies = [ - "darling_core 0.20.8", - "quote", - "syn 2.0.65", -] - [[package]] name = "data-encoding" version = "2.5.0" @@ -3657,12 +2929,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - [[package]] name = "dtoa" version = "1.0.9" @@ -3733,40 +2999,26 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek 4.1.3", + "curve25519-dalek", "ed25519", - "rand_core 0.6.4", + "rand_core", "serde", "sha2 0.10.8", "subtle 2.5.0", "zeroize", ] -[[package]] -name = "ed25519-zebra" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" -dependencies = [ - "curve25519-dalek 3.2.0", - "hashbrown 0.12.3", - "hex", - "rand_core 0.6.4", - "sha2 0.9.9", - "zeroize", -] - [[package]] name = "ed25519-zebra" version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ - "curve25519-dalek 4.1.3", + "curve25519-dalek", "ed25519", "hashbrown 0.14.3", "hex", - "rand_core 0.6.4", + "rand_core", "sha2 0.10.8", "zeroize", ] @@ -3790,64 +3042,19 @@ dependencies = [ "generic-array 0.14.7", "group", "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "serdect", "subtle 2.5.0", "zeroize", ] -[[package]] -name = "emulated-integration-tests-common" -version = "14.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f16722b84c80116230ed1eac5b49356bebeb0589786d9c651e010369f1c95" -dependencies = [ - "asset-test-utils", - "bp-messages", - "bp-xcm-bridge-hub", - "bridge-runtime-common", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "frame-support", - "pallet-assets", - "pallet-balances", - "pallet-bridge-messages", - "pallet-message-queue", - "pallet-xcm", - "pallet-xcm-bridge-hub", - "parachains-common", - "parity-scale-codec", - "paste", - "polkadot-parachain-primitives", - "polkadot-primitives 16.0.0", - "polkadot-runtime-parachains", - "sc-consensus-grandpa", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "staging-xcm", - "xcm-emulator", -] - [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - [[package]] name = "encointer-balances-tx-payment" version = "14.1.0" @@ -3862,7 +3069,7 @@ dependencies = [ "pallet-encointer-balances", "pallet-encointer-ceremonies", "pallet-transaction-payment", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -3886,7 +3093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d3890b05d20d81cd72e461b4e4a40e574f357bd8bd93095d60196bf85f0ca2b" dependencies = [ "encointer-primitives", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -3959,11 +3166,11 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", "sp-transaction-pool", @@ -3987,7 +3194,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -4005,9 +3212,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "substrate-geohash", ] @@ -4097,9 +3304,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-runtime", "sp-std", "substrate-fixed", ] @@ -4178,17 +3385,6 @@ dependencies = [ "pin-project-lite 0.2.13", ] -[[package]] -name = "event-listener" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite 0.2.13", -] - [[package]] name = "event-listener-strategy" version = "0.4.0" @@ -4199,16 +3395,6 @@ dependencies = [ "pin-project-lite 0.2.13", ] -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener 5.3.0", - "pin-project-lite 0.2.13", -] - [[package]] name = "expander" version = "2.0.0" @@ -4246,7 +3432,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "auto_impl", "bytes", ] @@ -4257,7 +3443,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", ] @@ -4323,16 +3509,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "float-cmp" version = "0.9.0" @@ -4363,15 +3539,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fork-tree" -version = "13.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad4cc2314d3be8b49c555f6a7e550f5559e73ffd6ef9690ffbd9a706774452e0" -dependencies = [ - "parity-scale-codec", -] - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -4403,12 +3570,12 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-runtime-interface 28.0.0", - "sp-storage 21.0.0", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-storage", "static_assertions", ] @@ -4435,10 +3602,10 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", + "sp-arithmetic", + "sp-core", "sp-npos-elections", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -4454,21 +3621,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-tracing 17.0.1", -] - -[[package]] -name = "frame-metadata" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" -dependencies = [ - "cfg-if", - "parity-scale-codec", - "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-tracing", ] [[package]] @@ -4496,7 +3652,7 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -4507,15 +3663,15 @@ checksum = "b2a946c33c9bd653f464bb158e020a9e85bd9d6746f39d702a84973bd6a4cde0" dependencies = [ "futures", "indicatif", - "jsonrpsee 0.24.7", + "jsonrpsee", "log", "parity-scale-codec", "serde", - "sp-core 34.0.0", + "sp-core", "sp-crypto-hashing", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-io", + "sp-runtime", + "sp-state-machine", "spinners", "substrate-rpc-client", "tokio", @@ -4533,7 +3689,7 @@ dependencies = [ "bitflags 1.3.2", "docify", "environmental", - "frame-metadata 16.0.0", + "frame-metadata", "frame-support-procedural", "impl-trait-for-tuples", "k256", @@ -4546,20 +3702,20 @@ dependencies = [ "serde_json", "smallvec", "sp-api", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", + "sp-arithmetic", + "sp-core", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-metadata-ir", - "sp-runtime 39.0.2", + "sp-runtime", "sp-staking 36.0.0", - "sp-state-machine 0.43.0", + "sp-state-machine", "sp-std", - "sp-tracing 17.0.1", - "sp-weights 31.0.0", + "sp-tracing", + "sp-weights", "static_assertions", "tt-call", ] @@ -4621,12 +3777,12 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "sp-version", - "sp-weights 31.0.0", + "sp-weights", ] [[package]] @@ -4640,8 +3796,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -4664,7 +3820,7 @@ dependencies = [ "frame-support", "parity-scale-codec", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -4747,10 +3903,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143" dependencies = [ - "fastrand", "futures-core", - "futures-io", - "parking", "pin-project-lite 0.2.13", ] @@ -4858,7 +4011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" dependencies = [ "rand", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4915,14 +4068,14 @@ dependencies = [ "serde_json", "sp-api", "sp-block-builder", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -4940,7 +4093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", ] @@ -5023,7 +4176,6 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash 0.8.8", "allocator-api2", - "serde", ] [[package]] @@ -5186,12 +4338,6 @@ dependencies = [ "pin-project-lite 0.2.13", ] -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - [[package]] name = "httparse" version = "1.8.0" @@ -5254,22 +4400,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.11", - "hyper 0.14.27", - "log", - "rustls 0.21.10", - "rustls-native-certs 0.6.3", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.2" @@ -5288,31 +4418,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.27", - "pin-project-lite 0.2.13", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper 0.14.27", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "hyper-util" version = "0.1.6" @@ -5356,12 +4461,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.2.3" @@ -5530,12 +4629,6 @@ dependencies = [ "hashbrown 0.14.3", ] -[[package]] -name = "indexmap-nostd" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" - [[package]] name = "indicatif" version = "0.17.7" @@ -5576,20 +4669,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "integration-tests-helpers" -version = "1.0.0" -dependencies = [ - "asset-test-utils", - "cumulus-pallet-xcmp-queue", - "pallet-balances", - "pallet-message-queue", - "pallet-xcm", - "paste", - "staging-xcm", - "xcm-emulator", -] - [[package]] name = "io-lifetimes" version = "1.0.11" @@ -5707,77 +4786,20 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json-patch" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" -dependencies = [ - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "jsonpath-rust" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cc127b7c3d270be504572364f9569761a180b981919dd0d87693a7f5fb7829" -dependencies = [ - "pest", - "pest_derive", - "regex", - "serde_json", - "thiserror", -] - -[[package]] -name = "jsonrpsee" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" -dependencies = [ - "jsonrpsee-client-transport 0.22.5", - "jsonrpsee-core 0.22.5", - "jsonrpsee-http-client 0.22.5", - "jsonrpsee-types 0.22.5", -] - [[package]] name = "jsonrpsee" version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" dependencies = [ - "jsonrpsee-core 0.24.7", - "jsonrpsee-http-client 0.24.7", + "jsonrpsee-core", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", - "jsonrpsee-types 0.24.7", + "jsonrpsee-types", "jsonrpsee-ws-client", "tracing", ] -[[package]] -name = "jsonrpsee-client-transport" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" -dependencies = [ - "futures-util", - "http 0.2.11", - "jsonrpsee-core 0.22.5", - "pin-project", - "rustls-native-certs 0.7.0", - "rustls-pki-types", - "soketto 0.7.1", - "thiserror", - "tokio", - "tokio-rustls 0.25.0", - "tokio-util", - "tracing", - "url", -] - [[package]] name = "jsonrpsee-client-transport" version = "0.24.7" @@ -5787,7 +4809,7 @@ dependencies = [ "base64 0.22.1", "futures-util", "http 1.1.0", - "jsonrpsee-core 0.24.7", + "jsonrpsee-core", "pin-project", "rustls 0.23.11", "rustls-pki-types", @@ -5801,29 +4823,6 @@ dependencies = [ "url", ] -[[package]] -name = "jsonrpsee-core" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-timer", - "futures-util", - "hyper 0.14.27", - "jsonrpsee-types 0.22.5", - "pin-project", - "rustc-hash 1.1.0", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - [[package]] name = "jsonrpsee-core" version = "0.24.7" @@ -5837,7 +4836,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "jsonrpsee-types 0.24.7", + "jsonrpsee-types", "parking_lot 0.12.3", "pin-project", "rand", @@ -5852,38 +4851,18 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.5" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" -dependencies = [ - "async-trait", - "hyper 0.14.27", - "hyper-rustls 0.24.2", - "jsonrpsee-core 0.22.5", - "jsonrpsee-types 0.22.5", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-http-client" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls", "hyper-util", - "jsonrpsee-core 0.24.7", - "jsonrpsee-types 0.24.7", + "jsonrpsee-core", + "jsonrpsee-types", "rustls 0.23.11", "rustls-platform-verifier", "serde", @@ -5908,19 +4887,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "jsonrpsee-types" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "jsonrpsee-types" version = "0.24.7" @@ -5940,9 +4906,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ "http 1.1.0", - "jsonrpsee-client-transport 0.24.7", - "jsonrpsee-core 0.24.7", - "jsonrpsee-types 0.24.7", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", "url", ] @@ -5960,20 +4926,6 @@ dependencies = [ "sha2 0.10.8", ] -[[package]] -name = "k8s-openapi" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc3606fd16aca7989db2f84bb25684d0270c6d6fa1dbcd0025af7b4130523a6" -dependencies = [ - "base64 0.21.6", - "bytes", - "chrono", - "serde", - "serde-value", - "serde_json", -] - [[package]] name = "keccak" version = "0.1.4" @@ -5989,129 +4941,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" -[[package]] -name = "kube" -version = "0.87.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3499c8d60c763246c7a213f51caac1e9033f46026904cb89bc8951ae8601f26e" -dependencies = [ - "k8s-openapi", - "kube-client", - "kube-core", - "kube-runtime", -] - -[[package]] -name = "kube-client" -version = "0.87.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033450dfa0762130565890dadf2f8835faedf749376ca13345bcd8ecd6b5f29f" -dependencies = [ - "base64 0.21.6", - "bytes", - "chrono", - "either", - "futures", - "home", - "http 0.2.11", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper-rustls 0.24.2", - "hyper-timeout", - "jsonpath-rust", - "k8s-openapi", - "kube-core", - "pem 3.0.4", - "pin-project", - "rand", - "rustls 0.21.10", - "rustls-pemfile 1.0.4", - "secrecy", - "serde", - "serde_json", - "serde_yaml", - "thiserror", - "tokio", - "tokio-tungstenite", - "tokio-util", - "tower", - "tower-http", - "tracing", -] - -[[package]] -name = "kube-core" -version = "0.87.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bba93d054786eba7994d03ce522f368ef7d48c88a1826faa28478d85fb63ae" -dependencies = [ - "chrono", - "form_urlencoded", - "http 0.2.11", - "json-patch", - "k8s-openapi", - "once_cell", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "kube-runtime" -version = "0.87.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8893eb18fbf6bb6c80ef6ee7dd11ec32b1dc3c034c988ac1b3a84d46a230ae" -dependencies = [ - "ahash 0.8.8", - "async-trait", - "backoff", - "derivative", - "futures", - "hashbrown 0.14.3", - "json-patch", - "k8s-openapi", - "kube-client", - "parking_lot 0.12.3", - "pin-project", - "serde", - "serde_json", - "smallvec", - "thiserror", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "kusama-emulated-chain" -version = "1.0.0" -dependencies = [ - "emulated-integration-tests-common", - "kusama-runtime-constants", - "parachains-common", - "polkadot-primitives 16.0.0", - "sc-consensus-grandpa", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core 34.0.0", - "staging-kusama-runtime", -] - -[[package]] -name = "kusama-polkadot-system-emulated-network" -version = "1.0.0" -dependencies = [ - "asset-hub-kusama-emulated-chain", - "asset-hub-polkadot-emulated-chain", - "bridge-hub-kusama-emulated-chain", - "bridge-hub-polkadot-emulated-chain", - "emulated-integration-tests-common", - "kusama-emulated-chain", - "penpal-emulated-chain", - "polkadot-emulated-chain", -] - [[package]] name = "kusama-runtime-constants" version = "1.0.0" @@ -6120,25 +4949,12 @@ dependencies = [ "polkadot-primitives 16.0.0", "polkadot-runtime-common", "smallvec", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-core", + "sp-runtime", + "sp-weights", "staging-xcm-builder", ] -[[package]] -name = "kusama-system-emulated-network" -version = "1.0.0" -dependencies = [ - "asset-hub-kusama-emulated-chain", - "bridge-hub-kusama-emulated-chain", - "coretime-kusama-emulated-chain", - "emulated-integration-tests-common", - "kusama-emulated-chain", - "penpal-emulated-chain", - "people-kusama-emulated-chain", -] - [[package]] name = "kvdb" version = "0.13.0" @@ -6318,7 +5134,7 @@ version = "0.44.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16ea178dabba6dde6ffc260a8e0452ccdc8f79becf544946692fff9d412fc29d" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "asynchronous-codec", "bytes", "either", @@ -6386,7 +5202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2eeec39ad3ad0677551907dd304b2f13f17208ccebe333bef194076cd2e8921" dependencies = [ "bytes", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "futures", "libp2p-core", "libp2p-identity", @@ -6882,15 +5698,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matchers" version = "0.1.0" @@ -6966,9 +5773,9 @@ checksum = "f313fcff1d2a4bcaa2deeaa00bf7530d77d5f7bd0467a117dde2e29a75a7a17a" dependencies = [ "array-bytes", "blake3", - "frame-metadata 16.0.0", + "frame-metadata", "parity-scale-codec", - "scale-decode 0.13.0", + "scale-decode", "scale-info", ] @@ -6980,16 +5787,10 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core 0.6.4", + "rand_core", "zeroize", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -7023,11 +5824,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "either", "hashlink", "lioness", @@ -7249,24 +6050,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -7356,29 +6139,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "libc", -] - -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -7443,7 +6203,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "itoa", ] @@ -7464,7 +6224,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint", "num-integer", "num-traits", ] @@ -7606,15 +6365,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - [[package]] name = "overload" version = "0.1.1" @@ -7636,10 +6386,10 @@ dependencies = [ "pallet-identity", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", + "sp-core", "sp-crypto-hashing", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -7655,10 +6405,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -7673,7 +6423,7 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -7687,8 +6437,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -7704,9 +6454,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -7722,8 +6472,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -7738,9 +6488,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-aura", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -7754,9 +6504,9 @@ dependencies = [ "pallet-session", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-authority-discovery", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -7770,7 +6520,7 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -7788,11 +6538,11 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-babe", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-session", "sp-staking 36.0.0", ] @@ -7813,10 +6563,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-tracing 17.0.1", + "sp-core", + "sp-io", + "sp-runtime", + "sp-tracing", ] [[package]] @@ -7832,7 +6582,7 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -7850,7 +6600,7 @@ dependencies = [ "scale-info", "serde", "sp-consensus-beefy", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-staking 36.0.0", ] @@ -7875,10 +6625,10 @@ dependencies = [ "serde", "sp-api", "sp-consensus-beefy", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", ] [[package]] @@ -7894,9 +6644,9 @@ dependencies = [ "pallet-treasury", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -7915,7 +6665,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-consensus-grandpa", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -7934,9 +6684,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", - "sp-trie 37.0.0", + "sp-trie", ] [[package]] @@ -7956,7 +6706,7 @@ dependencies = [ "pallet-bridge-grandpa", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -7980,8 +6730,8 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-runtime", "sp-std", ] @@ -7999,9 +6749,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-runtime", ] [[package]] @@ -8018,9 +6768,9 @@ dependencies = [ "pallet-treasury", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8039,7 +6789,7 @@ dependencies = [ "parity-scale-codec", "rand", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8055,9 +6805,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8073,8 +6823,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -8090,10 +6840,10 @@ dependencies = [ "pallet-ranked-collective", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8107,8 +6857,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8127,11 +6877,11 @@ dependencies = [ "parity-scale-codec", "rand", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-arithmetic", + "sp-core", + "sp-io", "sp-npos-elections", - "sp-runtime 39.0.2", + "sp-runtime", "strum 0.26.3", ] @@ -8146,7 +6896,7 @@ dependencies = [ "frame-system", "parity-scale-codec", "sp-npos-elections", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -8165,7 +6915,7 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -8183,7 +6933,7 @@ dependencies = [ "pallet-encointer-communities", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", + "sp-core", "sp-std", ] @@ -8219,10 +6969,10 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", ] @@ -8254,8 +7004,8 @@ dependencies = [ "pallet-encointer-scheduler", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "sp-std", ] @@ -8290,10 +7040,10 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", ] @@ -8313,8 +7063,8 @@ dependencies = [ "pallet-encointer-reputation-commitments", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", ] @@ -8336,8 +7086,8 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", ] @@ -8356,7 +7106,7 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", ] @@ -8376,8 +7126,8 @@ dependencies = [ "pallet-encointer-reputation-commitments", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", ] @@ -8409,8 +7159,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8427,10 +7177,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -8447,11 +7197,11 @@ dependencies = [ "pallet-session", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-grandpa", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-session", "sp-staking 36.0.0", ] @@ -8469,8 +7219,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -8486,10 +7236,10 @@ dependencies = [ "pallet-authorship", "parity-scale-codec", "scale-info", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8504,10 +7254,10 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-keyring", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -8521,7 +7271,7 @@ dependencies = [ "parity-scale-codec", "safe-mix", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -8536,9 +7286,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8554,11 +7304,11 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-weights", ] [[package]] @@ -8573,10 +7323,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-mmr-primitives", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -8591,8 +7341,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -8609,7 +7359,7 @@ dependencies = [ "pallet-nfts", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -8625,9 +7375,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8652,9 +7402,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-runtime", ] [[package]] @@ -8669,11 +7419,11 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-staking 36.0.0", - "sp-tracing 17.0.1", + "sp-tracing", ] [[package]] @@ -8692,8 +7442,8 @@ dependencies = [ "pallet-staking", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", - "sp-runtime-interface 28.0.0", + "sp-runtime", + "sp-runtime-interface", "sp-staking 36.0.0", ] @@ -8721,7 +7471,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-runtime 39.0.2", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8745,7 +7495,7 @@ dependencies = [ "pallet-staking", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8763,8 +7513,8 @@ dependencies = [ "paste", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -8779,9 +7529,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8795,8 +7545,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -8812,10 +7562,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8829,8 +7579,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -8847,9 +7597,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-arithmetic 26.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-io", + "sp-runtime", ] [[package]] @@ -8865,10 +7615,10 @@ dependencies = [ "pallet-ranked-collective", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -8884,9 +7634,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-io", + "sp-runtime", + "sp-weights", ] [[package]] @@ -8902,13 +7652,13 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-session", "sp-staking 36.0.0", - "sp-state-machine 0.43.0", - "sp-trie 37.0.0", + "sp-state-machine", + "sp-trie", ] [[package]] @@ -8924,7 +7674,7 @@ dependencies = [ "pallet-staking", "parity-scale-codec", "rand", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", ] @@ -8941,9 +7691,9 @@ dependencies = [ "parity-scale-codec", "rand_chacha", "scale-info", - "sp-arithmetic 26.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-io", + "sp-runtime", ] [[package]] @@ -8963,9 +7713,9 @@ dependencies = [ "rand_chacha", "scale-info", "serde", - "sp-application-crypto 38.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-application-crypto", + "sp-io", + "sp-runtime", "sp-staking 36.0.0", ] @@ -8988,7 +7738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "988a7ebeacc84d4bdb0b12409681e956ffe35438447d8f8bc78db547cffb6ebc" dependencies = [ "log", - "sp-arithmetic 26.0.0", + "sp-arithmetic", ] [[package]] @@ -9014,9 +7764,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -9031,8 +7781,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", ] [[package]] @@ -9049,9 +7799,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-inherents", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-storage 21.0.0", + "sp-io", + "sp-runtime", + "sp-storage", "sp-timestamp", ] @@ -9066,9 +7816,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -9080,8 +7830,8 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "sp-api", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-runtime", + "sp-weights", ] [[package]] @@ -9099,8 +7849,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -9115,7 +7865,7 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -9129,9 +7879,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", ] [[package]] @@ -9146,7 +7896,7 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -9161,7 +7911,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -9179,9 +7929,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -9200,8 +7950,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -9222,8 +7972,8 @@ dependencies = [ "pallet-bridge-messages", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", "staging-xcm", "staging-xcm-builder", @@ -9243,8 +7993,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", "staging-xcm", "staging-xcm-builder", @@ -9272,9 +8022,9 @@ dependencies = [ "polkadot-primitives 16.0.0", "scale-info", "sp-consensus-aura", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -9302,10 +8052,10 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "sp-consensus-aura", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-tracing 17.0.1", + "sp-core", + "sp-io", + "sp-runtime", + "sp-tracing", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -9318,9 +8068,9 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "rand", - "rand_core 0.6.4", + "rand_core", "serde", "unicode-normalization", ] @@ -9337,7 +8087,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bitvec", "byte-slice-cast", "bytes", @@ -9460,7 +8210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle 2.5.0", ] @@ -9490,84 +8240,63 @@ dependencies = [ ] [[package]] -name = "pem" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" -dependencies = [ - "base64 0.22.1", - "serde", -] - -[[package]] -name = "penpal-emulated-chain" +name = "people-kusama-runtime" version = "1.0.0" dependencies = [ - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "kusama-emulated-chain", - "parachains-common", - "penpal-runtime", - "polkadot-emulated-chain", - "sp-core 34.0.0", - "staging-xcm", -] - -[[package]] -name = "penpal-runtime" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20094cbee22c7e6099653d69ca9a36678be58d6a1739adceb0c98a7b20df53c7" -dependencies = [ - "assets-common", "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", + "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-utility", + "enumflags2", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", + "hex-literal", + "kusama-runtime-constants", "log", - "pallet-asset-conversion", - "pallet-asset-tx-payment", - "pallet-assets", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-identity", "pallet-message-queue", + "pallet-multisig", + "pallet-proxy", "pallet-session", - "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", "pallet-xcm", + "pallet-xcm-benchmarks", "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-primitives 16.0.0", "polkadot-runtime-common", - "primitive-types", "scale-info", - "smallvec", + "serde", + "serde_json", "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", - "sp-storage 21.0.0", + "sp-std", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -9575,51 +8304,12 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "system-parachains-constants", "xcm-runtime-apis", ] [[package]] -name = "people-kusama-emulated-chain" -version = "1.0.0" -dependencies = [ - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "kusama-emulated-chain", - "kusama-runtime-constants", - "parachains-common", - "people-kusama-runtime", - "sp-core 34.0.0", -] - -[[package]] -name = "people-kusama-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-test-utils", - "cumulus-pallet-parachain-system", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "kusama-runtime-constants", - "kusama-system-emulated-network", - "pallet-balances", - "pallet-identity", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "people-kusama-runtime", - "polkadot-runtime-common", - "sp-runtime 39.0.2", - "staging-kusama-runtime", - "staging-xcm", - "staging-xcm-executor", - "xcm-runtime-apis", -] - -[[package]] -name = "people-kusama-runtime" +name = "people-polkadot-runtime" version = "1.0.0" dependencies = [ "cumulus-pallet-aura-ext", @@ -9640,7 +8330,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "hex-literal", - "kusama-runtime-constants", "log", "pallet-aura", "pallet-authorship", @@ -9660,22 +8349,22 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", - "polkadot-primitives 16.0.0", "polkadot-runtime-common", + "polkadot-runtime-constants", "scale-info", "serde", "serde_json", "sp-api", "sp-block-builder", "sp-consensus-aura", - "sp-core 34.0.0", + "sp-core", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -9688,118 +8377,10 @@ dependencies = [ ] [[package]] -name = "people-polkadot-emulated-chain" -version = "1.0.0" -dependencies = [ - "cumulus-primitives-core", - "emulated-integration-tests-common", - "frame-support", - "parachains-common", - "people-polkadot-runtime", - "polkadot-emulated-chain", - "polkadot-runtime-constants", - "sp-core 34.0.0", -] - -[[package]] -name = "people-polkadot-integration-tests" -version = "1.0.0" -dependencies = [ - "asset-test-utils", - "cumulus-pallet-parachain-system", - "emulated-integration-tests-common", - "frame-support", - "integration-tests-helpers", - "pallet-balances", - "pallet-identity", - "pallet-message-queue", - "pallet-xcm", - "parachains-common", - "parity-scale-codec", - "people-polkadot-runtime", - "polkadot-runtime", - "polkadot-runtime-common", - "polkadot-runtime-constants", - "polkadot-system-emulated-network", - "sp-runtime 39.0.2", - "staging-xcm", - "staging-xcm-executor", - "xcm-runtime-apis", -] - -[[package]] -name = "people-polkadot-runtime" -version = "1.0.0" -dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "enumflags2", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "hex-literal", - "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-identity", - "pallet-message-queue", - "pallet-multisig", - "pallet-proxy", - "pallet-session", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-utility", - "pallet-xcm", - "pallet-xcm-benchmarks", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "polkadot-runtime-constants", - "scale-info", - "serde", - "serde_json", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core 34.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime 39.0.2", - "sp-session", - "sp-std", - "sp-storage 21.0.0", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", - "system-parachains-constants", - "xcm-runtime-apis", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" @@ -9812,40 +8393,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "pest_derive" -version = "2.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "pest_meta" -version = "2.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" -dependencies = [ - "once_cell", - "pest", - "sha2 0.10.8", -] - [[package]] name = "petgraph" version = "0.6.4" @@ -9894,17 +8441,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - [[package]] name = "pkcs8" version = "0.10.2" @@ -9939,26 +8475,8 @@ checksum = "e2900d3b857e34c480101618a950c3a4fbcddc8c0d50573d48553376185908b8" dependencies = [ "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", -] - -[[package]] -name = "polkadot-emulated-chain" -version = "1.0.0" -dependencies = [ - "emulated-integration-tests-common", - "pallet-staking", - "parachains-common", - "polkadot-primitives 16.0.0", - "polkadot-runtime", - "polkadot-runtime-constants", - "sc-consensus-grandpa", - "sp-authority-discovery", - "sp-consensus-babe", - "sp-consensus-beefy", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -9973,9 +8491,9 @@ dependencies = [ "polkadot-core-primitives", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-core", + "sp-runtime", + "sp-weights", ] [[package]] @@ -9993,15 +8511,15 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", + "sp-application-crypto", + "sp-arithmetic", "sp-authority-discovery", "sp-consensus-slots", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-io 38.0.0", - "sp-keystore 0.40.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-keystore", + "sp-runtime", "sp-staking 34.0.0", ] @@ -10020,15 +8538,15 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", + "sp-application-crypto", + "sp-arithmetic", "sp-authority-discovery", "sp-consensus-slots", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-io 38.0.0", - "sp-keystore 0.40.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-keystore", + "sp-runtime", "sp-staking 36.0.0", ] @@ -10107,28 +8625,28 @@ dependencies = [ "separator", "serde_json", "sp-api", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", + "sp-application-crypto", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core 34.0.0", + "sp-core", "sp-debug-derive", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-keyring", "sp-npos-elections", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-staking 36.0.0", "sp-std", - "sp-storage 21.0.0", - "sp-tracing 17.0.1", + "sp-storage", + "sp-tracing", "sp-transaction-pool", - "sp-trie 37.0.0", + "sp-trie", "sp-version", "ss58-registry", "staging-xcm", @@ -10177,11 +8695,11 @@ dependencies = [ "serde_derive", "slot-range-helper", "sp-api", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-npos-elections", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-staking 36.0.0", "staging-xcm", @@ -10198,9 +8716,9 @@ dependencies = [ "polkadot-primitives 16.0.0", "polkadot-runtime-common", "smallvec", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-core", + "sp-runtime", + "sp-weights", "staging-xcm-builder", ] @@ -10214,7 +8732,7 @@ dependencies = [ "frame-benchmarking", "parity-scale-codec", "polkadot-primitives 16.0.0", - "sp-tracing 17.0.1", + "sp-tracing", ] [[package]] @@ -10252,36 +8770,22 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", "sp-inherents", - "sp-io 38.0.0", - "sp-keystore 0.40.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-keystore", + "sp-runtime", "sp-session", "sp-staking 36.0.0", "sp-std", - "sp-tracing 17.0.1", + "sp-tracing", "staging-xcm", "staging-xcm-executor", "static_assertions", ] -[[package]] -name = "polkadot-system-emulated-network" -version = "1.0.0" -dependencies = [ - "asset-hub-polkadot-emulated-chain", - "bridge-hub-polkadot-emulated-chain", - "collectives-polkadot-emulated-chain", - "coretime-polkadot-emulated-chain", - "emulated-integration-tests-common", - "penpal-emulated-chain", - "people-polkadot-emulated-chain", - "polkadot-emulated-chain", -] - [[package]] name = "polkavm" version = "0.9.3" @@ -10291,7 +8795,7 @@ dependencies = [ "libc", "log", "polkavm-assembler", - "polkavm-common 0.9.0", + "polkavm-common", "polkavm-linux-raw", ] @@ -10304,12 +8808,6 @@ dependencies = [ "log", ] -[[package]] -name = "polkavm-common" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c99f7eee94e7be43ba37eef65ad0ee8cbaf89b7c00001c3f6d2be985cb1817" - [[package]] name = "polkavm-common" version = "0.9.0" @@ -10319,34 +8817,13 @@ dependencies = [ "log", ] -[[package]] -name = "polkavm-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fa916f7962348bd1bb1a65a83401675e6fc86c51a0fdbcf92a3108e58e6125" -dependencies = [ - "polkavm-derive-impl-macro 0.8.0", -] - [[package]] name = "polkavm-derive" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" dependencies = [ - "polkavm-derive-impl-macro 0.9.0", -] - -[[package]] -name = "polkavm-derive-impl" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c10b2654a8a10a83c260bfb93e97b262cf0017494ab94a65d389e0eda6de6c9c" -dependencies = [ - "polkavm-common 0.8.0", - "proc-macro2", - "quote", - "syn 2.0.65", + "polkavm-derive-impl-macro", ] [[package]] @@ -10355,29 +8832,19 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ - "polkavm-common 0.9.0", + "polkavm-common", "proc-macro2", "quote", "syn 2.0.65", ] -[[package]] -name = "polkavm-derive-impl-macro" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" -dependencies = [ - "polkavm-derive-impl 0.8.0", - "syn 2.0.65", -] - [[package]] name = "polkavm-derive-impl-macro" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ - "polkavm-derive-impl 0.9.0", + "polkavm-derive-impl", "syn 2.0.65", ] @@ -10391,7 +8858,7 @@ dependencies = [ "hashbrown 0.14.3", "log", "object 0.32.2", - "polkavm-common 0.9.0", + "polkavm-common", "regalloc2 0.9.3", "rustc-demangle", ] @@ -10938,7 +9405,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -10948,15 +9415,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - [[package]] name = "rand_core" version = "0.6.4" @@ -10982,7 +9443,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -11017,7 +9478,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ - "pem 1.1.1", + "pem", "ring 0.16.20", "time", "yasna", @@ -11150,47 +9611,7 @@ dependencies = [ "polkadot-primitives 16.0.0", "scale-info", "sp-api", - "sp-runtime 39.0.2", -] - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.6", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.22", - "http 0.2.11", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite 0.2.13", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", + "sp-runtime", ] [[package]] @@ -11262,7 +9683,7 @@ dependencies = [ "log", "netlink-packet-route", "netlink-proto", - "nix 0.24.3", + "nix", "thiserror", "tokio", ] @@ -11407,20 +9828,6 @@ dependencies = [ "sct", ] -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring 0.17.7", - "rustls-pki-types", - "rustls-webpki 0.102.5", - "subtle 2.5.0", - "zeroize", -] - [[package]] name = "rustls" version = "0.23.11" @@ -11552,17 +9959,6 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "ruzstd" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" -dependencies = [ - "byteorder", - "derive_more", - "twox-hash", -] - [[package]] name = "rw-stream-sink" version = "0.4.0" @@ -11614,27 +10010,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b975ee3a95eaacb611e7b415737a7fa2db4d8ad7b880cc1b97371b04e95c7903" dependencies = [ "log", - "sp-core 34.0.0", - "sp-wasm-interface 21.0.1", + "sp-core", + "sp-wasm-interface", "thiserror", ] -[[package]] -name = "sc-block-builder" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f666f8ff11f96bf6d90676739eb7ccb6a156a4507634b7af83b94f0aa8195a50" -dependencies = [ - "parity-scale-codec", - "sp-api", - "sp-block-builder", - "sp-blockchain", - "sp-core 34.0.0", - "sp-inherents", - "sp-runtime 39.0.2", - "sp-trie 37.0.0", -] - [[package]] name = "sc-chain-spec" version = "38.0.0" @@ -11654,13 +10034,13 @@ dependencies = [ "serde", "serde_json", "sp-blockchain", - "sp-core 34.0.0", + "sp-core", "sp-crypto-hashing", "sp-genesis-builder", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", - "sp-tracing 17.0.1", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-tracing", ] [[package]] @@ -11692,14 +10072,14 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-consensus", - "sp-core 34.0.0", + "sp-core", "sp-database", - "sp-externalities 0.29.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-externalities", + "sp-runtime", + "sp-state-machine", "sp-statement-store", - "sp-storage 21.0.0", - "sp-trie 37.0.0", + "sp-storage", + "sp-trie", "substrate-prometheus-endpoint", ] @@ -11721,63 +10101,18 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-consensus", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-core", + "sp-runtime", + "sp-state-machine", "substrate-prometheus-endpoint", "thiserror", ] [[package]] -name = "sc-consensus-grandpa" -version = "0.30.0" +name = "sc-executor" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3aaab70cf6f93ceea829ef0a4980ce95d84d5c7f4b5419b29bbed17fa04e1a6" -dependencies = [ - "ahash 0.8.8", - "array-bytes", - "async-trait", - "dyn-clone", - "finality-grandpa", - "fork-tree", - "futures", - "futures-timer", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "rand", - "sc-block-builder", - "sc-chain-spec", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-common", - "sc-network-gossip", - "sc-network-sync", - "sc-network-types", - "sc-telemetry", - "sc-transaction-pool-api", - "sc-utils", - "serde_json", - "sp-api", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", - "sp-blockchain", - "sp-consensus", - "sp-consensus-grandpa", - "sp-core 34.0.0", - "sp-crypto-hashing", - "sp-keystore 0.40.0", - "sp-runtime 39.0.2", - "substrate-prometheus-endpoint", - "thiserror", -] - -[[package]] -name = "sc-executor" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f0cc0a3728fd033589183460c5a49b2e7545d09dc89a098216ef9e9aadcd9dc" +checksum = "3f0cc0a3728fd033589183460c5a49b2e7545d09dc89a098216ef9e9aadcd9dc" dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", @@ -11786,14 +10121,14 @@ dependencies = [ "sc-executor-wasmtime", "schnellru", "sp-api", - "sp-core 34.0.0", - "sp-externalities 0.29.0", - "sp-io 38.0.0", + "sp-core", + "sp-externalities", + "sp-io", "sp-panic-handler", - "sp-runtime-interface 28.0.0", - "sp-trie 37.0.0", + "sp-runtime-interface", + "sp-trie", "sp-version", - "sp-wasm-interface 21.0.1", + "sp-wasm-interface", "tracing", ] @@ -11806,7 +10141,7 @@ dependencies = [ "polkavm", "sc-allocator", "sp-maybe-compressed-blob", - "sp-wasm-interface 21.0.1", + "sp-wasm-interface", "thiserror", "wasm-instrument", ] @@ -11820,7 +10155,7 @@ dependencies = [ "log", "polkavm", "sc-executor-common", - "sp-wasm-interface 21.0.1", + "sp-wasm-interface", ] [[package]] @@ -11837,8 +10172,8 @@ dependencies = [ "rustix 0.36.17", "sc-allocator", "sc-executor-common", - "sp-runtime-interface 28.0.0", - "sp-wasm-interface 21.0.1", + "sp-runtime-interface", + "sp-wasm-interface", "wasmtime", ] @@ -11849,7 +10184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "781a1ffd953074e060a5f9e253f7a029bedd935fe9621bb7483cc2d442a6b1d1" dependencies = [ "array-bytes", - "arrayvec 0.7.4", + "arrayvec", "blake2 0.10.6", "bytes", "futures", @@ -11865,10 +10200,10 @@ dependencies = [ "sc-transaction-pool-api", "sp-api", "sp-consensus", - "sp-core 34.0.0", - "sp-keystore 0.40.0", + "sp-core", + "sp-keystore", "sp-mixnet", - "sp-runtime 39.0.2", + "sp-runtime", "thiserror", ] @@ -11879,7 +10214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e729c49834b3c5cfd514cdd1209ad7ae9707abebef92c991b2d41db5a0191396" dependencies = [ "array-bytes", - "async-channel 1.9.0", + "async-channel", "async-trait", "asynchronous-codec", "bytes", @@ -11910,10 +10245,10 @@ dependencies = [ "serde", "serde_json", "smallvec", - "sp-arithmetic 26.0.0", + "sp-arithmetic", "sp-blockchain", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "substrate-prometheus-endpoint", "thiserror", "tokio", @@ -11940,65 +10275,7 @@ dependencies = [ "sc-network-types", "sp-consensus", "sp-consensus-grandpa", - "sp-runtime 39.0.2", -] - -[[package]] -name = "sc-network-gossip" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4086f4ac6b94ff2efd24f1776280c580454c5990b8665aa9f293fcd33c80630" -dependencies = [ - "ahash 0.8.8", - "futures", - "futures-timer", - "log", - "sc-network", - "sc-network-common", - "sc-network-sync", - "sc-network-types", - "schnellru", - "sp-runtime 39.0.2", - "substrate-prometheus-endpoint", - "tracing", -] - -[[package]] -name = "sc-network-sync" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c9df284544a234ed8e507c6b55e6e3ed4803b7730906b94339706cf12bcc32" -dependencies = [ - "array-bytes", - "async-channel 1.9.0", - "async-trait", - "fork-tree", - "futures", - "futures-timer", - "libp2p", - "log", - "mockall 0.11.4", - "parity-scale-codec", - "prost 0.12.6", - "prost-build 0.12.6", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-common", - "sc-network-types", - "sc-utils", - "schnellru", - "smallvec", - "sp-arithmetic 26.0.0", - "sp-blockchain", - "sp-consensus", - "sp-consensus-grandpa", - "sp-core 34.0.0", - "sp-runtime 39.0.2", - "substrate-prometheus-endpoint", - "thiserror", - "tokio", - "tokio-stream", + "sp-runtime", ] [[package]] @@ -12025,7 +10302,7 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147274633577e55db73dbdc64168c25b54cca6cac4fcde118bd9946cf7b24838" dependencies = [ - "jsonrpsee 0.24.7", + "jsonrpsee", "parity-scale-codec", "sc-chain-spec", "sc-mixnet", @@ -12033,9 +10310,9 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-core 34.0.0", + "sp-core", "sp-rpc", - "sp-runtime 39.0.2", + "sp-runtime", "sp-version", "thiserror", ] @@ -12073,8 +10350,8 @@ dependencies = [ "parity-scale-codec", "serde", "sp-blockchain", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "thiserror", ] @@ -12084,26 +10361,14 @@ version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf1bad736c230f16beb1cf48af9e69564df23b13aca9e5751a61266340b4bb5" dependencies = [ - "async-channel 1.9.0", + "async-channel", "futures", "futures-timer", "lazy_static", "log", "parking_lot 0.12.3", "prometheus", - "sp-arithmetic 26.0.0", -] - -[[package]] -name = "scale-bits" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662d10dcd57b1c2a3c41c9cf68f71fb09747ada1ea932ad961aca7e2ca28315f" -dependencies = [ - "parity-scale-codec", - "scale-info", - "scale-type-resolver 0.1.1", - "serde", + "sp-arithmetic", ] [[package]] @@ -12113,22 +10378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57b1e7f6b65ed1f04e79a85a57d755ad56d76fdf1e9bddcc9ae14f71fcdcf54" dependencies = [ "parity-scale-codec", - "scale-type-resolver 0.2.0", -] - -[[package]] -name = "scale-decode" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc79ba56a1c742f5aeeed1f1801f3edf51f7e818f0a54582cac6f131364ea7b" -dependencies = [ - "derive_more", - "parity-scale-codec", - "primitive-types", - "scale-bits 0.5.0", - "scale-decode-derive", - "scale-type-resolver 0.1.1", - "smallvec", + "scale-type-resolver", ] [[package]] @@ -12139,51 +10389,11 @@ checksum = "b12ebca36cec2a3f983c46295b282b35e5f8496346fb859a8776dad5389e5389" dependencies = [ "derive_more", "parity-scale-codec", - "scale-bits 0.6.0", - "scale-type-resolver 0.2.0", - "smallvec", -] - -[[package]] -name = "scale-decode-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5398fdb3c7bea3cb419bac4983aadacae93fe1a7b5f693f4ebd98c3821aad7a5" -dependencies = [ - "darling 0.14.4", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "scale-encode" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628800925a33794fb5387781b883b5e14d130fece9af5a63613867b8de07c5c7" -dependencies = [ - "derive_more", - "parity-scale-codec", - "primitive-types", - "scale-bits 0.5.0", - "scale-encode-derive", - "scale-type-resolver 0.1.1", + "scale-bits", + "scale-type-resolver", "smallvec", ] -[[package]] -name = "scale-encode-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a304e1af7cdfbe7a24e08b012721456cc8cecdedadc14b3d10513eada63233c" -dependencies = [ - "darling 0.14.4", - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "scale-info" version = "2.11.3" @@ -12210,56 +10420,12 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "scale-type-resolver" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b800069bfd43374e0f96f653e0d46882a2cb16d6d961ac43bea80f26c76843" -dependencies = [ - "scale-info", - "smallvec", -] - [[package]] name = "scale-type-resolver" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" -[[package]] -name = "scale-typegen" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d470fa75e71b12b3244a4113adc4bc49891f3daba2054703cacd06256066397e" -dependencies = [ - "proc-macro2", - "quote", - "scale-info", - "syn 2.0.65", - "thiserror", -] - -[[package]] -name = "scale-value" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07ccfee963104335c971aaf8b7b0e749be8569116322df23f1f75c4ca9e4a28" -dependencies = [ - "base58", - "blake2 0.10.6", - "derive_more", - "either", - "frame-metadata 15.1.0", - "parity-scale-codec", - "scale-bits 0.5.0", - "scale-decode 0.11.1", - "scale-encode", - "scale-info", - "scale-type-resolver 0.1.1", - "serde", - "yap", -] - [[package]] name = "schannel" version = "0.1.22" @@ -12288,11 +10454,11 @@ checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" dependencies = [ "aead", "arrayref", - "arrayvec 0.7.4", - "curve25519-dalek 4.1.3", + "arrayvec", + "curve25519-dalek", "getrandom_or_panic", "merlin", - "rand_core 0.6.4", + "rand_core", "serde_bytes", "sha2 0.10.8", "subtle 2.5.0", @@ -12375,7 +10541,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ - "serde", "zeroize", ] @@ -12484,16 +10649,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde_bytes" version = "0.11.14" @@ -12535,31 +10690,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap 2.2.6", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "serdect" version = "0.2.0" @@ -12658,15 +10788,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - [[package]] name = "signature" version = "2.2.0" @@ -12674,7 +10795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -12705,12 +10826,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "620a1d43d70e142b1d46a929af51d44f383db9c7a2ec122de2cd992ccfcf3c18" -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - [[package]] name = "slab" version = "0.4.9" @@ -12735,7 +10850,7 @@ dependencies = [ "enumn", "parity-scale-codec", "paste", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -12744,114 +10859,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smol" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" -dependencies = [ - "async-channel 2.3.0", - "async-executor", - "async-fs", - "async-io", - "async-lock 3.2.0", - "async-net", - "async-process", - "blocking", - "futures-lite", -] - -[[package]] -name = "smoldot" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d1eaa97d77be4d026a1e7ffad1bb3b78448763b357ea6f8188d3e6f736a9b9" -dependencies = [ - "arrayvec 0.7.4", - "async-lock 3.2.0", - "atomic-take", - "base64 0.21.6", - "bip39", - "blake2-rfc", - "bs58 0.5.1", - "chacha20", - "crossbeam-queue", - "derive_more", - "ed25519-zebra 4.0.3", - "either", - "event-listener 4.0.0", - "fnv", - "futures-lite", - "futures-util", - "hashbrown 0.14.3", - "hex", - "hmac 0.12.1", - "itertools 0.12.1", - "libm", - "libsecp256k1", - "merlin", - "no-std-net", - "nom", - "num-bigint", - "num-rational", - "num-traits", - "pbkdf2", - "pin-project", - "poly1305", - "rand", - "rand_chacha", - "ruzstd", - "schnorrkel", - "serde", - "serde_json", - "sha2 0.10.8", - "sha3", - "siphasher", - "slab", - "smallvec", - "soketto 0.7.1", - "twox-hash", - "wasmi", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "smoldot-light" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7" -dependencies = [ - "async-channel 2.3.0", - "async-lock 3.2.0", - "base64 0.21.6", - "blake2-rfc", - "derive_more", - "either", - "event-listener 4.0.0", - "fnv", - "futures-channel", - "futures-lite", - "futures-util", - "hashbrown 0.14.3", - "hex", - "itertools 0.12.1", - "log", - "lru 0.12.3", - "no-std-net", - "parking_lot 0.12.3", - "pin-project", - "rand", - "rand_chacha", - "serde", - "serde_json", - "siphasher", - "slab", - "smol", - "smoldot", - "zeroize", -] - [[package]] name = "snow" version = "0.9.4" @@ -12861,8 +10868,8 @@ dependencies = [ "aes-gcm", "blake2 0.10.6", "chacha20poly1305", - "curve25519-dalek 4.1.3", - "rand_core 0.6.4", + "curve25519-dalek", + "rand_core", "ring 0.17.7", "rustc_version 0.4.0", "sha2 0.10.8", @@ -12894,9 +10901,9 @@ dependencies = [ "serde", "snowbridge-ethereum", "snowbridge-milagro-bls", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "ssz_rs", "ssz_rs_derive", @@ -12917,10 +10924,10 @@ dependencies = [ "scale-info", "serde", "snowbridge-beacon-primitives", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "staging-xcm", "staging-xcm-builder", @@ -12942,8 +10949,8 @@ dependencies = [ "scale-info", "serde", "serde-big-array", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-io", + "sp-runtime", "sp-std", ] @@ -12970,8 +10977,8 @@ checksum = "74c6a9b65fa61711b704f0c6afb3663c6288288e8822ddae5cc1146fe3ad9ce8" dependencies = [ "parity-scale-codec", "scale-info", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -13007,9 +11014,9 @@ dependencies = [ "snowbridge-core", "snowbridge-ethereum", "snowbridge-pallet-ethereum-client-fixtures", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "static_assertions", ] @@ -13023,7 +11030,7 @@ dependencies = [ "hex-literal", "snowbridge-beacon-primitives", "snowbridge-core", - "sp-core 34.0.0", + "sp-core", "sp-std", ] @@ -13048,9 +11055,9 @@ dependencies = [ "snowbridge-core", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-router-primitives", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "staging-xcm", "staging-xcm-executor", @@ -13065,7 +11072,7 @@ dependencies = [ "hex-literal", "snowbridge-beacon-primitives", "snowbridge-core", - "sp-core 34.0.0", + "sp-core", "sp-std", ] @@ -13085,10 +11092,10 @@ dependencies = [ "serde", "snowbridge-core", "snowbridge-outbound-queue-merkle-tree", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", ] @@ -13105,9 +11112,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "snowbridge-core", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "staging-xcm", "staging-xcm-executor", @@ -13125,9 +11132,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "snowbridge-core", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-io", + "sp-runtime", "sp-std", "staging-xcm", "staging-xcm-executor", @@ -13143,7 +11150,7 @@ dependencies = [ "log", "parity-scale-codec", "snowbridge-core", - "sp-arithmetic 26.0.0", + "sp-arithmetic", "sp-std", "staging-xcm", "staging-xcm-builder", @@ -13173,10 +11180,10 @@ dependencies = [ "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-keyring", - "sp-runtime 39.0.2", + "sp-runtime", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -13257,13 +11264,13 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api-proc-macro", - "sp-core 34.0.0", - "sp-externalities 0.29.0", + "sp-core", + "sp-externalities", "sp-metadata-ir", - "sp-runtime 39.0.2", - "sp-runtime-interface 28.0.0", - "sp-state-machine 0.43.0", - "sp-trie 37.0.0", + "sp-runtime", + "sp-runtime-interface", + "sp-state-machine", + "sp-trie", "sp-version", "thiserror", ] @@ -13283,20 +11290,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "sp-application-crypto" -version = "33.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13ca6121c22c8bd3d1dce1f05c479101fd0d7b159bef2a3e8c834138d839c75c" -dependencies = [ - "parity-scale-codec", - "scale-info", - "serde", - "sp-core 31.0.0", - "sp-io 33.0.0", - "sp-std", -] - [[package]] name = "sp-application-crypto" version = "38.0.0" @@ -13306,23 +11299,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-io 38.0.0", -] - -[[package]] -name = "sp-arithmetic" -version = "25.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910c07fa263b20bf7271fdd4adcb5d3217dfdac14270592e0780223542e7e114" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "scale-info", - "serde", - "sp-std", - "static_assertions", + "sp-core", + "sp-io", ] [[package]] @@ -13350,8 +11328,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-application-crypto 38.0.0", - "sp-runtime 39.0.2", + "sp-application-crypto", + "sp-runtime", ] [[package]] @@ -13362,7 +11340,7 @@ checksum = "74738809461e3d4bd707b5b94e0e0c064a623a74a6a8fe5c98514417a02858dd" dependencies = [ "sp-api", "sp-inherents", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -13377,10 +11355,10 @@ dependencies = [ "schnellru", "sp-api", "sp-consensus", - "sp-core 34.0.0", + "sp-core", "sp-database", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-runtime", + "sp-state-machine", "thiserror", "tracing", ] @@ -13394,10 +11372,10 @@ dependencies = [ "async-trait", "futures", "log", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-runtime 39.0.2", - "sp-state-machine 0.43.0", + "sp-runtime", + "sp-state-machine", "thiserror", ] @@ -13411,10 +11389,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-slots", "sp-inherents", - "sp-runtime 39.0.2", + "sp-runtime", "sp-timestamp", ] @@ -13429,11 +11407,11 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", + "sp-application-crypto", "sp-consensus-slots", - "sp-core 34.0.0", + "sp-core", "sp-inherents", - "sp-runtime 39.0.2", + "sp-runtime", "sp-timestamp", ] @@ -13448,14 +11426,14 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", + "sp-application-crypto", + "sp-core", "sp-crypto-hashing", - "sp-io 38.0.0", - "sp-keystore 0.40.0", + "sp-io", + "sp-keystore", "sp-mmr-primitives", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-runtime", + "sp-weights", "strum 0.26.3", ] @@ -13471,10 +11449,10 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", - "sp-keystore 0.40.0", - "sp-runtime 39.0.2", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "sp-runtime", ] [[package]] @@ -13489,53 +11467,6 @@ dependencies = [ "sp-timestamp", ] -[[package]] -name = "sp-core" -version = "31.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d7a0fd8f16dcc3761198fc83be12872f823b37b749bc72a3a6a1f702509366" -dependencies = [ - "array-bytes", - "bitflags 1.3.2", - "blake2 0.10.6", - "bounded-collections", - "bs58 0.5.1", - "dyn-clonable", - "ed25519-zebra 3.1.0", - "futures", - "hash-db", - "hash256-std-hasher", - "impl-serde", - "itertools 0.10.5", - "k256", - "libsecp256k1", - "log", - "merlin", - "parity-bip39", - "parity-scale-codec", - "parking_lot 0.12.3", - "paste", - "primitive-types", - "rand", - "scale-info", - "schnorrkel", - "secp256k1", - "secrecy", - "serde", - "sp-crypto-hashing", - "sp-debug-derive", - "sp-externalities 0.27.0", - "sp-runtime-interface 26.0.0", - "sp-std", - "sp-storage 20.0.0", - "ss58-registry", - "substrate-bip39 0.5.0", - "thiserror", - "tracing", - "w3f-bls", - "zeroize", -] - [[package]] name = "sp-core" version = "34.0.0" @@ -13548,7 +11479,7 @@ dependencies = [ "bounded-collections", "bs58 0.5.1", "dyn-clonable", - "ed25519-zebra 4.0.3", + "ed25519-zebra", "futures", "hash-db", "hash256-std-hasher", @@ -13571,12 +11502,12 @@ dependencies = [ "serde", "sp-crypto-hashing", "sp-debug-derive", - "sp-externalities 0.29.0", - "sp-runtime-interface 28.0.0", + "sp-externalities", + "sp-runtime-interface", "sp-std", - "sp-storage 21.0.0", + "sp-storage", "ss58-registry", - "substrate-bip39 0.6.0", + "substrate-bip39", "thiserror", "tracing", "w3f-bls", @@ -13629,18 +11560,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "sp-externalities" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d6a4572eadd4a63cff92509a210bf425501a0c5e76574b30a366ac77653787" -dependencies = [ - "environmental", - "parity-scale-codec", - "sp-std", - "sp-storage 20.0.0", -] - [[package]] name = "sp-externalities" version = "0.29.0" @@ -13649,7 +11568,7 @@ checksum = "a904407d61cb94228c71b55a9d3708e9d6558991f9e83bd42bd91df37a159d30" dependencies = [ "environmental", "parity-scale-codec", - "sp-storage 21.0.0", + "sp-storage", ] [[package]] @@ -13662,7 +11581,7 @@ dependencies = [ "scale-info", "serde_json", "sp-api", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -13675,37 +11594,10 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", "thiserror", ] -[[package]] -name = "sp-io" -version = "33.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e09bba780b55bd9e67979cd8f654a31e4a6cf45426ff371394a65953d2177f2" -dependencies = [ - "bytes", - "ed25519-dalek", - "libsecp256k1", - "log", - "parity-scale-codec", - "polkavm-derive 0.9.1", - "rustversion", - "secp256k1", - "sp-core 31.0.0", - "sp-crypto-hashing", - "sp-externalities 0.27.0", - "sp-keystore 0.37.0", - "sp-runtime-interface 26.0.0", - "sp-state-machine 0.38.0", - "sp-std", - "sp-tracing 16.0.0", - "sp-trie 32.0.0", - "tracing", - "tracing-core", -] - [[package]] name = "sp-io" version = "38.0.0" @@ -13718,17 +11610,17 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive", "rustversion", "secp256k1", - "sp-core 34.0.0", + "sp-core", "sp-crypto-hashing", - "sp-externalities 0.29.0", - "sp-keystore 0.40.0", - "sp-runtime-interface 28.0.0", - "sp-state-machine 0.43.0", - "sp-tracing 17.0.1", - "sp-trie 37.0.0", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-tracing", + "sp-trie", "tracing", "tracing-core", ] @@ -13739,23 +11631,11 @@ version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c0e20624277f578b27f44ecfbe2ebc2e908488511ee2c900c5281599f700ab3" dependencies = [ - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "strum 0.26.3", ] -[[package]] -name = "sp-keystore" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbab8b61bd61d5f8625a0c75753b5d5a23be55d3445419acd42caf59cf6236b" -dependencies = [ - "parity-scale-codec", - "parking_lot 0.12.3", - "sp-core 31.0.0", - "sp-externalities 0.27.0", -] - [[package]] name = "sp-keystore" version = "0.40.0" @@ -13764,8 +11644,8 @@ checksum = "0248b4d784cb4a01472276928977121fa39d977a5bb24793b6b15e64b046df42" dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", - "sp-core 34.0.0", - "sp-externalities 0.29.0", + "sp-core", + "sp-externalities", ] [[package]] @@ -13784,7 +11664,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a616fa51350b35326682a472ee8e6ba742fdacb18babac38ecd46b3e05ead869" dependencies = [ - "frame-metadata 16.0.0", + "frame-metadata", "parity-scale-codec", "scale-info", ] @@ -13798,7 +11678,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-application-crypto 38.0.0", + "sp-application-crypto", ] [[package]] @@ -13813,9 +11693,9 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-core 34.0.0", + "sp-core", "sp-debug-derive", - "sp-runtime 39.0.2", + "sp-runtime", "thiserror", ] @@ -13828,9 +11708,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-arithmetic", + "sp-core", + "sp-runtime", ] [[package]] @@ -13840,8 +11720,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d9de237d72ecffd07f90826eef18360208b16d8de939d54e61591fac0fcbf99" dependencies = [ "sp-api", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -13854,41 +11734,16 @@ dependencies = [ "lazy_static", "regex", ] - -[[package]] -name = "sp-rpc" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45458f0955870a92b3969098d4f1f4e9b55b4282d9f1dc112a51bb5bb6584900" -dependencies = [ - "rustc-hash 1.1.0", - "serde", - "sp-core 34.0.0", -] - -[[package]] -name = "sp-runtime" -version = "34.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3cb126971e7db2f0fcf8053dce740684c438c7180cfca1959598230f342c58" -dependencies = [ - "docify", - "either", - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "paste", - "rand", - "scale-info", + +[[package]] +name = "sp-rpc" +version = "32.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45458f0955870a92b3969098d4f1f4e9b55b4282d9f1dc112a51bb5bb6584900" +dependencies = [ + "rustc-hash 1.1.0", "serde", - "simple-mermaid", - "sp-application-crypto 33.0.0", - "sp-arithmetic 25.0.0", - "sp-core 31.0.0", - "sp-io 33.0.0", - "sp-std", - "sp-weights 30.0.0", + "sp-core", ] [[package]] @@ -13909,35 +11764,15 @@ dependencies = [ "scale-info", "serde", "simple-mermaid", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", "sp-std", - "sp-weights 31.0.0", + "sp-weights", "tracing", ] -[[package]] -name = "sp-runtime-interface" -version = "26.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a675ea4858333d4d755899ed5ed780174aa34fec15953428d516af5452295" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "polkavm-derive 0.8.0", - "primitive-types", - "sp-externalities 0.27.0", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-storage 20.0.0", - "sp-tracing 16.0.0", - "sp-wasm-interface 20.0.0", - "static_assertions", -] - [[package]] name = "sp-runtime-interface" version = "28.0.0" @@ -13947,14 +11782,14 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive 0.9.1", + "polkavm-derive", "primitive-types", - "sp-externalities 0.29.0", + "sp-externalities", "sp-runtime-interface-proc-macro", "sp-std", - "sp-storage 21.0.0", - "sp-tracing 17.0.1", - "sp-wasm-interface 21.0.1", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", "static_assertions", ] @@ -13981,9 +11816,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-core 34.0.0", - "sp-keystore 0.40.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-keystore", + "sp-runtime", "sp-staking 36.0.0", ] @@ -13997,8 +11832,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", ] [[package]] @@ -14011,30 +11846,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.2", -] - -[[package]] -name = "sp-state-machine" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eae0eac8034ba14437e772366336f579398a46d101de13dbb781ab1e35e67c5" -dependencies = [ - "hash-db", - "log", - "parity-scale-codec", - "parking_lot 0.12.3", - "rand", - "smallvec", - "sp-core 31.0.0", - "sp-externalities 0.27.0", - "sp-panic-handler", - "sp-std", - "sp-trie 32.0.0", - "thiserror", - "tracing", - "trie-db 0.28.0", + "sp-core", + "sp-runtime", ] [[package]] @@ -14049,13 +11862,13 @@ dependencies = [ "parking_lot 0.12.3", "rand", "smallvec", - "sp-core 34.0.0", - "sp-externalities 0.29.0", + "sp-core", + "sp-externalities", "sp-panic-handler", - "sp-trie 37.0.0", + "sp-trie", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", ] [[package]] @@ -14065,7 +11878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c219bc34ef4d1f9835f3ed881f965643c32034fcc030eb33b759dadbc802c1c2" dependencies = [ "aes-gcm", - "curve25519-dalek 4.1.3", + "curve25519-dalek", "ed25519-dalek", "hkdf", "parity-scale-codec", @@ -14073,12 +11886,12 @@ dependencies = [ "scale-info", "sha2 0.10.8", "sp-api", - "sp-application-crypto 38.0.0", - "sp-core 34.0.0", + "sp-application-crypto", + "sp-core", "sp-crypto-hashing", - "sp-externalities 0.29.0", - "sp-runtime 39.0.2", - "sp-runtime-interface 28.0.0", + "sp-externalities", + "sp-runtime", + "sp-runtime-interface", "thiserror", "x25519-dalek", ] @@ -14089,20 +11902,6 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" -[[package]] -name = "sp-storage" -version = "20.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dba5791cb3978e95daf99dad919ecb3ec35565604e88cd38d805d9d4981e8bd" -dependencies = [ - "impl-serde", - "parity-scale-codec", - "ref-cast", - "serde", - "sp-debug-derive", - "sp-std", -] - [[package]] name = "sp-storage" version = "21.0.0" @@ -14125,23 +11924,10 @@ dependencies = [ "async-trait", "parity-scale-codec", "sp-inherents", - "sp-runtime 39.0.2", + "sp-runtime", "thiserror", ] -[[package]] -name = "sp-tracing" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0351810b9d074df71c4514c5228ed05c250607cba131c1c9d1526760ab69c05c" -dependencies = [ - "parity-scale-codec", - "sp-std", - "tracing", - "tracing-core", - "tracing-subscriber 0.2.25", -] - [[package]] name = "sp-tracing" version = "17.0.1" @@ -14151,7 +11937,7 @@ dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -14161,32 +11947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4bf251059485a7dd38fe4afeda8792983511cc47f342ff4695e2dcae6b5247" dependencies = [ "sp-api", - "sp-runtime 39.0.2", -] - -[[package]] -name = "sp-trie" -version = "32.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1aa91ad26c62b93d73e65f9ce7ebd04459c4bad086599348846a81988d6faa4" -dependencies = [ - "ahash 0.8.8", - "hash-db", - "lazy_static", - "memory-db", - "nohash-hasher", - "parity-scale-codec", - "parking_lot 0.12.3", - "rand", - "scale-info", - "schnellru", - "sp-core 31.0.0", - "sp-externalities 0.27.0", - "sp-std", - "thiserror", - "tracing", - "trie-db 0.28.0", - "trie-root", + "sp-runtime", ] [[package]] @@ -14205,11 +11966,11 @@ dependencies = [ "rand", "scale-info", "schnellru", - "sp-core 34.0.0", - "sp-externalities 0.29.0", + "sp-core", + "sp-externalities", "thiserror", "tracing", - "trie-db 0.29.1", + "trie-db", "trie-root", ] @@ -14225,7 +11986,7 @@ dependencies = [ "scale-info", "serde", "sp-crypto-hashing-proc-macro", - "sp-runtime 39.0.2", + "sp-runtime", "sp-std", "sp-version-proc-macro", "thiserror", @@ -14243,20 +12004,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "sp-wasm-interface" -version = "20.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef97172c42eb4c6c26506f325f48463e9bc29b2034a587f1b9e48c751229bee" -dependencies = [ - "anyhow", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "sp-std", - "wasmtime", -] - [[package]] name = "sp-wasm-interface" version = "21.0.1" @@ -14270,22 +12017,6 @@ dependencies = [ "wasmtime", ] -[[package]] -name = "sp-weights" -version = "30.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af6c661fe3066b29f9e1d258000f402ff5cc2529a9191972d214e5871d0ba87" -dependencies = [ - "bounded-collections", - "parity-scale-codec", - "scale-info", - "serde", - "smallvec", - "sp-arithmetic 25.0.0", - "sp-debug-derive", - "sp-std", -] - [[package]] name = "sp-weights" version = "31.0.0" @@ -14297,7 +12028,7 @@ dependencies = [ "scale-info", "serde", "smallvec", - "sp-arithmetic 26.0.0", + "sp-arithmetic", "sp-debug-derive", ] @@ -14452,28 +12183,28 @@ dependencies = [ "separator", "serde_json", "sp-api", - "sp-application-crypto 38.0.0", - "sp-arithmetic 26.0.0", + "sp-application-crypto", + "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core 34.0.0", + "sp-core", "sp-debug-derive", "sp-genesis-builder", "sp-inherents", - "sp-io 38.0.0", + "sp-io", "sp-keyring", "sp-npos-elections", "sp-offchain", - "sp-runtime 39.0.2", + "sp-runtime", "sp-session", "sp-staking 36.0.0", "sp-std", - "sp-storage 21.0.0", - "sp-tracing 17.0.1", + "sp-storage", + "sp-tracing", "sp-transaction-pool", - "sp-trie 37.0.0", + "sp-trie", "sp-version", "ss58-registry", "staging-xcm", @@ -14495,7 +12226,7 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -14513,8 +12244,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-runtime", + "sp-weights", "xcm-procedural", ] @@ -14533,10 +12264,10 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "scale-info", - "sp-arithmetic 26.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-weights", "staging-xcm", "staging-xcm-executor", ] @@ -14553,11 +12284,11 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-weights 31.0.0", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-weights", "staging-xcm", "tracing", ] @@ -14588,18 +12319,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strsim" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" - [[package]] name = "strum" version = "0.24.1" @@ -14644,19 +12363,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "substrate-bip39" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b564c293e6194e8b222e52436bcb99f60de72043c7f845cf6c4406db4df121" -dependencies = [ - "hmac 0.12.1", - "pbkdf2", - "schnorrkel", - "sha2 0.10.8", - "zeroize", -] - [[package]] name = "substrate-bip39" version = "0.6.0" @@ -14713,11 +12419,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5939d2b2a0b556714512dffb08ae3df3fc245039d9b08ee5b0df4e403007ee3a" dependencies = [ "async-trait", - "jsonrpsee 0.24.7", + "jsonrpsee", "log", "sc-rpc-api", "serde", - "sp-runtime 39.0.2", + "sp-runtime", ] [[package]] @@ -14741,17 +12447,17 @@ dependencies = [ "cargo_metadata", "console", "filetime", - "frame-metadata 16.0.0", + "frame-metadata", "jobserver", "merkleized-metadata", "parity-scale-codec", "parity-wasm", "polkavm-linker", "sc-executor", - "sp-core 34.0.0", - "sp-io 38.0.0", + "sp-core", + "sp-io", "sp-maybe-compressed-blob", - "sp-tracing 17.0.1", + "sp-tracing", "sp-version", "strum 0.26.3", "tempfile", @@ -14772,134 +12478,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" -[[package]] -name = "subxt" -version = "0.35.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd68bef23f4de5e513ab4c29af69053e232b098f9c87ab552d7ea153b4a1fbc5" -dependencies = [ - "async-trait", - "base58", - "blake2 0.10.6", - "derivative", - "either", - "frame-metadata 16.0.0", - "futures", - "hex", - "impl-serde", - "instant", - "jsonrpsee 0.22.5", - "parity-scale-codec", - "primitive-types", - "scale-bits 0.5.0", - "scale-decode 0.11.1", - "scale-encode", - "scale-info", - "scale-value", - "serde", - "serde_json", - "sp-core 31.0.0", - "sp-crypto-hashing", - "sp-runtime 34.0.0", - "subxt-lightclient", - "subxt-macro", - "subxt-metadata", - "thiserror", - "tokio-util", - "tracing", - "url", -] - -[[package]] -name = "subxt-codegen" -version = "0.35.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9e2b256b71d31a2629e44eb9cbfd944eb7d577c9e0c8e9802cc3c3943af2d9" -dependencies = [ - "frame-metadata 16.0.0", - "heck 0.4.1", - "hex", - "jsonrpsee 0.22.5", - "parity-scale-codec", - "proc-macro2", - "quote", - "scale-info", - "scale-typegen", - "subxt-metadata", - "syn 2.0.65", - "thiserror", - "tokio", -] - -[[package]] -name = "subxt-lightclient" -version = "0.35.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d51f1ac12e3be7aafea4d037730a57da4f22f2e9c73955666081ffa2697c6f1" -dependencies = [ - "futures", - "futures-util", - "serde", - "serde_json", - "smoldot-light", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "subxt-macro" -version = "0.35.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98dc84d7e6a0abd7ed407cce0bf60d7d58004f699460cffb979640717d1ab506" -dependencies = [ - "darling 0.20.8", - "parity-scale-codec", - "proc-macro-error", - "quote", - "scale-typegen", - "subxt-codegen", - "syn 2.0.65", -] - -[[package]] -name = "subxt-metadata" -version = "0.35.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc10c54028d079a9f1be65188707cd29e5ffd8d0031a2b1346a0941d57b7ab7e" -dependencies = [ - "derive_more", - "frame-metadata 16.0.0", - "hashbrown 0.14.3", - "parity-scale-codec", - "scale-info", - "sp-crypto-hashing", -] - -[[package]] -name = "subxt-signer" -version = "0.35.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ccb59a38fe357fab55247756174435e8626b93929864e8a498635a15e779df8" -dependencies = [ - "bip39", - "cfg-if", - "derive_more", - "hex", - "hmac 0.12.1", - "parity-scale-codec", - "pbkdf2", - "regex", - "schnorrkel", - "secp256k1", - "secrecy", - "sha2 0.10.8", - "sp-crypto-hashing", - "subxt", - "zeroize", -] - [[package]] name = "syn" version = "1.0.109" @@ -14934,12 +12512,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "synstructure" version = "0.12.6" @@ -14995,8 +12567,8 @@ dependencies = [ "polkadot-primitives 16.0.0", "polkadot-runtime-constants", "smallvec", - "sp-core 34.0.0", - "sp-runtime 39.0.2", + "sp-core", + "sp-runtime", "sp-std", "staging-xcm", ] @@ -15007,17 +12579,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tar" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "target-lexicon" version = "0.12.12" @@ -15150,22 +12711,11 @@ dependencies = [ "num_cpus", "parking_lot 0.12.3", "pin-project-lite 0.2.13", - "signal-hook-registry", "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite 0.2.13", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.3.0" @@ -15177,45 +12727,24 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-retry" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" dependencies = [ - "pin-project", - "rand", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.10", + "pin-project", + "rand", "tokio", ] [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.22.4", - "rustls-pki-types", + "rustls 0.21.10", "tokio", ] @@ -15267,7 +12796,6 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite 0.2.13", - "slab", "tokio", ] @@ -15280,18 +12808,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - [[package]] name = "toml" version = "0.8.12" @@ -15320,8 +12836,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.2.6", - "serde", - "serde_spanned", "toml_datetime", "winnow 0.5.33", ] @@ -15361,28 +12875,6 @@ dependencies = [ "pin-project", "pin-project-lite 0.2.13", "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "base64 0.21.6", - "bitflags 2.6.0", - "bytes", - "futures-core", - "futures-util", - "http 0.2.11", - "http-body 0.4.5", - "http-range-header", - "mime", - "pin-project-lite 0.2.13", "tower-layer", "tower-service", "tracing", @@ -15433,17 +12925,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -15455,45 +12936,13 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers 0.0.1", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log 0.1.4", - "tracing-serde", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ - "matchers 0.1.0", + "matchers", "nu-ansi-term", "once_cell", "regex", @@ -15503,20 +12952,7 @@ dependencies = [ "time", "tracing", "tracing-core", - "tracing-log 0.2.0", -] - -[[package]] -name = "trie-db" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff28e0f815c2fea41ebddf148e008b077d2faddb026c9555b29696114d602642" -dependencies = [ - "hash-db", - "hashbrown 0.13.2", - "log", - "rustc-hex", - "smallvec", + "tracing-log", ] [[package]] @@ -15735,12 +13171,6 @@ dependencies = [ "subtle 2.5.0", ] -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "unsigned-varint" version = "0.7.2" @@ -15784,7 +13214,6 @@ dependencies = [ "form_urlencoded", "idna 0.5.0", "percent-encoding", - "serde", ] [[package]] @@ -15793,21 +13222,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "getrandom", -] - [[package]] name = "valuable" version = "0.1.0" @@ -15849,7 +13263,7 @@ dependencies = [ "digest 0.10.7", "rand", "rand_chacha", - "rand_core 0.6.4", + "rand_core", "sha2 0.10.8", "sha3", "thiserror", @@ -16020,37 +13434,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmi" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8281d1d660cdf54c76a3efa9ddd0c270cada1383a995db3ccb43d166456c7" -dependencies = [ - "smallvec", - "spin 0.9.8", - "wasmi_arena", - "wasmi_core", - "wasmparser-nostd", -] - -[[package]] -name = "wasmi_arena" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" - -[[package]] -name = "wasmi_core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" -dependencies = [ - "downcast-rs", - "libm", - "num-traits", - "paste", -] - [[package]] name = "wasmparser" version = "0.102.0" @@ -16061,15 +13444,6 @@ dependencies = [ "url", ] -[[package]] -name = "wasmparser-nostd" -version = "0.100.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa" -dependencies = [ - "indexmap-nostd", -] - [[package]] name = "wasmtime" version = "8.0.1" @@ -16634,8 +14008,8 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek 4.1.3", - "rand_core 0.6.4", + "curve25519-dalek", + "rand_core", "serde", "zeroize", ] @@ -16674,53 +14048,6 @@ dependencies = [ "time", ] -[[package]] -name = "xattr" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" -dependencies = [ - "libc", - "linux-raw-sys 0.4.12", - "rustix 0.38.31", -] - -[[package]] -name = "xcm-emulator" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9ca0239660dd0303f2aa492e297d0be5051fc39e792c840580e05c522fecaa" -dependencies = [ - "array-bytes", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-test-relay-sproof-builder", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "lazy_static", - "log", - "pallet-balances", - "pallet-message-queue", - "parachains-common", - "parity-scale-codec", - "paste", - "polkadot-parachain-primitives", - "polkadot-primitives 16.0.0", - "polkadot-runtime-parachains", - "sp-arithmetic 26.0.0", - "sp-core 34.0.0", - "sp-crypto-hashing", - "sp-io 38.0.0", - "sp-runtime 39.0.2", - "sp-std", - "sp-tracing 17.0.1", - "staging-xcm", - "staging-xcm-executor", -] - [[package]] name = "xcm-procedural" version = "10.1.0" @@ -16743,7 +14070,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", - "sp-weights 31.0.0", + "sp-weights", "staging-xcm", "staging-xcm-executor", ] @@ -16778,12 +14105,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "yap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4524214bc4629eba08d78ceb1d6507070cc0bcbbed23af74e19e6e924a24cf" - [[package]] name = "yasna" version = "0.5.2" @@ -16833,142 +14154,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "zombienet-configuration" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd24a5c580ce4d871a4f3291144a731f0cfc633fedd681b99e73825f38181b6" -dependencies = [ - "anyhow", - "lazy_static", - "multiaddr 0.18.1", - "regex", - "serde", - "serde_json", - "thiserror", - "toml 0.7.8", - "url", - "zombienet-support", -] - -[[package]] -name = "zombienet-orchestrator" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2d240dea2272d66138cd510a39d580b6227966185bf63d7ec23eac14533c9c" -dependencies = [ - "anyhow", - "futures", - "hex", - "libp2p", - "multiaddr 0.18.1", - "rand", - "reqwest", - "serde_json", - "sha2 0.10.8", - "sp-core 31.0.0", - "subxt", - "subxt-signer", - "thiserror", - "tokio", - "tracing", - "uuid", - "zombienet-configuration", - "zombienet-prom-metrics-parser", - "zombienet-provider", - "zombienet-support", -] - -[[package]] -name = "zombienet-prom-metrics-parser" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ed716ba0901e603cbd3b5e3ddc59e3df20d69cd58109ef12bbea6097ffd325" -dependencies = [ - "pest", - "pest_derive", - "thiserror", -] - -[[package]] -name = "zombienet-provider" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7522089152c02622ac27f30f95652ff5b9e3d193ef7eafee41603e9d7cc785" -dependencies = [ - "anyhow", - "async-trait", - "flate2", - "futures", - "hex", - "k8s-openapi", - "kube", - "nix 0.27.1", - "regex", - "reqwest", - "serde", - "serde_json", - "serde_yaml", - "sha2 0.10.8", - "tar", - "thiserror", - "tokio", - "tokio-util", - "tracing", - "url", - "uuid", - "zombienet-configuration", - "zombienet-support", -] - -[[package]] -name = "zombienet-sdk" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d629add7e175261c047c9dc038b4b23fefb174edaf2868f858c5ff1b682f6541" -dependencies = [ - "async-trait", - "futures", - "lazy_static", - "subxt", - "tokio", - "zombienet-configuration", - "zombienet-orchestrator", - "zombienet-provider", - "zombienet-support", -] - -[[package]] -name = "zombienet-sdk-tests" -version = "0.1.0" -dependencies = [ - "anyhow", - "log", - "subxt", - "tokio", - "tracing-subscriber 0.3.18", - "zombienet-sdk", -] - -[[package]] -name = "zombienet-support" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6026607084432996fd590d4beb9d4fb15937bce4f3bd6bddd7e8c0ead1bbc141" -dependencies = [ - "anyhow", - "async-trait", - "futures", - "nix 0.27.1", - "rand", - "regex", - "reqwest", - "thiserror", - "tokio", - "tracing", - "uuid", -] - [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 3c91060a80..d1dd452899 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -257,33 +257,6 @@ ss58-registry = { version = "1.47.0" } resolver = "2" members = [ - "chain-spec-generator", - "integration-tests/emulated/chains/parachains/assets/asset-hub-kusama", - "integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot", - "integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama", - "integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot", - "integration-tests/emulated/chains/parachains/collectives/collectives-polkadot", - "integration-tests/emulated/chains/parachains/coretime/coretime-kusama", - "integration-tests/emulated/chains/parachains/coretime/coretime-polkadot", - "integration-tests/emulated/chains/parachains/people/people-kusama", - "integration-tests/emulated/chains/parachains/people/people-polkadot", - "integration-tests/emulated/chains/parachains/testing/penpal", - "integration-tests/emulated/chains/relays/kusama", - "integration-tests/emulated/chains/relays/polkadot", - "integration-tests/emulated/helpers", - "integration-tests/emulated/networks/kusama-polkadot-system", - "integration-tests/emulated/networks/kusama-system", - "integration-tests/emulated/networks/polkadot-system", - "integration-tests/emulated/tests/assets/asset-hub-kusama", - "integration-tests/emulated/tests/assets/asset-hub-polkadot", - "integration-tests/emulated/tests/bridges/bridge-hub-kusama", - "integration-tests/emulated/tests/bridges/bridge-hub-polkadot", - "integration-tests/emulated/tests/collectives/collectives-polkadot", - "integration-tests/emulated/tests/coretime/coretime-kusama", - "integration-tests/emulated/tests/coretime/coretime-polkadot", - "integration-tests/emulated/tests/people/people-kusama", - "integration-tests/emulated/tests/people/people-polkadot", - "integration-tests/zombienet", "relay/common", "relay/kusama", "relay/kusama/constants", diff --git a/README.md b/README.md index d46a2d472e..a01bd86bb7 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,34 @@ -# Runtimes - -This repository houses the code required to build the runtimes for Polkadot, Kusama, and their System-Parachains. Its maintenance is overseen by the Fellowship, as decreed by the Polkadot and Kusama Governance. The primary objective is to provide excellent code, which can subsequently be enacted on-chain through a decentralized referendum. - -## Structure - -Each leaf folder contains one runtime crate: - - - -```pre -├── relay -│ ├── kusama -│ └── polkadot -└── system-parachains - ├── asset-hubs - │ ├── asset-hub-kusama - │ └── asset-hub-polkadot - ├── bridge-hubs - │ ├── bridge-hub-kusama - │ └── bridge-hub-polkadot - ├── collectives - │ └── collectives-polkadot - └── gluttons - └── glutton-kusama -``` - -## Approval rights - -The approval rights are configured in [`review-bot.yml`](.github/review-bot.yml). The rights are configured as: - -- All files in `.github` require two approvals from Fellowship members of rank 4 or higher. -- `CHANGELOG.md`, `relay/*` or `system-parachains/*` require four approvals from Fellowship members of rank 3 or higher. -- All other files require the approval from one Fellowship member of rank 2 or higher. - -The review-bot uses the on-chain identity to map from a GitHub account to a Fellowship member. This requires that each Fellowship member add their GitHub handle to their on-chain identity. Check [here](docs/on-chain-identity.md) for instructions. - -- [Official List of Fellows](https://polkadot-fellows.github.io/dashboard/#/members) -- [List of Fellows with their GitHub handles](https://fellowship.tasty.limo/) - -## Working on Pull Requests - -To merge a pull request, we use [Auto Merge Bot](https://github.com/paritytech/auto-merge-bot). - -To use it, write a comment in a PR that says: - -> `/merge` - -This will enable [`auto-merge`](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/automatically-merging-a-pull-request) in the Pull Request (or merge it if it is ready to merge). - -The automation can be triggered by the author of the PR or any fellow whose GitHub handle is part of their identity. - -## Release process - -Releases are automatically pushed on commits merged to master that fulfill the following requirements: - -- The [`CHANGELOG.md`](CHANGELOG.md) file was modified. -- The latest version (the version at the top of the file) in [`CHANGELOG.md`](CHANGELOG.md) has no tag in the repository. - -The release process is building all runtimes and then puts them into a release in this github repository. - -The format of [`CHANGELOG.md`](CHANGELOG.md) is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## Release guidelines - -Here is an overview of the recommended steps. - -|Steps |Description | -|------|------------| -|0 |Open an [issue](https://github.com/polkadot-fellows/runtimes/issues) for the release in the runtimes repo with the **version number**. | -|1 |Update **[polkadot-sdk](https://github.com/paritytech/polkadot-sdk?tab=readme-ov-file#-releases)**, if applicable. | -|2 |Identify and monitor **potential blockers** (old dependencies, pending or failed upgrades). | -|3 |Identify and include **PRs** with required tests, highlighting the integration tests that have changed. | -|4 |Identify and communicate all details about **potential breaking changes** (transaction/event/error encoding, polkadot-sdk migrations, XCM and storage format, etc.) or **disruptions**. Make sure to **ping @SBalaguer and @anaelleltd** in your commentary. | -|5 |Run **[benchmarking](https://github.com/polkadot-fellows/runtimes/blob/main/docs/weight-generation.md)** for changed pallets. | -|6 |Trigger the release for **final reviews**, making sure to highlight information about all breaking changes or disruptions in the **CHANGELOG entry**. | -|7 |Create the **[whitelisting proposal (Fellowship)](https://github.com/joepetrowski/opengov-cli)** with contextual information.| -|8 |Create the **[whitelisted caller referendum (OpenGov)](https://github.com/joepetrowski/opengov-cli)** with contextual information and **instructions for following up** on breaking changes or disruptions. | -|9 |Close the issue for the release once the referendum is **approved and executed**. | -|10 |Open an issue for **the next release** in the runtimes repo, if applicable.| - - -## Communication channels - -The Fellowship is using Matrix for communication. Right now there exists two channels: - -- [Polkadot Technical Fellowship Channel](https://matrix.to/#/#fellowship-members:parity.io): The channel for all Fellowship members to discuss. To get voice rights, you need to be part of the Fellowship. However, the channel is readable by anyone. -- [Polkadot Technical Fellowship - Open Channel](https://matrix.to/#/#fellowship-open-channel:parity.io): Open channel for anyone. Should be used to reach out to the Fellowship e.g. to request review or help on a topic. +## Polkadot Runtime Releaser Workshop +This repository contains a production-ready polkadot-sdk-based runtime release setup. + +### Override +> Why do we need to override the runtime? +> +> Always keep the on-chain runtime as minimal as possible which can help reduce the runtime size and improve the performance. +> Override with the `force-debug` runtime, you can get more debug information in the runtime log. +> Override with the `evm-tracing` runtime, you can enable the EVM tracing feature in the runtime. + +1. Create a runtime-overrides repository for your runtime. +2. Copy and configure the [overrides](.github/workflows/override.yml) action to your runtime-overrides repository. With this action, you can maintain the runtime overrides in the runtime-overrides repository automatically and easily without need to build it every time when you need it and can provide this repository for other developers/users. +3. The action file has pretty detailed comments, you can follow the comments to configure the action. Please feel free to open an issue in this repository if you find any issues or have any questions. +4. Create the runtime branches in the runtime-overrides repository, otherwise the action will fail since it can not push the commit to the corresponding branch. The name should be the same as runtime crate time, for example, [`polkadot-runtime`](https://github.com/polkadot-fellows/runtimes/blob/2e73a6c90159b723c741b1a5b5898ba002c5e87d/relay/polkadot/Cargo.toml#L2), [`staging-kusama-runtime`](https://github.com/polkadot-fellows/runtimes/blob/2e73a6c90159b723c741b1a5b5898ba002c5e87d/relay/kusama/Cargo.toml#L7). + +#### Workshop Example +- []() + +### Try Runtime +1. Copy and configure the [try-runtime](.github/workflows/try-runtime.yml) action to your runtime repository. +2. The action file has pretty detailed comments, you can follow the comments to configure the action. Please feel free to open an issue in this repository if you find any issues or have any questions. +3. Open a PR to the runtime repository. +4. Comment `/bot try-runtime` in the PR, the action will run and comment the result in the PR. + +#### Workshop Example +- []() + +### Release +1. Copy and configure the [release](.github/workflows/release.yml) action to your runtime repository. +2. The action file has pretty detailed comments, you can follow the comments to configure the action. Please feel free to open an issue in this repository if you find any issues or have any questions. +3. Add and push a tag to the runtime repository, the action will run and release the runtime in runtime repository and trigger the override for runtime-overrides repository. + +#### Workshop Example +- []() diff --git a/chain-spec-generator/Cargo.toml b/chain-spec-generator/Cargo.toml deleted file mode 100644 index 157c51981a..0000000000 --- a/chain-spec-generator/Cargo.toml +++ /dev/null @@ -1,64 +0,0 @@ -[package] -name = "chain-spec-generator" -version.workspace = true -authors.workspace = true -edition.workspace = true -repository.workspace = true -license.workspace = true - -[dependencies] -clap = { features = ["derive"], workspace = true } -serde_json = { workspace = true } -serde = { features = ["derive"], workspace = true } - -polkadot-runtime = { workspace = true } -kusama-runtime = { workspace = true } - -sc-chain-spec = { workspace = true } -sc-network = { workspace = true } - -asset-hub-polkadot-runtime = { workspace = true } -asset-hub-kusama-runtime = { workspace = true } -collectives-polkadot-runtime = { workspace = true } -bridge-hub-polkadot-runtime = { workspace = true } -bridge-hub-kusama-runtime = { workspace = true } -encointer-kusama-runtime = { workspace = true } -glutton-kusama-runtime = { workspace = true } -coretime-kusama-runtime = { workspace = true } -coretime-polkadot-runtime = { workspace = true } -people-kusama-runtime = { workspace = true } -people-polkadot-runtime = { workspace = true } - -[features] -fast-runtime = ["kusama-runtime/fast-runtime", "polkadot-runtime/fast-runtime"] -runtime-benchmarks = [ - "asset-hub-kusama-runtime/runtime-benchmarks", - "asset-hub-polkadot-runtime/runtime-benchmarks", - "bridge-hub-kusama-runtime/runtime-benchmarks", - "bridge-hub-polkadot-runtime/runtime-benchmarks", - "collectives-polkadot-runtime/runtime-benchmarks", - "coretime-kusama-runtime/runtime-benchmarks", - "coretime-polkadot-runtime/runtime-benchmarks", - "encointer-kusama-runtime/runtime-benchmarks", - "glutton-kusama-runtime/runtime-benchmarks", - "kusama-runtime/runtime-benchmarks", - "people-kusama-runtime/runtime-benchmarks", - "people-polkadot-runtime/runtime-benchmarks", - "polkadot-runtime/runtime-benchmarks", -] - -on-chain-release-build = [ - "asset-hub-kusama-runtime/on-chain-release-build", - "asset-hub-polkadot-runtime/on-chain-release-build", - "bridge-hub-kusama-runtime/on-chain-release-build", - "bridge-hub-polkadot-runtime/on-chain-release-build", - "collectives-polkadot-runtime/on-chain-release-build", - "coretime-kusama-runtime/on-chain-release-build", - "coretime-polkadot-runtime/on-chain-release-build", - "encointer-kusama-runtime/on-chain-release-build", - "glutton-kusama-runtime/on-chain-release-build", - "kusama-runtime/on-chain-release-build", - "people-kusama-runtime/on-chain-release-build", - "people-polkadot-runtime/on-chain-release-build", - "polkadot-runtime/on-chain-release-build", -] diff --git a/chain-spec-generator/src/common.rs b/chain-spec-generator/src/common.rs deleted file mode 100644 index d05e597c4a..0000000000 --- a/chain-spec-generator/src/common.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use crate::{ - relay_chain_specs::{KusamaChainSpec, PolkadotChainSpec}, - system_parachains_specs::{ - AssetHubKusamaChainSpec, AssetHubPolkadotChainSpec, BridgeHubKusamaChainSpec, - BridgeHubPolkadotChainSpec, CollectivesPolkadotChainSpec, CoretimeKusamaChainSpec, - EncointerKusamaChainSpec, GluttonKusamaChainSpec, PeopleKusamaChainSpec, - PeoplePolkadotChainSpec, - }, - ChainSpec, -}; - -#[derive(Debug, serde::Deserialize)] -struct EmptyChainSpecWithId { - id: String, -} - -pub fn from_json_file(filepath: &str, supported: String) -> Result, String> { - let path = std::path::PathBuf::from(&filepath); - let file = std::fs::File::open(filepath).expect("Failed to open file"); - let reader = std::io::BufReader::new(file); - let chain_spec: EmptyChainSpecWithId = serde_json::from_reader(reader) - .expect("Failed to read 'json' file with ChainSpec configuration"); - match &chain_spec.id { - x if x.starts_with("polkadot") | x.starts_with("dot") => - Ok(Box::new(PolkadotChainSpec::from_json_file(path)?)), - x if x.starts_with("kusama") | x.starts_with("ksm") => - Ok(Box::new(KusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("asset-hub-polkadot") => - Ok(Box::new(AssetHubPolkadotChainSpec::from_json_file(path)?)), - x if x.starts_with("asset-hub-kusama") => - Ok(Box::new(AssetHubKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("collectives-polkadot") => - Ok(Box::new(CollectivesPolkadotChainSpec::from_json_file(path)?)), - x if x.starts_with("bridge-hub-polkadot") => - Ok(Box::new(BridgeHubPolkadotChainSpec::from_json_file(path)?)), - x if x.starts_with("bridge-hub-kusama") => - Ok(Box::new(BridgeHubKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("coretime-kusama") => - Ok(Box::new(CoretimeKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("coretime-polkadot") => - Ok(Box::new(CoretimeKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("glutton-kusama") => - Ok(Box::new(GluttonKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("encointer-kusama") => - Ok(Box::new(EncointerKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("people-kusama") => - Ok(Box::new(PeopleKusamaChainSpec::from_json_file(path)?)), - x if x.starts_with("people-polkadot") => - Ok(Box::new(PeoplePolkadotChainSpec::from_json_file(path)?)), - _ => Err(format!("Unknown chain 'id' in json file. Only supported: {supported}'")), - } -} diff --git a/chain-spec-generator/src/main.rs b/chain-spec-generator/src/main.rs deleted file mode 100644 index 3b6ed2288c..0000000000 --- a/chain-spec-generator/src/main.rs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use clap::Parser; -use sc_chain_spec::ChainSpec; -use std::collections::HashMap; - -mod common; -mod relay_chain_specs; -mod system_parachains_specs; - -#[derive(Parser)] -struct Cli { - /// The chain spec to generate. - chain: String, - - /// Generate the chain spec as raw? - #[arg(long)] - raw: bool, -} - -fn main() -> Result<(), String> { - let cli = Cli::parse(); - - let supported_chains = - HashMap::<_, Box Result, String>>>::from([ - ("polkadot-dev", Box::new(relay_chain_specs::polkadot_development_config) as Box<_>), - ( - "polkadot-local", - Box::new(relay_chain_specs::polkadot_local_testnet_config) as Box<_>, - ), - ("kusama-dev", Box::new(relay_chain_specs::kusama_development_config) as Box<_>), - ("kusama-local", Box::new(relay_chain_specs::kusama_local_testnet_config) as Box<_>), - ( - "asset-hub-kusama-local", - Box::new(system_parachains_specs::asset_hub_kusama_local_testnet_config) as Box<_>, - ), - ( - "asset-hub-polkadot-local", - Box::new(system_parachains_specs::asset_hub_polkadot_local_testnet_config) - as Box<_>, - ), - ( - "collectives-polkadot-local", - Box::new(system_parachains_specs::collectives_polkadot_local_testnet_config) - as Box<_>, - ), - ( - "bridge-hub-polkadot-local", - Box::new(system_parachains_specs::bridge_hub_polkadot_local_testnet_config) - as Box<_>, - ), - ( - "bridge-hub-kusama-local", - Box::new(system_parachains_specs::bridge_hub_kusama_local_testnet_config) as Box<_>, - ), - ( - "glutton-kusama-local", - Box::new(system_parachains_specs::glutton_kusama_local_testnet_config) as Box<_>, - ), - ( - "encointer-kusama-local", - Box::new(system_parachains_specs::encointer_kusama_local_testnet_config) as Box<_>, - ), - ( - "coretime-kusama", - Box::new(system_parachains_specs::coretime_kusama_config) as Box<_>, - ), - ( - "coretime-kusama-local", - Box::new(system_parachains_specs::coretime_kusama_local_testnet_config) as Box<_>, - ), - ( - "coretime-polkadot", - Box::new(system_parachains_specs::coretime_polkadot_config) as Box<_>, - ), - ( - "coretime-polkadot-local", - Box::new(system_parachains_specs::coretime_polkadot_local_testnet_config) as Box<_>, - ), - ( - "people-kusama-local", - Box::new(system_parachains_specs::people_kusama_local_testnet_config) as Box<_>, - ), - ( - "people-polkadot-local", - Box::new(system_parachains_specs::people_polkadot_local_testnet_config) as Box<_>, - ), - ]); - - if let Some(function) = supported_chains.get(&*cli.chain) { - let chain_spec = (*function)()?.as_json(cli.raw)?; - print!("{chain_spec}"); - Ok(()) - } else { - let supported = supported_chains.keys().enumerate().fold(String::new(), |c, (n, k)| { - let extra = if n + 1 < supported_chains.len() { ", " } else { "" }; - format!("{c}{k}{extra}") - }); - if cli.chain.ends_with(".json") { - let chain_spec = common::from_json_file(&cli.chain, supported)?.as_json(cli.raw)?; - print!("{chain_spec}"); - Ok(()) - } else { - Err(format!("Unknown chain, only supported: {supported} or a json file")) - } - } -} diff --git a/chain-spec-generator/src/relay_chain_specs.rs b/chain-spec-generator/src/relay_chain_specs.rs deleted file mode 100644 index d2c793b99b..0000000000 --- a/chain-spec-generator/src/relay_chain_specs.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use sc_chain_spec::{ChainSpec, ChainType, NoExtension}; - -pub type PolkadotChainSpec = sc_chain_spec::GenericChainSpec; - -pub type KusamaChainSpec = sc_chain_spec::GenericChainSpec; - -const DEFAULT_PROTOCOL_ID: &str = "dot"; - -/// Returns the properties for the [`PolkadotChainSpec`]. -pub fn polkadot_chain_spec_properties() -> serde_json::map::Map { - serde_json::json!({ - "tokenDecimals": 10, - }) - .as_object() - .expect("Map given; qed") - .clone() -} - -/// Polkadot development config (single validator Alice) -pub fn polkadot_development_config() -> Result, String> { - Ok(Box::new( - PolkadotChainSpec::builder( - polkadot_runtime::WASM_BINARY.ok_or("Polkadot development wasm not available")?, - Default::default(), - ) - .with_name("Polakdot Development") - .with_id("polkadot-dev") - .with_chain_type(ChainType::Development) - .with_genesis_config_patch( - polkadot_runtime::genesis_config_presets::polkadot_development_config_genesis(), - ) - .with_protocol_id(DEFAULT_PROTOCOL_ID) - .with_properties(polkadot_chain_spec_properties()) - .build(), - )) -} - -/// Kusama development config (single validator Alice) -pub fn kusama_development_config() -> Result, String> { - Ok(Box::new( - KusamaChainSpec::builder( - kusama_runtime::WASM_BINARY.ok_or("Kusama development wasm not available")?, - Default::default(), - ) - .with_name("Kusama Development") - .with_id("kusama-dev") - .with_chain_type(ChainType::Development) - .with_genesis_config_patch( - kusama_runtime::genesis_config_presets::kusama_development_config_genesis(), - ) - .with_protocol_id(DEFAULT_PROTOCOL_ID) - .build(), - )) -} - -/// Polkadot local testnet config (multivalidator Alice + Bob) -pub fn polkadot_local_testnet_config() -> Result, String> { - Ok(Box::new( - PolkadotChainSpec::builder( - polkadot_runtime::WASM_BINARY.ok_or("Polkadot development wasm not available")?, - Default::default(), - ) - .with_name("Polkadot Local Testnet") - .with_id("polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch( - polkadot_runtime::genesis_config_presets::polkadot_local_testnet_genesis(), - ) - .with_protocol_id(DEFAULT_PROTOCOL_ID) - .with_properties(polkadot_chain_spec_properties()) - .build(), - )) -} - -/// Kusama local testnet config (multivalidator Alice + Bob) -pub fn kusama_local_testnet_config() -> Result, String> { - Ok(Box::new( - KusamaChainSpec::builder( - kusama_runtime::WASM_BINARY.ok_or("Kusama development wasm not available")?, - Default::default(), - ) - .with_name("Kusama Local Testnet") - .with_id("kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch( - kusama_runtime::genesis_config_presets::kusama_local_testnet_genesis(), - ) - .with_protocol_id(DEFAULT_PROTOCOL_ID) - .build(), - )) -} diff --git a/chain-spec-generator/src/system_parachains_specs.rs b/chain-spec-generator/src/system_parachains_specs.rs deleted file mode 100644 index dd37d8d7b2..0000000000 --- a/chain-spec-generator/src/system_parachains_specs.rs +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -use sc_chain_spec::{ChainSpec, ChainSpecExtension, ChainSpecGroup, ChainType}; -use sc_network::config::MultiaddrWithPeerId; -use serde::{Deserialize, Serialize}; -use std::str::FromStr; - -/// Generic extensions for Parachain ChainSpecs. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] -#[serde(deny_unknown_fields)] -pub struct Extensions { - /// The relay chain of the Parachain. - pub relay_chain: String, - /// The id of the Parachain. - pub para_id: u32, -} - -pub type AssetHubPolkadotChainSpec = sc_chain_spec::GenericChainSpec; - -pub type AssetHubKusamaChainSpec = sc_chain_spec::GenericChainSpec; - -pub type CollectivesPolkadotChainSpec = sc_chain_spec::GenericChainSpec; - -pub type BridgeHubPolkadotChainSpec = sc_chain_spec::GenericChainSpec; - -pub type BridgeHubKusamaChainSpec = sc_chain_spec::GenericChainSpec; - -pub type GluttonKusamaChainSpec = sc_chain_spec::GenericChainSpec; - -pub type EncointerKusamaChainSpec = sc_chain_spec::GenericChainSpec; - -pub type CoretimeKusamaChainSpec = sc_chain_spec::GenericChainSpec; - -pub type CoretimePolkadotChainSpec = sc_chain_spec::GenericChainSpec; - -pub type PeopleKusamaChainSpec = sc_chain_spec::GenericChainSpec; - -pub type PeoplePolkadotChainSpec = sc_chain_spec::GenericChainSpec; - -pub fn asset_hub_polkadot_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - Ok(Box::new( - AssetHubPolkadotChainSpec::builder( - asset_hub_polkadot_runtime::WASM_BINARY.expect("AssetHubPolkadot wasm not available!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1000 }, - ) - .with_name("Polkadot Asset Hub Local") - .with_id("asset-hub-polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn asset_hub_kusama_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - Ok(Box::new( - AssetHubKusamaChainSpec::builder( - asset_hub_kusama_runtime::WASM_BINARY.expect("AssetHubKusama wasm not available!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1000 }, - ) - .with_name("Kusama Asset Hub Local") - .with_id("asset-hub-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn collectives_polkadot_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - Ok(Box::new( - CollectivesPolkadotChainSpec::builder( - collectives_polkadot_runtime::WASM_BINARY - .expect("CollectivesPolkadot wasm not available!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1001 }, - ) - .with_name("Polkadot Collectives Local") - .with_id("collectives-polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn bridge_hub_polkadot_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - Ok(Box::new( - BridgeHubPolkadotChainSpec::builder( - bridge_hub_polkadot_runtime::WASM_BINARY - .expect("BridgeHubPolkadot wasm not available!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1002 }, - ) - .with_name("Polkadot Bridge Hub Local") - .with_id("bridge-hub-polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn bridge_hub_kusama_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - Ok(Box::new( - BridgeHubKusamaChainSpec::builder( - bridge_hub_kusama_runtime::WASM_BINARY.expect("BridgeHubKusama wasm not available!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1002 }, - ) - .with_name("Kusama Bridge Hub Local") - .with_id("bridge-hub-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn glutton_kusama_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - - Ok(Box::new( - GluttonKusamaChainSpec::builder( - glutton_kusama_runtime::WASM_BINARY.expect("GluttonKusama wasm not available!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1300 }, - ) - .with_name("Kusama Glutton Local") - .with_id("glutton-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn encointer_kusama_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - Ok(Box::new( - EncointerKusamaChainSpec::builder( - encointer_kusama_runtime::WASM_BINARY.expect("EncointerKusama wasm not available!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1001 }, - ) - .with_name("Kusama Encointer Local") - .with_id("encointer-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn coretime_kusama_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - Ok(Box::new( - CoretimeKusamaChainSpec::builder( - coretime_kusama_runtime::WASM_BINARY.expect("CoretimeKusama wasm not available!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1005 }, - ) - .with_name("Kusama Coretime Local") - .with_id("coretime-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn coretime_kusama_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - let boot_nodes = [ - "/dns/kusama-coretime-connect-a-0.polkadot.io/tcp/30334/p2p/12D3KooWR7Biy6nPgQFhk2eYP62pAkcFA6he9RUFURTDh7ewTjpo", - "/dns/kusama-coretime-connect-a-1.polkadot.io/tcp/30334/p2p/12D3KooWAGFiMZDF9RxdacrkenzGdo8nhfSe9EXofHc5mHeJ9vGX", - "/dns/kusama-coretime-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWR7Biy6nPgQFhk2eYP62pAkcFA6he9RUFURTDh7ewTjpo", - "/dns/kusama-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAGFiMZDF9RxdacrkenzGdo8nhfSe9EXofHc5mHeJ9vGX", - ]; - - Ok(Box::new( - CoretimeKusamaChainSpec::builder( - coretime_kusama_runtime::WASM_BINARY.expect("Kusama Coretime wasm not available!"), - Extensions { relay_chain: "kusama".into(), para_id: 1005 }, - ) - .with_name("Kusama Coretime") - .with_id("coretime-kusama") - .with_chain_type(ChainType::Live) - .with_genesis_config_preset_name("live") - .with_properties(properties) - .with_boot_nodes( - boot_nodes - .iter() - .map(|addr| { - MultiaddrWithPeerId::from_str(addr).expect("Boot node address is incorrect.") - }) - .collect(), - ) - .build(), - )) -} - -pub fn coretime_polkadot_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - Ok(Box::new( - CoretimePolkadotChainSpec::builder( - coretime_polkadot_runtime::WASM_BINARY.expect("CoretimePolkadot wasm not available!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1005 }, - ) - .with_name("Polkadot Coretime Local") - .with_id("coretime-polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn coretime_polkadot_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - let boot_nodes = [ - "/dns/polkadot-coretime-connect-a-0.polkadot.io/tcp/30334/p2p/12D3KooWKjnixAHbKMsPTJwGx8SrBeGEJLHA8KmKcEDYMp3YmWgR", - "/dns/polkadot-coretime-connect-a-1.polkadot.io/tcp/30334/p2p/12D3KooWQ7B7p4DFv1jWqaKfhrZBcMmi5g8bWFnmskguLaGEmT6n", - "/dns/polkadot-coretime-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWKjnixAHbKMsPTJwGx8SrBeGEJLHA8KmKcEDYMp3YmWgR", - "/dns/polkadot-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQ7B7p4DFv1jWqaKfhrZBcMmi5g8bWFnmskguLaGEmT6n", - "/dns4/coretime-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWFJ2yBTKFKYwgKUjfY3F7XfaxHV8hY6fbJu5oMkpP7wZ9", - "/dns4/coretime-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWCy5pToLafcQzPHn5kadxAftmF6Eh8ZJGPXhSeXSUDfjv", - - ]; - - Ok(Box::new( - CoretimePolkadotChainSpec::builder( - coretime_polkadot_runtime::WASM_BINARY.expect("Polkadot Coretime wasm not available!"), - Extensions { relay_chain: "polkadot".into(), para_id: 1005 }, - ) - .with_name("Polkadot Coretime") - .with_id("coretime-polkadot") - .with_chain_type(ChainType::Live) - .with_genesis_config_preset_name("live") - .with_properties(properties) - .with_boot_nodes( - boot_nodes - .iter() - .map(|addr| { - MultiaddrWithPeerId::from_str(addr).expect("Boot node address is incorrect.") - }) - .collect(), - ) - .build(), - )) -} - -pub fn people_kusama_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 2.into()); - properties.insert("tokenSymbol".into(), "KSM".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - Ok(Box::new( - PeopleKusamaChainSpec::builder( - people_kusama_runtime::WASM_BINARY.expect("PeopleKusama wasm not available!"), - Extensions { relay_chain: "kusama-local".into(), para_id: 1004 }, - ) - .with_name("Kusama People Local") - .with_id("people-kusama-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} - -pub fn people_polkadot_local_testnet_config() -> Result, String> { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("ss58Format".into(), 0.into()); - properties.insert("tokenSymbol".into(), "DOT".into()); - properties.insert("tokenDecimals".into(), 10.into()); - - Ok(Box::new( - PeoplePolkadotChainSpec::builder( - people_polkadot_runtime::WASM_BINARY.expect("PeoplePolkadot wasm not available!"), - Extensions { relay_chain: "polkadot-local".into(), para_id: 1004 }, - ) - .with_name("Polkadot People Local") - .with_id("people-polkadot-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_properties(properties) - .build(), - )) -} diff --git a/docs/on-chain-identity-process.png b/docs/on-chain-identity-process.png deleted file mode 100644 index fb08c7e6c19a73079ab71f850d2f4f22d21e6a4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 365121 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≫c*VdRrR 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
3RsVgTMbo>g-zzrV&@ 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 Extrinsics`. Select your fellowship member account and pick the extrinsic `identity.setIdentity`. Below is an example screenshot of what it should look like including the `github` field. - -![Example extrinsic to set on-chain identity](on-chain-identity-process.png) - -Keep in mind that when filling in the data with `Raw` type only ASCII is accepted, therefore if you need to use UTF-8 characters (e.g. diacritics or emojis), you should convert the data to hex beforehand. For example, my legal name is "André Silva", which I need to submit as `0x416e6472c3a92053696c7661`. You can use [this](https://onlinehextools.com/convert-utf8-to-hex) tool to do the conversion, just disable the options `Add Hex Base` and `Space Between Hex Values`, after the conversion you should prepend the result with a single `0x` and submit as `Raw`. - -After submitting the extrinsic you won't be able to see the `github` field in the polkadot.js UI (custom fields aren't shown). You can confirm that everything was set correctly by checking the state (`Developer > Chain State > identity.identityOf`), or by using a block explorer like [Statescan](https://polkadot.statescan.io) which shows custom fields. - -## Getting a judgment on your identity - -After your identity is properly set you can get a judgment on it from one of the existing registrars. For instructions on how to get a judgment from the W3F registrar check [this](https://registrar.web3.foundation/) page which contains links to instructions. Due to the custom field in your identity the automated verification process won't work and you'll need to join the support channel on matrix to complete the verification. diff --git a/docs/pull_request_template.md b/docs/pull_request_template.md deleted file mode 100644 index 0a8b80548e..0000000000 --- a/docs/pull_request_template.md +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - -- [ ] Does not require a CHANGELOG entry diff --git a/docs/removing-migrations.md b/docs/removing-migrations.md deleted file mode 100644 index 43a3812c6a..0000000000 --- a/docs/removing-migrations.md +++ /dev/null @@ -1,25 +0,0 @@ -# Process for removing runtime migrations - -We want to keep the `migrations` lists in the runtimes nice and tidy, without keeping around a lot of migration code once we know it's no longer needed - meaning once it's been enacted on-chain. - -The following is a quick guide/process for removing applied migrations while making sure you don't remove migrations not yet applied. - -## Prerequisites - -For some chain runtime `spec_version: a_bcd_efg,` (e.g. `spec_version: 1_000_001`): -- has been officially released on https://github.com/polkadot-fellows/runtimes/releases/ as part of `Runtimes X.Y.Z` release/tag. -- the **on-chain** runtime version has been upgraded to spec version `a_bcd_efg` (using wasm blob released above). - -## Steps - -1. Sync tags: `git pull upstream main --tags`, -2. Check-out **the released** code: `git checkout vX.Y.Z`, - - This is required to make sure you are not accidentally removing yet unreleased migrations (PRs merged between `X.Y.Z` release and when you are doing this). -3. Create patch with your changes: `git diff --patch > remove-migrations.patch`, -4. Now `git checkout main` and apply your patch `git am -3 remove-migrations.patch` or `git apply -3 remove-migrations.patch`, - - thus ensuring you are not removing any migrations merged to main after the release. -5. `git checkout -b `, `git push --set-upstream origin `, then open PR. - -## Automation - -Currently, all of the above is done manually, but (at least parts of) it could be automated. Prerequisites can definitely be automated, so could the branches/patches dance. Code changes would easily be done manually and that's it. diff --git a/docs/running-commands.md b/docs/running-commands.md deleted file mode 100644 index a7d55e371c..0000000000 --- a/docs/running-commands.md +++ /dev/null @@ -1,32 +0,0 @@ -# Running Commands in PRs - -You can run commands in PRs by triggering it via comment. It will use the context of your PR and post the results back. - -## Usage - -`/cmd --help` to see all available commands and usage format - -`/cmd --help` to see the usage of a specific command - - -### Commands - -- `/cmd fmt` to format the code in the PR. It commits back with the formatted code (fmt) and configs (taplo). - -- `/cmd bench` to generate weights for a runtime. Read more about [Weight Generation](./weight-generation.md) - -### Flags - -1.`--quiet` to suppress the output of the command in the comments. -By default, the Start and End/Failure of the command will be commented with the link to a pipeline. -If you want to avoid, use this flag. Go to [Action Tab](https://github.com/polkadot-fellows/runtimes/actions/workflows/cmd.yml) to see the pipeline status. - -2.`--continue-on-fail` to continue running the command even if something inside a command (like specific pallet weight generation) are failed. -Basically avoids interruption in the middle with `exit 1` -The pipeline logs will include what is failed (like which runtimes/pallets), then you can re-run them separately or not. - -3.`--clean` to clean up all yours and bot's comments in PR relevant to `/cmd` commands. If you run too many commands, or they keep failing, and you're rerunning them again, it's handy to add this flag to keep a PR clean. - -### Adding new Commands -Feel free to add new commands to the workflow, however **_note_** that triggered workflows will use the actions from `main` (default) branch, meaning they will take effect only after the PR with new changes/command is merged. -If you want to test the new command, it's better to test in your fork and local-to-fork PRs, where you control the default branch. diff --git a/docs/weight-generation.md b/docs/weight-generation.md deleted file mode 100644 index fea2d41f5f..0000000000 --- a/docs/weight-generation.md +++ /dev/null @@ -1,43 +0,0 @@ -# Weight Generation - -To generate weights for a runtime. -Weights generation is using self-hosted runner which is provided by [Amforc](https://amforc.com/), the rest commands are using standard Github runners on `ubuntu-latest` or `ubuntu-20.04`. -Self-hosted runner for benchmarks is configured to meet requirements of reference hardware for running validators https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware - -In a PR run the actions through comment: - -```sh -/cmd bench --help # outputs the actual usage documentation with examples and supported runtimes - -# or - -/cmd --help # to see all available commands -``` - -To generate weights for all pallets in a particular runtime(s), run the following command: -```sh -/cmd bench --runtime kusama polkadot -``` - -> **📝 Note**: The action is not being run right-away, it will be queued and run in the next available runner. So might be quick, but might also take up to 10 mins (That's in control of Github). -Once the action is run, you'll see reaction 👀 on original comment, and if you didn't pass `--quiet` - it will also send a link to a pipeline when started, and link to whole workflow when finished. - -> **💡Hint #1** : if you run all runtimes or all pallets, it might be that some pallet in the middle is failed to generate weights, thus it stops (fails) the whole pipeline. -> If you want, you can make it to continue running, even if some pallets are failed, add `--continue-on-fail` flag to the command. The report will include which runtimes/pallets have failed, then you can re-run them separately after all is done. - -This way it runs all possible runtimes for the specified pallets, if it finds them in the runtime -```sh -/cmd bench --pallet pallet_balances pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible -``` - -If you want to run all specific pallet(s) for specific runtime(s), you can do it like this: -```sh -/cmd bench --runtime bridge-hub-polkadot --pallet pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible -``` - - -> **💡Hint #2** : Sometimes when you run too many commands, or they keep failing and you're rerunning them again, it's handy to add `--clean` flag to the command. This will clean up all yours and bot's comments in PR relevant to /cmd commands. - -```sh -/cmd bench --runtime kusama polkadot --pallet=pallet_balances --clean --continue-on-fail -``` diff --git a/integration-tests/bridges/README.md b/integration-tests/bridges/README.md deleted file mode 100644 index 3e499da7c8..0000000000 --- a/integration-tests/bridges/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Bridges Tests for Local Polkadot <> Kusama Bridge - -This folder contains zombienet based integration test for both onchain and offchain bridges code. -The tests are designed to be run manually. - -To start a test, you need to: - -- download latest [zombienet release](https://github.com/paritytech/zombienet/releases) to `~/local_bridge_testing/bin/zombienet`. -- build Polkadot binaries by running commands in the [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone: - ``` - cargo build -p polkadot --release - cargo build --bin polkadot-prepare-worker --release - cargo build --bin polkadot-execute-worker --release - ``` - Copy the binaries to: - ``` - ~/local_bridge_testing/bin/polkadot - ~/local_bridge_testing/bin/polkadot-prepare-worker - ~/local_bridge_testing/bin/polkadot-execute-worker - ``` -- build Polkadot Parachain binary by running `cargo build -p polkadot-parachain-bin --release` command in the -[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone. Copy the binary to `~/local_bridge_testing/bin/polkadot-parachain`. -- ensure that you have [`node`](https://nodejs.org/en) installed. Additionally, we'll need globally installed -`polkadot/api-cli` / `polkadot/api` packages (use `yarn global add @polkadot/api-cli` to install it). -- build Substrate relay by running `cargo build -p substrate-relay --release` command in the -[`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common) repository clone. Copy the binary to `~/local_bridge_testing/bin/substrate-relay`. -- build chain spec generator: - - (you can use the current branch, or you can build generators from different branches, such as from specific tags or releases) - - add the `sudo` pallet to the Polkadot and Kusama runtimes and give sudo rights to Alice, e.g. by running `git apply ./integration-tests/bridges/sudo-relay.patch` from the fellows root dir. - - with this change build the chain spec generator by running `cargo build --release -p chain-spec-generator --features fast-runtime` -command. - - Copy the binary to `~/local_bridge_testing/bin/chain-spec-generator-kusama`. - - Copy the binary to `~/local_bridge_testing/bin/chain-spec-generator-polkadot`. -- check/change the `POLKADOT_BINARY` and `POLKADOT_PARACHAIN_BINARY` paths (and ensure that the nearby variables -have correct values) in the `./run-test.sh`. - -After that, you can run `./run-tests.sh ` command. -E.g. `./run-test.sh 0001-polkadot-kusama-asset-transfer`. -or -E.g. `FRAMEWORK_REPO_PATH=/home/username/polkadot-sdk ./run-test.sh 0001-polkadot-kusama-asset-transfer`. diff --git a/integration-tests/bridges/environments/polkadot-kusama/bridge_hub_kusama_local_network.toml b/integration-tests/bridges/environments/polkadot-kusama/bridge_hub_kusama_local_network.toml deleted file mode 100644 index fd0b90a565..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/bridge_hub_kusama_local_network.toml +++ /dev/null @@ -1,75 +0,0 @@ -[settings] -node_spawn_timeout = 240 - -[relaychain] -default_command = "{{POLKADOT_BINARY}}" -default_args = ["-lparachain=debug,xcm=trace"] -chain = "kusama-local" -chain_spec_command = "{{CHAIN_SPEC_GEN_BINARY_FOR_KUSAMA}} {% raw %} {{chainName}} {% endraw %}" - -[[relaychain.nodes]] -name = "alice" -validator = true -rpc_port = 9935 -ws_port = 9945 -balance = 2000000000000 - -[[relaychain.nodes]] -name = "bob" -validator = true -rpc_port = 9936 -ws_port = 9946 -balance = 2000000000000 - -[[relaychain.nodes]] -name = "charlie" -validator = true -rpc_port = 9937 -ws_port = 9947 -balance = 2000000000000 - -[[parachains]] -id = 1000 -chain = "asset-hub-kusama-local" -chain_spec_command = "{{CHAIN_SPEC_GEN_BINARY_FOR_KUSAMA}} {% raw %} {{chainName}} {% endraw %}" -cumulus_based = true - -[[parachains.collators]] -name = "asset-hub-kusama-collator-1" -rpc_port = 9011 -ws_port = 9010 -command = "{{POLKADOT_PARACHAIN_BINARY}}" -args = ["-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace"] - -[[parachains.collators]] -name = "asset-hub-kusama-collator-2" -command = "{{POLKADOT_PARACHAIN_BINARY}}" -args = ["-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace"] - -[[parachains]] -id = 1002 -chain = "bridge-hub-kusama-local" -chain_spec_command = "{{ENV_PATH}}/generate_bhk_spec.sh Polkadot {% raw %} {{chainName}} {% endraw %}" -cumulus_based = true - -# run alice as parachain collator -[[parachains.collators]] -name = "bridge-hub-kusama-collator-1" -validator = true -command = "{{POLKADOT_PARACHAIN_BINARY}}" -rpc_port = 8935 -ws_port = 8945 -args = [ - "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", -] - -# run bob as parachain collator -[[parachains.collators]] -name = "bridge-hub-kusama-collator-2" -validator = true -command = "{{POLKADOT_PARACHAIN_BINARY}}" -rpc_port = 8936 -ws_port = 8946 -args = [ - "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", -] diff --git a/integration-tests/bridges/environments/polkadot-kusama/bridge_hub_polkadot_local_network.toml b/integration-tests/bridges/environments/polkadot-kusama/bridge_hub_polkadot_local_network.toml deleted file mode 100644 index 2724921739..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/bridge_hub_polkadot_local_network.toml +++ /dev/null @@ -1,73 +0,0 @@ -[settings] -node_spawn_timeout = 240 - -[relaychain] -default_command = "{{POLKADOT_BINARY}}" -default_args = ["-lparachain=debug,xcm=trace"] -chain = "polkadot-local" -chain_spec_command = "{{CHAIN_SPEC_GEN_BINARY_FOR_POLKADOT}} {% raw %} {{chainName}} {% endraw %}" - -[[relaychain.nodes]] -name = "alice" -validator = true -rpc_port = 9932 -ws_port = 9942 -balance = 2000000000000 - -[[relaychain.nodes]] -name = "bob" -validator = true -rpc_port = 9933 -ws_port = 9943 -balance = 2000000000000 - -[[relaychain.nodes]] -name = "charlie" -validator = true -rpc_port = 9934 -ws_port = 9944 -balance = 2000000000000 - -[[parachains]] -id = 1000 -chain = "asset-hub-polkadot-local" -chain_spec_command = "{{CHAIN_SPEC_GEN_BINARY_FOR_POLKADOT}} {% raw %} {{chainName}} {% endraw %}" -cumulus_based = true - -[[parachains.collators]] -name = "asset-hub-polkadot-collator-1" -rpc_port = 9911 -ws_port = 9910 -command = "{{POLKADOT_PARACHAIN_BINARY}}" -args = ["-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace"] - -[[parachains.collators]] -name = "asset-hub-polkadot-collator-2" -command = "{{POLKADOT_PARACHAIN_BINARY}}" -args = ["-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace"] - -[[parachains]] -id = 1002 -chain = "bridge-hub-polkadot-local" -chain_spec_command = "{{ENV_PATH}}/generate_bhp_spec.sh Kusama {% raw %} {{chainName}} {% endraw %}" -cumulus_based = true - -[[parachains.collators]] -name = "bridge-hub-polkadot-collator-1" -validator = true -command = "{{POLKADOT_PARACHAIN_BINARY}}" -rpc_port = 8933 -ws_port = 8943 -args = [ - "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", -] - -[[parachains.collators]] -name = "bridge-hub-polkadot-collator-2" -validator = true -command = "{{POLKADOT_PARACHAIN_BINARY}}" -rpc_port = 8934 -ws_port = 8944 -args = [ - "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace", -] diff --git a/integration-tests/bridges/environments/polkadot-kusama/bridges_polkadot_kusama.sh b/integration-tests/bridges/environments/polkadot-kusama/bridges_polkadot_kusama.sh deleted file mode 100755 index 040db39db3..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/bridges_polkadot_kusama.sh +++ /dev/null @@ -1,385 +0,0 @@ -#!/bin/bash - -# import common functions -source "$FRAMEWORK_PATH/utils/bridges.sh" - -# Expected sovereign accounts. -# -# Generated by: -# -##[test] -#fn generate_sovereign_accounts() { -# use polkadot_parachain_primitives::primitives::Sibling; -# use sp_core::crypto::Ss58Codec; -# -# parameter_types! { -# pub UniversalLocationAHP: InteriorLocation = [GlobalConsensus(Polkadot), Parachain(1000)].into(); -# pub UniversalLocationAHK: InteriorLocation = [GlobalConsensus(Kusama), Parachain(1000)].into(); -# } -# -# -# println!( -# "GLOBAL_CONSENSUS_POLKADOT_SOVEREIGN_ACCOUNT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusConvertsFor::::convert_location( -# &Location { parents: 2, interior: [GlobalConsensus(Polkadot)].into() } -# ) -# .unwrap() -# ) -# .to_ss58check_with_version(2_u16.into()) -# ); -# -# println!( -# "ASSET_HUB_KUSAMA_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_KUSAMA=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# SiblingParachainConvertsVia::::convert_location(&Location { -# parents: 1, -# interior: [Parachain(1000)].into() -# }) -# .unwrap() -# ) -# .to_ss58check_with_version(2_u16.into()) -# ); -# -# -# println!( -# "GLOBAL_CONSENSUS_KUSAMA_SOVEREIGN_ACCOUNT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# GlobalConsensusConvertsFor::::convert_location( -# &Location { parents: 2, interior: [GlobalConsensus(Kusama)].into() } -# ) -# .unwrap() -# ) -# .to_ss58check_with_version(0_u16.into()) -# ); -# println!( -# "ASSET_HUB_POLKADOT_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_POLKADOT=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# SiblingParachainConvertsVia::::convert_location(&Location { -# parents: 1, -# interior: [Parachain(1000)].into() -# }) -# .unwrap() -# ) -# .to_ss58check_with_version(0_u16.into()) -# ); -#} -GLOBAL_CONSENSUS_POLKADOT_SOVEREIGN_ACCOUNT="FxqimVubBRPqJ8kTwb3wL7G4q645hEkBEnXPyttLsTrFc5Q" -ASSET_HUB_KUSAMA_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_KUSAMA="FBeL7EFTDeHnuViqaUHUXvhhUusN5FawDmHgfvzF97DXFr3" -GLOBAL_CONSENSUS_KUSAMA_SOVEREIGN_ACCOUNT="14zcUAhP5XypiFQWA3b1AnGKrhZqR4XWUo4deWkwuN5y983G" -ASSET_HUB_POLKADOT_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_POLKADOT="13cKp89SgdtqUngo2WiEijPrQWdHFhzYZLf2TJePKRvExk7o" - -# Expected sovereign accounts for rewards on BridgeHubs. -# -# Generated by: -##[test] -#fn generate_sovereign_accounts_for_rewards() { -# use bp_messages::LaneId; -# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; -# use sp_core::crypto::Ss58Codec; -# -# println!( -# "ON_BRIDGE_HUB_POLKADOT_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhks_ThisChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 1]), -# *b"bhks", -# RewardsAccountOwner::ThisChain -# )) -# ) -# .to_ss58check_with_version(0_u16.into()) -# ); -# -# println!( -# "ON_BRIDGE_HUB_POLKADOT_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhks_BridgedChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 1]), -# *b"bhks", -# RewardsAccountOwner::BridgedChain -# )) -# ) -# .to_ss58check_with_version(0_u16.into()) -# ); -# -# -# println!( -# "ON_BRIDGE_HUB_KUSAMA_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhpd_ThisChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 1]), -# *b"bhpd", -# RewardsAccountOwner::ThisChain -# )) -# ) -# .to_ss58check_with_version(2_u16.into()) -# ); -# -# println!( -# "ON_BRIDGE_HUB_KUSAMA_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhpd_BridgedChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 1]), -# *b"bhpd", -# RewardsAccountOwner::BridgedChain -# )) -# ) -# .to_ss58check_with_version(2_u16.into()) -# ); -#} -ON_BRIDGE_HUB_POLKADOT_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhks_ThisChain="13E5fui93Uyua5RtDv2LQj4aVBBHo6YREe3n6CBwYdqNqoxj" -ON_BRIDGE_HUB_POLKADOT_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhks_BridgedChain="13E5fui93Uyua5RtDv2c9kcAbfrVFeeHyJzHe8sn1Ti77Afd" -ON_BRIDGE_HUB_KUSAMA_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhpd_ThisChain="EoQBtnwp4jMtCEpV7C88rKrz6x1qMBh2z74ibGSqtZRnuMM" -ON_BRIDGE_HUB_KUSAMA_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhpd_BridgedChain="EoQBtnwp4jMtCEpV7CPsssT6bdDHuHZmf3aGXxHJiSA4Dz3" - -LANE_ID="00000001" -XCM_VERSION=3 - -AHK_DOT_ED=10000000 -DOT=10000000000 - -AHP_KSM_ED=10000000 -KSM=1000000000000 - -function init_polkadot_kusama() { - local relayer_path=$(ensure_relayer) - - RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - $relayer_path init-bridge polkadot-to-bridge-hub-kusama \ - --source-host localhost \ - --source-port 9942 \ - --source-version-mode Auto \ - --target-host localhost \ - --target-port 8945 \ - --target-version-mode Auto \ - --target-signer //Alice -} - -function init_kusama_polkadot() { - local relayer_path=$(ensure_relayer) - - RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - $relayer_path init-bridge kusama-to-bridge-hub-polkadot \ - --source-host localhost \ - --source-port 9945 \ - --source-version-mode Auto \ - --target-host localhost \ - --target-port 8943 \ - --target-version-mode Auto \ - --target-signer //Alice -} - -function run_relay() { - local relayer_path=$(ensure_relayer) - - RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - $relayer_path relay-headers-and-messages bridge-hub-kusama-bridge-hub-polkadot \ - --polkadot-host localhost \ - --polkadot-port 9942 \ - --polkadot-version-mode Auto \ - --bridge-hub-polkadot-host localhost \ - --bridge-hub-polkadot-port 8943 \ - --bridge-hub-polkadot-version-mode Auto \ - --bridge-hub-polkadot-signer //Charlie \ - --bridge-hub-polkadot-transactions-mortality 4 \ - --kusama-host localhost \ - --kusama-port 9945 \ - --kusama-version-mode Auto \ - --bridge-hub-kusama-host localhost \ - --bridge-hub-kusama-port 8945 \ - --bridge-hub-kusama-version-mode Auto \ - --bridge-hub-kusama-signer //Charlie \ - --bridge-hub-kusama-transactions-mortality 4 \ - --lane "${LANE_ID}" -} - -case "$1" in - run-relay) - init_kusama_polkadot - init_polkadot_kusama - run_relay - ;; - init-asset-hub-polkadot-local) - ensure_polkadot_js_api - # create foreign assets for native Kusama token (governance call on Polkadot) - force_create_foreign_asset \ - "ws://127.0.0.1:9942" \ - "//Alice" \ - 1000 \ - "ws://127.0.0.1:9910" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Kusama" } } }')" \ - "$GLOBAL_CONSENSUS_KUSAMA_SOVEREIGN_ACCOUNT" \ - $AHP_KSM_ED \ - true - # HRMP - open_hrmp_channels \ - "ws://127.0.0.1:9942" \ - "//Alice" \ - 1000 1002 4 524288 - open_hrmp_channels \ - "ws://127.0.0.1:9942" \ - "//Alice" \ - 1002 1000 4 524288 - # set XCM version of remote AssetHubKusama - force_xcm_version \ - "ws://127.0.0.1:9942" \ - "//Alice" \ - 1000 \ - "ws://127.0.0.1:9910" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Kusama" }, { "Parachain": 1000 } ] } }')" \ - $XCM_VERSION - ;; - init-bridge-hub-polkadot-local) - ensure_polkadot_js_api - # SA of sibling asset hub pays for the execution - transfer_balance \ - "ws://127.0.0.1:8943" \ - "//Alice" \ - "$ASSET_HUB_POLKADOT_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_POLKADOT" \ - $((25 * $DOT)) - # drip SA of lane dedicated to asset hub for paying rewards for delivery - transfer_balance \ - "ws://127.0.0.1:8943" \ - "//Alice" \ - "$ON_BRIDGE_HUB_POLKADOT_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhks_ThisChain" \ - $((25 * $DOT)) - # drip SA of lane dedicated to asset hub for paying rewards for delivery confirmation - transfer_balance \ - "ws://127.0.0.1:8943" \ - "//Alice" \ - "$ON_BRIDGE_HUB_POLKADOT_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhks_BridgedChain" \ - $((25 * $DOT)) - # set XCM version of remote BridgeHubKusama - force_xcm_version \ - "ws://127.0.0.1:9942" \ - "//Alice" \ - 1002 \ - "ws://127.0.0.1:8943" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Kusama" }, { "Parachain": 1002 } ] } }')" \ - $XCM_VERSION - ;; - init-asset-hub-kusama-local) - ensure_polkadot_js_api - # create foreign assets for native Polkadot token (governance call on Kusama) - force_create_foreign_asset \ - "ws://127.0.0.1:9945" \ - "//Alice" \ - 1000 \ - "ws://127.0.0.1:9010" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Polkadot" } } }')" \ - "$GLOBAL_CONSENSUS_POLKADOT_SOVEREIGN_ACCOUNT" \ - $AHK_DOT_ED \ - true - # HRMP - open_hrmp_channels \ - "ws://127.0.0.1:9945" \ - "//Alice" \ - 1000 1002 4 524288 - open_hrmp_channels \ - "ws://127.0.0.1:9945" \ - "//Alice" \ - 1002 1000 4 524288 - # set XCM version of remote AssetHubPolkadot - force_xcm_version \ - "ws://127.0.0.1:9945" \ - "//Alice" \ - 1000 \ - "ws://127.0.0.1:9010" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Polkadot" }, { "Parachain": 1000 } ] } }')" \ - $XCM_VERSION - ;; - init-bridge-hub-kusama-local) - # SA of sibling asset hub pays for the execution - transfer_balance \ - "ws://127.0.0.1:8945" \ - "//Alice" \ - "$ASSET_HUB_KUSAMA_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_KUSAMA" \ - $((25 * $KSM)) - # drip SA of lane dedicated to asset hub for paying rewards for delivery - transfer_balance \ - "ws://127.0.0.1:8945" \ - "//Alice" \ - "$ON_BRIDGE_HUB_KUSAMA_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhpd_ThisChain" \ - $((25 * $KSM)) - # drip SA of lane dedicated to asset hub for paying rewards for delivery confirmation - transfer_balance \ - "ws://127.0.0.1:8945" \ - "//Alice" \ - "$ON_BRIDGE_HUB_KUSAMA_SOVEREIGN_ACCOUNT_FOR_LANE_00000001_bhpd_BridgedChain" \ - $((25 * $KSM)) - # set XCM version of remote BridgeHubPolkadot - force_xcm_version \ - "ws://127.0.0.1:9945" \ - "//Alice" \ - 1002 \ - "ws://127.0.0.1:8945" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Polkadot" }, { "Parachain": 1002 } ] } }')" \ - $XCM_VERSION - ;; - reserve-transfer-assets-from-asset-hub-polkadot-local) - amount=$2 - ensure_polkadot_js_api - # send DOTs to Alice account on AHK - limited_reserve_transfer_assets \ - "ws://127.0.0.1:9910" \ - "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Kusama" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ - 0 \ - "Unlimited" - ;; - withdraw-reserve-assets-from-asset-hub-polkadot-local) - amount=$2 - ensure_polkadot_js_api - # send back some wrappedKSMs to Alice account on AHK - limited_reserve_transfer_assets \ - "ws://127.0.0.1:9910" \ - "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Kusama" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Kusama" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ - 0 \ - "Unlimited" - ;; - reserve-transfer-assets-from-asset-hub-kusama-local) - amount=$2 - ensure_polkadot_js_api - # send KSMs to Alice account on AHP - limited_reserve_transfer_assets \ - "ws://127.0.0.1:9010" \ - "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Polkadot" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ - 0 \ - "Unlimited" - ;; - withdraw-reserve-assets-from-asset-hub-kusama-local) - amount=$2 - ensure_polkadot_js_api - # send back some wrappedDOTs to Alice account on AHP - limited_reserve_transfer_assets \ - "ws://127.0.0.1:9010" \ - "//Alice" \ - "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Polkadot" }, { "Parachain": 1000 } ] } } }')" \ - "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ - "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Polkadot" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ - 0 \ - "Unlimited" - ;; - *) - echo "A command is require. Supported commands for: - Local (zombienet) run: - - run-relay - - init-asset-hub-polkadot-local - - init-bridge-hub-polkadot-local - - init-asset-hub-kusama-local - - init-bridge-hub-kusama-local - - reserve-transfer-assets-from-asset-hub-polkadot-local - - withdraw-reserve-assets-from-asset-hub-polkadot-local - - reserve-transfer-assets-from-asset-hub-kusama-local - - withdraw-reserve-assets-from-asset-hub-kusama-local"; - exit 1 - ;; -esac diff --git a/integration-tests/bridges/environments/polkadot-kusama/generate_bhk_spec.sh b/integration-tests/bridges/environments/polkadot-kusama/generate_bhk_spec.sh deleted file mode 100755 index 33e54bbb57..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/generate_bhk_spec.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -bridged_chain=$1 -shift - -# Add Alice as bridge owner -# We do this only if there is a `.genesis.runtimeGenesis.patch` object. -# Otherwise we're working with the raw chain spec. -$CHAIN_SPEC_GEN_BINARY_FOR_KUSAMA "$@" \ - | jq 'if .genesis.runtimeGenesis.patch - then .genesis.runtimeGenesis.patch.bridge'$bridged_chain'Grandpa.owner = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" - else . - end' diff --git a/integration-tests/bridges/environments/polkadot-kusama/generate_bhp_spec.sh b/integration-tests/bridges/environments/polkadot-kusama/generate_bhp_spec.sh deleted file mode 100755 index d1a2d43970..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/generate_bhp_spec.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -bridged_chain=$1 -shift - -# Add Alice as bridge owner -# We do this only if there is a `.genesis.runtimeGenesis.patch` object. -# Otherwise we're working with the raw chain spec. -$CHAIN_SPEC_GEN_BINARY_FOR_POLKADOT "$@" \ - | jq 'if .genesis.runtimeGenesis.patch - then .genesis.runtimeGenesis.patch.bridge'$bridged_chain'Grandpa.owner = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" - else . - end' diff --git a/integration-tests/bridges/environments/polkadot-kusama/helper.sh b/integration-tests/bridges/environments/polkadot-kusama/helper.sh deleted file mode 100755 index ab48938386..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/helper.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -$ENV_PATH/bridges_polkadot_kusama.sh "$@" diff --git a/integration-tests/bridges/environments/polkadot-kusama/kusama-bridge.zndsl b/integration-tests/bridges/environments/polkadot-kusama/kusama-bridge.zndsl deleted file mode 100644 index e2902892aa..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/kusama-bridge.zndsl +++ /dev/null @@ -1,5 +0,0 @@ -Network: ./bridge_hub_kusama_local_network.toml -Creds: config - -# relay is already started - let's wait until with-Rococo GRANPDA pallet is initialized at Polkadot -bridge-hub-kusama-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Polkadot,0" within 400 seconds diff --git a/integration-tests/bridges/environments/polkadot-kusama/kusama-init.zndsl b/integration-tests/bridges/environments/polkadot-kusama/kusama-init.zndsl deleted file mode 100644 index 4f6bac65af..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/kusama-init.zndsl +++ /dev/null @@ -1,6 +0,0 @@ -Network: ./bridge_hub_kusama_local_network.toml -Creds: config - -# ensure that initialization has completed -asset-hub-kusama-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/wait-hrmp-channel-opened.js with "1002" within 300 seconds - diff --git a/integration-tests/bridges/environments/polkadot-kusama/polkadot-bridge.zndsl b/integration-tests/bridges/environments/polkadot-kusama/polkadot-bridge.zndsl deleted file mode 100644 index 7dac894542..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/polkadot-bridge.zndsl +++ /dev/null @@ -1,5 +0,0 @@ -Network: ./bridge_hub_polkadot_local_network.toml -Creds: config - -# relay is already started - let's wait until with-Rococo GRANPDA pallet is initialized at Polkadot -bridge-hub-polkadot-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Kusama,0" within 400 seconds diff --git a/integration-tests/bridges/environments/polkadot-kusama/polkadot-init.zndsl b/integration-tests/bridges/environments/polkadot-kusama/polkadot-init.zndsl deleted file mode 100644 index 4d7fb281bb..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/polkadot-init.zndsl +++ /dev/null @@ -1,7 +0,0 @@ -Network: ./bridge_hub_polkadot_local_network.toml -Creds: config - -# ensure that initialization has completed -asset-hub-polkadot-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/wait-hrmp-channel-opened.js with "1002" within 300 seconds - - diff --git a/integration-tests/bridges/environments/polkadot-kusama/spawn.sh b/integration-tests/bridges/environments/polkadot-kusama/spawn.sh deleted file mode 100755 index 3786ce1d4d..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/spawn.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -set -e - -trap "trap - SIGTERM && kill -9 -$$" SIGINT SIGTERM EXIT - -source "$FRAMEWORK_PATH/utils/zombienet.sh" - -logs_dir=$TEST_DIR/logs -helper_script="${BASH_SOURCE%/*}/helper.sh" - -polkadot_def=${BASH_SOURCE%/*}/bridge_hub_polkadot_local_network.toml -start_zombienet $TEST_DIR $polkadot_def polkadot_dir polkadot_pid -echo - -kusama_def=${BASH_SOURCE%/*}/bridge_hub_kusama_local_network.toml -start_zombienet $TEST_DIR $kusama_def kusama_dir kusama_pid -echo - -polkadot_init_log=$logs_dir/polkadot-init.log -echo -e "Setting up the polkadot side of the bridge. Logs available at: $polkadot_init_log\n" - -kusama_init_log=$logs_dir/kusama-init.log -echo -e "Setting up the kusama side of the bridge. Logs available at: $kusama_init_log\n" - -$helper_script init-asset-hub-polkadot-local >> $polkadot_init_log 2>&1 & -polkadot_init_pid=$! -$helper_script init-asset-hub-kusama-local >> $kusama_init_log 2>&1 & -kusama_init_pid=$! -wait -n $polkadot_init_pid $kusama_init_pid - - -$helper_script init-bridge-hub-polkadot-local >> $polkadot_init_log 2>&1 & -polkadot_init_pid=$! -$helper_script init-bridge-hub-kusama-local >> $kusama_init_log 2>&1 & -kusama_init_pid=$! -wait -n $polkadot_init_pid $kusama_init_pid - -run_zndsl ${BASH_SOURCE%/*}/polkadot-init.zndsl $polkadot_dir -run_zndsl ${BASH_SOURCE%/*}/kusama-init.zndsl $kusama_dir - -${BASH_SOURCE%/*}/start_relayer.sh $polkadot_dir $kusama_dir relayer_pid - -echo $polkadot_dir > $TEST_DIR/polkadot.env -echo $kusama_dir > $TEST_DIR/kusama.env -echo - -wait -n $polkadot_pid $kusama_pid $relayer_pid -kill -9 -$$ diff --git a/integration-tests/bridges/environments/polkadot-kusama/start_relayer.sh b/integration-tests/bridges/environments/polkadot-kusama/start_relayer.sh deleted file mode 100755 index 73e51f99a7..0000000000 --- a/integration-tests/bridges/environments/polkadot-kusama/start_relayer.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -e - -source "$FRAMEWORK_PATH/utils/common.sh" -source "$FRAMEWORK_PATH/utils/zombienet.sh" - -polkadot_dir=$1 -kusama_dir=$2 -__relayer_pid=$3 - -logs_dir=$TEST_DIR/logs -helper_script="${BASH_SOURCE%/*}/helper.sh" - -relayer_log=$logs_dir/relayer.log -echo -e "Starting polkadot-kusama relayer. Logs available at: $relayer_log\n" -start_background_process "$helper_script run-relay" $relayer_log relayer_pid - -run_zndsl ${BASH_SOURCE%/*}/polkadot-bridge.zndsl $polkadot_dir -run_zndsl ${BASH_SOURCE%/*}/kusama-bridge.zndsl $kusama_dir - -eval $__relayer_pid="'$relayer_pid'" - diff --git a/integration-tests/bridges/run-test.sh b/integration-tests/bridges/run-test.sh deleted file mode 100755 index 5ba302893a..0000000000 --- a/integration-tests/bridges/run-test.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -e - -trap 'kill -9 -$$ || echo "Environment already teared down"' SIGINT SIGTERM EXIT - -test=$1 - -export LOCAL_BRIDGE_TESTING_PATH=~/local_bridge_testing - -if [ -z "$FRAMEWORK_REPO_PATH" ]; then - # Download the bridge testing "framework" from the `polkadot-sdk` repo - # to `~/local_bridge_testing/downloads/polkadot-sdk`. - export DOWNLOADS_PATH=$LOCAL_BRIDGE_TESTING_PATH/downloads - echo "FRAMEWORK_REPO_PATH is NOT set, so downloading 'polkadot-sdk' repo to the: $DOWNLOADS_PATH" - mkdir -p $DOWNLOADS_PATH - framework_repo_path=$DOWNLOADS_PATH/polkadot-sdk - rm -rf $framework_repo_path - git clone --branch master -n --depth=1 --filter=tree:0 \ - https://github.com/paritytech/polkadot-sdk.git $framework_repo_path - pushd $framework_repo_path - git sparse-checkout set --no-cone bridges/testing/framework - git fetch --tags - git checkout polkadot-stable2409 - popd -else - framework_repo_path=$FRAMEWORK_REPO_PATH -fi - -export FRAMEWORK_PATH=$framework_repo_path/bridges/testing/framework -echo "Using bridges testing framework from path: $FRAMEWORK_PATH" -echo - -export ZOMBIENET_BINARY=$LOCAL_BRIDGE_TESTING_PATH/bin/zombienet -export POLKADOT_BINARY=$LOCAL_BRIDGE_TESTING_PATH/bin/polkadot -export POLKADOT_PARACHAIN_BINARY=$LOCAL_BRIDGE_TESTING_PATH/bin/polkadot-parachain -export CHAIN_SPEC_GEN_BINARY_FOR_KUSAMA=$LOCAL_BRIDGE_TESTING_PATH/bin/chain-spec-generator-kusama -export CHAIN_SPEC_GEN_BINARY_FOR_POLKADOT=$LOCAL_BRIDGE_TESTING_PATH/bin/chain-spec-generator-polkadot -export SUBSTRATE_RELAY_BINARY=$LOCAL_BRIDGE_TESTING_PATH/bin/substrate-relay - -export TEST_DIR=`mktemp -d /tmp/bridges-tests-run-XXXXX` -echo -e "Test folder: $TEST_DIR\n" - -${BASH_SOURCE%/*}/tests/$test/run.sh diff --git a/integration-tests/bridges/sudo-relay.patch b/integration-tests/bridges/sudo-relay.patch deleted file mode 100644 index 8edade4dc6..0000000000 --- a/integration-tests/bridges/sudo-relay.patch +++ /dev/null @@ -1,136 +0,0 @@ -diff --git a/Cargo.lock b/Cargo.lock -index 0ccf9de0a..e33f5da78 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -10024,6 +10024,7 @@ dependencies = [ - "pallet-staking-reward-fn", - "pallet-staking-runtime-api", - "pallet-state-trie-migration", -+ "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", -@@ -14334,6 +14335,7 @@ dependencies = [ - "pallet-society", - "pallet-staking", - "pallet-staking-runtime-api", -+ "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", -diff --git a/relay/kusama/Cargo.toml b/relay/kusama/Cargo.toml -index 5a600a1d3..4db7ea092 100644 ---- a/relay/kusama/Cargo.toml -+++ b/relay/kusama/Cargo.toml -@@ -106,6 +106,8 @@ xcm-runtime-apis = { workspace = true } - - sp-debug-derive = { workspace = true } - -+pallet-sudo = { workspace = true } -+ - [dev-dependencies] - sp-keyring = { workspace = true } - sp-trie = { workspace = true } -@@ -175,6 +177,7 @@ std = [ - "pallet-society/std", - "pallet-staking-runtime-api/std", - "pallet-staking/std", -+ "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", -diff --git a/relay/kusama/src/genesis_config_presets.rs b/relay/kusama/src/genesis_config_presets.rs -index dda349608..4714ecd51 100644 ---- a/relay/kusama/src/genesis_config_presets.rs -+++ b/relay/kusama/src/genesis_config_presets.rs -@@ -188,6 +188,9 @@ fn kusama_testnet_genesis( - "forceEra": Forcing::NotForcing, - "slashRewardFraction": Perbill::from_percent(10), - }, -+ "sudo": { -+ "key": Some(_root_key), -+ }, - "babe": { - "epochConfig": Some(BABE_GENESIS_EPOCH_CONFIG), - }, -diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs -index bb31116d0..0075f394a 100644 ---- a/relay/kusama/src/lib.rs -+++ b/relay/kusama/src/lib.rs -@@ -1657,9 +1657,18 @@ construct_runtime! { - // refer to block. See issue #160 for details. - Mmr: pallet_mmr = 201, - BeefyMmrLeaf: pallet_beefy_mmr = 202, -+ -+ // Sudo. -+ Sudo: pallet_sudo = 255, - } - } - -+impl pallet_sudo::Config for Runtime { -+ type RuntimeEvent = RuntimeEvent; -+ type RuntimeCall = RuntimeCall; -+ type WeightInfo = (); -+} -+ - /// The address format for describing accounts. - pub type Address = sp_runtime::MultiAddress; - /// Block header type as expected by this runtime. -diff --git a/relay/polkadot/Cargo.toml b/relay/polkadot/Cargo.toml -index c8a5404fa..8c3c3404b 100644 ---- a/relay/polkadot/Cargo.toml -+++ b/relay/polkadot/Cargo.toml -@@ -103,6 +103,8 @@ xcm-runtime-apis = { workspace = true } - - sp-debug-derive = { workspace = true } - -+pallet-sudo = { workspace = true } -+ - [dev-dependencies] - sp-keyring = { workspace = true } - sp-trie = { workspace = true } -@@ -169,6 +171,7 @@ std = [ - "pallet-staking-runtime-api/std", - "pallet-staking/std", - "pallet-state-trie-migration/std", -+ "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", -diff --git a/relay/polkadot/src/genesis_config_presets.rs b/relay/polkadot/src/genesis_config_presets.rs -index 38abd8e48..127813f1c 100644 ---- a/relay/polkadot/src/genesis_config_presets.rs -+++ b/relay/polkadot/src/genesis_config_presets.rs -@@ -188,6 +188,9 @@ fn polkadot_testnet_genesis( - "forceEra": Forcing::NotForcing, - "slashRewardFraction": Perbill::from_percent(10), - }, -+ "sudo": { -+ "key": Some(_root_key), -+ }, - "babe": { - "epochConfig": Some(BABE_GENESIS_EPOCH_CONFIG), - }, -diff --git a/relay/polkadot/src/lib.rs b/relay/polkadot/src/lib.rs -index 1e44c81fc..f0cf68788 100644 ---- a/relay/polkadot/src/lib.rs -+++ b/relay/polkadot/src/lib.rs -@@ -1680,9 +1680,18 @@ construct_runtime! { - // refer to block. See issue #160 for details. - Mmr: pallet_mmr = 201, - BeefyMmrLeaf: pallet_beefy_mmr = 202, -+ -+ // Sudo. -+ Sudo: pallet_sudo = 255, - } - } - -+impl pallet_sudo::Config for Runtime { -+ type RuntimeEvent = RuntimeEvent; -+ type RuntimeCall = RuntimeCall; -+ type WeightInfo = (); -+} -+ - /// The address format for describing accounts. - pub type Address = sp_runtime::MultiAddress; - /// Block header type as expected by this runtime. diff --git a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/dot-reaches-kusama.zndsl b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/dot-reaches-kusama.zndsl deleted file mode 100644 index 13db4cca35..0000000000 --- a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/dot-reaches-kusama.zndsl +++ /dev/null @@ -1,12 +0,0 @@ -Description: User is able to transfer DOT from Polkadot Asset Hub to Kusama Asset Hub -Network: {{ENV_PATH}}/bridge_hub_kusama_local_network.toml -Creds: config - -# send 5 DOT to //Alice from Polkadot AH to Kusama AH -asset-hub-kusama-collator-1: run {{ENV_PATH}}/helper.sh with "reserve-transfer-assets-from-asset-hub-polkadot-local 50000000000" within 120 seconds - -# check that //Alice received at least 4.8 DOT on Kusama AH -asset-hub-kusama-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,48000000000,Polkadot" within 300 seconds - -# check that the relayer //Charlie is rewarded by Kusama AH -bridge-hub-kusama-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x62687064,ThisChain,0" within 30 seconds diff --git a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/ksm-reaches-polkadot.zndsl b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/ksm-reaches-polkadot.zndsl deleted file mode 100644 index c07bfa9732..0000000000 --- a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/ksm-reaches-polkadot.zndsl +++ /dev/null @@ -1,12 +0,0 @@ -Description: User is able to transfer KSM from Kusama Asset Hub to Polkadot Asset Hub -Network: {{ENV_PATH}}/bridge_hub_polkadot_local_network.toml -Creds: config - -# send 5 KSM to //Alice from Kusama AH to Polkadot AH -asset-hub-polkadot-collator-1: run {{ENV_PATH}}/helper.sh with "reserve-transfer-assets-from-asset-hub-kusama-local 5000000000000" within 120 seconds - -# check that //Alice received at least 4.8 KSM on Polkadot AH -asset-hub-polkadot-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Kusama" within 300 seconds - -# check that the relayer //Charlie is rewarded by Polkadot AH -bridge-hub-polkadot-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x62686b73,ThisChain,0" within 30 seconds diff --git a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/run.sh b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/run.sh deleted file mode 100755 index 0cfc116119..0000000000 --- a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/run.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# Test that checks if asset transfer works on P<>K bridge. -# This test is intentionally not added to the CI. It is meant to be ran manually. - -set -e - -source "$FRAMEWORK_PATH/utils/common.sh" -source "$FRAMEWORK_PATH/utils/zombienet.sh" - -export ENV_PATH=`realpath ${BASH_SOURCE%/*}/../../environments/polkadot-kusama` - -$ENV_PATH/spawn.sh & -env_pid=$! - -ensure_process_file $env_pid $TEST_DIR/polkadot.env 600 -polkadot_dir=`cat $TEST_DIR/polkadot.env` -echo - -ensure_process_file $env_pid $TEST_DIR/kusama.env 300 -kusama_dir=`cat $TEST_DIR/kusama.env` -echo - -run_zndsl ${BASH_SOURCE%/*}/dot-reaches-kusama.zndsl $kusama_dir -run_zndsl ${BASH_SOURCE%/*}/ksm-reaches-polkadot.zndsl $polkadot_dir - -run_zndsl ${BASH_SOURCE%/*}/wdot-reaches-polkadot.zndsl $polkadot_dir -run_zndsl ${BASH_SOURCE%/*}/wksm-reaches-kusama.zndsl $kusama_dir diff --git a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wdot-reaches-polkadot.zndsl b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wdot-reaches-polkadot.zndsl deleted file mode 100644 index f1546b2a16..0000000000 --- a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wdot-reaches-polkadot.zndsl +++ /dev/null @@ -1,10 +0,0 @@ -Description: User is able to transfer wDOT back from Kusama Asset Hub to Polkadot Asset Hub -Network: {{ENV_PATH}}/bridge_hub_polkadot_local_network.toml -Creds: config - -# send 3 wDOT back to Alice from Kusama AH to Polkadot AH -asset-hub-polkadot-collator-1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-kusama-local 30000000000" within 120 seconds - -# check that //Alice received at least 2.8 wDOT on Polkadot AH -# (we wait until //Alice account increases here - there are no other transactions that may increase it) -asset-hub-polkadot-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY, 28000000000" within 300 seconds diff --git a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl b/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl deleted file mode 100644 index fd8b9bc5c3..0000000000 --- a/integration-tests/bridges/tests/0001-polkadot-kusama-asset-transfer/wksm-reaches-kusama.zndsl +++ /dev/null @@ -1,10 +0,0 @@ -Description: User is able to transfer wKSM from Polkadot Asset Hub back to Kusama Asset Hub -Network: {{ENV_PATH}}/bridge_hub_kusama_local_network.toml -Creds: config - -# send 3 wKSM back to Alice from Polkadot AH to Kusama AH -asset-hub-kusama-collator-1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-polkadot-local 3000000000000" within 120 seconds - -# check that //Alice received at least 2.8 wKSM on Polkadot AH -# (we wait until //Alice account increases here - there are no other transactions that may increase it) -asset-hub-kusama-collator-1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 300 seconds diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml deleted file mode 100644 index a14a2362bd..0000000000 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "asset-hub-kusama-emulated-chain" -authors.workspace = true -edition.workspace = true -version.workspace = true -license = "Apache-2.0" -description = "Asset Hub Kusama emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -xcm = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true } - -# Runtimes -asset-hub-kusama-runtime = { workspace = true } -kusama-emulated-chain = { workspace = true } -penpal-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs deleted file mode 100644 index 94cf5eeb07..0000000000 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/genesis.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::{sr25519, storage::Storage}; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, RESERVABLE_ASSET_ID, - SAFE_XCM_VERSION, -}; -use frame_support::sp_runtime::traits::AccountIdConversion; -use parachains_common::{AccountId, Balance}; -use polkadot_parachain_primitives::primitives::Sibling; -use xcm::prelude::*; - -pub const PARA_ID: u32 = 1000; -pub const ED: Balance = asset_hub_kusama_runtime::ExistentialDeposit::get(); -pub const USDT_ID: u32 = 1984; - -frame_support::parameter_types! { - pub AssetHubKusamaAssetOwner: AccountId = get_account_id_from_seed::("Alice"); - pub PenpalATeleportableAssetLocation: Location - = Location::new(1, [ - Junction::Parachain(penpal_emulated_chain::PARA_ID_A), - Junction::PalletInstance(penpal_emulated_chain::ASSETS_PALLET_ID), - Junction::GeneralIndex(penpal_emulated_chain::TELEPORTABLE_ASSET_ID.into()), - ] - ); - pub PenpalASiblingSovereignAccount: AccountId = Sibling::from(penpal_emulated_chain::PARA_ID_A).into_account_truncating(); -} - -pub fn genesis() -> Storage { - let genesis_config = asset_hub_kusama_runtime::RuntimeGenesisConfig { - system: asset_hub_kusama_runtime::SystemConfig::default(), - balances: asset_hub_kusama_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096 * 4096)) - .collect(), - }, - parachain_info: asset_hub_kusama_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: asset_hub_kusama_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: asset_hub_kusama_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_kusama_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: asset_hub_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - assets: asset_hub_kusama_runtime::AssetsConfig { - assets: vec![ - (RESERVABLE_ASSET_ID, AssetHubKusamaAssetOwner::get(), false, ED), - (USDT_ID, AssetHubKusamaAssetOwner::get(), true, ED), - ], - ..Default::default() - }, - foreign_assets: asset_hub_kusama_runtime::ForeignAssetsConfig { - assets: vec![ - // Penpal's teleportable asset representation - ( - PenpalATeleportableAssetLocation::get(), - PenpalASiblingSovereignAccount::get(), - false, - ED, - ), - ], - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - asset_hub_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/lib.rs b/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/lib.rs deleted file mode 100644 index af127b7e1a..0000000000 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-kusama/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, - impl_foreign_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, -}; -use kusama_emulated_chain::Kusama; - -// AssetHubKusama Parachain declaration -decl_test_parachains! { - pub struct AssetHubKusama { - genesis = genesis::genesis(), - on_init = { - asset_hub_kusama_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_kusama_runtime, - core = { - XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue, - LocationToAccountId: asset_hub_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_kusama_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: asset_hub_kusama_runtime::PolkadotXcm, - Assets: asset_hub_kusama_runtime::Assets, - ForeignAssets: asset_hub_kusama_runtime::ForeignAssets, - PoolAssets: asset_hub_kusama_runtime::PoolAssets, - AssetConversion: asset_hub_kusama_runtime::AssetConversion, - Balances: asset_hub_kusama_runtime::Balances, - } - }, -} - -// AssetHubKusama implementation -impl_accounts_helpers_for_parachain!(AssetHubKusama); -impl_assert_events_helpers_for_parachain!(AssetHubKusama); -impl_assets_helpers_for_system_parachain!(AssetHubKusama, Kusama); -impl_assets_helpers_for_parachain!(AssetHubKusama); -impl_foreign_assets_helpers_for_parachain!(AssetHubKusama, xcm::v4::Location); -impl_xcm_helpers_for_parachain!(AssetHubKusama); diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml deleted file mode 100644 index 4b217ac017..0000000000 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "asset-hub-polkadot-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Polkadot emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -xcm = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true } - -# Runtimes -asset-hub-polkadot-runtime = { workspace = true } -polkadot-emulated-chain = { workspace = true } -penpal-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs deleted file mode 100644 index 8f1ee3a5c1..0000000000 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/genesis.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::storage::Storage; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, RESERVABLE_ASSET_ID, - SAFE_XCM_VERSION, -}; -use frame_support::sp_runtime::traits::AccountIdConversion; -use parachains_common::{AccountId, AssetHubPolkadotAuraId, Balance}; -use polkadot_parachain_primitives::primitives::Sibling; -use sp_core::sr25519; -use xcm::prelude::*; - -pub const PARA_ID: u32 = 1000; -pub const ED: Balance = asset_hub_polkadot_runtime::ExistentialDeposit::get(); -pub const USDT_ID: u32 = 1984; - -frame_support::parameter_types! { - pub AssetHubPolkadotAssetOwner: AccountId = get_account_id_from_seed::("Alice"); - pub PenpalATeleportableAssetLocation: Location - = Location::new(1, [ - Junction::Parachain(penpal_emulated_chain::PARA_ID_A), - Junction::PalletInstance(penpal_emulated_chain::ASSETS_PALLET_ID), - Junction::GeneralIndex(penpal_emulated_chain::TELEPORTABLE_ASSET_ID.into()), - ] - ); - pub PenpalBTeleportableAssetLocation: Location - = Location::new(1, [ - Junction::Parachain(penpal_emulated_chain::PARA_ID_B), - Junction::PalletInstance(penpal_emulated_chain::ASSETS_PALLET_ID), - Junction::GeneralIndex(penpal_emulated_chain::TELEPORTABLE_ASSET_ID.into()), - ] - ); - pub PenpalASiblingSovereignAccount: AccountId = Sibling::from(penpal_emulated_chain::PARA_ID_A).into_account_truncating(); - pub PenpalBSiblingSovereignAccount: AccountId = Sibling::from(penpal_emulated_chain::PARA_ID_B).into_account_truncating(); -} - -fn invulnerables_asset_hub_polkadot() -> Vec<(AccountId, AssetHubPolkadotAuraId)> { - vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), - ] -} - -pub fn genesis() -> Storage { - let genesis_config = asset_hub_polkadot_runtime::RuntimeGenesisConfig { - system: asset_hub_polkadot_runtime::SystemConfig::default(), - balances: asset_hub_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances() - .iter() - .cloned() - .map(|k| (k, ED * 4096 * 4096)) - .collect(), - }, - parachain_info: asset_hub_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: asset_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: invulnerables_asset_hub_polkadot() - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: asset_hub_polkadot_runtime::SessionConfig { - keys: invulnerables_asset_hub_polkadot() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: asset_hub_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - assets: asset_hub_polkadot_runtime::AssetsConfig { - assets: vec![ - (RESERVABLE_ASSET_ID, AssetHubPolkadotAssetOwner::get(), false, ED), - (USDT_ID, AssetHubPolkadotAssetOwner::get(), true, ED), - ], - ..Default::default() - }, - foreign_assets: asset_hub_polkadot_runtime::ForeignAssetsConfig { - assets: vec![ - // Penpal's teleportable asset representation - ( - PenpalATeleportableAssetLocation::get(), - PenpalASiblingSovereignAccount::get(), - false, - ED, - ), - ( - PenpalBTeleportableAssetLocation::get(), - PenpalBSiblingSovereignAccount::get(), - false, - ED, - ), - ], - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - asset_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/lib.rs b/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/lib.rs deleted file mode 100644 index ecefcf0148..0000000000 --- a/integration-tests/emulated/chains/parachains/assets/asset-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, - impl_foreign_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, -}; -use polkadot_emulated_chain::Polkadot; - -// AssetHubPolkadot Parachain declaration -decl_test_parachains! { - pub struct AssetHubPolkadot { - genesis = genesis::genesis(), - on_init = { - asset_hub_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = asset_hub_polkadot_runtime, - core = { - XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue, - LocationToAccountId: asset_hub_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: asset_hub_polkadot_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: asset_hub_polkadot_runtime::PolkadotXcm, - Balances: asset_hub_polkadot_runtime::Balances, - Assets: asset_hub_polkadot_runtime::Assets, - ForeignAssets: asset_hub_polkadot_runtime::ForeignAssets, - PoolAssets: asset_hub_polkadot_runtime::PoolAssets, - AssetConversion: asset_hub_polkadot_runtime::AssetConversion, - } - }, -} - -// AssetHubPolkadot implementation -impl_accounts_helpers_for_parachain!(AssetHubPolkadot); -impl_assert_events_helpers_for_parachain!(AssetHubPolkadot); -impl_assets_helpers_for_system_parachain!(AssetHubPolkadot, Polkadot); -impl_assets_helpers_for_parachain!(AssetHubPolkadot); -impl_foreign_assets_helpers_for_parachain!(AssetHubPolkadot, xcm::v4::Location); -impl_xcm_helpers_for_parachain!(AssetHubPolkadot); diff --git a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/Cargo.toml deleted file mode 100644 index a56869a1d2..0000000000 --- a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "bridge-hub-kusama-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Kusama emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Bridges -bp-messages = { workspace = true } -xcm = { workspace = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -bridge-hub-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -bridge-hub-kusama-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/genesis.rs deleted file mode 100644 index 11c614d0a1..0000000000 --- a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/genesis.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::{sr25519, storage::Storage}; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, -}; -use parachains_common::Balance; -use xcm::latest::prelude::*; - -pub const ASSET_HUB_PARA_ID: u32 = 1000; -pub const PARA_ID: u32 = 1002; -pub const ED: Balance = bridge_hub_kusama_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = bridge_hub_kusama_runtime::RuntimeGenesisConfig { - system: bridge_hub_kusama_runtime::SystemConfig::default(), - balances: bridge_hub_kusama_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), - }, - parachain_info: bridge_hub_kusama_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: bridge_hub_kusama_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: bridge_hub_kusama_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_kusama_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: bridge_hub_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - bridge_polkadot_grandpa: bridge_hub_kusama_runtime::BridgePolkadotGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_polkadot_messages: bridge_hub_kusama_runtime::BridgePolkadotMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - xcm_over_bridge_hub_polkadot: bridge_hub_kusama_runtime::XcmOverBridgeHubPolkadotConfig { - opened_bridges: vec![ - // open KAH -> PAH bridge - ( - Location::new(1, [Parachain(1000)]), - Junctions::from([Polkadot.into(), Parachain(1000)]), - Some(bp_messages::LegacyLaneId([0, 0, 0, 1])), - ), - ], - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - bridge_hub_kusama_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/lib.rs b/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/lib.rs deleted file mode 100644 index 808c2fb894..0000000000 --- a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// BridgeHubKusama Parachain declaration -decl_test_parachains! { - pub struct BridgeHubKusama { - genesis = genesis::genesis(), - on_init = { - bridge_hub_kusama_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_kusama_runtime, - core = { - XcmpMessageHandler: bridge_hub_kusama_runtime::XcmpQueue, - LocationToAccountId: bridge_hub_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_kusama_runtime::ParachainInfo, - MessageOrigin: bridge_hub_common::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: bridge_hub_kusama_runtime::PolkadotXcm, - Balances: bridge_hub_kusama_runtime::Balances, - } - }, -} - -// BridgeHubKusama implementation -impl_accounts_helpers_for_parachain!(BridgeHubKusama); -impl_assert_events_helpers_for_parachain!(BridgeHubKusama); -impl_xcm_helpers_for_parachain!(BridgeHubKusama); diff --git a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/Cargo.toml deleted file mode 100644 index 28715623c2..0000000000 --- a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "bridge-hub-polkadot-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Polkadot emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Bridges -bp-messages = { workspace = true } -xcm = { workspace = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -bridge-hub-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -bridge-hub-polkadot-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/genesis.rs deleted file mode 100644 index 19141625fe..0000000000 --- a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/genesis.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::{sr25519, storage::Storage}; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, -}; -use parachains_common::Balance; -use xcm::latest::prelude::*; - -pub const ASSET_HUB_PARA_ID: u32 = 1000; -pub const PARA_ID: u32 = 1002; -pub const ED: Balance = bridge_hub_polkadot_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = bridge_hub_polkadot_runtime::RuntimeGenesisConfig { - system: bridge_hub_polkadot_runtime::SystemConfig::default(), - balances: bridge_hub_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), - }, - parachain_info: bridge_hub_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: bridge_hub_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: bridge_hub_polkadot_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: bridge_hub_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - bridge_kusama_grandpa: bridge_hub_polkadot_runtime::BridgeKusamaGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - bridge_kusama_messages: bridge_hub_polkadot_runtime::BridgeKusamaMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), - ..Default::default() - }, - ethereum_system: bridge_hub_polkadot_runtime::EthereumSystemConfig { - para_id: PARA_ID.into(), - asset_hub_para_id: ASSET_HUB_PARA_ID.into(), - ..Default::default() - }, - xcm_over_bridge_hub_kusama: bridge_hub_polkadot_runtime::XcmOverBridgeHubKusamaConfig { - opened_bridges: vec![ - // open PAH -> KAH bridge - ( - Location::new(1, [Parachain(1000)]), - Junctions::from([Kusama.into(), Parachain(1000)]), - Some(bp_messages::LegacyLaneId([0, 0, 0, 1])), - ), - ], - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - bridge_hub_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/lib.rs b/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/lib.rs deleted file mode 100644 index cf50845853..0000000000 --- a/integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// BridgeHubPolkadot Parachain declaration -decl_test_parachains! { - pub struct BridgeHubPolkadot { - genesis = genesis::genesis(), - on_init = { - bridge_hub_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = bridge_hub_polkadot_runtime, - core = { - XcmpMessageHandler: bridge_hub_polkadot_runtime::XcmpQueue, - LocationToAccountId: bridge_hub_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: bridge_hub_polkadot_runtime::ParachainInfo, - MessageOrigin: bridge_hub_common::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: bridge_hub_polkadot_runtime::PolkadotXcm, - Balances: bridge_hub_polkadot_runtime::Balances, - EthereumSystem: bridge_hub_polkadot_runtime::EthereumSystem, - EthereumInboundQueue: bridge_hub_polkadot_runtime::EthereumInboundQueue, - EthereumOutboundQueue: bridge_hub_polkadot_runtime::EthereumOutboundQueue, - } - }, -} - -// BridgeHubPolkadot implementation -impl_accounts_helpers_for_parachain!(BridgeHubPolkadot); -impl_assert_events_helpers_for_parachain!(BridgeHubPolkadot); -impl_xcm_helpers_for_parachain!(BridgeHubPolkadot); diff --git a/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/Cargo.toml deleted file mode 100644 index ffd5689c64..0000000000 --- a/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "collectives-polkadot-emulated-chain" -version = "0.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Collectives Polkadot emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -collectives-polkadot-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/genesis.rs deleted file mode 100644 index 7becb87c8b..0000000000 --- a/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/genesis.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::storage::Storage; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, -}; -use parachains_common::Balance; - -pub const PARA_ID: u32 = 1001; -pub const ED: Balance = collectives_polkadot_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = collectives_polkadot_runtime::RuntimeGenesisConfig { - system: collectives_polkadot_runtime::SystemConfig::default(), - balances: collectives_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), - }, - parachain_info: collectives_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: collectives_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: collectives_polkadot_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - collectives_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: collectives_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - collectives_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/lib.rs b/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/lib.rs deleted file mode 100644 index d8ffbdcaf6..0000000000 --- a/integration-tests/emulated/chains/parachains/collectives/collectives-polkadot/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// CollectivesPolkadot Parachain declaration -decl_test_parachains! { - pub struct CollectivesPolkadot { - genesis = genesis::genesis(), - on_init = { - collectives_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = collectives_polkadot_runtime, - core = { - XcmpMessageHandler: collectives_polkadot_runtime::XcmpQueue, - LocationToAccountId: collectives_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: collectives_polkadot_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: collectives_polkadot_runtime::PolkadotXcm, - Balances: collectives_polkadot_runtime::Balances, - FellowshipTreasury: collectives_polkadot_runtime::FellowshipTreasury, - AssetRate: collectives_polkadot_runtime::AssetRate, - } - }, -} - -// CollectivesPolkadot implementation -impl_accounts_helpers_for_parachain!(CollectivesPolkadot); -impl_assert_events_helpers_for_parachain!(CollectivesPolkadot); diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml deleted file mode 100644 index dbf6e7138e..0000000000 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "coretime-kusama-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Coretime Kusama emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -coretime-kusama-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs deleted file mode 100644 index b9aff33084..0000000000 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::storage::Storage; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, -}; -use parachains_common::Balance; - -pub const PARA_ID: u32 = 1005; -pub const ED: Balance = coretime_kusama_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = coretime_kusama_runtime::RuntimeGenesisConfig { - system: coretime_kusama_runtime::SystemConfig::default(), - balances: coretime_kusama_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), - }, - parachain_info: coretime_kusama_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: coretime_kusama_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: coretime_kusama_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - coretime_kusama_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: coretime_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - coretime_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs deleted file mode 100644 index c35d01722a..0000000000 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// CollectivesPolkadot Parachain declaration -decl_test_parachains! { - pub struct CoretimeKusama { - genesis = genesis::genesis(), - on_init = { - coretime_kusama_runtime::AuraExt::on_initialize(1); - }, - runtime = coretime_kusama_runtime, - core = { - XcmpMessageHandler: coretime_kusama_runtime::XcmpQueue, - LocationToAccountId: coretime_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: coretime_kusama_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: coretime_kusama_runtime::PolkadotXcm, - Balances: coretime_kusama_runtime::Balances, - Broker: coretime_kusama_runtime::Broker, - } - }, -} - -// CoretimeKusama implementation -impl_accounts_helpers_for_parachain!(CoretimeKusama); -impl_assert_events_helpers_for_parachain!(CoretimeKusama); diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/Cargo.toml deleted file mode 100644 index 10d9e8d946..0000000000 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "coretime-polkadot-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Coretime Polkadot emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -coretime-polkadot-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/genesis.rs deleted file mode 100644 index 7622fca4c1..0000000000 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/genesis.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::storage::Storage; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, -}; -use parachains_common::Balance; - -pub const PARA_ID: u32 = 1005; -pub const ED: Balance = coretime_polkadot_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = coretime_polkadot_runtime::RuntimeGenesisConfig { - system: coretime_polkadot_runtime::SystemConfig::default(), - balances: coretime_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), - }, - parachain_info: coretime_polkadot_runtime::ParachainInfoConfig { - parachain_id: PARA_ID.into(), - ..Default::default() - }, - collator_selection: coretime_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: coretime_polkadot_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - coretime_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: coretime_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - coretime_polkadot_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/lib.rs b/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/lib.rs deleted file mode 100644 index b39e412c80..0000000000 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-polkadot/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// CollectivesPolkadot Parachain declaration -decl_test_parachains! { - pub struct CoretimePolkadot { - genesis = genesis::genesis(), - on_init = { - coretime_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = coretime_polkadot_runtime, - core = { - XcmpMessageHandler: coretime_polkadot_runtime::XcmpQueue, - LocationToAccountId: coretime_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: coretime_polkadot_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: coretime_polkadot_runtime::PolkadotXcm, - Balances: coretime_polkadot_runtime::Balances, - Broker: coretime_polkadot_runtime::Broker, - } - }, -} - -// CoretimePolkadot implementation -impl_accounts_helpers_for_parachain!(CoretimePolkadot); -impl_assert_events_helpers_for_parachain!(CoretimePolkadot); diff --git a/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml deleted file mode 100644 index f6bb6403ee..0000000000 --- a/integration-tests/emulated/chains/parachains/people/people-kusama/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "people-kusama-emulated-chain" -authors.workspace = true -edition.workspace = true -version.workspace = true -license = "Apache-2.0" -description = "People Kusama emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -kusama-runtime-constants = { workspace = true, default-features = true } - -# Local -people-kusama-runtime = { workspace = true } -kusama-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs deleted file mode 100644 index cca03c7d8e..0000000000 --- a/integration-tests/emulated/chains/parachains/people/people-kusama/src/genesis.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::storage::Storage; - -// Cumulus -use cumulus_primitives_core::ParaId; -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, -}; -use kusama_runtime_constants::currency::UNITS as KSM; -use parachains_common::Balance; - -const ENDOWMENT: u128 = 1_000 * KSM; -pub const PARA_ID: u32 = 1004; -pub const ED: Balance = people_kusama_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = people_kusama_runtime::RuntimeGenesisConfig { - balances: people_kusama_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ENDOWMENT)).collect(), - }, - system: people_kusama_runtime::SystemConfig::default(), - parachain_info: people_kusama_runtime::ParachainInfoConfig { - parachain_id: ParaId::from(PARA_ID), - ..Default::default() - }, - collator_selection: people_kusama_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: people_kusama_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - people_kusama_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: people_kusama_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - people_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/people/people-kusama/src/lib.rs b/integration-tests/emulated/chains/parachains/people/people-kusama/src/lib.rs deleted file mode 100644 index c070d43ce0..0000000000 --- a/integration-tests/emulated/chains/parachains/people/people-kusama/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// PeopleKusama Parachain declaration -decl_test_parachains! { - pub struct PeopleKusama { - genesis = genesis::genesis(), - on_init = { - people_kusama_runtime::AuraExt::on_initialize(1); - }, - runtime = people_kusama_runtime, - core = { - XcmpMessageHandler: people_kusama_runtime::XcmpQueue, - LocationToAccountId: people_kusama_runtime::xcm_config::LocationToAccountId, - ParachainInfo: people_kusama_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: people_kusama_runtime::PolkadotXcm, - Balances: people_kusama_runtime::Balances, - Identity: people_kusama_runtime::Identity, - } - }, -} - -// PeopleKusama implementation -impl_accounts_helpers_for_parachain!(PeopleKusama); -impl_assert_events_helpers_for_parachain!(PeopleKusama); diff --git a/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml b/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml deleted file mode 100644 index 6414084696..0000000000 --- a/integration-tests/emulated/chains/parachains/people/people-polkadot/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "people-polkadot-emulated-chain" -authors.workspace = true -edition.workspace = true -version.workspace = true -license = "Apache-2.0" -description = "People Polkadot emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -polkadot-runtime-constants = { workspace = true, default-features = true } - -# Local -people-polkadot-runtime = { workspace = true } -polkadot-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs b/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs deleted file mode 100644 index 177eaa64e2..0000000000 --- a/integration-tests/emulated/chains/parachains/people/people-polkadot/src/genesis.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use sp_core::storage::Storage; - -// Cumulus -use cumulus_primitives_core::ParaId; -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, -}; -use parachains_common::Balance; -use polkadot_runtime_constants::currency::UNITS as DOT; - -const ENDOWMENT: u128 = 1_000 * DOT; -pub const PARA_ID: u32 = 1004; -pub const ED: Balance = people_polkadot_runtime::ExistentialDeposit::get(); - -pub fn genesis() -> Storage { - let genesis_config = people_polkadot_runtime::RuntimeGenesisConfig { - balances: people_polkadot_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ENDOWMENT)).collect(), - }, - system: people_polkadot_runtime::SystemConfig::default(), - parachain_info: people_polkadot_runtime::ParachainInfoConfig { - parachain_id: ParaId::from(PARA_ID), - ..Default::default() - }, - collator_selection: people_polkadot_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: people_polkadot_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - people_polkadot_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: people_polkadot_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - people_polkadot_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/people/people-polkadot/src/lib.rs b/integration-tests/emulated/chains/parachains/people/people-polkadot/src/lib.rs deleted file mode 100644 index 8026089f1d..0000000000 --- a/integration-tests/emulated/chains/parachains/people/people-polkadot/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Substrate -use frame_support::traits::OnInitialize; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, -}; - -// PeoplePolkadot Parachain declaration -decl_test_parachains! { - pub struct PeoplePolkadot { - genesis = genesis::genesis(), - on_init = { - people_polkadot_runtime::AuraExt::on_initialize(1); - }, - runtime = people_polkadot_runtime, - core = { - XcmpMessageHandler: people_polkadot_runtime::XcmpQueue, - LocationToAccountId: people_polkadot_runtime::xcm_config::LocationToAccountId, - ParachainInfo: people_polkadot_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: people_polkadot_runtime::PolkadotXcm, - Balances: people_polkadot_runtime::Balances, - Identity: people_polkadot_runtime::Identity, - } - }, -} - -// PeoplePolkadot implementation -impl_accounts_helpers_for_parachain!(PeoplePolkadot); -impl_assert_events_helpers_for_parachain!(PeoplePolkadot); diff --git a/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml deleted file mode 100644 index a9b5ce3aa6..0000000000 --- a/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "penpal-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Penpal emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -penpal-runtime = { workspace = true } -xcm = { workspace = true, default-features = true } - -# Runtimes -kusama-emulated-chain = { workspace = true } -polkadot-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs deleted file mode 100644 index c5ba18a90a..0000000000 --- a/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, -}; -use parachains_common::{AccountId, Balance}; -use penpal_runtime::xcm_config::{LocalReservableFromAssetHub, RelayLocation, UsdtFromAssetHub}; - -// Penpal -pub const PARA_ID_A: u32 = 2000; -pub const PARA_ID_B: u32 = 2001; -pub const ED: Balance = penpal_runtime::ExistentialDeposit::get(); -pub const USDT_ED: Balance = 70_000; - -parameter_types! { - pub PenpalSudoAccount: AccountId = get_account_id_from_seed::("Alice"); - pub PenpalAssetOwner: AccountId = PenpalSudoAccount::get(); -} - -pub fn genesis(para_id: u32) -> Storage { - let genesis_config = penpal_runtime::RuntimeGenesisConfig { - system: penpal_runtime::SystemConfig::default(), - balances: penpal_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), - }, - parachain_info: penpal_runtime::ParachainInfoConfig { - parachain_id: para_id.into(), - ..Default::default() - }, - collator_selection: penpal_runtime::CollatorSelectionConfig { - invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ED * 16, - ..Default::default() - }, - session: penpal_runtime::SessionConfig { - keys: collators::invulnerables() - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - penpal_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect(), - ..Default::default() - }, - polkadot_xcm: penpal_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - sudo: penpal_runtime::SudoConfig { key: Some(PenpalSudoAccount::get()) }, - assets: penpal_runtime::AssetsConfig { - assets: vec![( - penpal_runtime::xcm_config::TELEPORTABLE_ASSET_ID, - PenpalAssetOwner::get(), - false, - ED, - )], - ..Default::default() - }, - foreign_assets: penpal_runtime::ForeignAssetsConfig { - assets: vec![ - // Relay Native asset representation - (RelayLocation::get(), PenpalAssetOwner::get(), true, ED), - // Sufficient AssetHub asset representation - (LocalReservableFromAssetHub::get(), PenpalAssetOwner::get(), true, ED), - // USDT from AssetHub - (UsdtFromAssetHub::get(), PenpalAssetOwner::get(), true, USDT_ED), - ], - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage( - &genesis_config, - penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - ) -} diff --git a/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs deleted file mode 100644 index bcb7bbb4b9..0000000000 --- a/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod genesis; -pub use genesis::{genesis, PenpalAssetOwner, ED, PARA_ID_A, PARA_ID_B}; -pub use penpal_runtime::{ - self, - xcm_config::{ - CustomizableAssetFromSystemAssetHub, LocalReservableFromAssetHub, - LocalTeleportableToAssetHub, RelayNetworkId as PenpalRelayNetworkId, XcmConfig, - ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, TELEPORTABLE_ASSET_ID, - }, -}; - -// Substrate -use frame_support::traits::OnInitialize; -use sp_core::Encode; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, - impl_xcm_helpers_for_parachain, - impls::{NetworkId, Parachain}, - xcm_emulator::decl_test_parachains, -}; - -// Penpal Parachain declaration -decl_test_parachains! { - pub struct PenpalA { - genesis = genesis(PARA_ID_A), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - frame_support::assert_ok!(penpal_runtime::System::set_storage( - penpal_runtime::RuntimeOrigin::root(), - vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Kusama.encode())], - )); - }, - runtime = penpal_runtime, - core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, - ForeignAssets: penpal_runtime::ForeignAssets, - AssetConversion: penpal_runtime::AssetConversion, - Balances: penpal_runtime::Balances, - } - }, - pub struct PenpalB { - genesis = genesis(PARA_ID_B), - on_init = { - penpal_runtime::AuraExt::on_initialize(1); - frame_support::assert_ok!(penpal_runtime::System::set_storage( - penpal_runtime::RuntimeOrigin::root(), - vec![(PenpalRelayNetworkId::key().to_vec(), NetworkId::Polkadot.encode())], - )); - }, - runtime = penpal_runtime, - core = { - XcmpMessageHandler: penpal_runtime::XcmpQueue, - LocationToAccountId: penpal_runtime::xcm_config::LocationToAccountId, - ParachainInfo: penpal_runtime::ParachainInfo, - MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, - }, - pallets = { - PolkadotXcm: penpal_runtime::PolkadotXcm, - Assets: penpal_runtime::Assets, - ForeignAssets: penpal_runtime::ForeignAssets, - AssetConversion: penpal_runtime::AssetConversion, - Balances: penpal_runtime::Balances, - } - }, -} - -// Penpal implementation -impl_accounts_helpers_for_parachain!(PenpalA); -impl_accounts_helpers_for_parachain!(PenpalB); -impl_assert_events_helpers_for_parachain!(PenpalA); -impl_assert_events_helpers_for_parachain!(PenpalB); -impl_assets_helpers_for_parachain!(PenpalA); -impl_assets_helpers_for_parachain!(PenpalB); -impl_foreign_assets_helpers_for_parachain!(PenpalA, xcm::latest::Location); -impl_foreign_assets_helpers_for_parachain!(PenpalB, xcm::latest::Location); -impl_xcm_helpers_for_parachain!(PenpalA); -impl_xcm_helpers_for_parachain!(PenpalB); diff --git a/integration-tests/emulated/chains/relays/kusama/Cargo.toml b/integration-tests/emulated/chains/relays/kusama/Cargo.toml deleted file mode 100644 index 504c79e1eb..0000000000 --- a/integration-tests/emulated/chains/relays/kusama/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "kusama-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Kusama emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -authority-discovery-primitives = { workspace = true, default-features = true } -babe-primitives = { workspace = true, default-features = true } -beefy-primitives = { workspace = true, default-features = true } -grandpa = { workspace = true } - -# Polkadot -polkadot-primitives = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -kusama-runtime-constants = { workspace = true, default-features = true } -kusama-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/relays/kusama/src/genesis.rs b/integration-tests/emulated/chains/relays/kusama/src/genesis.rs deleted file mode 100644 index de368cae62..0000000000 --- a/integration-tests/emulated/chains/relays/kusama/src/genesis.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; -use babe_primitives::AuthorityId as BabeId; -use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; -use grandpa::AuthorityId as GrandpaId; -use sp_core::{sr25519, storage::Storage}; - -// Polkadot -use polkadot_primitives::{AssignmentId, ValidatorId}; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, get_host_config, -}; -use kusama_runtime_constants::currency::UNITS as KSM; -use parachains_common::Balance; - -pub const ED: Balance = kusama_runtime::ExistentialDeposit::get(); -const ENDOWMENT: u128 = 1_000_000 * KSM; - -mod validators { - use super::*; - use parachains_common::AccountId; - - #[allow(clippy::type_complexity)] - pub fn initial_authorities() -> Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, - )> { - let seed = "Alice"; - vec![( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - )] - } -} - -fn session_keys( - babe: BabeId, - grandpa: GrandpaId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, - beefy: BeefyId, -) -> kusama_runtime::SessionKeys { - kusama_runtime::SessionKeys { - grandpa, - babe, - para_validator, - para_assignment, - authority_discovery, - beefy, - } -} - -pub fn genesis() -> Storage { - let genesis_config = kusama_runtime::RuntimeGenesisConfig { - system: kusama_runtime::SystemConfig::default(), - balances: kusama_runtime::BalancesConfig { - balances: accounts::init_balances().iter().map(|k| (k.clone(), ENDOWMENT)).collect(), - }, - session: kusama_runtime::SessionConfig { - keys: validators::initial_authorities() - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - ), - ) - }) - .collect::>(), - ..Default::default() - }, - babe: kusama_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: kusama_runtime::BABE_GENESIS_EPOCH_CONFIG, - ..Default::default() - }, - configuration: kusama_runtime::ConfigurationConfig { config: get_host_config() }, - registrar: kusama_runtime::RegistrarConfig { - next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, - ..Default::default() - }, - ..Default::default() - }; - - build_genesis_storage(&genesis_config, kusama_runtime::WASM_BINARY.unwrap()) -} diff --git a/integration-tests/emulated/chains/relays/kusama/src/lib.rs b/integration-tests/emulated/chains/relays/kusama/src/lib.rs deleted file mode 100644 index ec65fffb83..0000000000 --- a/integration-tests/emulated/chains/relays/kusama/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_relay_chain, impl_assert_events_helpers_for_relay_chain, - impl_hrmp_channels_helpers_for_relay_chain, impl_send_transact_helpers_for_relay_chain, - xcm_emulator::decl_test_relay_chains, -}; - -// Kusama declaration -decl_test_relay_chains! { - #[api_version(11)] - pub struct Kusama { - genesis = genesis::genesis(), - on_init = (), - runtime = kusama_runtime, - core = { - SovereignAccountOf: kusama_runtime::xcm_config::SovereignAccountOf, - }, - pallets = { - XcmPallet: kusama_runtime::XcmPallet, - Balances: kusama_runtime::Balances, - Hrmp: kusama_runtime::Hrmp, - Treasury: kusama_runtime::Treasury, - AssetRate: kusama_runtime::AssetRate, - } - }, -} - -// Kusama implementation -impl_accounts_helpers_for_relay_chain!(Kusama); -impl_assert_events_helpers_for_relay_chain!(Kusama); -impl_hrmp_channels_helpers_for_relay_chain!(Kusama); -impl_send_transact_helpers_for_relay_chain!(Kusama); diff --git a/integration-tests/emulated/chains/relays/polkadot/Cargo.toml b/integration-tests/emulated/chains/relays/polkadot/Cargo.toml deleted file mode 100644 index 8c6e2c2a15..0000000000 --- a/integration-tests/emulated/chains/relays/polkadot/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "polkadot-emulated-chain" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Polkadot emulated chain used for integration tests" -publish = false - -[dependencies] - -# Substrate -sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -authority-discovery-primitives = { workspace = true, default-features = true } -babe-primitives = { workspace = true, default-features = true } -beefy-primitives = { workspace = true, default-features = true } -grandpa = { workspace = true } -pallet-staking = { workspace = true, default-features = true } - -# Polkadot -polkadot-primitives = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } - -# Runtimes -polkadot-runtime-constants = { workspace = true, default-features = true } -polkadot-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/relays/polkadot/src/genesis.rs b/integration-tests/emulated/chains/relays/polkadot/src/genesis.rs deleted file mode 100644 index 51bbfcb71c..0000000000 --- a/integration-tests/emulated/chains/relays/polkadot/src/genesis.rs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; -use babe_primitives::AuthorityId as BabeId; -use beefy_primitives::ecdsa_crypto::AuthorityId as BeefyId; -use grandpa::AuthorityId as GrandpaId; -use sp_core::{sr25519, storage::Storage}; -use sp_runtime::Perbill; - -// Polkadot -use polkadot_primitives::{AssignmentId, ValidatorId}; - -// Cumulus -use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_from_seed, get_host_config, -}; -use parachains_common::Balance; -use polkadot_runtime_constants::currency::UNITS as DOT; - -pub const ED: Balance = polkadot_runtime::ExistentialDeposit::get(); -const ENDOWMENT: u128 = 1_000_000 * DOT; -const STASH: u128 = 100 * DOT; - -mod validators { - use super::*; - use parachains_common::AccountId; - - #[allow(clippy::type_complexity)] - pub fn initial_authorities() -> Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, - )> { - let seed = "Alice"; - vec![( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - )] - } -} - -fn session_keys( - babe: BabeId, - grandpa: GrandpaId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, - beefy: BeefyId, -) -> polkadot_runtime::SessionKeys { - polkadot_runtime::SessionKeys { - babe, - grandpa, - para_validator, - para_assignment, - authority_discovery, - beefy, - } -} - -pub fn genesis() -> Storage { - let genesis_config = polkadot_runtime::RuntimeGenesisConfig { - system: polkadot_runtime::SystemConfig::default(), - balances: polkadot_runtime::BalancesConfig { - balances: accounts::init_balances().iter().cloned().map(|k| (k, ENDOWMENT)).collect(), - }, - session: polkadot_runtime::SessionConfig { - keys: validators::initial_authorities() - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - ), - ) - }) - .collect::>(), - ..Default::default() - }, - staking: polkadot_runtime::StakingConfig { - validator_count: validators::initial_authorities().len() as u32, - minimum_validator_count: 1, - stakers: validators::initial_authorities() - .iter() - .map(|x| (x.0.clone(), x.1.clone(), STASH, pallet_staking::StakerStatus::Validator)) - .collect(), - invulnerables: validators::initial_authorities().iter().map(|x| x.0.clone()).collect(), - force_era: pallet_staking::Forcing::ForceNone, - slash_reward_fraction: Perbill::from_percent(10), - ..Default::default() - }, - babe: polkadot_runtime::BabeConfig { - authorities: Default::default(), - epoch_config: polkadot_runtime::BABE_GENESIS_EPOCH_CONFIG, - ..Default::default() - }, - configuration: polkadot_runtime::ConfigurationConfig { config: get_host_config() }, - ..Default::default() - }; - - build_genesis_storage(&genesis_config, polkadot_runtime::WASM_BINARY.unwrap()) -} diff --git a/integration-tests/emulated/chains/relays/polkadot/src/lib.rs b/integration-tests/emulated/chains/relays/polkadot/src/lib.rs deleted file mode 100644 index 3093c3f3bb..0000000000 --- a/integration-tests/emulated/chains/relays/polkadot/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub mod genesis; - -// Cumulus -use emulated_integration_tests_common::{ - impl_accounts_helpers_for_relay_chain, impl_assert_events_helpers_for_relay_chain, - impl_hrmp_channels_helpers_for_relay_chain, impl_send_transact_helpers_for_relay_chain, - xcm_emulator::decl_test_relay_chains, -}; - -// Polkadot declaration -decl_test_relay_chains! { - #[api_version(11)] - pub struct Polkadot { - genesis = genesis::genesis(), - on_init = (), - runtime = polkadot_runtime, - core = { - SovereignAccountOf: polkadot_runtime::xcm_config::SovereignAccountOf, - }, - pallets = { - XcmPallet: polkadot_runtime::XcmPallet, - Balances: polkadot_runtime::Balances, - Treasury: polkadot_runtime::Treasury, - AssetRate: polkadot_runtime::AssetRate, - Hrmp: polkadot_runtime::Hrmp, - } - }, -} - -// Polkadot implementation -impl_accounts_helpers_for_relay_chain!(Polkadot); -impl_assert_events_helpers_for_relay_chain!(Polkadot); -impl_hrmp_channels_helpers_for_relay_chain!(Polkadot); -impl_send_transact_helpers_for_relay_chain!(Polkadot); diff --git a/integration-tests/emulated/helpers/Cargo.toml b/integration-tests/emulated/helpers/Cargo.toml deleted file mode 100644 index b5c6401bf9..0000000000 --- a/integration-tests/emulated/helpers/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "integration-tests-helpers" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Emulated integration tests helpers" -publish = false - -[dependencies] -paste = { workspace = true } - -# Substrate -pallet-balances = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } - -# Polkadot -xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } - -# Cumulus -xcm-emulator = { workspace = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } -asset-test-utils = { workspace = true } diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs deleted file mode 100644 index 08bf402e9d..0000000000 --- a/integration-tests/emulated/helpers/src/lib.rs +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use paste; - -// Substrate -pub use pallet_balances; -pub use pallet_message_queue; - -// Polkadot -pub use pallet_xcm; -pub use xcm::prelude::{AccountId32, VersionedAssets, Weight, WeightLimit}; - -// Cumulus -pub use asset_test_utils; -pub use cumulus_pallet_xcmp_queue; -pub use xcm_emulator::Chain; - -/// TODO: when bumping to polkadot-sdk v1.8.0, -/// remove this crate altogether and get the macros from `emulated-integration-tests-common`. -/// TODO: backport this macros to polkadot-sdk -#[macro_export] -macro_rules! test_relay_is_trusted_teleporter { - ( $sender_relay:ty, $sender_xcm_config:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr) ) => { - $crate::paste::paste! { - // init Origin variables - let sender = [<$sender_relay Sender>]::get(); - let mut relay_sender_balance_before = - <$sender_relay as $crate::Chain>::account_data_of(sender.clone()).free; - let fee_asset_item = 0; - let weight_limit = $crate::WeightLimit::Unlimited; - - $( - { - // init Destination variables - let receiver = [<$receiver_para Receiver>]::get(); - let para_receiver_balance_before = - <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; - let para_destination = - <$sender_relay>::child_location_of(<$receiver_para>::para_id()); - let beneficiary: Location = - $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); - - // Dry-run first. - let call = <$sender_relay as Chain>::RuntimeCall::XcmPallet(pallet_xcm::Call::limited_teleport_assets { - dest: bx!(para_destination.clone().into()), - beneficiary: bx!(beneficiary.clone().into()), - assets: bx!($assets.clone().into()), - fee_asset_item: fee_asset_item, - weight_limit: weight_limit.clone(), - }); - let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); - <$sender_relay>::execute_with(|| { - type Runtime = <$sender_relay as Chain>::Runtime; - type OriginCaller = <$sender_relay as Chain>::OriginCaller; - - let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); - let result = Runtime::dry_run_call(origin, call.clone()).unwrap(); - // We filter the result to get only the messages we are interested in. - let (destination_to_query, messages_to_query) = &result - .forwarded_xcms - .iter() - .find(|(destination, _)| { - *destination == VersionedLocation::from(Location::new(0, [Parachain(<$receiver_para>::para_id().into())])) - }) - .unwrap(); - assert_eq!(messages_to_query.len(), 1); - remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); - let latest_delivery_fees: Assets = delivery_fees.clone().try_into().unwrap(); - let Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else { - unreachable!("asset is non-fungible"); - }; - delivery_fees_amount = inner_delivery_fees_amount; - }); - - // Reset to send actual message. - <$sender_relay>::reset_ext(); - <$receiver_para>::reset_ext(); - - // Send XCM message from Relay. - <$sender_relay>::execute_with(|| { - let origin = <$sender_relay as Chain>::RuntimeOrigin::signed(sender.clone()); - assert_ok!(call.dispatch(origin)); - - type RuntimeEvent = <$sender_relay as $crate::Chain>::RuntimeEvent; - - assert_expected_events!( - $sender_relay, - vec![ - RuntimeEvent::XcmPallet( - $crate::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } - ) => {}, - RuntimeEvent::Balances( - $crate::pallet_balances::Event::Burned { who: sender, amount } - ) => {}, - RuntimeEvent::XcmPallet( - $crate::pallet_xcm::Event::Sent { .. } - ) => {}, - ] - ); - }); - - // Receive XCM message in Destination Parachain - <$receiver_para>::execute_with(|| { - type RuntimeEvent = <$receiver_para as $crate::Chain>::RuntimeEvent; - - assert_expected_events!( - $receiver_para, - vec![ - RuntimeEvent::Balances( - $crate::pallet_balances::Event::Minted { who: receiver, .. } - ) => {}, - RuntimeEvent::MessageQueue( - $crate::pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - // Check if balances are updated accordingly in Origin and Parachain - let relay_sender_balance_after = - <$sender_relay as $crate::Chain>::account_data_of(sender.clone()).free; - let para_receiver_balance_after = - <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; - - assert_eq!(relay_sender_balance_before - $amount - delivery_fees_amount, relay_sender_balance_after); - assert!(para_receiver_balance_after > para_receiver_balance_before); - - // Update sender balance - relay_sender_balance_before = <$sender_relay as $crate::Chain>::account_data_of(sender.clone()).free; - } - )+ - } - }; -} - -#[macro_export] -macro_rules! test_parachain_is_trusted_teleporter_for_relay { - ( $sender_para:ty, $sender_xcm_config:ty, $receiver_relay:ty, $amount:expr ) => { - $crate::paste::paste! { - // init Origin variables - let sender = [<$sender_para Sender>]::get(); - // Mint assets to `$sender_para` to succeed with teleport. - <$sender_para>::execute_with(|| { - assert_ok!(<$sender_para as [<$sender_para Pallet>]>::Balances::mint_into( - &sender, - $amount + 10_000_000_000, // Some extra for delivery fees. - )); - }); - let mut para_sender_balance_before = - <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; - let origin = <$sender_para as $crate::Chain>::RuntimeOrigin::signed(sender.clone()); - let assets: Assets = (Parent, $amount).into(); - let fee_asset_item = 0; - let weight_limit = $crate::WeightLimit::Unlimited; - - // We need to mint funds into the checking account of `$receiver_relay` - // for it to accept a teleport from `$sender_para`. - // Else we'd get a `NotWithdrawable` error since it tries to reduce the check account balance, which - // would be 0. - <$receiver_relay>::execute_with(|| { - let check_account = <$receiver_relay as [<$receiver_relay Pallet>]>::XcmPallet::check_account(); - assert_ok!(<$receiver_relay as [<$receiver_relay Pallet>]>::Balances::mint_into( - &check_account, - $amount, - )); - }); - - // Init destination variables. - let receiver = [<$receiver_relay Receiver>]::get(); - let relay_receiver_balance_before = - <$receiver_relay as $crate::Chain>::account_data_of(receiver.clone()).free; - let relay_destination: Location = Parent.into(); - let beneficiary: Location = - $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); - - // Dry-run first. - let call = <$sender_para as Chain>::RuntimeCall::PolkadotXcm(pallet_xcm::Call::limited_teleport_assets { - dest: bx!(relay_destination.clone().into()), - beneficiary: bx!(beneficiary.clone().into()), - assets: bx!(assets.clone().into()), - fee_asset_item: fee_asset_item, - weight_limit: weight_limit.clone(), - }); - // These will be filled in the closure. - let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); - <$sender_para>::execute_with(|| { - type Runtime = <$sender_para as Chain>::Runtime; - type OriginCaller = <$sender_para as Chain>::OriginCaller; - - let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); - let result = Runtime::dry_run_call(origin, call.clone()).unwrap(); - // We filter the result to get only the messages we are interested in. - let (destination_to_query, messages_to_query) = &result - .forwarded_xcms - .iter() - .find(|(destination, _)| { - *destination == VersionedLocation::from(Location::parent()) - }) - .unwrap(); - assert_eq!(messages_to_query.len(), 1); - remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); - let latest_delivery_fees: Assets = delivery_fees.clone().try_into().unwrap(); - delivery_fees_amount = if let Some(first_asset) = latest_delivery_fees.inner().first() { - let Fungible(inner_delivery_fees_amount) = first_asset.fun else { - unreachable!("asset is non-fungible"); - }; - inner_delivery_fees_amount - } else { - 0 - } - }); - - // Reset to send actual message. - <$sender_para>::reset_ext(); - <$receiver_relay>::reset_ext(); - - // Mint assets to `$sender_para` to succeed with teleport. - <$sender_para>::execute_with(|| { - assert_ok!(<$sender_para as [<$sender_para Pallet>]>::Balances::mint_into( - &sender, - $amount + 10_000_000_000, // Some extra for delivery fees. - )); - }); - - // Since we reset everything, we need to mint funds into the checking account again. - <$receiver_relay>::execute_with(|| { - let check_account = <$receiver_relay as [<$receiver_relay Pallet>]>::XcmPallet::check_account(); - assert_ok!(<$receiver_relay as [<$receiver_relay Pallet>]>::Balances::mint_into( - &check_account, - $amount, - )); - }); - - // Send XCM message from Parachain. - <$sender_para>::execute_with(|| { - let origin = <$sender_para as Chain>::RuntimeOrigin::signed(sender.clone()); - assert_ok!(call.dispatch(origin)); - - type RuntimeEvent = <$sender_para as $crate::Chain>::RuntimeEvent; - - assert_expected_events!( - $sender_para, - vec![ - RuntimeEvent::PolkadotXcm( - $crate::pallet_xcm::Event::Attempted { outcome: Outcome::Complete { .. } } - ) => {}, - RuntimeEvent::Balances( - $crate::pallet_balances::Event::Burned { who: sender, amount } - ) => {}, - RuntimeEvent::PolkadotXcm( - $crate::pallet_xcm::Event::Sent { .. } - ) => {}, - ] - ); - }); - - // Receive XCM message in Destination Parachain - <$receiver_relay>::execute_with(|| { - type RuntimeEvent = <$receiver_relay as $crate::Chain>::RuntimeEvent; - - assert_expected_events!( - $receiver_relay, - vec![ - RuntimeEvent::Balances( - $crate::pallet_balances::Event::Minted { who: receiver, .. } - ) => {}, - RuntimeEvent::MessageQueue( - $crate::pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - // Check if balances are updated accordingly in Origin and Relay Chain - let para_sender_balance_after = - <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; - let relay_receiver_balance_after = - <$receiver_relay as $crate::Chain>::account_data_of(receiver.clone()).free; - - assert_eq!(para_sender_balance_before - $amount - delivery_fees_amount, para_sender_balance_after); - assert!(relay_receiver_balance_after > relay_receiver_balance_before); - - // Update sender balance - para_sender_balance_before = <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; - } - }; -} - -#[macro_export] -macro_rules! test_chain_can_claim_assets { - ( $sender_para:ty, $runtime_call:ty, $network_id:expr, $assets:expr, $amount:expr ) => { - $crate::paste::paste! { - let sender = [<$sender_para Sender>]::get(); - let origin = <$sender_para as $crate::Chain>::RuntimeOrigin::signed(sender.clone()); - // Receiver is the same as sender - let beneficiary: Location = - $crate::AccountId32 { network: Some($network_id), id: sender.clone().into() }.into(); - let versioned_assets: $crate::VersionedAssets = $assets.clone().into(); - - <$sender_para>::execute_with(|| { - // Assets are trapped for whatever reason. - // The possible reasons for this might differ from runtime to runtime, so here we just drop them directly. - <$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::drop_assets( - &beneficiary, - $assets.clone().into(), - &XcmContext { origin: None, message_id: [0u8; 32], topic: None }, - ); - - type RuntimeEvent = <$sender_para as $crate::Chain>::RuntimeEvent; - assert_expected_events!( - $sender_para, - vec![ - RuntimeEvent::PolkadotXcm( - $crate::pallet_xcm::Event::AssetsTrapped { origin: beneficiary, assets: versioned_assets, .. } - ) => {}, - ] - ); - - let balance_before = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&sender); - - // Different origin or different assets won't work. - let other_origin = <$sender_para as $crate::Chain>::RuntimeOrigin::signed([<$sender_para Receiver>]::get()); - assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( - other_origin, - bx!(versioned_assets.clone().into()), - bx!(beneficiary.clone().into()), - ).is_err()); - let other_versioned_assets: $crate::VersionedAssets = Assets::new().into(); - assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( - origin.clone(), - bx!(other_versioned_assets.into()), - bx!(beneficiary.clone().into()), - ).is_err()); - - // Assets will be claimed to `beneficiary`, which is the same as `sender`. - assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( - origin.clone(), - bx!(versioned_assets.clone().into()), - bx!(beneficiary.clone().into()), - )); - - assert_expected_events!( - $sender_para, - vec![ - RuntimeEvent::PolkadotXcm( - $crate::pallet_xcm::Event::AssetsClaimed { origin: beneficiary, assets: versioned_assets, .. } - ) => {}, - ] - ); - - // After claiming the assets, the balance has increased. - let balance_after = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&sender); - assert_eq!(balance_after, balance_before + $amount); - - // Claiming the assets again doesn't work. - assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( - origin.clone(), - bx!(versioned_assets.clone().into()), - bx!(beneficiary.clone().into()), - ).is_err()); - - let balance = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&sender); - assert_eq!(balance, balance_after); - - // You can also claim assets and send them to a different account. - <$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::drop_assets( - &beneficiary, - $assets.clone().into(), - &XcmContext { origin: None, message_id: [0u8; 32], topic: None }, - ); - let receiver = [<$sender_para Receiver>]::get(); - let other_beneficiary: Location = - $crate::AccountId32 { network: Some($network_id), id: receiver.clone().into() }.into(); - let balance_before = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&receiver); - assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets( - origin.clone(), - bx!(versioned_assets.clone().into()), - bx!(other_beneficiary.clone().into()), - )); - let balance_after = <$sender_para as [<$sender_para Pallet>]>::Balances::free_balance(&receiver); - assert_eq!(balance_after, balance_before + $amount); - }); - } - }; -} diff --git a/integration-tests/emulated/networks/kusama-polkadot-system/Cargo.toml b/integration-tests/emulated/networks/kusama-polkadot-system/Cargo.toml deleted file mode 100644 index 04781b34cd..0000000000 --- a/integration-tests/emulated/networks/kusama-polkadot-system/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "kusama-polkadot-system-emulated-network" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Kusama<>Polkadot emulated bridged network" -publish = false - -[dependencies] - -# Cumulus -emulated-integration-tests-common = { workspace = true } - -# Runtimes -asset-hub-kusama-emulated-chain = { workspace = true } -asset-hub-polkadot-emulated-chain = { workspace = true } -bridge-hub-kusama-emulated-chain = { workspace = true } -bridge-hub-polkadot-emulated-chain = { workspace = true } -kusama-emulated-chain = { workspace = true } -penpal-emulated-chain = { workspace = true } -polkadot-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/networks/kusama-polkadot-system/src/lib.rs b/integration-tests/emulated/networks/kusama-polkadot-system/src/lib.rs deleted file mode 100644 index eebf786e02..0000000000 --- a/integration-tests/emulated/networks/kusama-polkadot-system/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use asset_hub_kusama_emulated_chain; -pub use asset_hub_polkadot_emulated_chain; -pub use bridge_hub_kusama_emulated_chain; -pub use bridge_hub_polkadot_emulated_chain; -pub use kusama_emulated_chain; -pub use penpal_emulated_chain; -pub use polkadot_emulated_chain; - -use asset_hub_kusama_emulated_chain::AssetHubKusama; -use asset_hub_polkadot_emulated_chain::AssetHubPolkadot; -use bridge_hub_kusama_emulated_chain::BridgeHubKusama; -use bridge_hub_polkadot_emulated_chain::BridgeHubPolkadot; -use kusama_emulated_chain::Kusama; -use penpal_emulated_chain::{PenpalA, PenpalB}; -use polkadot_emulated_chain::Polkadot; - -// Cumulus -use emulated_integration_tests_common::{ - accounts::{ALICE, BOB}, - impls::{BridgeHubMessageHandler, BridgeMessagesInstance1}, - xcm_emulator::{ - decl_test_bridges, decl_test_networks, decl_test_sender_receiver_accounts_parameter_types, - Chain, - }, -}; - -decl_test_networks! { - pub struct KusamaMockNet { - relay_chain = Kusama, - parachains = vec![ - AssetHubKusama, - BridgeHubKusama, - PenpalA, - ], - bridge = KusamaPolkadotMockBridge - - }, - pub struct PolkadotMockNet { - relay_chain = Polkadot, - parachains = vec![ - AssetHubPolkadot, - BridgeHubPolkadot, - PenpalB, - ], - bridge = PolkadotKusamaMockBridge - }, -} - -decl_test_bridges! { - pub struct KusamaPolkadotMockBridge { - source = BridgeHubKusamaPara, - target = BridgeHubPolkadotPara, - handler = KusamaPolkadotMessageHandler - }, - pub struct PolkadotKusamaMockBridge { - source = BridgeHubPolkadotPara, - target = BridgeHubKusamaPara, - handler = PolkadotKusamaMessageHandler - } -} - -type BridgeHubKusamaRuntime = ::Runtime; -type BridgeHubPolkadotRuntime = ::Runtime; - -pub type KusamaPolkadotMessageHandler = BridgeHubMessageHandler< - BridgeHubKusamaRuntime, - BridgeMessagesInstance1, - BridgeHubPolkadotRuntime, - BridgeMessagesInstance1, ->; -pub type PolkadotKusamaMessageHandler = BridgeHubMessageHandler< - BridgeHubPolkadotRuntime, - BridgeMessagesInstance1, - BridgeHubKusamaRuntime, - BridgeMessagesInstance1, ->; - -decl_test_sender_receiver_accounts_parameter_types! { - KusamaRelay { sender: ALICE, receiver: BOB }, - AssetHubKusamaPara { sender: ALICE, receiver: BOB }, - BridgeHubKusamaPara { sender: ALICE, receiver: BOB }, - PolkadotRelay { sender: ALICE, receiver: BOB }, - AssetHubPolkadotPara { sender: ALICE, receiver: BOB }, - BridgeHubPolkadotPara { sender: ALICE, receiver: BOB }, - PenpalAPara { sender: ALICE, receiver: BOB }, - PenpalBPara { sender: ALICE, receiver: BOB } -} diff --git a/integration-tests/emulated/networks/kusama-system/Cargo.toml b/integration-tests/emulated/networks/kusama-system/Cargo.toml deleted file mode 100644 index 4f8c90bded..0000000000 --- a/integration-tests/emulated/networks/kusama-system/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "kusama-system-emulated-network" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Kusama System emulated network" -publish = false - -[dependencies] - -# Cumulus -emulated-integration-tests-common = { workspace = true } - -# Runtimes -asset-hub-kusama-emulated-chain = { workspace = true } -bridge-hub-kusama-emulated-chain = { workspace = true } -kusama-emulated-chain = { workspace = true } -penpal-emulated-chain = { workspace = true } -people-kusama-emulated-chain = { workspace = true } -coretime-kusama-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/networks/kusama-system/src/lib.rs b/integration-tests/emulated/networks/kusama-system/src/lib.rs deleted file mode 100644 index ed785d60af..0000000000 --- a/integration-tests/emulated/networks/kusama-system/src/lib.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use asset_hub_kusama_emulated_chain; -pub use bridge_hub_kusama_emulated_chain; -pub use coretime_kusama_emulated_chain; -pub use kusama_emulated_chain; -pub use penpal_emulated_chain; -pub use people_kusama_emulated_chain; - -use asset_hub_kusama_emulated_chain::AssetHubKusama; -use bridge_hub_kusama_emulated_chain::BridgeHubKusama; -use coretime_kusama_emulated_chain::CoretimeKusama; -use kusama_emulated_chain::Kusama; -use penpal_emulated_chain::{PenpalA, PenpalB}; -use people_kusama_emulated_chain::PeopleKusama; - -// Cumulus -use emulated_integration_tests_common::{ - accounts::{ALICE, BOB}, - xcm_emulator::{decl_test_networks, decl_test_sender_receiver_accounts_parameter_types}, -}; - -decl_test_networks! { - pub struct KusamaMockNet { - relay_chain = Kusama, - parachains = vec![ - AssetHubKusama, - BridgeHubKusama, - PenpalA, - PenpalB, - PeopleKusama, - CoretimeKusama, - ], - bridge = () - }, -} - -decl_test_sender_receiver_accounts_parameter_types! { - KusamaRelay { sender: ALICE, receiver: BOB }, - AssetHubKusamaPara { sender: ALICE, receiver: BOB }, - BridgeHubKusamaPara { sender: ALICE, receiver: BOB }, - PenpalAPara { sender: ALICE, receiver: BOB }, - PenpalBPara { sender: ALICE, receiver: BOB }, - PeopleKusamaPara { sender: ALICE, receiver: BOB }, - CoretimeKusamaPara { sender: ALICE, receiver: BOB } -} diff --git a/integration-tests/emulated/networks/polkadot-system/Cargo.toml b/integration-tests/emulated/networks/polkadot-system/Cargo.toml deleted file mode 100644 index 592aad9520..0000000000 --- a/integration-tests/emulated/networks/polkadot-system/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "polkadot-system-emulated-network" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Polkadot System emulated network" -publish = false - -[dependencies] - -# Cumulus -emulated-integration-tests-common = { workspace = true } - -# Runtimes -asset-hub-polkadot-emulated-chain = { workspace = true } -bridge-hub-polkadot-emulated-chain = { workspace = true } -collectives-polkadot-emulated-chain = { workspace = true } -coretime-polkadot-emulated-chain = { workspace = true } -penpal-emulated-chain = { workspace = true } -polkadot-emulated-chain = { workspace = true } -people-polkadot-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/networks/polkadot-system/src/lib.rs b/integration-tests/emulated/networks/polkadot-system/src/lib.rs deleted file mode 100644 index 57fcb8a7b3..0000000000 --- a/integration-tests/emulated/networks/polkadot-system/src/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use asset_hub_polkadot_emulated_chain; -pub use bridge_hub_polkadot_emulated_chain; -pub use collectives_polkadot_emulated_chain; -pub use coretime_polkadot_emulated_chain; -pub use penpal_emulated_chain; -pub use people_polkadot_emulated_chain; -pub use polkadot_emulated_chain; - -use asset_hub_polkadot_emulated_chain::AssetHubPolkadot; -use bridge_hub_polkadot_emulated_chain::BridgeHubPolkadot; -use collectives_polkadot_emulated_chain::CollectivesPolkadot; -use coretime_polkadot_emulated_chain::CoretimePolkadot; -use penpal_emulated_chain::{PenpalA, PenpalB}; -use people_polkadot_emulated_chain::PeoplePolkadot; -use polkadot_emulated_chain::Polkadot; - -// Cumulus -use emulated_integration_tests_common::{ - accounts::{ALICE, BOB}, - xcm_emulator::{decl_test_networks, decl_test_sender_receiver_accounts_parameter_types}, -}; - -decl_test_networks! { - pub struct PolkadotMockNet { - relay_chain = Polkadot, - parachains = vec![ - AssetHubPolkadot, - BridgeHubPolkadot, - CollectivesPolkadot, - CoretimePolkadot, - PenpalA, - PenpalB, - PeoplePolkadot, - ], - bridge = () - }, -} - -decl_test_sender_receiver_accounts_parameter_types! { - PolkadotRelay { sender: ALICE, receiver: BOB }, - AssetHubPolkadotPara { sender: ALICE, receiver: BOB }, - BridgeHubPolkadotPara { sender: ALICE, receiver: BOB }, - CollectivesPolkadotPara { sender: ALICE, receiver: BOB }, - CoretimePolkadotPara { sender: ALICE, receiver: BOB }, - PenpalAPara { sender: ALICE, receiver: BOB }, - PenpalBPara { sender: ALICE, receiver: BOB }, - PeoplePolkadotPara { sender: ALICE, receiver: BOB } -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml b/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml deleted file mode 100644 index 461c279945..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "asset-hub-kusama-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Kusama runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } -assert_matches = { workspace = true } - -# Substrate -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-asset-conversion = { workspace = true, default-features = true } -pallet-treasury = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } - -# Polkadot -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true } -pallet-xcm = { workspace = true, default-features = true } -polkadot-runtime-common = { workspace = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -asset-test-utils = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -asset-hub-kusama-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -kusama-runtime = { workspace = true } -kusama-system-emulated-network = { workspace = true } -system-parachains-constants = { workspace = true, default-features = true } -kusama-runtime-constants = { workspace = true, default-features = true } diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs deleted file mode 100644 index af4c48a3d0..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - dispatch::RawOrigin, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; -pub use sp_runtime::traits::Dispatchable; - -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v4::{self, Error, NetworkId::Kusama as KusamaId}, -}; -pub use xcm_executor::traits::TransferType; - -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, RESERVABLE_ASSET_ID, XCM_V4, -}; -pub use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -pub use kusama_runtime::xcm_config::UniversalLocation as KusamaUniversalLocation; -pub use kusama_system_emulated_network::{ - asset_hub_kusama_emulated_chain::{ - genesis::{AssetHubKusamaAssetOwner, ED as ASSET_HUB_KUSAMA_ED}, - AssetHubKusamaParaPallet as AssetHubKusamaPallet, - }, - kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, - penpal_emulated_chain::{ - CustomizableAssetFromSystemAssetHub, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, - PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, - }, - AssetHubKusamaPara as AssetHubKusama, AssetHubKusamaParaReceiver as AssetHubKusamaReceiver, - AssetHubKusamaParaSender as AssetHubKusamaSender, BridgeHubKusamaPara as BridgeHubKusama, - BridgeHubKusamaParaReceiver as BridgeHubKusamaReceiver, KusamaRelay as Kusama, - KusamaRelayReceiver as KusamaReceiver, KusamaRelaySender as KusamaSender, - PenpalAPara as PenpalA, PenpalAParaReceiver as PenpalAReceiver, - PenpalAParaSender as PenpalASender, PenpalBPara as PenpalB, - PenpalBParaReceiver as PenpalBReceiver, -}; -pub use parachains_common::{AccountId, Balance}; - -pub const ASSET_ID: u32 = 3; -pub const ASSET_MIN_BALANCE: u128 = 1000; -// `Assets` pallet index -pub const ASSETS_PALLET_ID: u8 = 50; - -pub type RelayToParaTest = Test; -pub type ParaToRelayTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; -pub type ParaToParaThroughRelayTest = Test; -pub type ParaToParaThroughAHTest = Test; -pub type RelayToParaThroughAHTest = Test; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/claim_assets.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/claim_assets.rs deleted file mode 100644 index a08bc885c0..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/claim_assets.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests related to claiming assets trapped during XCM execution. - -use crate::*; - -use asset_hub_kusama_runtime::ExistentialDeposit; -use integration_tests_helpers::test_chain_can_claim_assets; -use xcm_executor::traits::DropAssets; - -#[test] -fn assets_can_be_claimed() { - let amount = ExistentialDeposit::get(); - let assets: Assets = (Parent, amount).into(); - - test_chain_can_claim_assets!(AssetHubKusama, RuntimeCall, NetworkId::Kusama, assets, amount); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs deleted file mode 100644 index 125883cbe8..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/hybrid_transfers.rs +++ /dev/null @@ -1,790 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::reserve_transfer::*; -use crate::{ - tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt, - *, -}; -use asset_hub_kusama_runtime::xcm_config::KsmLocation; - -fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_a_on_ah = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - let sov_penpal_b_on_ah = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalB::para_id()), - ); - - assert_expected_events!( - AssetHubKusama, - vec![ - // Withdrawn from sender parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_a_on_ah, - amount: *amount == t.args.amount, - }, - // Deposited to receiver parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Minted { who, .. } - ) => { - who: *who == sov_penpal_b_on_ah, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::LocalReserve), - bx!(fee.id.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::DestinationReserve), - bx!(fee.id.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(fee.id.into()), - bx!(TransferType::RemoteReserve(asset_hub_location.into())), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::Teleport), - bx!(fee.id.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::Teleport), - bx!(fee.id.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -// =========================================================================== -// ======= Transfer - Native + Bridged Assets - AssetHub->Parachain ========== -// =========================================================================== -/// Transfers of native asset plus bridged asset from AssetHub to some Parachain -/// while paying fees using native asset. -#[test] -fn transfer_foreign_assets_from_asset_hub_to_para() { - let destination = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sender = AssetHubKusamaSender::get(); - let native_amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; - let native_asset_location = KsmLocation::get(); - let receiver = PenpalAReceiver::get(); - let assets_owner = PenpalAssetOwner::get(); - // Foreign asset used: bridged DOT - let foreign_amount_to_send = ASSET_HUB_KUSAMA_ED * 10_000_000; - let dot_at_kusama_parachains = Location::new(2, [GlobalConsensus(Polkadot)]); - - // Configure destination chain to trust AH as reserve of DOT - PenpalA::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Polkadot)]).encode(), - )], - )); - }); - PenpalA::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - AssetHubKusama::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - AssetHubKusama::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner), - dot_at_kusama_parachains.clone(), - sender.clone(), - foreign_amount_to_send * 2, - ); - - // Assets to send - let assets: Vec = vec![ - (Parent, native_amount_to_send).into(), - (dot_at_kusama_parachains.clone(), foreign_amount_to_send).into(), - ]; - let fee_asset_id = AssetId(Parent.into()); - let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - native_amount_to_send, - assets.into(), - None, - fee_asset_item, - ), - }; - let mut test = SystemParaToParaTest::new(test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let sender_dots_before = AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location.clone(), &receiver) - }); - let receiver_dots_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(system_para_to_para_receiver_assertions); - test.set_dispatchable::(ah_to_para_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let sender_dots_after = AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location, &receiver) - }); - let receiver_dots_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - native_amount_to_send); - // Sender's balance is reduced by foreign amount sent - assert_eq!(sender_dots_after, sender_dots_before - foreign_amount_to_send); - // Receiver's assets is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + native_amount_to_send); - // Receiver's balance is increased by foreign amount sent - assert_eq!(receiver_dots_after, receiver_dots_before + foreign_amount_to_send); -} - -/// Reserve Transfers of native asset from Parachain to System Parachain should work -// =========================================================================== -// ======= Transfer - Native + Bridged Assets - Parachain->AssetHub ========== -// =========================================================================== -/// Transfers of native asset plus bridged asset from some Parachain to AssetHub -/// while paying fees using native asset. -#[test] -fn transfer_foreign_assets_from_para_to_asset_hub() { - // Init values for Parachain - let destination = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let sender = PenpalASender::get(); - let native_amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; - let native_asset_location = KsmLocation::get(); - let assets_owner = PenpalAssetOwner::get(); - - // Foreign asset used: bridged DOT - let foreign_amount_to_send = ASSET_HUB_KUSAMA_ED * 10_000_000; - let dot_at_kusama_parachains = Location::new(2, [GlobalConsensus(Polkadot)]); - - // Configure destination chain to trust AH as reserve of DOT - PenpalA::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Polkadot)]).encode(), - )], - )); - }); - PenpalA::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - AssetHubKusama::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - native_asset_location.clone(), - sender.clone(), - native_amount_to_send * 2, - ); - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - dot_at_kusama_parachains.clone(), - sender.clone(), - foreign_amount_to_send * 2, - ); - - // Init values for System Parachain - let receiver = AssetHubKusamaReceiver::get(); - let penpal_location_as_seen_by_ahk = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of(penpal_location_as_seen_by_ahk); - - // fund Parachain's SA on AssetHub with the assets held in reserve - AssetHubKusama::fund_accounts(vec![(sov_penpal_on_ahk.clone(), native_amount_to_send * 2)]); - AssetHubKusama::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner), - dot_at_kusama_parachains.clone(), - sov_penpal_on_ahk, - foreign_amount_to_send * 2, - ); - - // Assets to send - let assets: Vec = vec![ - (Parent, native_amount_to_send).into(), - (dot_at_kusama_parachains.clone(), foreign_amount_to_send).into(), - ]; - let fee_asset_id = AssetId(Parent.into()); - let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - native_amount_to_send, - assets.into(), - None, - fee_asset_item, - ), - }; - let mut test = ParaToSystemParaTest::new(test_args); - - // Query initial balances - let sender_native_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location.clone(), &sender) - }); - let sender_dots_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let receiver_native_before = test.receiver.balance; - let receiver_dots_before = AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_system_para_sender_assertions); - test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_ah_transfer_assets); - test.assert(); - - // Query final balances - let sender_native_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location, &sender) - }); - let sender_dots_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let receiver_native_after = test.receiver.balance; - let receiver_dots_after = AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_native_after < sender_native_before - native_amount_to_send); - // Sender's balance is reduced by foreign amount sent - assert_eq!(sender_dots_after, sender_dots_before - foreign_amount_to_send); - // Receiver's balance is increased - assert!(receiver_native_after > receiver_native_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_native_after < receiver_native_before + native_amount_to_send); - // Receiver's balance is increased by foreign amount sent - assert_eq!(receiver_dots_after, receiver_dots_before + foreign_amount_to_send); -} - -// ============================================================================== -// ===== Transfer - Native + Bridged Assets - Parachain->AssetHub->Parachain ==== -// ============================================================================== -/// Transfers of native asset plus bridged asset from Parachain to Parachain -/// (through AssetHub reserve) with fees paid using native asset. -#[test] -fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { - // Init values for Parachain Origin - let destination = PenpalA::sibling_location_of(PenpalB::para_id()); - let sender = PenpalASender::get(); - let ksm_to_send: Balance = KUSAMA_ED * 10000; - let assets_owner = PenpalAssetOwner::get(); - let ksm_location = KsmLocation::get(); - let sender_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_of_sender_on_ah = AssetHubKusama::sovereign_account_id_of(sender_as_seen_by_ah); - let receiver_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalB::para_id()); - let sov_of_receiver_on_ah = AssetHubKusama::sovereign_account_id_of(receiver_as_seen_by_ah); - let dot_to_send = ASSET_HUB_KUSAMA_ED * 10_000_000; - - // Configure source and destination chains to trust AH as reserve of DOT - PenpalA::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Polkadot)]).encode(), - )], - )); - }); - PenpalB::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Polkadot)]).encode(), - )], - )); - }); - - // Register DOT as foreign asset and transfer it around the Kusama ecosystem - let dot_at_kusama_parachains = Location::new(2, [GlobalConsensus(Polkadot)]); - AssetHubKusama::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - PenpalA::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - PenpalB::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - ksm_location.clone(), - sender.clone(), - ksm_to_send * 2, - ); - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - dot_at_kusama_parachains.clone(), - sender.clone(), - dot_to_send * 2, - ); - // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve - AssetHubKusama::fund_accounts(vec![(sov_of_sender_on_ah.clone(), ksm_to_send * 2)]); - AssetHubKusama::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner), - dot_at_kusama_parachains.clone(), - sov_of_sender_on_ah.clone(), - dot_to_send * 2, - ); - - // Init values for Parachain Destination - let receiver = PenpalBReceiver::get(); - - // Assets to send - let assets: Vec = vec![ - (ksm_location.clone(), ksm_to_send).into(), - (dot_at_kusama_parachains.clone(), dot_to_send).into(), - ]; - let fee_asset_id: AssetId = ksm_location.clone().into(); - let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination, - receiver.clone(), - ksm_to_send, - assets.into(), - None, - fee_asset_item, - ), - }; - let mut test = ParaToParaThroughAHTest::new(test_args); - - // Query initial balances - let sender_ksms_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_location.clone(), &sender) - }); - let sender_dots_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let ksms_in_sender_reserve_on_ahk_before = - ::account_data_of(sov_of_sender_on_ah.clone()).free; - let dots_in_sender_reserve_on_ahk_before = AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sov_of_sender_on_ah) - }); - let ksms_in_receiver_reserve_on_ahk_before = - ::account_data_of(sov_of_receiver_on_ah.clone()).free; - let dots_in_receiver_reserve_on_ahk_before = AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sov_of_receiver_on_ah) - }); - let receiver_ksms_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_location.clone(), &receiver) - }); - let receiver_dots_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_para_through_hop_sender_assertions); - test.set_assertion::(para_to_para_assethub_hop_assertions); - test.set_assertion::(para_to_para_through_hop_receiver_assertions); - test.set_dispatchable::(para_to_para_transfer_assets_through_ah); - test.assert(); - - // Query final balances - let sender_ksms_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_location.clone(), &sender) - }); - let sender_dots_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let dots_in_sender_reserve_on_ahk_after = AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sov_of_sender_on_ah) - }); - let ksms_in_sender_reserve_on_ahk_after = - ::account_data_of(sov_of_sender_on_ah).free; - let dots_in_receiver_reserve_on_ahk_after = AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sov_of_receiver_on_ah) - }); - let ksms_in_receiver_reserve_on_ahk_after = - ::account_data_of(sov_of_receiver_on_ah).free; - let receiver_ksms_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_location, &receiver) - }); - let receiver_dots_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_ksms_after < sender_ksms_before - ksm_to_send); - assert_eq!(sender_dots_after, sender_dots_before - dot_to_send); - // Sovereign accounts on reserve are changed accordingly - assert_eq!( - ksms_in_sender_reserve_on_ahk_after, - ksms_in_sender_reserve_on_ahk_before - ksm_to_send - ); - assert_eq!( - dots_in_sender_reserve_on_ahk_after, - dots_in_sender_reserve_on_ahk_before - dot_to_send - ); - assert!(ksms_in_receiver_reserve_on_ahk_after > ksms_in_receiver_reserve_on_ahk_before); - assert_eq!( - dots_in_receiver_reserve_on_ahk_after, - dots_in_receiver_reserve_on_ahk_before + dot_to_send - ); - // Receiver's balance is increased - assert!(receiver_ksms_after > receiver_ksms_before); - assert_eq!(receiver_dots_after, receiver_dots_before + dot_to_send); -} - -// ============================================================================================== -// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Parachain<->AssetHub ==== -// ============================================================================================== -/// Transfers of native asset plus teleportable foreign asset from Parachain to AssetHub and back -/// with fees paid using native asset. -#[test] -fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explicit_transfer_types() { - do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( - para_to_asset_hub_teleport_foreign_assets, - asset_hub_to_para_teleport_foreign_assets, - ); -} - -// =============================================================== -// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== -// =============================================================== -/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid -/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their -/// Sovereign Account on Asset Hub. -#[test] -fn transfer_native_asset_from_relay_to_para_through_asset_hub() { - // Init values for Relay - let destination = Kusama::child_location_of(PenpalA::para_id()); - let sender = KusamaSender::get(); - let amount_to_send: Balance = KUSAMA_ED * 1000; - - // Init values for Parachain - let relay_native_asset_location = KsmLocation::get(); - let receiver = PenpalAReceiver::get(); - - // Init Test - let test_args = TestContext { - sender, - receiver: receiver.clone(), - args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), - }; - let mut test = RelayToParaThroughAHTest::new(test_args); - - let sov_penpal_on_ah = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - // Query initial balances - let sender_balance_before = test.sender.balance; - let sov_penpal_on_ah_before = AssetHubKusama::execute_with(|| { - ::Balances::free_balance(sov_penpal_on_ah.clone()) - }); - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); - - fn relay_assertions(t: RelayToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - Kusama, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); - } - fn asset_hub_assertions(_: RelayToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ah = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - assert_expected_events!( - AssetHubKusama, - vec![ - // Deposited to receiver parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Minted { who, .. } - ) => { - who: *who == sov_penpal_on_ah, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - } - fn penpal_assertions(t: RelayToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let expected_id = t.args.assets.into_inner().first().unwrap().id.0.clone(); - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.receiver.account_id, - }, - ] - ); - } - fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let asset_hub_location = Kusama::child_location_of(AssetHubKusama::para_id()); - let context = KusamaUniversalLocation::get(); - - // reanchor fees to the view of destination (Penpal) - let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); - if let Fungible(ref mut amount) = remote_fees.fun { - // we already spent some fees along the way, just use half of what we started with - *amount /= 2; - } - let xcm_on_final_dest = Xcm::<()>(vec![ - BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, - DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }, - ]); - - // reanchor final dest (Penpal) to the view of hop (Asset Hub) - let mut dest = t.args.dest.clone(); - dest.reanchor(&asset_hub_location, &context).unwrap(); - // on Asset Hub, forward assets to Penpal - let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - dest, - xcm: xcm_on_final_dest, - }]); - - // First leg is a teleport, from there a local-reserve-transfer to final dest - ::XcmPallet::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(asset_hub_location.into()), - bx!(t.args.assets.into()), - bx!(TransferType::Teleport), - bx!(fee.id.into()), - bx!(TransferType::Teleport), - bx!(VersionedXcm::from(xcm_on_hop)), - t.args.weight_limit, - ) - } - - // Set assertions and dispatchables - test.set_assertion::(relay_assertions); - test.set_assertion::(asset_hub_assertions); - test.set_assertion::(penpal_assertions); - test.set_dispatchable::(transfer_assets_dispatchable); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let sov_penpal_on_ah_after = AssetHubKusama::execute_with(|| { - ::Balances::free_balance(sov_penpal_on_ah) - }); - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - amount_to_send); - // SA on AH balance is increased - assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before); - // Receiver's asset balance is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + amount_to_send); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs deleted file mode 100644 index 88fa379c40..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod claim_assets; -mod hybrid_transfers; -mod reserve_transfer; -mod send; -mod set_xcm_versions; -mod swap; -mod teleport; -mod treasury; -mod xcm_fee_estimation; diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs deleted file mode 100644 index e3f9b2af88..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/reserve_transfer.rs +++ /dev/null @@ -1,1112 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_kusama_runtime::xcm_config::KsmLocation; -use kusama_system_emulated_network::penpal_emulated_chain::LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub; - -fn relay_to_para_sender_assertions(t: RelayToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); - - assert_expected_events!( - Kusama, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == Kusama::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn para_to_relay_sender_assertions(t: ParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance, .. } - ) => { - asset_id: *asset_id == KsmLocation::get(), - owner: *owner == t.sender.account_id, - balance: *balance == t.args.amount, - }, - ] - ); -} - -pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 864_610_000, - 8_799, - ))); - - assert_expected_events!( - AssetHubKusama, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubKusama::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalB::assert_xcmp_queue_success(None); - for asset in t.args.assets.into_inner().into_iter() { - let expected_id = asset.id.0; - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.receiver.account_id, - }, - ] - ); - } -} - -fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == KsmLocation::get(), - owner: *owner == t.receiver.account_id, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -fn para_to_relay_receiver_assertions(t: ParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_relay = - Kusama::sovereign_account_id_of(Kusama::child_location_of(PenpalA::para_id())); - - Kusama::assert_ump_queue_processed(true, Some(PenpalA::para_id()), None); - assert_expected_events!( - Kusama, - vec![ - // Amount to reserve transfer is withdrawn from Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_relay.clone(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -pub fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalA::assert_xcm_pallet_attempted_complete(None); - for asset in t.args.assets.into_inner().into_iter() { - let expected_id = asset.id.0; - let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance } - ) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.sender.account_id, - balance: *balance == asset_amount, - }, - ] - ); - } -} - -pub fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - - assert_expected_events!( - AssetHubKusama, - vec![ - // Amount to reserve transfer is withdrawn from Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahk.clone(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 864_610_000, - 8799, - ))); - assert_expected_events!( - AssetHubKusama, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Assets( - pallet_assets::Event::Transferred { asset_id, from, to, amount } - ) => { - asset_id: *asset_id == RESERVABLE_ASSET_ID, - from: *from == t.sender.account_id, - to: *to == AssetHubKusama::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - // Native asset to pay for fees is transferred to Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == AssetHubKusama::sovereign_account_id_of( - t.args.dest.clone() - ), - }, - // Transport fees are paid - RuntimeEvent::PolkadotXcm( - pallet_xcm::Event::FeesPaid { .. } - ) => {}, - ] - ); -} - -fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = KsmLocation::get(); - let reservable_asset_location = PenpalLocalReservableFromAssetHub::get(); - PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); - assert_expected_events!( - PenpalA, - vec![ - // Fees amount to reserve transfer is burned from Parachains's sender account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, .. } - ) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.sender.account_id, - }, - // Amount to reserve transfer is burned from Parachains's sender account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance } - ) => { - asset_id: *asset_id == reservable_asset_location, - owner: *owner == t.sender.account_id, - balance: *balance == t.args.amount, - }, - // Transport fees are paid - RuntimeEvent::PolkadotXcm( - pallet_xcm::Event::FeesPaid { .. } - ) => {}, - ] - ); -} - -fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - let system_para_asset_location = PenpalLocalReservableFromAssetHub::get(); - PenpalA::assert_xcmp_queue_success(None); - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == KsmLocation::get(), - owner: *owner == t.receiver.account_id, - }, - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == system_para_asset_location, - owner: *owner == t.receiver.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn para_to_system_para_assets_receiver_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - AssetHubKusama::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubKusama, - vec![ - // Amount to reserve transfer is burned from Parachain's Sovereign account - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == RESERVABLE_ASSET_ID, - owner: *owner == sov_penpal_on_ahr, - balance: *balance == t.args.amount, - }, - // Fee amount is burned from Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, .. }) => { - who: *who == sov_penpal_on_ahr, - }, - // Amount to reserve transfer is issued for beneficiary - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == RESERVABLE_ASSET_ID, - owner: *owner == t.receiver.account_id, - amount: *amount == t.args.amount, - }, - // Remaining fee amount is minted for for beneficiary - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -pub fn para_to_para_through_hop_sender_assertions(t: Test) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalA::assert_xcm_pallet_attempted_complete(None); - for asset in t.args.assets.into_inner() { - let expected_id = asset.id.0.clone(); - let amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance }, - ) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.sender.account_id, - balance: *balance == amount, - }, - ] - ); - } -} - -fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_a_on_kusama = - Kusama::sovereign_account_id_of(Kusama::child_location_of(PenpalA::para_id())); - let sov_penpal_b_on_kusama = - Kusama::sovereign_account_id_of(Kusama::child_location_of(PenpalB::para_id())); - assert_expected_events!( - Kusama, - vec![ - // Withdrawn from sender parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } | pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_a_on_kusama, - amount: *amount == t.args.amount, - }, - // Deposited to receiver parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Deposit { who, .. } | pallet_balances::Event::Minted { who, .. } - ) => { - who: *who == sov_penpal_b_on_kusama, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -pub fn para_to_para_through_hop_receiver_assertions(t: Test) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalB::assert_xcmp_queue_success(None); - for asset in t.args.assets.into_inner().into_iter() { - let expected_id = asset.id.0; - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.receiver.account_id, - }, - ] - ); - } -} - -fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { - ::XcmPallet::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_relay_reserve_transfer_assets(t: ParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_para_through_relay_limited_reserve_transfer_assets( - t: ParaToParaThroughRelayTest, -) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -/// Reserve Transfers of KSM from Relay Chain to the Asset Hub shouldn't work -#[test] -fn reserve_transfer_ksm_from_relay_to_asset_hub_fails() { - let signed_origin = ::RuntimeOrigin::signed(KusamaSender::get()); - let destination = Kusama::child_location_of(AssetHubKusama::para_id()); - let beneficiary: Location = - AccountId32Junction { network: None, id: AssetHubKusamaReceiver::get().into() }.into(); - let amount_to_send: Balance = KUSAMA_ED * 1000; - let assets: Assets = (Here, amount_to_send).into(); - let fee_asset_item = 0; - - // this should fail - Kusama::execute_with(|| { - let result = ::XcmPallet::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ); - assert_err!( - result, - DispatchError::Module(sp_runtime::ModuleError { - index: 99, - error: [2, 0, 0, 0], - message: Some("Filtered") - }) - ); - }); -} - -/// Reserve Transfers of KSM from Asset Hub to Relay Chain shouldn't work -#[test] -fn reserve_transfer_ksm_from_asset_hub_to_relay_fails() { - // Init values for Asset Hub - let signed_origin = - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()); - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let beneficiary: Location = - AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - - let assets: Assets = (Parent, amount_to_send).into(); - let fee_asset_item = 0; - - // this should fail - AssetHubKusama::execute_with(|| { - let result = - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ); - assert_err!( - result, - DispatchError::Module(sp_runtime::ModuleError { - index: 31, - error: [2, 0, 0, 0], - message: Some("Filtered") - }) - ); - }); -} - -/// Reserve Transfers of KSM from Relay to Parachain should work -#[test] -fn reserve_transfer_ksm_from_relay_to_para() { - // Init values for Relay - let destination = Kusama::child_location_of(PenpalA::para_id()); - let sender = KusamaSender::get(); - let amount_to_send: Balance = KUSAMA_ED * 1000; - - // Init values for Parachain - let relay_native_asset_location = KsmLocation::get(); - let receiver = PenpalAReceiver::get(); - - // Init Test - let test_args = TestContext { - sender, - receiver: receiver.clone(), - args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), - }; - let mut test = RelayToParaTest::new(test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(relay_to_para_assets_receiver_assertions); - test.set_dispatchable::(relay_to_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - amount_to_send); - // Receiver's asset balance is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + amount_to_send); -} - -/// Reserve Transfers of KSM from Parachain to Relay should work -#[test] -fn reserve_transfer_ksm_from_para_to_relay() { - // Init values for Parachain - let destination = PenpalA::parent_location(); - let sender = PenpalASender::get(); - let amount_to_send: Balance = KUSAMA_ED * 1000; - let assets: Assets = (Parent, amount_to_send).into(); - let asset_owner = PenpalAssetOwner::get(); - let relay_native_asset_location = KsmLocation::get(); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // Init values for Relay - let receiver = KusamaReceiver::get(); - let penpal_location_as_seen_by_relay = Kusama::child_location_of(PenpalA::para_id()); - let sov_penpal_on_relay = Kusama::sovereign_account_id_of(penpal_location_as_seen_by_relay); - - // fund Parachain's SA on Relay with the native tokens held in reserve - Kusama::fund_accounts(vec![(sov_penpal_on_relay, amount_to_send * 2)]); - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver, - amount_to_send, - assets.clone(), - None, - 0, - ), - }; - let mut test = ParaToRelayTest::new(test_args); - - // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_balance_before = test.receiver.balance; - - // Set assertions and dispatchables - test.set_assertion::(para_to_relay_sender_assertions); - test.set_assertion::(para_to_relay_receiver_assertions); - test.set_dispatchable::(para_to_relay_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &sender) - }); - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_assets_after < sender_assets_before - amount_to_send); - // Receiver's asset balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); -} - -/// Reserve Transfers of KSM from Asset Hub to Parachain should work -#[test] -fn reserve_transfer_ksm_from_asset_hub_to_para() { - // Init values for Asset Hub - let destination = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sender = AssetHubKusamaSender::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; - let assets: Assets = (Parent, amount_to_send).into(); - - // Init values for Parachain - let system_para_native_asset_location = KsmLocation::get(); - let receiver = PenpalAReceiver::get(); - - // Init Test - let test_args = TestContext { - sender, - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - amount_to_send, - assets.clone(), - None, - 0, - ), - }; - let mut test = SystemParaToParaTest::new(test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(system_para_to_para_receiver_assertions); - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - amount_to_send); - // Receiver's assets is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + amount_to_send); -} - -/// Reserve Transfers of KSM from Parachain to Asset Hub should work -#[test] -fn reserve_transfer_ksm_from_para_to_asset_hub() { - // Init values for Parachain - let destination = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let sender = PenpalASender::get(); - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; - let assets: Assets = (Parent, amount_to_send).into(); - let system_para_native_asset_location = KsmLocation::get(); - let asset_owner = PenpalAssetOwner::get(); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - system_para_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // Init values for Asset Hub - let receiver = AssetHubKusamaReceiver::get(); - let penpal_location_as_seen_by_ahr = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - - // fund Parachain's SA on Asset Hub with the native tokens held in reserve - AssetHubKusama::fund_accounts(vec![(sov_penpal_on_ahr, amount_to_send * 2)]); - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - amount_to_send, - assets.clone(), - None, - 0, - ), - }; - let mut test = ParaToSystemParaTest::new(test_args); - - // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &sender) - }); - let receiver_balance_before = test.receiver.balance; - - // Set assertions and dispatchables - test.set_assertion::(para_to_system_para_sender_assertions); - test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &sender) - }); - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_assets_after < sender_assets_before - amount_to_send); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); -} - -/// Reserve Transfers of a local asset and KSM from Asset Hub to Parachain should work -#[test] -fn reserve_transfer_multiple_assets_from_asset_hub_to_para() { - // Init values for Asset Hub - let destination = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of(destination.clone()); - let sender = AssetHubKusamaSender::get(); - let fee_amount_to_send = ASSET_HUB_KUSAMA_ED * 10000; - let asset_amount_to_send = PENPAL_ED * 10000; - let asset_owner = AssetHubKusamaAssetOwner::get(); - let asset_owner_signer = ::RuntimeOrigin::signed(asset_owner.clone()); - let assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - ( - [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())], - asset_amount_to_send, - ) - .into(), - ] - .into(); - let fee_asset_index = assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - AssetHubKusama::mint_asset( - asset_owner_signer, - RESERVABLE_ASSET_ID, - asset_owner, - asset_amount_to_send * 2, - ); - - // Create SA-of-Penpal-on-AHR with ED. - AssetHubKusama::fund_accounts(vec![(sov_penpal_on_ahr, ASSET_HUB_KUSAMA_ED)]); - - // Init values for Parachain - let receiver = PenpalAReceiver::get(); - let system_para_native_asset_location = KsmLocation::get(); - let system_para_foreign_asset_location = PenpalLocalReservableFromAssetHub::get(); - - // Init Test - let para_test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination, - receiver.clone(), - asset_amount_to_send, - assets, - None, - fee_asset_index, - ), - }; - let mut test = SystemParaToParaTest::new(para_test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let sender_assets_before = AssetHubKusama::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &sender) - }); - let receiver_system_native_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - let receiver_foreign_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_foreign_asset_location.clone(), - &receiver, - ) - }); - - // Set assertions and dispatchables - test.set_assertion::(system_para_to_para_assets_sender_assertions); - test.set_assertion::(system_para_to_para_assets_receiver_assertions); - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let sender_assets_after = AssetHubKusama::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &sender) - }); - let receiver_system_native_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - let receiver_foreign_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location, &receiver) - }); - // Sender's balance is reduced - assert!(sender_balance_after < sender_balance_before); - // Receiver's foreign asset balance is increased - assert!(receiver_foreign_assets_after > receiver_foreign_assets_before); - // Receiver's system asset balance increased by `amount_to_send - delivery_fees - - // bought_execution`; `delivery_fees` might be paid from transfer or JIT, also - // `bought_execution` is unknown but should be non-zero - assert!( - receiver_system_native_assets_after < - receiver_system_native_assets_before + fee_amount_to_send - ); - - // Sender's asset balance is reduced by exact amount - assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); - // Receiver's foreign asset balance is increased by exact amount - assert_eq!( - receiver_foreign_assets_after, - receiver_foreign_assets_before + asset_amount_to_send - ); -} - -/// Reserve Transfers of a random asset and KSM from Parachain to Asset Hub should work -#[test] -fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { - // Init values for Parachain - let destination = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let sender = PenpalASender::get(); - let fee_amount_to_send = ASSET_HUB_KUSAMA_ED * 10000; - let asset_amount_to_send = ASSET_HUB_KUSAMA_ED * 10000; - let penpal_asset_owner = PenpalAssetOwner::get(); - let penpal_asset_owner_signer = ::RuntimeOrigin::signed(penpal_asset_owner); - let asset_location_on_penpal = PenpalLocalReservableFromAssetHub::get(); - let system_asset_location_on_penpal = KsmLocation::get(); - let assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - (asset_location_on_penpal.clone(), asset_amount_to_send).into(), - ] - .into(); - let fee_asset_index = assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - // Fund Parachain's sender account with some foreign assets - PenpalA::mint_foreign_asset( - penpal_asset_owner_signer.clone(), - asset_location_on_penpal.clone(), - sender.clone(), - asset_amount_to_send * 2, - ); - // Fund Parachain's sender account with some system assets - PenpalA::mint_foreign_asset( - penpal_asset_owner_signer, - system_asset_location_on_penpal.clone(), - sender.clone(), - fee_amount_to_send * 2, - ); - - // Init values for Asset Hub - let receiver = AssetHubKusamaReceiver::get(); - let penpal_location_as_seen_by_ahr = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahr = AssetHubKusama::sovereign_account_id_of(penpal_location_as_seen_by_ahr); - let ah_asset_owner = AssetHubKusamaAssetOwner::get(); - let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); - - // Fund SA-of-Penpal-on-AHR to be able to pay for the fees. - AssetHubKusama::fund_accounts(vec![( - sov_penpal_on_ahr.clone(), - ASSET_HUB_KUSAMA_ED * 10000000, - )]); - // Fund SA-of-Penpal-on-AHR to be able to pay for the sent amount. - AssetHubKusama::mint_asset( - ah_asset_owner_signer, - RESERVABLE_ASSET_ID, - sov_penpal_on_ahr, - asset_amount_to_send * 2, - ); - - // Init Test - let para_test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination, - receiver.clone(), - asset_amount_to_send, - assets, - None, - fee_asset_index, - ), - }; - let mut test = ParaToSystemParaTest::new(para_test_args); - - // Query initial balances - let sender_system_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_asset_location_on_penpal.clone(), &sender) - }); - let sender_foreign_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(asset_location_on_penpal.clone(), &sender) - }); - let receiver_balance_before = test.receiver.balance; - let receiver_assets_before = AssetHubKusama::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_system_para_assets_sender_assertions); - test.set_assertion::(para_to_system_para_assets_receiver_assertions); - test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_system_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_asset_location_on_penpal, &sender) - }); - let sender_foreign_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(asset_location_on_penpal, &sender) - }); - let receiver_balance_after = test.receiver.balance; - let receiver_assets_after = AssetHubKusama::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &receiver) - }); - // Sender's system asset balance is reduced - assert!(sender_system_assets_after < sender_system_assets_before); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); - - // Sender's asset balance is reduced by exact amount - assert_eq!(sender_foreign_assets_before - asset_amount_to_send, sender_foreign_assets_after); - // Receiver's foreign asset balance is increased by exact amount - assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); -} - -/// Reserve Transfers of KSM from Parachain to Parachain (through Relay reserve) should work -#[test] -fn reserve_transfer_ksm_from_para_to_para_through_relay() { - // Init values for Parachain Origin - let destination = PenpalA::sibling_location_of(PenpalB::para_id()); - let sender = PenpalASender::get(); - let amount_to_send: Balance = KUSAMA_ED * 10000; - let asset_owner = PenpalAssetOwner::get(); - let assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = KsmLocation::get(); - let sender_as_seen_by_relay = Kusama::child_location_of(PenpalA::para_id()); - let sov_of_sender_on_relay = Kusama::sovereign_account_id_of(sender_as_seen_by_relay); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve - Kusama::fund_accounts(vec![(sov_of_sender_on_relay, amount_to_send * 2)]); - - // Init values for Parachain Destination - let receiver = PenpalBReceiver::get(); - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para(destination, receiver.clone(), amount_to_send, assets, None, 0), - }; - let mut test = ParaToParaThroughRelayTest::new(test_args); - - // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_para_through_hop_sender_assertions); - test.set_assertion::(para_to_para_relay_hop_assertions); - test.set_assertion::(para_to_para_through_hop_receiver_assertions); - test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_assets_after < sender_assets_before - amount_to_send); - // Receiver's balance is increased - assert!(receiver_assets_after > receiver_assets_before); -} - -/// Reserve Withdraw Native Asset from AssetHub to Parachain fails. -#[test] -fn reserve_withdraw_from_untrusted_reserve_fails() { - // Init values for Parachain Origin - let destination = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let signed_origin = - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()); - let ksm_to_send: Balance = KUSAMA_ED * 10000; - let ksm_location = KsmLocation::get(); - - // Assets to send - let assets: Vec = vec![(ksm_location.clone(), ksm_to_send).into()]; - let fee_id: AssetId = ksm_location.into(); - - // this should fail - AssetHubKusama::execute_with(|| { - let result = ::PolkadotXcm::transfer_assets_using_type_and_then( - signed_origin.clone(), - bx!(destination.clone().into()), - bx!(assets.clone().into()), - bx!(TransferType::DestinationReserve), - bx!(fee_id.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(Xcm::<()>::new())), - Unlimited, - ); - assert_err!( - result, - DispatchError::Module(sp_runtime::ModuleError { - index: 31, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve") - }) - ); - }); - - // this should also fail - AssetHubKusama::execute_with(|| { - let xcm: Xcm = Xcm(vec![ - WithdrawAsset(assets.into()), - InitiateReserveWithdraw { - assets: Wild(All), - reserve: destination, - xcm: Xcm::<()>::new(), - }, - ]); - let result = ::PolkadotXcm::execute( - signed_origin, - bx!(xcm::VersionedXcm::V4(xcm)), - Weight::MAX, - ); - assert!(result.is_err()); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/send.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/send.rs deleted file mode 100644 index d5a24ed0f2..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/send.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -/// Relay Chain should be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Superuser`. -#[test] -fn send_transact_as_superuser_from_relay_to_asset_hub_works() { - AssetHubKusama::force_create_asset_from_relay_as_root( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubKusamaSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ) -} - -/// We tests two things here: -/// - Parachain should be able to send XCM paying its fee at Asset Hub using KSM -/// - Parachain should be able to create a new Foreign Asset at Asset Hub -#[test] -fn send_xcm_from_para_to_asset_hub_paying_fee_with_system_asset() { - let para_sovereign_account = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - let asset_location_on_penpal = v4::Location::new( - 0, - [ - v4::Junction::PalletInstance(ASSETS_PALLET_ID), - v4::Junction::GeneralIndex(ASSET_ID.into()), - ], - ); - let foreign_asset_at_asset_hub = - v4::Location::new(1, [v4::Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - - // Encoded `create_asset` call to be executed in AssetHub - let call = AssetHubKusama::create_foreign_asset_call( - foreign_asset_at_asset_hub.clone(), - ASSET_MIN_BALANCE, - para_sovereign_account.clone(), - ); - - let origin_kind = OriginKind::Xcm; - let fee_amount = ASSET_HUB_KUSAMA_ED * 1000000; - let system_asset = (Parent, fee_amount).into(); - - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = PenpalA::sibling_location_of(AssetHubKusama::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - origin_kind, - system_asset, - para_sovereign_account.clone(), - ); - - // SA-of-Penpal-on-AHK needs to have balance to pay for fees and asset creation deposit - AssetHubKusama::fund_accounts(vec![( - para_sovereign_account.clone(), - ASSET_HUB_KUSAMA_ED * 10000000000, - )]); - - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - PenpalA::assert_xcm_pallet_sent(); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubKusama, - vec![ - // Burned the fee - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == para_sovereign_account, - amount: *amount == fee_amount, - }, - // Foreign Asset created - RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { - asset_id: *asset_id == foreign_asset_at_asset_hub.clone(), - creator: *creator == para_sovereign_account.clone(), - owner: *owner == para_sovereign_account, - }, - ] - ); - - type ForeignAssets = ::ForeignAssets; - assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub)); - }); -} - -/// We tests two things here: -/// - Parachain should be able to send XCM paying its fee at Asset Hub using sufficient asset -/// - Parachain should be able to create a new Asset at Asset Hub -#[test] -fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() { - let para_sovereign_account = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - - // Force create and mint sufficient assets for Parachain's sovereign account - AssetHubKusama::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - para_sovereign_account.clone(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000000, - ); - - // Just a different `asset_id`` that does not exist yet - let new_asset_id = ASSET_ID + 1; - - // Encoded `create_asset` call to be executed in AssetHub - let call = AssetHubKusama::create_asset_call( - new_asset_id, - ASSET_MIN_BALANCE, - para_sovereign_account.clone(), - ); - - let origin_kind = OriginKind::SovereignAccount; - let fee_amount = ASSET_MIN_BALANCE * 1000000; - let asset = - ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); - - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = PenpalA::sibling_location_of(AssetHubKusama::para_id()).into(); - let xcm = xcm_transact_paid_execution(call, origin_kind, asset, para_sovereign_account.clone()); - - // SA-of-Penpal-on-AHK needs to have balance to pay for asset creation deposit - AssetHubKusama::fund_accounts(vec![( - para_sovereign_account.clone(), - ASSET_HUB_KUSAMA_ED * 10000000000, - )]); - - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - PenpalA::assert_xcm_pallet_sent(); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubKusama, - vec![ - // Burned the fee - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == para_sovereign_account, - balance: *balance == fee_amount, - }, - // Asset created - RuntimeEvent::Assets(pallet_assets::Event::Created { asset_id, creator, owner }) => { - asset_id: *asset_id == new_asset_id, - creator: *creator == para_sovereign_account.clone(), - owner: *owner == para_sovereign_account, - }, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs deleted file mode 100644 index b621c7c2b7..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/set_xcm_versions.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -#[test] -fn relay_sets_system_para_xcm_supported_version() { - // Init tests variables - let sudo_origin = ::RuntimeOrigin::root(); - let system_para_destination: Location = Kusama::child_location_of(AssetHubKusama::para_id()); - - // Relay Chain sets supported version for Asset Parachain - Kusama::execute_with(|| { - assert_ok!(::XcmPallet::force_xcm_version( - sudo_origin, - bx!(system_para_destination.clone()), - XCM_V4 - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { - location, - version: XCM_V4 - }) => { location: *location == system_para_destination, }, - ] - ); - }); -} - -#[test] -fn system_para_sets_relay_xcm_supported_version() { - // Init test variables - let parent_location = AssetHubKusama::parent_location(); - let force_xcm_version_call = - ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< - ::Runtime, - >::force_xcm_version { - location: bx!(parent_location.clone()), - version: XCM_V4, - }) - .encode() - .into(); - - // System Parachain sets supported version for Relay Chain through it - Kusama::send_unpaid_transact_to_parachain_as_root( - AssetHubKusama::para_id(), - force_xcm_version_call, - ); - - // System Parachain receive the XCM message - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_dmp_queue_complete(Some(Weight::from_parts(1_019_210_000, 200_000))); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { - location, - version: XCM_V4 - }) => { location: *location == parent_location, }, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs deleted file mode 100644 index e31b1b6426..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/swap.rs +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use kusama_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; -use sp_runtime::ModuleError; -use system_parachains_constants::kusama::currency::SYSTEM_PARA_EXISTENTIAL_DEPOSIT; - -#[test] -fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new(asset_hub_kusama_runtime::xcm_config::KsmLocation::get()); - let asset_one = Box::new(v4::Location::new( - 0, - [ - v4::Junction::PalletInstance(ASSETS_PALLET_ID), - v4::Junction::GeneralIndex(ASSET_ID.into()), - ], - )); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - 1000, - )); - assert!(::Assets::asset_exists(ASSET_ID)); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - 100_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - asset_one.clone(), - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - asset_one.clone(), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - AssetHubKusamaSender::get() - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, - ] - ); - - let path = vec![asset_native.clone(), asset_one.clone()]; - - assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - path, - 100, - 1, - AssetHubKusamaSender::get(), - true - ) - ); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. }) => { - amount_in: *amount_in == 100, - amount_out: *amount_out == 199, - }, - ] - ); - - assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native, - asset_one, - 1414213562273 - SYSTEM_PARA_EXISTENTIAL_DEPOSIT * 2, /* all but the 2 EDs can't be - * retrieved. */ - 0, - 0, - AssetHubKusamaSender::get(), - )); - }); -} - -#[test] -fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = Box::new(asset_hub_kusama_runtime::xcm_config::KsmLocation::get()); - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); - let foreign_asset_at_asset_hub_kusama = - v4::Location::new(1, [v4::Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - - let penpal_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of(penpal_as_seen_by_ah); - AssetHubKusama::fund_accounts(vec![ - // An account to swap ksmfor something else. - (AssetHubKusamaSender::get(), 5_000_000 * ASSET_HUB_KUSAMA_ED), - // Penpal's sovereign account in AH should have some balance - (sov_penpal_on_ahk.clone(), 100_000_000 * ASSET_HUB_KUSAMA_ED), - ]); - - AssetHubKusama::execute_with(|| { - // 0: No need to create foreign asset as it exists in genesis. - // - // 1:: Mint foreign asset on asset_hub_kusama: - // - // (While it might be nice to use batch, - // currently that's disabled due to safe call filters.) - - type RuntimeEvent = ::RuntimeEvent; - // 3. Mint foreign asset (in reality this should be a teleport or some such) - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), - foreign_asset_at_asset_hub_kusama.clone(), - sov_penpal_on_ahk.clone().into(), - ASSET_HUB_KUSAMA_ED * 3_000_000_000_000, - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - - // 4. Create pool: - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_kusama.clone()), - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - // 5. Add liquidity: - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), - asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_kusama.clone()), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - sov_penpal_on_ahk.clone() - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { - lp_token_minted: *lp_token_minted == 1414213562273, - }, - ] - ); - - // 6. Swap! - let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_kusama.clone())]; - - assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - path, - 100000 * ASSET_HUB_KUSAMA_ED, - 1000 * ASSET_HUB_KUSAMA_ED, - AssetHubKusamaSender::get(), - true - ) - ); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 333333300000, - amount_out: *amount_out == 498874118173, - }, - ] - ); - - // 7. Remove liquidity - assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahk.clone()), - asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_kusama), - 1414213562273 / 2, // remove only half - 0, - 0, - sov_penpal_on_ahk.clone(), - )); - }); -} - -#[test] -fn cannot_create_pool_from_pool_assets() { - let asset_native = asset_hub_kusama_runtime::xcm_config::KsmLocation::get(); - let asset_one = asset_hub_kusama_runtime::xcm_config::PoolAssetsPalletLocation::get() - .appended_with(GeneralIndex(ASSET_ID.into())) - .expect("valid location"); - - AssetHubKusama::execute_with(|| { - let pool_owner_account_id = asset_hub_kusama_runtime::AssetConversionOrigin::get(); - - assert_ok!(::PoolAssets::create( - ::RuntimeOrigin::signed(pool_owner_account_id.clone()), - ASSET_ID, - pool_owner_account_id.clone().into(), - 1000, - )); - assert!(::PoolAssets::asset_exists(ASSET_ID)); - - assert_ok!(::PoolAssets::mint( - ::RuntimeOrigin::signed(pool_owner_account_id), - ASSET_ID, - AssetHubKusamaSender::get().into(), - 3_000_000_000_000, - )); - - assert_matches::assert_matches!( - ::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - Box::new(asset_native), - Box::new(asset_one), - ), - Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) - ); - }); -} - -#[test] -fn pay_xcm_fee_with_some_asset_swapped_for_native() { - let asset_native: xcm::v4::Location = asset_hub_kusama_runtime::xcm_config::KsmLocation::get(); - let asset_one = xcm::v4::Location { - parents: 0, - interior: [ - xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v4::Junction::GeneralIndex(ASSET_ID.into()), - ] - .into(), - }; - let penpal = AssetHubKusama::sovereign_account_id_of(AssetHubKusama::sibling_location_of( - PenpalA::para_id(), - )); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // set up pool with ASSET_ID <> NATIVE pair - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - ASSET_MIN_BALANCE, - )); - assert!(::Assets::asset_exists(ASSET_ID)); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - AssetHubKusamaSender::get().into(), - 3_000_000_000_000, - )); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - Box::new(asset_native.clone()), - Box::new(asset_one.clone()), - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - Box::new(asset_native), - Box::new(asset_one), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - AssetHubKusamaSender::get() - )); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, - ] - ); - - // ensure `penpal` sovereign account has no native tokens and mint some `ASSET_ID` - assert_eq!( - ::Balances::free_balance(penpal.clone()), - 0 - ); - - assert_ok!(::Assets::touch_other( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - penpal.clone().into(), - )); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()), - ASSET_ID.into(), - penpal.clone().into(), - 10_000_000_000_000, - )); - }); - - PenpalA::execute_with(|| { - // send xcm transact from `penpal` account which has only `ASSET_ID` tokens on - // `AssetHubKusama` - let call = AssetHubKusama::force_create_asset_call( - ASSET_ID + 1000, - penpal.clone(), - true, - ASSET_MIN_BALANCE, - ); - - let penpal_root = ::RuntimeOrigin::root(); - let fee_amount = 4_000_000_000_000u128; - let asset_one = - ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); - let asset_hub_location = PenpalA::sibling_location_of(AssetHubKusama::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - OriginKind::SovereignAccount, - asset_one, - penpal.clone(), - ); - - assert_ok!(::PolkadotXcm::send( - penpal_root, - bx!(asset_hub_location), - bx!(xcm), - )); - - PenpalA::assert_xcm_pallet_sent(); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapCreditExecuted { .. },) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true,.. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs deleted file mode 100644 index 76776b44b3..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/teleport.rs +++ /dev/null @@ -1,537 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_kusama_runtime::xcm_config::{KsmLocation, XcmConfig as AssetHubKusamaXcmConfig}; -use emulated_integration_tests_common::xcm_helpers::non_fee_asset; -use frame_support::traits::fungible::Mutate; -use kusama_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Kusama::assert_ump_queue_processed( - false, - Some(AssetHubKusama::para_id()), - Some(Weight::from_parts(157_718_000, 3_593)), - ); -} - -fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 720_053_000, - 7_203, - ))); - - AssetHubKusama::assert_parachain_system_ump_sent(); - - assert_expected_events!( - AssetHubKusama, - vec![ - // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = KsmLocation::get(); - let expected_asset_id = t.args.asset_id.unwrap(); - let (_, expected_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - - PenpalA::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, .. } - ) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.sender.account_id, - }, - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_asset_id, - owner: *owner == t.sender.account_id, - balance: *balance == expected_asset_amount, - }, - ] - ); -} - -fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahk = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - let (expected_foreign_asset_id, expected_foreign_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - - AssetHubKusama::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubKusama, - vec![ - // native asset reserve transfer for paying fees, withdrawn from Penpal's sov account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahk.clone(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == expected_foreign_asset_id, - owner: *owner == t.receiver.account_id, - amount: *amount == expected_foreign_asset_amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Issued { .. }) => {}, - ] - ); -} - -fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcm_pallet_attempted_complete(None); - let (expected_foreign_asset_id, expected_foreign_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - assert_expected_events!( - AssetHubKusama, - vec![ - // native asset used for fees is transferred to Parachain's Sovereign account as reserve - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubKusama::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - // foreign asset is burned locally as part of teleportation - RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_foreign_asset_id, - owner: *owner == t.sender.account_id, - balance: *balance == expected_foreign_asset_amount, - }, - ] - ); -} - -fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let expected_asset_id = t.args.asset_id.unwrap(); - let (_, expected_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let checking_account = ::PolkadotXcm::check_account(); - let system_para_native_asset_location = KsmLocation::get(); - - PenpalA::assert_xcmp_queue_success(None); - assert_expected_events!( - PenpalA, - vec![ - // checking account burns local asset as part of incoming teleport - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_asset_id, - owner: *owner == checking_account, - balance: *balance == expected_asset_amount, - }, - // local asset is teleported into account of receiver - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == expected_asset_id, - owner: *owner == t.receiver.account_id, - amount: *amount == expected_asset_amount, - }, - // native asset for fee is deposited to receiver - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.receiver.account_id, - amount: *amount == expected_asset_amount, - }, - ] - ); -} - -fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -#[test] -fn teleport_to_other_system_parachains_works() { - let amount = ASSET_HUB_KUSAMA_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - AssetHubKusama, // Origin - AssetHubKusamaXcmConfig, // XCM Configuration - vec![BridgeHubKusama], // Destinations - (native_asset, amount) - ); -} - -#[test] -fn teleport_from_and_to_relay() { - let amount = KUSAMA_ED * 100; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Kusama, - KusamaXcmConfig, - vec![AssetHubKusama], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - AssetHubKusama, - AssetHubKusamaXcmConfig, - Kusama, - amount - ); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 1000; - let destination = AssetHubKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: KusamaReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubKusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >( - test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest - ) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - -/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying -/// fees using (reserve transferred) native asset. -pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( - para_to_ah_dispatchable: fn(ParaToSystemParaTest) -> DispatchResult, - ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult, -) { - // Init values for Parachain - let fee_amount_to_send: Balance = ASSET_HUB_KUSAMA_ED * 10000; - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); - let asset_id_on_penpal = match asset_location_on_penpal.last() { - Some(Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - let asset_amount_to_send = ASSET_HUB_KUSAMA_ED * 1000; - let asset_owner = PenpalAssetOwner::get(); - let system_para_native_asset_location = KsmLocation::get(); - let sender = PenpalASender::get(); - let penpal_check_account = ::PolkadotXcm::check_account(); - let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let penpal_assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - (asset_location_on_penpal.clone(), asset_amount_to_send).into(), - ] - .into(); - let fee_asset_index = penpal_assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), - system_para_native_asset_location.clone(), - sender.clone(), - fee_amount_to_send * 2, - ); - // No need to create the asset (only mint) as it exists in genesis. - PenpalA::mint_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), - asset_id_on_penpal, - sender.clone(), - asset_amount_to_send, - ); - // fund Parachain's check account to be able to teleport - PenpalA::fund_accounts(vec![(penpal_check_account.clone(), ASSET_HUB_KUSAMA_ED * 1000)]); - - // prefund SA of Penpal on AssetHub with enough native tokens to pay for fees - let penpal_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ah = AssetHubKusama::sovereign_account_id_of(penpal_as_seen_by_ah); - AssetHubKusama::fund_accounts(vec![( - sov_penpal_on_ah.clone(), - ASSET_HUB_KUSAMA_ED * 100_000_000_000, - )]); - - // Init values for System Parachain - let foreign_asset_at_asset_hub_kusama = - Location::new(1, [Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - let penpal_to_ah_beneficiary_id = AssetHubKusamaReceiver::get(); - - // Penpal to AH test args - let penpal_to_ah_test_args = TestContext { - sender: PenpalASender::get(), - receiver: AssetHubKusamaReceiver::get(), - args: TestArgs::new_para( - ah_as_seen_by_penpal, - penpal_to_ah_beneficiary_id, - asset_amount_to_send, - penpal_assets, - Some(asset_id_on_penpal), - fee_asset_index, - ), - }; - let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); - let penpal_sender_balance_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalASender::get(), - ) - }); - - let ah_receiver_balance_before = penpal_to_ah.receiver.balance; - - let penpal_sender_assets_before = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalASender::get()) - }); - let ah_receiver_assets_before = AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_kusama.clone(), - &AssetHubKusamaReceiver::get(), - ) - }); - - penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); - penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); - penpal_to_ah.set_dispatchable::(para_to_ah_dispatchable); - penpal_to_ah.assert(); - - let penpal_sender_balance_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalASender::get(), - ) - }); - - let ah_receiver_balance_after = penpal_to_ah.receiver.balance; - - let penpal_sender_assets_after = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalASender::get()) - }); - let ah_receiver_assets_after = AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_kusama.clone(), - &AssetHubKusamaReceiver::get(), - ) - }); - - // Sender's balance is reduced - assert!(penpal_sender_balance_after < penpal_sender_balance_before); - // Receiver's balance is increased - assert!(ah_receiver_balance_after > ah_receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send); - - // Sender's balance is reduced by exact amount - assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after); - // Receiver's balance is increased by exact amount - assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send); - - /////////////////////////////////////////////////////////////////////// - // Now test transferring foreign assets back from AssetHub to Penpal // - /////////////////////////////////////////////////////////////////////// - - // Move funds on AH from AHReceiver to AHSender - AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - assert_ok!(ForeignAssets::transfer( - ::RuntimeOrigin::signed(AssetHubKusamaReceiver::get()), - foreign_asset_at_asset_hub_kusama.clone(), - AssetHubKusamaSender::get().into(), - asset_amount_to_send, - )); - }); - - let ah_to_penpal_beneficiary_id = PenpalAReceiver::get(); - let penpal_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let ah_assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - (foreign_asset_at_asset_hub_kusama.clone(), asset_amount_to_send).into(), - ] - .into(); - let fee_asset_index = ah_assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - - // AH to Penpal test args - let ah_to_penpal_test_args = TestContext { - sender: AssetHubKusamaSender::get(), - receiver: PenpalAReceiver::get(), - args: TestArgs::new_para( - penpal_as_seen_by_ah, - ah_to_penpal_beneficiary_id, - asset_amount_to_send, - ah_assets, - Some(asset_id_on_penpal), - fee_asset_index, - ), - }; - let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); - - let ah_sender_balance_before = ah_to_penpal.sender.balance; - let penpal_receiver_balance_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalAReceiver::get(), - ) - }); - - let ah_sender_assets_before = AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_kusama.clone(), - &AssetHubKusamaSender::get(), - ) - }); - let penpal_receiver_assets_before = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) - }); - - ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); - ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); - ah_to_penpal.set_dispatchable::(ah_to_para_dispatchable); - ah_to_penpal.assert(); - - let ah_sender_balance_after = ah_to_penpal.sender.balance; - let penpal_receiver_balance_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location, - &PenpalAReceiver::get(), - ) - }); - - let ah_sender_assets_after = AssetHubKusama::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_kusama, - &AssetHubKusamaSender::get(), - ) - }); - let penpal_receiver_assets_after = PenpalA::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) - }); - - // Sender's balance is reduced - assert!(ah_sender_balance_after < ah_sender_balance_before); - // Receiver's balance is increased - assert!(penpal_receiver_balance_after > penpal_receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send); - - // Sender's balance is reduced by exact amount - assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after); - // Receiver's balance is increased by exact amount - assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send); -} - -/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work -/// (using native reserve-based transfer for fees) -#[test] -fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { - do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( - para_to_system_para_transfer_assets, - system_para_to_para_transfer_assets, - ); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/treasury.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/treasury.rs deleted file mode 100644 index f060fc96e7..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/treasury.rs +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests concerning the Kusama Treasury. - -use crate::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; -use frame_support::{ - dispatch::RawOrigin, - sp_runtime::traits::Dispatchable, - traits::{ - fungible::Inspect, - fungibles::{Inspect as FungiblesInspect, Mutate}, - }, -}; -use kusama_runtime::OriginCaller; -use kusama_runtime_constants::currency::GRAND; -use polkadot_runtime_common::impls::VersionedLocatableAsset; -use xcm_executor::traits::ConvertLocation; - -// Fund Treasury account on Asset Hub from Treasury account on Relay Chain with KSMs. -#[test] -fn spend_ksm_on_asset_hub() { - // initial treasury balance on Asset Hub in KSMs. - let treasury_balance = 9_000 * GRAND; - // the balance spend on Asset Hub. - let treasury_spend_balance = 1_000 * GRAND; - - let init_alice_balance = AssetHubKusama::execute_with(|| { - <::Balances as Inspect<_>>::balance( - &AssetHubKusama::account_id_of(ALICE), - ) - }); - - Kusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeCall = ::RuntimeCall; - type Runtime = ::Runtime; - type Balances = ::Balances; - type Treasury = ::Treasury; - - // Fund Treasury account on Asset Hub with KSMs. - - let root = ::RuntimeOrigin::root(); - let treasury_account = Treasury::account_id(); - - // Mint assets to Treasury account on Relay Chain. - assert_ok!(Balances::force_set_balance( - root.clone(), - treasury_account.clone().into(), - treasury_balance * 2, - )); - - let native_asset = Location::here(); - let asset_hub_location: Location = [Parachain(1000)].into(); - let treasury_location: Location = (Parent, PalletInstance(18)).into(); - - let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { - as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))), - call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { - dest: bx!(VersionedLocation::from(asset_hub_location.clone())), - beneficiary: bx!(VersionedLocation::from(treasury_location)), - assets: bx!(VersionedAssets::from(Assets::from(Asset { - id: native_asset.clone().into(), - fun: treasury_balance.into() - }))), - fee_asset_item: 0, - })), - }); - - // Dispatched from Root to `dispatch_as` `Signed(treasury_account)`. - assert_ok!(teleport_call.dispatch(root)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - Kusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeCall = ::RuntimeCall; - type RuntimeOrigin = ::RuntimeOrigin; - type Runtime = ::Runtime; - type Treasury = ::Treasury; - - // Fund Alice account from Kusama Treasury account on Asset Hub. - - let treasury_origin: RuntimeOrigin = - kusama_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); - - let alice_location: Location = - [Junction::AccountId32 { network: None, id: Kusama::account_id_of(ALICE).into() }] - .into(); - let asset_hub_location: Location = [Parachain(1000)].into(); - let native_asset_on_asset_hub = Location::parent(); - - let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::::spend { - asset_kind: bx!(VersionedLocatableAsset::V4 { - location: asset_hub_location.clone(), - asset_id: native_asset_on_asset_hub.into(), - }), - amount: treasury_spend_balance, - beneficiary: bx!(VersionedLocation::from(alice_location)), - valid_from: None, - }); - - assert_ok!(treasury_spend_call.dispatch(treasury_origin)); - - // Claim the spend. - - let bob_signed = RuntimeOrigin::signed(Kusama::account_id_of(BOB)); - assert_ok!(Treasury::payout(bob_signed.clone(), 0)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, - RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, - ] - ); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Balances = ::Balances; - - // Ensure that the funds deposited to Alice account. - - let alice_account = AssetHubKusama::account_id_of(ALICE); - assert_eq!( - >::balance(&alice_account), - treasury_spend_balance + init_alice_balance - ); - - // Assert events triggered by xcm pay program: - // 1. treasury asset transferred to spend beneficiary; - // 2. response to Relay Chain Treasury pallet instance sent back; - // 3. XCM program completed; - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, - RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - }); -} - -#[test] -fn create_and_claim_treasury_spend_in_usdt() { - const USDT_ID: u32 = 1984; - const SPEND_AMOUNT: u128 = 10_000_000; - // treasury location from a sibling parachain. - let treasury_location: Location = Location::new(1, PalletInstance(18)); - // treasury account on a sibling parachain. - let treasury_account = - asset_hub_kusama_runtime::xcm_config::LocationToAccountId::convert_location( - &treasury_location, - ) - .unwrap(); - let asset_hub_location = - v4::Location::new(0, v4::Junction::Parachain(AssetHubKusama::para_id().into())); - let root = ::RuntimeOrigin::root(); - // asset kind to be spend from the treasury. - let asset_kind = VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: v4::AssetId( - (v4::Junction::PalletInstance(50), v4::Junction::GeneralIndex(USDT_ID.into())).into(), - ), - }; - // treasury spend beneficiary. - let alice: AccountId = Kusama::account_id_of(ALICE); - let bob: AccountId = Kusama::account_id_of(BOB); - let bob_signed = ::RuntimeOrigin::signed(bob.clone()); - - AssetHubKusama::execute_with(|| { - type Assets = ::Assets; - - // USDT created at genesis, mint some assets to the treasury account. - assert_ok!(>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4)); - // beneficiary has zero balance. - assert_eq!(>::balance(USDT_ID, &alice,), 0u128,); - }); - - Kusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Treasury = ::Treasury; - type AssetRate = ::AssetRate; - - // create a conversion rate from `asset_kind` to the native currency. - assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); - - // create and approve a treasury spend. - assert_ok!(Treasury::spend( - root, - Box::new(asset_kind), - SPEND_AMOUNT, - Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), - None, - )); - // claim the spend. - assert_ok!(Treasury::payout(bob_signed.clone(), 0)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, - ] - ); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Assets = ::Assets; - - // assert events triggered by xcm pay program - // 1. treasury asset transferred to spend beneficiary - // 2. response to Relay Chain treasury pallet instance sent back - // 3. XCM program completed - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { - id: id == &USDT_ID, - from: from == &treasury_account, - to: to == &alice, - amount: amount == &SPEND_AMOUNT, - }, - RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - // beneficiary received the assets from the treasury. - assert_eq!(>::balance(USDT_ID, &alice,), SPEND_AMOUNT,); - }); - - Kusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Treasury = ::Treasury; - - // check the payment status to ensure the response from the AssetHub was received. - assert_ok!(Treasury::check_status(bob_signed, 0)); - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs deleted file mode 100644 index 0ad9953be2..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests for XCM fee estimation in the runtime. - -use crate::{ - assert_expected_events, bx, AssetHubKusama, Chain, ParaToParaThroughAHTest, PenpalA, - PenpalAPallet, PenpalASender, PenpalAssetOwner, PenpalB, PenpalBPallet, PenpalBReceiver, - TestArgs, TestContext, TransferType, -}; -use emulated_integration_tests_common::impls::{Parachain, TestExt}; -use frame_support::{ - dispatch::RawOrigin, - sp_runtime::{traits::Dispatchable, DispatchResult}, - traits::fungibles::Inspect, -}; -use xcm::prelude::*; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -/// We are able to dry-run and estimate the fees for a multi-hop XCM journey. -/// Scenario: Alice on PenpalA has some DOTs and wants to send them to PenpalB. -/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`. -#[test] -fn multi_hop_works() { - let destination = PenpalA::sibling_location_of(PenpalB::para_id()); - let sender = PenpalASender::get(); - let amount_to_send = 1_000_000_000_000; - let asset_owner = PenpalAssetOwner::get(); - let assets: Assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = Location::parent(); - let sender_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_of_sender_on_ah = AssetHubKusama::sovereign_account_id_of(sender_as_seen_by_ah.clone()); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // fund the Parachain Origin's SA on AssetHub with the native tokens held in reserve. - AssetHubKusama::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); - - // Init values for Parachain Destination - let beneficiary_id = PenpalBReceiver::get(); - - let test_args = TestContext { - sender: PenpalASender::get(), // Bob in PenpalB. - receiver: PenpalBReceiver::get(), // Alice. - args: TestArgs::new_para( - destination, - beneficiary_id.clone(), - amount_to_send, - assets, - None, - 0, - ), - }; - let mut test = ParaToParaThroughAHTest::new(test_args); - - // We get them from the PenpalA closure. - let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); - ::execute_with(|| { - type Runtime = ::Runtime; - type OriginCaller = ::OriginCaller; - - let call = transfer_assets_para_to_para_through_ah_call(test.clone()); - let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); - let result = Runtime::dry_run_call(origin, call).unwrap(); - // We filter the result to get only the messages we are interested in. - let (destination_to_query, messages_to_query) = &result - .forwarded_xcms - .iter() - .find(|(destination, _)| { - *destination == VersionedLocation::from(Location::new(1, [Parachain(1000)])) - }) - .unwrap(); - assert_eq!(messages_to_query.len(), 1); - remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); - delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); - }); - - // These are set in the AssetHub closure. - let mut intermediate_execution_fees = 0; - let mut intermediate_delivery_fees_amount = 0; - let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new())); - ::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - - // First we get the execution fees. - let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); - intermediate_execution_fees = Runtime::query_weight_to_asset_fee( - weight, - VersionedAssetId::from(AssetId(Location::parent())), - ) - .unwrap(); - - // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. - let xcm_program = VersionedXcm::from(Xcm::::from( - remote_message.clone().try_into().unwrap(), - )); - - // Now we get the delivery fees to the final destination. - let result = - Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); - let (destination_to_query, messages_to_query) = &result - .forwarded_xcms - .iter() - .find(|(destination, _)| { - *destination == VersionedLocation::from(Location::new(1, [Parachain(2001)])) - }) - .unwrap(); - // There's actually two messages here. - // One created when the message we sent from PenpalA arrived and was executed. - // The second one when we dry-run the xcm. - // We could've gotten the message from the queue without having to dry-run, but - // offchain applications would have to dry-run, so we do it here as well. - intermediate_remote_message = messages_to_query[0].clone(); - let delivery_fees = Runtime::query_delivery_fees( - destination_to_query.clone(), - intermediate_remote_message.clone(), - ) - .unwrap(); - intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); - }); - - // Get the final execution fees in the destination. - let mut final_execution_fees = 0; - ::execute_with(|| { - type Runtime = ::Runtime; - - let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); - final_execution_fees = Runtime::query_weight_to_asset_fee( - weight, - VersionedAssetId::from(AssetId(Parent.into())), - ) - .unwrap(); - }); - - // Dry-running is done. - PenpalA::reset_ext(); - AssetHubKusama::reset_ext(); - PenpalB::reset_ext(); - - // Fund accounts again. - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - AssetHubKusama::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]); - - // Actually run the extrinsic. - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &beneficiary_id) - }); - - test.set_assertion::(sender_assertions); - test.set_assertion::(hop_assertions); - test.set_assertion::(receiver_assertions); - test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); - test.assert(); - - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &beneficiary_id) - }); - - // We know the exact fees on every hop. - assert_eq!( - sender_assets_after, - sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly - * from the sender's - * account. */ - ); - assert_eq!( - receiver_assets_after, - receiver_assets_before + amount_to_send - - intermediate_execution_fees - - intermediate_delivery_fees_amount - - final_execution_fees - ); -} - -fn sender_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance } - ) => { - asset_id: *asset_id == Location::parent(), - owner: *owner == test.sender.account_id, - balance: *balance == test.args.amount, - }, - ] - ); -} - -fn hop_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcmp_queue_success(None); - - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::Balances( - pallet_balances::Event::Burned { amount, .. } - ) => { - amount: *amount == test.args.amount, - }, - ] - ); -} - -fn receiver_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcmp_queue_success(None); - - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Issued { asset_id, owner, .. } - ) => { - asset_id: *asset_id == Location::parent(), - owner: *owner == test.receiver.account_id, - }, - ] - ); -} - -fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { - let latest_assets: Assets = assets.try_into().unwrap(); - let Fungible(amount) = latest_assets.inner()[0].fun else { - unreachable!("asset is non-fungible"); - }; - amount -} - -fn transfer_assets_para_to_para_through_ah_dispatchable( - test: ParaToParaThroughAHTest, -) -> DispatchResult { - let call = transfer_assets_para_to_para_through_ah_call(test.clone()); - match call.dispatch(test.signed_origin) { - Ok(_) => Ok(()), - Err(error_with_post_info) => Err(error_with_post_info.error), - } -} - -fn transfer_assets_para_to_para_through_ah_call( - test: ParaToParaThroughAHTest, -) -> ::RuntimeCall { - type RuntimeCall = ::RuntimeCall; - - let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubKusama::para_id()); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(test.args.assets.len() as u32)), - beneficiary: test.args.beneficiary, - }]); - RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets_using_type_and_then { - dest: bx!(test.args.dest.into()), - assets: bx!(test.args.assets.clone().into()), - assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::parent()))), - fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), - custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), - weight_limit: test.args.weight_limit, - }) -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml b/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml deleted file mode 100644 index f212448067..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "asset-hub-polkadot-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Asset Hub Polkadot runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } -assert_matches = { workspace = true } - -# Substrate -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-asset-conversion = { workspace = true, default-features = true } -pallet-treasury = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } - -# Polkadot -polkadot-runtime-common = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -asset-test-utils = { workspace = true } -emulated-integration-tests-common = { workspace = true } -parachains-common = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -asset-hub-polkadot-runtime = { workspace = true } -collectives-polkadot-runtime-constants = { workspace = true } -integration-tests-helpers = { workspace = true } -polkadot-runtime = { workspace = true } -polkadot-system-emulated-network = { workspace = true } -system-parachains-constants = { workspace = true, default-features = true } diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs deleted file mode 100644 index e47727b67b..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - dispatch::RawOrigin, - instances::Instance2, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult, ModuleError}, - traits::fungibles::Inspect, - BoundedVec, -}; -pub use sp_runtime::traits::Dispatchable; - -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v4::{self, Error, NetworkId::Polkadot as PolkadotId}, -}; -pub use xcm_executor::traits::TransferType; - -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V4, -}; -pub use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -pub use parachains_common::{AccountId, Balance}; -pub use polkadot_runtime::xcm_config::UniversalLocation as PolkadotUniversalLocation; -pub use polkadot_system_emulated_network::{ - asset_hub_polkadot_emulated_chain::{ - genesis::{AssetHubPolkadotAssetOwner, ED as ASSET_HUB_POLKADOT_ED}, - AssetHubPolkadotParaPallet as AssetHubPolkadotPallet, - }, - collectives_polkadot_emulated_chain::{ - genesis::ED as COLLECTIVES_POLKADOT_ED, - CollectivesPolkadotParaPallet as CollectivesPolkadotPallet, - }, - penpal_emulated_chain::{ - CustomizableAssetFromSystemAssetHub, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, - PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, - }, - polkadot_emulated_chain::{genesis::ED as POLKADOT_ED, PolkadotRelayPallet as PolkadotPallet}, - AssetHubPolkadotPara as AssetHubPolkadot, - AssetHubPolkadotParaReceiver as AssetHubPolkadotReceiver, - AssetHubPolkadotParaSender as AssetHubPolkadotSender, - BridgeHubPolkadotPara as BridgeHubPolkadot, - BridgeHubPolkadotParaReceiver as BridgeHubPolkadotReceiver, - CollectivesPolkadotPara as CollectivesPolkadot, PenpalAPara as PenpalA, - PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, - PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, - PenpalBParaSender as PenpalBSender, PolkadotRelay as Polkadot, - PolkadotRelayReceiver as PolkadotReceiver, PolkadotRelaySender as PolkadotSender, -}; - -pub const ASSET_ID: u32 = 3; -pub const ASSET_MIN_BALANCE: u128 = 1000; -// `Assets` pallet index -pub const ASSETS_PALLET_ID: u8 = 50; - -pub type RelayToParaTest = Test; -pub type ParaToRelayTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; -pub type ParaToParaThroughRelayTest = Test; -pub type ParaToParaThroughAHTest = Test; -pub type RelayToParaThroughAHTest = Test; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/claim_assets.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/claim_assets.rs deleted file mode 100644 index 676b210170..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/claim_assets.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests related to claiming assets trapped during XCM execution. - -use crate::*; - -use asset_hub_polkadot_runtime::ExistentialDeposit; -use integration_tests_helpers::test_chain_can_claim_assets; -use xcm_executor::traits::DropAssets; - -#[test] -fn assets_can_be_claimed() { - let amount = ExistentialDeposit::get(); - let assets: Assets = (Parent, amount).into(); - - test_chain_can_claim_assets!( - AssetHubPolkadot, - RuntimeCall, - NetworkId::Polkadot, - assets, - amount - ); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/fellowship_treasury.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/fellowship_treasury.rs deleted file mode 100644 index e1783f63b4..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/fellowship_treasury.rs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; -use frame_support::traits::fungibles::Mutate; -use polkadot_runtime_common::impls::VersionedLocatableAsset; -use xcm_executor::traits::ConvertLocation; - -#[test] -fn create_and_claim_treasury_spend_in_usdt() { - const USDT_ID: u32 = 1984; - const SPEND_AMOUNT: u128 = 1_000_000_000; - // treasury location from a sibling parachain. - let treasury_location: Location = Location::new( - 1, - [ - Parachain(CollectivesPolkadot::para_id().into()), - PalletInstance( - collectives_polkadot_runtime_constants::FELLOWSHIP_TREASURY_PALLET_INDEX, - ), - ], - ); - // treasury account on a sibling parachain. - let treasury_account = - asset_hub_polkadot_runtime::xcm_config::LocationToAccountId::convert_location( - &treasury_location, - ) - .unwrap(); - let asset_hub_location = - v4::Location::new(1, v4::Junction::Parachain(AssetHubPolkadot::para_id().into())); - let root = ::RuntimeOrigin::root(); - // asset kind to be spent from the treasury. - let asset_kind = VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: v4::AssetId( - (v4::Junction::PalletInstance(50), v4::Junction::GeneralIndex(USDT_ID.into())).into(), - ), - }; - // treasury spend beneficiary. - let alice: AccountId = Polkadot::account_id_of(ALICE); - let bob: AccountId = CollectivesPolkadot::account_id_of(BOB); - let bob_signed = ::RuntimeOrigin::signed(bob.clone()); - - AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - - // USDT created at genesis, mint some assets to the treasury account. - assert_ok!(>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4)); - // beneficiary has zero balance. - assert_eq!(>::balance(USDT_ID, &alice,), 0u128,); - }); - - CollectivesPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type FellowshipTreasury = - ::FellowshipTreasury; - type AssetRate = ::AssetRate; - - // create a conversion rate from `asset_kind` to the native currency. - assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); - - // create and approve a treasury spend. - assert_ok!(FellowshipTreasury::spend( - root, - Box::new(asset_kind), - SPEND_AMOUNT, - Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), - None, - )); - // claim the spend. - assert_ok!(FellowshipTreasury::payout(bob_signed.clone(), 0)); - - assert_expected_events!( - CollectivesPolkadot, - vec![ - RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::Paid { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Assets = ::Assets; - - // assert events triggered by xcm pay program - // 1. treasury asset transferred to spend beneficiary - // 2. response to the Fellowship treasury pallet instance sent back - // 3. XCM program completed - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { - id: id == &USDT_ID, - from: from == &treasury_account, - to: to == &alice, - amount: amount == &SPEND_AMOUNT, - }, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - // beneficiary received the assets from the treasury. - assert_eq!(>::balance(USDT_ID, &alice,), SPEND_AMOUNT,); - }); - - CollectivesPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type FellowshipTreasury = - ::FellowshipTreasury; - - // check the payment status to ensure the response from the AssetHub was received. - assert_ok!(FellowshipTreasury::check_status(bob_signed, 0)); - assert_expected_events!( - CollectivesPolkadot, - vec![ - RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs deleted file mode 100644 index cf38d67912..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/hybrid_transfers.rs +++ /dev/null @@ -1,793 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::reserve_transfer::*; -use crate::{ - tests::teleport::do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt, - *, -}; -use asset_hub_polkadot_runtime::xcm_config::DotLocation; - -fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_a_on_ah = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), - ); - let sov_penpal_b_on_ah = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalA::para_id()), - ); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Withdrawn from sender parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_a_on_ah, - amount: *amount == t.args.amount, - }, - // Deposited to receiver parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Minted { who, .. } - ) => { - who: *who == sov_penpal_b_on_ah, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::LocalReserve), - bx!(fee.id.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::DestinationReserve), - bx!(fee.id.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(fee.id.into()), - bx!(TransferType::RemoteReserve(asset_hub_location.into())), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::Teleport), - bx!(fee.id.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.assets.into()), - bx!(TransferType::Teleport), - bx!(fee.id.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - t.args.weight_limit, - ) -} - -// =========================================================================== -// ======= Transfer - Native + Bridged Assets - AssetHub->Parachain ========== -// =========================================================================== -/// Transfers of native asset plus bridged asset from AssetHub to some Parachain -/// while paying fees using native asset. -#[test] -fn transfer_foreign_assets_from_asset_hub_to_para() { - let destination = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sender = AssetHubPolkadotSender::get(); - let native_amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; - let native_asset_location = DotLocation::get(); - let receiver = PenpalBReceiver::get(); - let assets_owner = PenpalAssetOwner::get(); - // Foreign asset used: bridged KSM - let foreign_amount_to_send = ASSET_HUB_POLKADOT_ED * 10_000_000; - let ksm_at_polkadot_parachains = Location::new(2, [GlobalConsensus(Kusama)]); - - // Configure destination chain to trust AH as reserve of KSM - PenpalB::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Kusama)]).encode(), - )], - )); - }); - PenpalB::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - AssetHubPolkadot::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - AssetHubPolkadot::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner), - ksm_at_polkadot_parachains.clone(), - sender.clone(), - foreign_amount_to_send * 2, - ); - - // Assets to send - let assets: Vec = vec![ - (Parent, native_amount_to_send).into(), - (ksm_at_polkadot_parachains.clone(), foreign_amount_to_send).into(), - ]; - let fee_asset_id = AssetId(Parent.into()); - let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - native_amount_to_send, - assets.into(), - None, - fee_asset_item, - ), - }; - let mut test = SystemParaToParaTest::new(test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let sender_ksm_before = AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location.clone(), &receiver) - }); - let receiver_ksm_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(system_para_to_para_receiver_assertions); - test.set_dispatchable::(ah_to_para_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let sender_ksm_after = AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location, &receiver) - }); - let receiver_ksm_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - native_amount_to_send); - // Sender's balance is reduced by foreign amount sent - assert_eq!(sender_ksm_after, sender_ksm_before - foreign_amount_to_send); - // Receiver's assets is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + native_amount_to_send); - // Receiver's balance is increased by foreign amount sent - assert_eq!(receiver_ksm_after, receiver_ksm_before + foreign_amount_to_send); -} - -/// Reserve Transfers of native asset from Parachain to System Parachain should work -// =========================================================================== -// ======= Transfer - Native + Bridged Assets - Parachain->AssetHub ========== -// =========================================================================== -/// Transfers of native asset plus bridged asset from some Parachain to AssetHub -/// while paying fees using native asset. -#[test] -fn transfer_foreign_assets_from_para_to_asset_hub() { - // Init values for Parachain - let destination = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let sender = PenpalBSender::get(); - let native_amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; - let native_asset_location = DotLocation::get(); - let assets_owner = PenpalAssetOwner::get(); - - // Foreign asset used: bridged KSM - let foreign_amount_to_send = ASSET_HUB_POLKADOT_ED * 10_000_000; - let ksm_at_polkadot_parachains = Location::new(2, [GlobalConsensus(Kusama)]); - - // Configure destination chain to trust AH as reserve of KSM - PenpalB::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Kusama)]).encode(), - )], - )); - }); - PenpalB::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - AssetHubPolkadot::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - - // fund Parachain's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - native_asset_location.clone(), - sender.clone(), - native_amount_to_send * 2, - ); - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - ksm_at_polkadot_parachains.clone(), - sender.clone(), - foreign_amount_to_send * 2, - ); - - // Init values for System Parachain - let receiver = AssetHubPolkadotReceiver::get(); - let penpal_location_as_seen_by_ahp = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahp = - AssetHubPolkadot::sovereign_account_id_of(penpal_location_as_seen_by_ahp); - - // fund Parachain's SA on AssetHub with the assets held in reserve - AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_ahp.clone(), native_amount_to_send * 2)]); - AssetHubPolkadot::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner), - ksm_at_polkadot_parachains.clone(), - sov_penpal_on_ahp, - foreign_amount_to_send * 2, - ); - - // Assets to send - let assets: Vec = vec![ - (Parent, native_amount_to_send).into(), - (ksm_at_polkadot_parachains.clone(), foreign_amount_to_send).into(), - ]; - let fee_asset_id = AssetId(Parent.into()); - let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - native_amount_to_send, - assets.into(), - None, - fee_asset_item, - ), - }; - let mut test = ParaToSystemParaTest::new(test_args); - - // Query initial balances - let sender_native_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location.clone(), &sender) - }); - let sender_ksm_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let receiver_native_before = test.receiver.balance; - let receiver_ksm_before = AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_system_para_sender_assertions); - test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_ah_transfer_assets); - test.assert(); - - // Query final balances - let sender_native_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(native_asset_location, &sender) - }); - let sender_ksm_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let receiver_native_after = test.receiver.balance; - let receiver_ksm_after = AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_native_after < sender_native_before - native_amount_to_send); - // Sender's balance is reduced by foreign amount sent - assert_eq!(sender_ksm_after, sender_ksm_before - foreign_amount_to_send); - // Receiver's balance is increased - assert!(receiver_native_after > receiver_native_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_native_after < receiver_native_before + native_amount_to_send); - // Receiver's balance is increased by foreign amount sent - assert_eq!(receiver_ksm_after, receiver_ksm_before + foreign_amount_to_send); -} - -// ============================================================================== -// ===== Transfer - Native + Bridged Assets - Parachain->AssetHub->Parachain ==== -// ============================================================================== -/// Transfers of native asset plus bridged asset from Parachain to Parachain -/// (through AssetHub reserve) with fees paid using native asset. -#[test] -fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { - // Init values for Parachain Origin - let destination = PenpalB::sibling_location_of(PenpalA::para_id()); - let sender = PenpalBSender::get(); - let dot_to_send: Balance = POLKADOT_ED * 10000; - let assets_owner = PenpalAssetOwner::get(); - let dot_location = DotLocation::get(); - let sender_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_of_sender_on_ah = AssetHubPolkadot::sovereign_account_id_of(sender_as_seen_by_ah); - let receiver_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalA::para_id()); - let sov_of_receiver_on_ah = AssetHubPolkadot::sovereign_account_id_of(receiver_as_seen_by_ah); - let ksm_to_send = ASSET_HUB_POLKADOT_ED * 10_000_000; - - // Configure source and destination chains to trust AH as reserve of KSM - PenpalA::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Kusama)]).encode(), - )], - )); - }); - PenpalB::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Kusama)]).encode(), - )], - )); - }); - - // Register KSM as foreign asset and transfer it around the Polkadot ecosystem - let ksm_at_polkadot_parachains = Location::new(2, [GlobalConsensus(Kusama)]); - AssetHubPolkadot::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - PenpalB::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - PenpalA::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - assets_owner.clone(), - false, - ASSET_MIN_BALANCE, - vec![], - ); - - // fund Parachain's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - dot_location.clone(), - sender.clone(), - dot_to_send * 2, - ); - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner.clone()), - ksm_at_polkadot_parachains.clone(), - sender.clone(), - ksm_to_send * 2, - ); - // fund the Parachain Origin's SA on Asset Hub with the assets held in reserve - AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone(), dot_to_send * 2)]); - AssetHubPolkadot::mint_foreign_asset( - ::RuntimeOrigin::signed(assets_owner), - ksm_at_polkadot_parachains.clone(), - sov_of_sender_on_ah.clone(), - ksm_to_send * 2, - ); - - // Init values for Parachain Destination - let receiver = PenpalAReceiver::get(); - - // Assets to send - let assets: Vec = vec![ - (dot_location.clone(), dot_to_send).into(), - (ksm_at_polkadot_parachains.clone(), ksm_to_send).into(), - ]; - let fee_asset_id: AssetId = dot_location.clone().into(); - let fee_asset_item = assets.iter().position(|a| a.id == fee_asset_id).unwrap() as u32; - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination, - receiver.clone(), - dot_to_send, - assets.into(), - None, - fee_asset_item, - ), - }; - let mut test = ParaToParaThroughAHTest::new(test_args); - - // Query initial balances - let sender_dot_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_location.clone(), &sender) - }); - let sender_ksm_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let dot_in_sender_reserve_on_ahp_before = - ::account_data_of(sov_of_sender_on_ah.clone()).free; - let ksm_in_sender_reserve_on_ahp_before = AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sov_of_sender_on_ah) - }); - let dot_in_receiver_reserve_on_ahp_before = - ::account_data_of(sov_of_receiver_on_ah.clone()).free; - let ksm_in_receiver_reserve_on_ahp_before = AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sov_of_receiver_on_ah) - }); - let receiver_dot_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_location.clone(), &receiver) - }); - let receiver_ksm_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_para_through_hop_sender_assertions); - test.set_assertion::(para_to_para_assethub_hop_assertions); - test.set_assertion::(para_to_para_through_hop_receiver_assertions); - test.set_dispatchable::(para_to_para_transfer_assets_through_ah); - test.assert(); - - // Query final balances - let sender_dot_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_location.clone(), &sender) - }); - let sender_ksm_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let ksm_in_sender_reserve_on_ahp_after = AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sov_of_sender_on_ah) - }); - let dot_in_sender_reserve_on_ahp_after = - ::account_data_of(sov_of_sender_on_ah).free; - let ksm_in_receiver_reserve_on_ahp_after = AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sov_of_receiver_on_ah) - }); - let dot_in_receiver_reserve_on_ahp_after = - ::account_data_of(sov_of_receiver_on_ah).free; - let receiver_dot_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_location, &receiver) - }); - let receiver_ksm_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_dot_after < sender_dot_before - dot_to_send); - assert_eq!(sender_ksm_after, sender_ksm_before - ksm_to_send); - // Sovereign accounts on reserve are changed accordingly - assert_eq!( - dot_in_sender_reserve_on_ahp_after, - dot_in_sender_reserve_on_ahp_before - dot_to_send - ); - assert_eq!( - ksm_in_sender_reserve_on_ahp_after, - ksm_in_sender_reserve_on_ahp_before - ksm_to_send - ); - assert!(dot_in_receiver_reserve_on_ahp_after > dot_in_receiver_reserve_on_ahp_before); - assert_eq!( - ksm_in_receiver_reserve_on_ahp_after, - ksm_in_receiver_reserve_on_ahp_before + ksm_to_send - ); - // Receiver's balance is increased - assert!(receiver_dot_after > receiver_dot_before); - assert_eq!(receiver_ksm_after, receiver_ksm_before + ksm_to_send); -} - -// ============================================================================================== -// ==== Bidirectional Transfer - Native + Teleportable Foreign Assets - Parachain<->AssetHub ==== -// ============================================================================================== -/// Transfers of native asset plus teleportable foreign asset from Parachain to AssetHub and back -/// with fees paid using native asset. -#[test] -fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explicit_transfer_types() { - do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( - para_to_asset_hub_teleport_foreign_assets, - asset_hub_to_para_teleport_foreign_assets, - ); -} - -// =============================================================== -// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== -// =============================================================== -/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid -/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their -/// Sovereign Account on Asset Hub. -#[test] -fn transfer_native_asset_from_relay_to_para_through_asset_hub() { - // Init values for Relay - let destination = Polkadot::child_location_of(PenpalB::para_id()); - let sender = PolkadotSender::get(); - let amount_to_send: Balance = POLKADOT_ED * 1000; - - // Init values for Parachain - let relay_native_asset_location = DotLocation::get(); - let receiver = PenpalBReceiver::get(); - - // Init Test - let test_args = TestContext { - sender, - receiver: receiver.clone(), - args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), - }; - let mut test = RelayToParaThroughAHTest::new(test_args); - - let sov_penpal_on_ah = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), - ); - // Query initial balances - let sender_balance_before = test.sender.balance; - let sov_penpal_on_ah_before = AssetHubPolkadot::execute_with(|| { - ::Balances::free_balance( - sov_penpal_on_ah.clone(), - ) - }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); - - fn relay_assertions(t: RelayToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - Polkadot::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - Polkadot, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); - } - fn asset_hub_assertions(_: RelayToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ah = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), - ); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Deposited to receiver parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Minted { who, .. } - ) => { - who: *who == sov_penpal_on_ah, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - } - fn penpal_assertions(t: RelayToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - let expected_id = t.args.assets.into_inner().first().unwrap().id.0.clone(); - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.receiver.account_id, - }, - ] - ); - } - fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult { - let fee_idx = t.args.fee_asset_item as usize; - let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - let asset_hub_location = Polkadot::child_location_of(AssetHubPolkadot::para_id()); - let context = PolkadotUniversalLocation::get(); - - // reanchor fees to the view of destination (Penpal) - let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); - if let Fungible(ref mut amount) = remote_fees.fun { - // we already spent some fees along the way, just use half of what we started with - *amount /= 2; - } - let xcm_on_final_dest = Xcm::<()>(vec![ - BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, - DepositAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - beneficiary: t.args.beneficiary, - }, - ]); - - // reanchor final dest (Penpal) to the view of hop (Asset Hub) - let mut dest = t.args.dest.clone(); - dest.reanchor(&asset_hub_location, &context).unwrap(); - // on Asset Hub, forward assets to Penpal - let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset { - assets: Wild(AllCounted(t.args.assets.len() as u32)), - dest, - xcm: xcm_on_final_dest, - }]); - - // First leg is a teleport, from there a local-reserve-transfer to final dest - ::XcmPallet::transfer_assets_using_type_and_then( - t.signed_origin, - bx!(asset_hub_location.into()), - bx!(t.args.assets.into()), - bx!(TransferType::Teleport), - bx!(fee.id.into()), - bx!(TransferType::Teleport), - bx!(VersionedXcm::from(xcm_on_hop)), - t.args.weight_limit, - ) - } - - // Set assertions and dispatchables - test.set_assertion::(relay_assertions); - test.set_assertion::(asset_hub_assertions); - test.set_assertion::(penpal_assertions); - test.set_dispatchable::(transfer_assets_dispatchable); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let sov_penpal_on_ah_after = AssetHubPolkadot::execute_with(|| { - ::Balances::free_balance(sov_penpal_on_ah) - }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - amount_to_send); - // SA on AH balance is increased - assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before); - // Receiver's asset balance is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + amount_to_send); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs deleted file mode 100644 index 73b73b239a..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod claim_assets; -mod fellowship_treasury; -mod hybrid_transfers; -mod reserve_transfer; -mod send; -mod set_xcm_versions; -mod swap; -mod teleport; -mod treasury; -mod xcm_fee_estimation; diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs deleted file mode 100644 index 79c7ace374..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/reserve_transfer.rs +++ /dev/null @@ -1,1053 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_polkadot_runtime::xcm_config::DotLocation; -use emulated_integration_tests_common::RESERVABLE_ASSET_ID; -use polkadot_system_emulated_network::penpal_emulated_chain::LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub; - -fn relay_to_para_sender_assertions(t: RelayToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Polkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); - - assert_expected_events!( - Polkadot, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == Polkadot::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn para_to_relay_sender_assertions(t: ParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - PenpalA, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance, .. } - ) => { - asset_id: *asset_id == DotLocation::get(), - owner: *owner == t.sender.account_id, - balance: *balance == t.args.amount, - }, - ] - ); -} - -pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubPolkadot::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -pub fn system_para_to_para_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalB::assert_xcmp_queue_success(None); - for asset in t.args.assets.into_inner().into_iter() { - let expected_id = asset.id.0; - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.receiver.account_id, - }, - ] - ); - } -} - -fn relay_to_para_assets_receiver_assertions(t: RelayToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == DotLocation::get(), - owner: *owner == t.receiver.account_id, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -fn para_to_relay_receiver_assertions(t: ParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_relay = - Polkadot::sovereign_account_id_of(Polkadot::child_location_of(PenpalA::para_id())); - - Polkadot::assert_ump_queue_processed(true, Some(PenpalA::para_id()), None); - assert_expected_events!( - Polkadot, - vec![ - // Amount to reserve transfer is withdrawn from Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_relay.clone(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -pub fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalB::assert_xcm_pallet_attempted_complete(None); - for asset in t.args.assets.into_inner().into_iter() { - let expected_id = asset.id.0; - let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance } - ) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.sender.account_id, - balance: *balance == asset_amount, - }, - ] - ); - } -} - -pub fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahp = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), - ); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahp.clone(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { .. }) => {}, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 676_119_000, - 6196, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::Assets( - pallet_assets::Event::Transferred { asset_id, from, to, amount } - ) => { - asset_id: *asset_id == ASSET_ID, - from: *from == t.sender.account_id, - to: *to == AssetHubPolkadot::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn para_to_system_para_assets_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = DotLocation::get(); - let reservable_asset_location = PenpalLocalReservableFromAssetHub::get(); - PenpalB::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8799))); - assert_expected_events!( - PenpalB, - vec![ - // Fees amount to reserve transfer is burned from Parachains's sender account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, .. } - ) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.sender.account_id, - }, - // Amount to reserve transfer is burned from Parachains's sender account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance } - ) => { - asset_id: *asset_id == reservable_asset_location, - owner: *owner == t.sender.account_id, - balance: *balance == t.args.amount, - }, - // Transport fees are paid - RuntimeEvent::PolkadotXcm( - pallet_xcm::Event::FeesPaid { .. } - ) => {}, - ] - ); -} - -fn system_para_to_para_assets_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - let system_para_asset_location = PenpalLocalReservableFromAssetHub::get(); - PenpalB::assert_xcmp_queue_success(None); - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == DotLocation::get(), - owner: *owner == t.receiver.account_id, - }, - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == system_para_asset_location, - owner: *owner == t.receiver.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn para_to_system_para_assets_receiver_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahr = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalA::para_id()), - ); - AssetHubPolkadot::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is burned from Parachain's Sovereign account - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == RESERVABLE_ASSET_ID, - owner: *owner == sov_penpal_on_ahr, - balance: *balance == t.args.amount, - }, - // Fee amount is burned from Parachain's Sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, .. }) => { - who: *who == sov_penpal_on_ahr, - }, - // Amount to reserve transfer is issued for beneficiary - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == RESERVABLE_ASSET_ID, - owner: *owner == t.receiver.account_id, - amount: *amount == t.args.amount, - }, - // Remaining fee amount is minted for for beneficiary - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -pub fn para_to_para_through_hop_sender_assertions(t: Test) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalB::assert_xcm_pallet_attempted_complete(None); - for asset in t.args.assets.into_inner() { - let expected_id = asset.id.0.clone(); - let amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); - assert_expected_events!( - PenpalB, - vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance }, - ) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.sender.account_id, - balance: *balance == amount, - }, - ] - ); - } -} - -fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_a_on_polkadot = - Polkadot::sovereign_account_id_of(Polkadot::child_location_of(PenpalA::para_id())); - let sov_penpal_b_on_polkadot = - Polkadot::sovereign_account_id_of(Polkadot::child_location_of(PenpalB::para_id())); - assert_expected_events!( - Polkadot, - vec![ - // Withdrawn from sender parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Withdraw { who, amount } | pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_b_on_polkadot, - amount: *amount == t.args.amount, - }, - // Deposited to receiver parachain SA - RuntimeEvent::Balances( - pallet_balances::Event::Deposit { who, .. } | pallet_balances::Event::Minted { who, .. } - ) => { - who: *who == sov_penpal_a_on_polkadot, - }, - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); -} - -pub fn para_to_para_through_hop_receiver_assertions(t: Test) { - type RuntimeEvent = ::RuntimeEvent; - - PenpalA::assert_xcmp_queue_success(None); - for asset in t.args.assets.into_inner().into_iter() { - let expected_id = asset.id.0; - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == expected_id, - owner: *owner == t.receiver.account_id, - }, - ] - ); - } -} - -fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { - ::XcmPallet::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_relay_reserve_transfer_assets(t: ParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_para_through_relay_limited_reserve_transfer_assets( - t: ParaToParaThroughRelayTest, -) -> DispatchResult { - ::PolkadotXcm::limited_reserve_transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -/// Reserve Transfers of DOT from Relay Chain to the Asset Hub shouldn't work -#[test] -fn reserve_transfer_dot_from_relay_to_asset_hub_fails() { - let signed_origin = ::RuntimeOrigin::signed(PolkadotSender::get()); - let destination = Polkadot::child_location_of(AssetHubPolkadot::para_id()); - let beneficiary: Location = - AccountId32Junction { network: None, id: AssetHubPolkadotReceiver::get().into() }.into(); - let amount_to_send: Balance = POLKADOT_ED * 1000; - let assets: Assets = (Here, amount_to_send).into(); - let fee_asset_item = 0; - - // this should fail - Polkadot::execute_with(|| { - let result = ::XcmPallet::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ); - assert_err!( - result, - DispatchError::Module(sp_runtime::ModuleError { - index: 99, - error: [2, 0, 0, 0], - message: Some("Filtered") - }) - ); - }); -} - -/// Reserve Transfers of DOT from Asset Hub to Relay Chain shouldn't work -#[test] -fn reserve_transfer_dot_from_asset_hub_to_relay_fails() { - // Init values for Asset Hub - let signed_origin = - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()); - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let beneficiary: Location = - AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - - let assets: Assets = (Parent, amount_to_send).into(); - let fee_asset_item = 0; - - // this should fail - AssetHubPolkadot::execute_with(|| { - let result = - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ); - assert_err!( - result, - DispatchError::Module(sp_runtime::ModuleError { - index: 31, - error: [2, 0, 0, 0], - message: Some("Filtered") - }) - ); - }); -} - -/// Reserve Transfers of DOT from Relay to Parachain should work -#[test] -fn reserve_transfer_dot_from_relay_to_para() { - // Init values for Relay - let destination = Polkadot::child_location_of(PenpalB::para_id()); - let sender = PolkadotSender::get(); - let amount_to_send: Balance = POLKADOT_ED * 1000; - - // Init values for Parachain - let relay_native_asset_location = DotLocation::get(); - let receiver = PenpalBReceiver::get(); - - // Init Test - let test_args = TestContext { - sender, - receiver: receiver.clone(), - args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), - }; - let mut test = RelayToParaTest::new(test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(relay_to_para_sender_assertions); - test.set_assertion::(relay_to_para_assets_receiver_assertions); - test.set_dispatchable::(relay_to_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - amount_to_send); - // Receiver's asset balance is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + amount_to_send); -} - -/// Reserve Transfers of DOT from Parachain to Relay should work -#[test] -fn reserve_transfer_dot_from_para_to_relay() { - // Init values for Parachain - let destination = PenpalA::parent_location(); - let sender = PenpalASender::get(); - let amount_to_send: Balance = POLKADOT_ED * 1000; - let assets: Assets = (Parent, amount_to_send).into(); - let asset_owner = PenpalAssetOwner::get(); - let relay_native_asset_location = DotLocation::get(); - - // fund Parachain's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // Init values for Relay - let receiver = PolkadotReceiver::get(); - let penpal_location_as_seen_by_relay = Polkadot::child_location_of(PenpalA::para_id()); - let sov_penpal_on_relay = Polkadot::sovereign_account_id_of(penpal_location_as_seen_by_relay); - - // fund Parachain's SA on Relay with the native tokens held in reserve - Polkadot::fund_accounts(vec![(sov_penpal_on_relay, amount_to_send * 2)]); - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver, - amount_to_send, - assets.clone(), - None, - 0, - ), - }; - let mut test = ParaToRelayTest::new(test_args); - - // Query initial balances - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_balance_before = test.receiver.balance; - - // Set assertions and dispatchables - test.set_assertion::(para_to_relay_sender_assertions); - test.set_assertion::(para_to_relay_receiver_assertions); - test.set_dispatchable::(para_to_relay_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &sender) - }); - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_assets_after < sender_assets_before - amount_to_send); - // Receiver's asset balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); -} - -/// Reserve Transfers of DOT from Asset Hub to Parachain should work -#[test] -fn reserve_transfer_dot_from_asset_hub_to_para() { - // Init values for Asset Hub - let destination = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sender = AssetHubPolkadotSender::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; - let assets: Assets = (Parent, amount_to_send).into(); - - // Init values for Parachain - let system_para_native_asset_location = DotLocation::get(); - let receiver = PenpalBReceiver::get(); - - // Init Test - let test_args = TestContext { - sender, - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - amount_to_send, - assets.clone(), - None, - 0, - ), - }; - let mut test = SystemParaToParaTest::new(test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(system_para_to_para_sender_assertions); - test.set_assertion::(system_para_to_para_receiver_assertions); - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_balance_after < sender_balance_before - amount_to_send); - // Receiver's assets is increased - assert!(receiver_assets_after > receiver_assets_before); - // Receiver's assets increased by `amount_to_send - delivery_fees - bought_execution`; - - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_assets_after < receiver_assets_before + amount_to_send); -} - -/// Reserve Transfers of DOT from Parachain to Asset Hub should work -#[test] -fn reserve_transfer_dot_from_para_to_asset_hub() { - // Init values for Parachain - let destination = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let sender = PenpalBSender::get(); - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; - let assets: Assets = (Parent, amount_to_send).into(); - let system_para_native_asset_location = DotLocation::get(); - let asset_owner = PenpalAssetOwner::get(); - - // fund Parachain's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - system_para_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // Init values for Asset Hub - let receiver = AssetHubPolkadotReceiver::get(); - let penpal_location_as_seen_by_ahp = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahp = - AssetHubPolkadot::sovereign_account_id_of(penpal_location_as_seen_by_ahp); - - // fund Parachain's SA on Asset Hub with the native tokens held in reserve - AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_ahp, amount_to_send * 2)]); - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination.clone(), - receiver.clone(), - amount_to_send, - assets.clone(), - None, - 0, - ), - }; - let mut test = ParaToSystemParaTest::new(test_args); - - // Query initial balances - let sender_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &sender) - }); - let receiver_balance_before = test.receiver.balance; - - // Set assertions and dispatchables - test.set_assertion::(para_to_system_para_sender_assertions); - test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location, &sender) - }); - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_assets_after < sender_assets_before - amount_to_send); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + amount_to_send); -} - -/// Reserve Transfers of a local asset and DOT from Asset Hub to Parachain should work -#[test] -fn reserve_transfer_multiple_assets_from_asset_hub_to_para() { - // Init values for Asset Hub - let destination = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahp = AssetHubPolkadot::sovereign_account_id_of(destination.clone()); - let sender = AssetHubPolkadotSender::get(); - let fee_amount_to_send = ASSET_HUB_POLKADOT_ED * 10000; - let asset_amount_to_send = PENPAL_ED * 10000; - let asset_owner = AssetHubPolkadotAssetOwner::get(); - let asset_owner_signer = - ::RuntimeOrigin::signed(asset_owner.clone()); - let assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - ( - [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())], - asset_amount_to_send, - ) - .into(), - ] - .into(); - let fee_asset_index = assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - AssetHubPolkadot::mint_asset( - asset_owner_signer, - RESERVABLE_ASSET_ID, - asset_owner, - asset_amount_to_send * 2, - ); - - // Create SA-of-Penpal-on-AHP with ED. - AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_ahp, ASSET_HUB_POLKADOT_ED)]); - - // Init values for Parachain - let receiver = PenpalBReceiver::get(); - let system_para_native_asset_location = DotLocation::get(); - let system_para_foreign_asset_location = PenpalLocalReservableFromAssetHub::get(); - - // Init Test - let para_test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination, - receiver.clone(), - asset_amount_to_send, - assets, - None, - fee_asset_index, - ), - }; - let mut test = SystemParaToParaTest::new(para_test_args); - - // Query initial balances - let sender_balance_before = test.sender.balance; - let sender_assets_before = AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &sender) - }); - let receiver_system_native_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - let receiver_foreign_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_foreign_asset_location.clone(), - &receiver, - ) - }); - - // Set assertions and dispatchables - test.set_assertion::(system_para_to_para_assets_sender_assertions); - test.set_assertion::(system_para_to_para_assets_receiver_assertions); - test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_balance_after = test.sender.balance; - let sender_assets_after = AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &sender) - }); - let receiver_system_native_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_native_asset_location.clone(), &receiver) - }); - let receiver_foreign_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_para_foreign_asset_location, &receiver) - }); - // Sender's balance is reduced - assert!(sender_balance_after < sender_balance_before); - // Receiver's foreign asset balance is increased - assert!(receiver_foreign_assets_after > receiver_foreign_assets_before); - // Receiver's system asset balance increased by `amount_to_send - delivery_fees - - // bought_execution`; `delivery_fees` might be paid from transfer or JIT, also - // `bought_execution` is unknown but should be non-zero - assert!( - receiver_system_native_assets_after < - receiver_system_native_assets_before + fee_amount_to_send - ); - - // Sender's asset balance is reduced by exact amount - assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after); - // Receiver's foreign asset balance is increased by exact amount - assert_eq!( - receiver_foreign_assets_after, - receiver_foreign_assets_before + asset_amount_to_send - ); -} - -/// Reserve Transfers of a random asset and DOT asset from Parachain to Asset Hub should work -#[test] -fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { - // Init values for Parachain - let destination = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let sender = PenpalBSender::get(); - let fee_amount_to_send = ASSET_HUB_POLKADOT_ED * 10000; - let asset_amount_to_send = ASSET_HUB_POLKADOT_ED * 10000; - let penpal_asset_owner = PenpalAssetOwner::get(); - let penpal_asset_owner_signer = ::RuntimeOrigin::signed(penpal_asset_owner); - let asset_location_on_penpal = PenpalLocalReservableFromAssetHub::get(); - let system_asset_location_on_penpal = DotLocation::get(); - let assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - (asset_location_on_penpal.clone(), asset_amount_to_send).into(), - ] - .into(); - let fee_asset_index = assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - // Fund Parachain's sender account with some foreign assets - PenpalB::mint_foreign_asset( - penpal_asset_owner_signer.clone(), - asset_location_on_penpal.clone(), - sender.clone(), - asset_amount_to_send * 2, - ); - // Fund Parachain's sender account with some system assets - PenpalB::mint_foreign_asset( - penpal_asset_owner_signer, - system_asset_location_on_penpal.clone(), - sender.clone(), - fee_amount_to_send * 2, - ); - - // Init values for Asset Hub - let receiver = AssetHubPolkadotReceiver::get(); - let penpal_location_as_seen_by_ahp = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ahp = - AssetHubPolkadot::sovereign_account_id_of(penpal_location_as_seen_by_ahp); - let ah_asset_owner = AssetHubPolkadotAssetOwner::get(); - let ah_asset_owner_signer = ::RuntimeOrigin::signed(ah_asset_owner); - - // Fund SA-of-Penpal-on-AHP to be able to pay for the fees. - AssetHubPolkadot::fund_accounts(vec![( - sov_penpal_on_ahp.clone(), - ASSET_HUB_POLKADOT_ED * 10000000, - )]); - // Fund SA-of-Penpal-on-AHP to be able to pay for the sent amount. - AssetHubPolkadot::mint_asset( - ah_asset_owner_signer, - RESERVABLE_ASSET_ID, - sov_penpal_on_ahp, - asset_amount_to_send * 2, - ); - - // Init Test - let para_test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para( - destination, - receiver.clone(), - asset_amount_to_send, - assets, - None, - fee_asset_index, - ), - }; - let mut test = ParaToSystemParaTest::new(para_test_args); - - // Query initial balances - let sender_system_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_asset_location_on_penpal.clone(), &sender) - }); - let sender_foreign_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(asset_location_on_penpal.clone(), &sender) - }); - let receiver_balance_before = test.receiver.balance; - let receiver_assets_before = AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_system_para_assets_sender_assertions); - test.set_assertion::(para_to_system_para_assets_receiver_assertions); - test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_system_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(system_asset_location_on_penpal, &sender) - }); - let sender_foreign_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(asset_location_on_penpal, &sender) - }); - let receiver_balance_after = test.receiver.balance; - let receiver_assets_after = AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - >::balance(RESERVABLE_ASSET_ID, &receiver) - }); - // Sender's system asset balance is reduced - assert!(sender_system_assets_after < sender_system_assets_before); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(receiver_balance_after < receiver_balance_before + fee_amount_to_send); - - // Sender's asset balance is reduced by exact amount - assert_eq!(sender_foreign_assets_before - asset_amount_to_send, sender_foreign_assets_after); - // Receiver's foreign asset balance is increased by exact amount - assert_eq!(receiver_assets_after, receiver_assets_before + asset_amount_to_send); -} - -/// Reserve Transfers of DOT from Parachain to Parachain (through Relay reserve) should work -#[test] -fn reserve_transfer_dot_from_para_to_para_through_relay() { - // Init values for Parachain Origin - let destination = PenpalB::sibling_location_of(PenpalA::para_id()); - let sender = PenpalBSender::get(); - let amount_to_send: Balance = POLKADOT_ED * 10000; - let asset_owner = PenpalAssetOwner::get(); - let assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = DotLocation::get(); - let sender_as_seen_by_relay = Polkadot::child_location_of(PenpalB::para_id()); - let sov_of_sender_on_relay = Polkadot::sovereign_account_id_of(sender_as_seen_by_relay); - - // fund Parachain's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve - Polkadot::fund_accounts(vec![(sov_of_sender_on_relay, amount_to_send * 2)]); - - // Init values for Parachain Destination - let receiver = PenpalAReceiver::get(); - - // Init Test - let test_args = TestContext { - sender: sender.clone(), - receiver: receiver.clone(), - args: TestArgs::new_para(destination, receiver.clone(), amount_to_send, assets, None, 0), - }; - let mut test = ParaToParaThroughRelayTest::new(test_args); - - // Query initial balances - let sender_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &receiver) - }); - - // Set assertions and dispatchables - test.set_assertion::(para_to_para_through_hop_sender_assertions); - test.set_assertion::(para_to_para_relay_hop_assertions); - test.set_assertion::(para_to_para_through_hop_receiver_assertions); - test.set_dispatchable::(para_to_para_through_relay_limited_reserve_transfer_assets); - test.assert(); - - // Query final balances - let sender_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &receiver) - }); - - // Sender's balance is reduced by amount sent plus delivery fees - assert!(sender_assets_after < sender_assets_before - amount_to_send); - // Receiver's balance is increased - assert!(receiver_assets_after > receiver_assets_before); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/send.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/send.rs deleted file mode 100644 index 23e6fe4323..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/send.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -/// Relay Chain should be able to execute `Transact` instructions in System Parachain -/// when `OriginKind::Superuser`. -#[test] -fn send_transact_as_superuser_from_relay_to_asset_hub_works() { - AssetHubPolkadot::force_create_asset_from_relay_as_root( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - AssetHubPolkadotSender::get(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ) -} - -/// We tests two things here: -/// - Parachain should be able to send XCM paying its fee at Asset Hub using DOT -/// - Parachain should be able to create a new Foreign Asset at Asset Hub -#[test] -fn send_xcm_from_para_to_asset_hub_paying_fee_with_system_asset() { - let para_sovereign_account = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalA::para_id()), - ); - let asset_location_on_penpal = v4::Location::new( - 0, - [ - v4::Junction::PalletInstance(ASSETS_PALLET_ID), - v4::Junction::GeneralIndex(ASSET_ID.into()), - ], - ); - let foreign_asset_at_asset_hub = - v4::Location::new(1, [v4::Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - - // Encoded `create_asset` call to be executed in AssetHub - let call = AssetHubPolkadot::create_foreign_asset_call( - foreign_asset_at_asset_hub.clone(), - ASSET_MIN_BALANCE, - para_sovereign_account.clone(), - ); - - let origin_kind = OriginKind::Xcm; - let fee_amount = ASSET_HUB_POLKADOT_ED * 1000000; - let system_asset = (Parent, fee_amount).into(); - - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = PenpalA::sibling_location_of(AssetHubPolkadot::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - origin_kind, - system_asset, - para_sovereign_account.clone(), - ); - - // SA-of-Penpal-on-AHP needs to have balance to pay for fees and asset creation deposit - AssetHubPolkadot::fund_accounts(vec![( - para_sovereign_account.clone(), - ASSET_HUB_POLKADOT_ED * 10000000000, - )]); - - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - PenpalA::assert_xcm_pallet_sent(); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Burned the fee - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == para_sovereign_account, - amount: *amount == fee_amount, - }, - // Foreign Asset created - RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { - asset_id: *asset_id == foreign_asset_at_asset_hub.clone(), - creator: *creator == para_sovereign_account.clone(), - owner: *owner == para_sovereign_account, - }, - ] - ); - - type ForeignAssets = ::ForeignAssets; - assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub)); - }); -} - -/// We tests two things here: -/// - Parachain should be able to send XCM paying its fee at Asset Hub using sufficient asset -/// - Parachain should be able to create a new Asset at Asset Hub -#[test] -fn send_xcm_from_para_to_asset_hub_paying_fee_with_sufficient_asset() { - let para_sovereign_account = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalA::para_id()), - ); - - // Force create and mint sufficient assets for Parachain's sovereign account - AssetHubPolkadot::force_create_and_mint_asset( - ASSET_ID, - ASSET_MIN_BALANCE, - true, - para_sovereign_account.clone(), - Some(Weight::from_parts(1_019_445_000, 200_000)), - ASSET_MIN_BALANCE * 1000000000, - ); - - // Just a different `asset_id`` that does not exist yet - let new_asset_id = ASSET_ID + 1; - - // Encoded `create_asset` call to be executed in AssetHub - let call = AssetHubPolkadot::create_asset_call( - new_asset_id, - ASSET_MIN_BALANCE, - para_sovereign_account.clone(), - ); - - let origin_kind = OriginKind::SovereignAccount; - let fee_amount = ASSET_MIN_BALANCE * 1000000; - let asset = - ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); - - let root_origin = ::RuntimeOrigin::root(); - let system_para_destination = PenpalA::sibling_location_of(AssetHubPolkadot::para_id()).into(); - let xcm = xcm_transact_paid_execution(call, origin_kind, asset, para_sovereign_account.clone()); - - // SA-of-Penpal-on-AHP needs to have balance to pay for asset creation deposit - AssetHubPolkadot::fund_accounts(vec![( - para_sovereign_account.clone(), - ASSET_HUB_POLKADOT_ED * 10000000000, - )]); - - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(system_para_destination), - bx!(xcm), - )); - - PenpalA::assert_xcm_pallet_sent(); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Burned the fee - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == ASSET_ID, - owner: *owner == para_sovereign_account, - balance: *balance == fee_amount, - }, - // Asset created - RuntimeEvent::Assets(pallet_assets::Event::Created { asset_id, creator, owner }) => { - asset_id: *asset_id == new_asset_id, - creator: *creator == para_sovereign_account.clone(), - owner: *owner == para_sovereign_account, - }, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs deleted file mode 100644 index 1835b2931c..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/set_xcm_versions.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -#[test] -fn relay_sets_system_para_xcm_supported_version() { - // Init tests variables - let sudo_origin = ::RuntimeOrigin::root(); - let system_para_destination: Location = - Polkadot::child_location_of(AssetHubPolkadot::para_id()); - - // Relay Chain sets supported version for Asset Parachain - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::force_xcm_version( - sudo_origin, - bx!(system_para_destination.clone()), - XCM_V4 - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::SupportedVersionChanged { - location, - version: XCM_V4 - }) => { location: *location == system_para_destination, }, - ] - ); - }); -} - -#[test] -fn system_para_sets_relay_xcm_supported_version() { - // Init test variables - let parent_location = AssetHubPolkadot::parent_location(); - let force_xcm_version_call = - ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::< - ::Runtime, - >::force_xcm_version { - location: bx!(parent_location.clone()), - version: XCM_V4, - }) - .encode() - .into(); - - // System Parachain sets supported version for Relay Chain through it - Polkadot::send_unpaid_transact_to_parachain_as_root( - AssetHubPolkadot::para_id(), - force_xcm_version_call, - ); - - // System Parachain receive the XCM message - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_dmp_queue_complete(Some(Weight::from_parts( - 1_019_210_000, - 200_000, - ))); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::SupportedVersionChanged { - location, - version: XCM_V4 - }) => { location: *location == parent_location, }, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs deleted file mode 100644 index c3188c67b4..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/swap.rs +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use polkadot_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; -use system_parachains_constants::polkadot::currency::SYSTEM_PARA_EXISTENTIAL_DEPOSIT; - -#[test] -fn swap_locally_on_chain_using_local_assets() { - use frame_support::traits::fungible::Mutate; - - let asset_native = asset_hub_polkadot_runtime::xcm_config::DotLocation::get(); - let asset_one = v4::Location::new( - 0, - [ - v4::Junction::PalletInstance(ASSETS_PALLET_ID), - v4::Junction::GeneralIndex(ASSET_ID.into()), - ], - ); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - ASSET_ID.into(), - AssetHubPolkadotSender::get().into(), - 1000, - )); - assert!(::Assets::asset_exists(ASSET_ID)); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - ASSET_ID.into(), - AssetHubPolkadotSender::get().into(), - 3_000_000_000_000, - )); - - ::Balances::set_balance( - &AssetHubPolkadotSender::get(), - 3_000_000_000_000, - ); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - bx!(asset_native.clone()), - bx!(asset_one.clone()), - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - bx!(asset_native.clone()), - bx!(asset_one.clone()), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - AssetHubPolkadotSender::get() - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, - ] - ); - - let path = vec![bx!(asset_native.clone()), bx!(asset_one.clone())]; - - assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - path, - 100, - 1, - AssetHubPolkadotSender::get(), - true - ) - ); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. }) => { - amount_in: *amount_in == 100, - amount_out: *amount_out == 199, - }, - ] - ); - - assert_ok!( - ::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - bx!(asset_native), - bx!(asset_one), - 1414213562273 - SYSTEM_PARA_EXISTENTIAL_DEPOSIT * 2, /* all but the 2 EDs can't - * be - * retrieved. */ - 0, - 0, - AssetHubPolkadotSender::get(), - ) - ); - }); -} - -#[test] -fn swap_locally_on_chain_using_foreign_assets() { - let asset_native = Box::new(asset_hub_polkadot_runtime::xcm_config::DotLocation::get()); - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); - let foreign_asset_at_asset_hub_polkadot = - v4::Location::new(1, [v4::Junction::Parachain(PenpalA::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - - let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_ahp = AssetHubPolkadot::sovereign_account_id_of(penpal_as_seen_by_ah); - AssetHubPolkadot::fund_accounts(vec![ - // An account to swap dot for something else. - (AssetHubPolkadotSender::get(), 5_000_000 * ASSET_HUB_POLKADOT_ED), - // Penpal's sovereign account in AH should have some balance - (sov_penpal_on_ahp.clone(), 100_000_000 * ASSET_HUB_POLKADOT_ED), - ]); - - AssetHubPolkadot::execute_with(|| { - // 0: No need to create foreign asset as it exists in genesis. - // - // 1:: Mint foreign asset on asset_hub_polkadot: - // - // (While it might be nice to use batch, - // currently that's disabled due to safe call filters.) - - type RuntimeEvent = ::RuntimeEvent; - // 3. Mint foreign asset (in reality this should be a teleport or some such) - assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed(sov_penpal_on_ahp.clone()), - foreign_asset_at_asset_hub_polkadot.clone(), - sov_penpal_on_ahp.clone().into(), - ASSET_HUB_POLKADOT_ED * 3_000_000_000_000, - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - - // 4. Create pool: - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_polkadot.clone()), - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - // 5. Add liquidity: - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahp.clone()), - asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_polkadot.clone()), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - sov_penpal_on_ahp.clone() - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { - lp_token_minted: *lp_token_minted == 1414213562273, - }, - ] - ); - - // 6. Swap! - let path = - vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_polkadot.clone())]; - - assert_ok!( - ::AssetConversion::swap_exact_tokens_for_tokens( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - path, - 100000 * ASSET_HUB_POLKADOT_ED, - 1000 * ASSET_HUB_POLKADOT_ED, - AssetHubPolkadotSender::get(), - true - ) - ); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => { - amount_in: *amount_in == 10000000000000, - amount_out: *amount_out == 1817684594348, - }, - ] - ); - - // 7. Remove liquidity - assert_ok!( - ::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed(sov_penpal_on_ahp.clone()), - asset_native.clone(), - Box::new(foreign_asset_at_asset_hub_polkadot), - 1414213562273 / 2, // remove only half - 0, - 0, - sov_penpal_on_ahp.clone(), - ) - ); - }); -} - -#[test] -fn cannot_create_pool_from_pool_assets() { - use frame_support::traits::fungibles::{Create, Mutate}; - - let asset_native = asset_hub_polkadot_runtime::xcm_config::DotLocation::get(); - let asset_one = asset_hub_polkadot_runtime::xcm_config::PoolAssetsPalletLocation::get() - .appended_with(GeneralIndex(ASSET_ID.into())) - .expect("valid location"); - - AssetHubPolkadot::execute_with(|| { - assert_ok!( - <::PoolAssets as Create<_>>::create( - ASSET_ID, - AssetHubPolkadotSender::get(), - false, - 1000, - ) - ); - assert!(::PoolAssets::asset_exists(ASSET_ID)); - - assert_ok!(::PoolAssets::mint_into( - ASSET_ID, - &AssetHubPolkadotSender::get(), - 3_000_000_000_000, - )); - - assert_matches::assert_matches!( - ::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - Box::new(asset_native), - Box::new(asset_one), - ), - Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) - ); - }); -} - -#[test] -fn pay_xcm_fee_with_some_asset_swapped_for_native() { - use frame_support::traits::fungible::Mutate; - - let asset_native: xcm::v4::Location = - asset_hub_polkadot_runtime::xcm_config::DotLocation::get(); - let asset_one = xcm::v4::Location { - parents: 0, - interior: [ - xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID), - xcm::v4::Junction::GeneralIndex(ASSET_ID.into()), - ] - .into(), - }; - let penpal = AssetHubPolkadot::sovereign_account_id_of(AssetHubPolkadot::sibling_location_of( - PenpalB::para_id(), - )); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // set up pool with ASSET_ID <> NATIVE pair - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - ASSET_ID.into(), - AssetHubPolkadotSender::get().into(), - ASSET_MIN_BALANCE, - )); - assert!(::Assets::asset_exists(ASSET_ID)); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - ASSET_ID.into(), - AssetHubPolkadotSender::get().into(), - 3_000_000_000_000, - )); - - ::Balances::set_balance( - &AssetHubPolkadotSender::get(), - 3_000_000_000_000, - ); - - assert_ok!(::AssetConversion::create_pool( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - Box::new(asset_native.clone()), - Box::new(asset_one.clone()), - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - - assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - Box::new(asset_native), - Box::new(asset_one), - 1_000_000_000_000, - 2_000_000_000_000, - 0, - 0, - AssetHubPolkadotSender::get() - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => { lp_token_minted: *lp_token_minted == 1414213562273, }, - ] - ); - - // ensure `penpal` sovereign account has no native tokens and mint some `ASSET_ID` - assert_eq!( - ::Balances::free_balance(penpal.clone()), - 0 - ); - - assert_ok!(::Assets::touch_other( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - ASSET_ID.into(), - penpal.clone().into(), - )); - - assert_ok!(::Assets::mint( - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - ASSET_ID.into(), - penpal.clone().into(), - 10_000_000_000_000, - )); - }); - - PenpalB::execute_with(|| { - // send xcm transact from `penpal` account which as only `ASSET_ID` tokens on - // `AssetHubPolkadot` - let call = AssetHubPolkadot::force_create_asset_call( - ASSET_ID + 1000, - penpal.clone(), - true, - ASSET_MIN_BALANCE, - ); - - let penpal_root = ::RuntimeOrigin::root(); - let fee_amount = 4_000_000_000_000u128; - let asset_one = - ([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into(); - let asset_hub_location = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()).into(); - let xcm = xcm_transact_paid_execution( - call, - OriginKind::SovereignAccount, - asset_one, - penpal.clone(), - ); - - assert_ok!(::PolkadotXcm::send( - penpal_root, - bx!(asset_hub_location), - bx!(xcm), - )); - - PenpalB::assert_xcm_pallet_sent(); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapCreditExecuted { .. },) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true,.. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs deleted file mode 100644 index 6965fe571d..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/teleport.rs +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_polkadot_runtime::xcm_config::{DotLocation, XcmConfig as AssetHubPolkadotXcmConfig}; -use emulated_integration_tests_common::xcm_helpers::non_fee_asset; -use frame_support::traits::fungible::Mutate; -use polkadot_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Polkadot::assert_ump_queue_processed( - false, - Some(AssetHubPolkadot::para_id()), - Some(Weight::from_parts(148_705_000, 3_593)), - ); -} - -fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 533_910_000, - 7167, - ))); - - AssetHubPolkadot::assert_parachain_system_ump_sent(); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let system_para_native_asset_location = DotLocation::get(); - let expected_asset_id = t.args.asset_id.unwrap(); - let (_, expected_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - - PenpalB::assert_xcm_pallet_attempted_complete(None); - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, .. } - ) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.sender.account_id, - }, - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_asset_id, - owner: *owner == t.sender.account_id, - balance: *balance == expected_asset_amount, - }, - ] - ); -} - -fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahk = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), - ); - let (expected_foreign_asset_id, expected_foreign_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - AssetHubPolkadot::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // native asset reserve transfer for paying fees, withdrawn from Penpal's sov account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_penpal_on_ahk.clone(), - amount: *amount == t.args.amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == expected_foreign_asset_id, - owner: *owner == t.receiver.account_id, - amount: *amount == expected_foreign_asset_amount, - }, - RuntimeEvent::Balances(pallet_balances::Event::Issued { .. }) => {}, - ] - ); -} - -fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcm_pallet_attempted_complete(None); - let (expected_foreign_asset_id, expected_foreign_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // native asset used for fees is transferred to Parachain's Sovereign account as reserve - RuntimeEvent::Balances( - pallet_balances::Event::Transfer { from, to, amount } - ) => { - from: *from == t.sender.account_id, - to: *to == AssetHubPolkadot::sovereign_account_id_of( - t.args.dest.clone() - ), - amount: *amount == t.args.amount, - }, - // foreign asset is burned locally as part of teleportation - RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_foreign_asset_id, - owner: *owner == t.sender.account_id, - balance: *balance == expected_foreign_asset_amount, - }, - ] - ); -} - -fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { - type RuntimeEvent = ::RuntimeEvent; - let expected_asset_id = t.args.asset_id.unwrap(); - let (_, expected_asset_amount) = - non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); - let checking_account = ::PolkadotXcm::check_account(); - let system_para_native_asset_location = DotLocation::get(); - - PenpalB::assert_xcmp_queue_success(None); - assert_expected_events!( - PenpalB, - vec![ - // checking account burns local asset as part of incoming teleport - RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { - asset_id: *asset_id == expected_asset_id, - owner: *owner == checking_account, - balance: *balance == expected_asset_amount, - }, - // local asset is teleported into account of receiver - RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == expected_asset_id, - owner: *owner == t.receiver.account_id, - amount: *amount == expected_asset_amount, - }, - // native asset for fee is deposited to receiver - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { - asset_id: *asset_id == system_para_native_asset_location, - owner: *owner == t.receiver.account_id, - amount: *amount == expected_asset_amount, - }, - ] - ); -} - -fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { - ::PolkadotXcm::transfer_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -#[test] -fn teleport_to_other_system_parachains_works() { - let amount = ASSET_HUB_POLKADOT_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - AssetHubPolkadot, // Origin - AssetHubPolkadotXcmConfig, // XCM Configuration - vec![BridgeHubPolkadot], // Destinations - (native_asset, amount) - ); -} - -#[test] -fn teleport_from_and_to_relay() { - let amount = POLKADOT_ED * 100; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Polkadot, - PolkadotXcmConfig, - vec![AssetHubPolkadot], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - AssetHubPolkadot, - AssetHubPolkadotXcmConfig, - Polkadot, - amount - ); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 1000; - let destination = AssetHubPolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubPolkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >( - test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest - ) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - -/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets while paying -/// fees using (reserve transferred) native asset. -pub fn do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( - para_to_ah_dispatchable: fn(ParaToSystemParaTest) -> DispatchResult, - ah_to_para_dispatchable: fn(SystemParaToParaTest) -> DispatchResult, -) { - // Init values for Parachain - let fee_amount_to_send: Balance = ASSET_HUB_POLKADOT_ED * 10000; - let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); - let asset_id_on_penpal = match asset_location_on_penpal.last() { - Some(Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - let asset_amount_to_send = ASSET_HUB_POLKADOT_ED * 1000; - let asset_owner = PenpalAssetOwner::get(); - let system_para_native_asset_location = DotLocation::get(); - let sender = PenpalBSender::get(); - let penpal_check_account = ::PolkadotXcm::check_account(); - let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let penpal_assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - (asset_location_on_penpal.clone(), asset_amount_to_send).into(), - ] - .into(); - let fee_asset_index = penpal_assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - - // fund Parachain's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), - system_para_native_asset_location.clone(), - sender.clone(), - fee_amount_to_send * 2, - ); - // No need to create the asset (only mint) as it exists in genesis. - PenpalB::mint_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), - asset_id_on_penpal, - sender.clone(), - asset_amount_to_send, - ); - // fund Parachain's check account to be able to teleport - PenpalB::fund_accounts(vec![(penpal_check_account.clone(), ASSET_HUB_POLKADOT_ED * 1000)]); - - // prefund SA of Penpal on AssetHub with enough native tokens to pay for fees - let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_ah = AssetHubPolkadot::sovereign_account_id_of(penpal_as_seen_by_ah); - AssetHubPolkadot::fund_accounts(vec![( - sov_penpal_on_ah.clone(), - ASSET_HUB_POLKADOT_ED * 100_000_000_000, - )]); - - // Init values for System Parachain - let foreign_asset_at_asset_hub_polkadot = - Location::new(1, [Junction::Parachain(PenpalB::para_id().into())]) - .appended_with(asset_location_on_penpal) - .unwrap(); - let penpal_to_ah_beneficiary_id = AssetHubPolkadotReceiver::get(); - - // Penpal to AH test args - let penpal_to_ah_test_args = TestContext { - sender: PenpalBSender::get(), - receiver: AssetHubPolkadotReceiver::get(), - args: TestArgs::new_para( - ah_as_seen_by_penpal, - penpal_to_ah_beneficiary_id, - asset_amount_to_send, - penpal_assets, - Some(asset_id_on_penpal), - fee_asset_index, - ), - }; - let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); - let penpal_sender_balance_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalBSender::get(), - ) - }); - - let ah_receiver_balance_before = penpal_to_ah.receiver.balance; - - let penpal_sender_assets_before = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBSender::get()) - }); - let ah_receiver_assets_before = AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_polkadot.clone(), - &AssetHubPolkadotReceiver::get(), - ) - }); - - penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); - penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); - penpal_to_ah.set_dispatchable::(para_to_ah_dispatchable); - penpal_to_ah.assert(); - - let penpal_sender_balance_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalBSender::get(), - ) - }); - - let ah_receiver_balance_after = penpal_to_ah.receiver.balance; - - let penpal_sender_assets_after = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBSender::get()) - }); - let ah_receiver_assets_after = AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_polkadot.clone(), - &AssetHubPolkadotReceiver::get(), - ) - }); - - // Sender's balance is reduced - assert!(penpal_sender_balance_after < penpal_sender_balance_before); - // Receiver's balance is increased - assert!(ah_receiver_balance_after > ah_receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send); - - // Sender's balance is reduced by exact amount - assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after); - // Receiver's balance is increased by exact amount - assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send); - - /////////////////////////////////////////////////////////////////////// - // Now test transferring foreign assets back from AssetHub to Penpal // - /////////////////////////////////////////////////////////////////////// - - // Move funds on AH from AHReceiver to AHSender - AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - assert_ok!(ForeignAssets::transfer( - ::RuntimeOrigin::signed(AssetHubPolkadotReceiver::get()), - foreign_asset_at_asset_hub_polkadot.clone(), - AssetHubPolkadotSender::get().into(), - asset_amount_to_send, - )); - }); - - let ah_to_penpal_beneficiary_id = PenpalBReceiver::get(); - let penpal_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let ah_assets: Assets = vec![ - (Parent, fee_amount_to_send).into(), - (foreign_asset_at_asset_hub_polkadot.clone(), asset_amount_to_send).into(), - ] - .into(); - let fee_asset_index = ah_assets - .inner() - .iter() - .position(|r| r == &(Parent, fee_amount_to_send).into()) - .unwrap() as u32; - - // AH to Penpal test args - let ah_to_penpal_test_args = TestContext { - sender: AssetHubPolkadotSender::get(), - receiver: PenpalBReceiver::get(), - args: TestArgs::new_para( - penpal_as_seen_by_ah, - ah_to_penpal_beneficiary_id, - asset_amount_to_send, - ah_assets, - Some(asset_id_on_penpal), - fee_asset_index, - ), - }; - let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); - - let ah_sender_balance_before = ah_to_penpal.sender.balance; - let penpal_receiver_balance_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location.clone(), - &PenpalBReceiver::get(), - ) - }); - - let ah_sender_assets_before = AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_polkadot.clone(), - &AssetHubPolkadotSender::get(), - ) - }); - let penpal_receiver_assets_before = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBReceiver::get()) - }); - - ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); - ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); - ah_to_penpal.set_dispatchable::(ah_to_para_dispatchable); - ah_to_penpal.assert(); - - let ah_sender_balance_after = ah_to_penpal.sender.balance; - let penpal_receiver_balance_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - system_para_native_asset_location, - &PenpalBReceiver::get(), - ) - }); - - let ah_sender_assets_after = AssetHubPolkadot::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance( - foreign_asset_at_asset_hub_polkadot, - &AssetHubPolkadotSender::get(), - ) - }); - let penpal_receiver_assets_after = PenpalB::execute_with(|| { - type Assets = ::Assets; - >::balance(asset_id_on_penpal, &PenpalBReceiver::get()) - }); - - // Sender's balance is reduced - assert!(ah_sender_balance_after < ah_sender_balance_before); - // Receiver's balance is increased - assert!(penpal_receiver_balance_after > penpal_receiver_balance_before); - // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; - // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but - // should be non-zero - assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send); - - // Sender's balance is reduced by exact amount - assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after); - // Receiver's balance is increased by exact amount - assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send); -} - -/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work -/// (using native reserve-based transfer for fees) -#[test] -fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { - do_bidirectional_teleport_foreign_assets_between_para_and_asset_hub_using_xt( - para_to_system_para_transfer_assets, - system_para_to_para_transfer_assets, - ); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/treasury.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/treasury.rs deleted file mode 100644 index 57319bb5fe..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/treasury.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; -use frame_support::traits::fungibles::Mutate; -use polkadot_runtime_common::impls::VersionedLocatableAsset; -use xcm_executor::traits::ConvertLocation; - -#[test] -fn create_and_claim_treasury_spend_in_usdt() { - const USDT_ID: u32 = 1984; - const SPEND_AMOUNT: u128 = 1_000_000_000; - // treasury location from a sibling parachain. - let treasury_location: Location = Location::new(1, PalletInstance(19)); - // treasury account on a sibling parachain. - let treasury_account = - asset_hub_polkadot_runtime::xcm_config::LocationToAccountId::convert_location( - &treasury_location, - ) - .unwrap(); - let asset_hub_location = - v4::Location::new(0, v4::Junction::Parachain(AssetHubPolkadot::para_id().into())); - let root = ::RuntimeOrigin::root(); - // asset kind to be spend from the treasury. - let asset_kind = VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: v4::AssetId( - (v4::Junction::PalletInstance(50), v4::Junction::GeneralIndex(USDT_ID.into())).into(), - ), - }; - // treasury spend beneficiary. - let alice: AccountId = Polkadot::account_id_of(ALICE); - let bob: AccountId = Polkadot::account_id_of(BOB); - let bob_signed = ::RuntimeOrigin::signed(bob.clone()); - - AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - - // USDT created at genesis, mint some assets to the treasury account. - assert_ok!(>::mint_into(USDT_ID, &treasury_account, SPEND_AMOUNT * 4)); - // beneficiary has zero balance. - assert_eq!(>::balance(USDT_ID, &alice,), 0u128,); - }); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Treasury = ::Treasury; - type AssetRate = ::AssetRate; - - // create a conversion rate from `asset_kind` to the native currency. - assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); - - // create and approve a treasury spend. - assert_ok!(Treasury::spend( - root, - Box::new(asset_kind), - SPEND_AMOUNT, - Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), - None, - )); - // claim the spend. - assert_ok!(Treasury::payout(bob_signed.clone(), 0)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Assets = ::Assets; - - // assert events triggered by xcm pay program - // 1. treasury asset transferred to spend beneficiary - // 2. response to Relay Chain treasury pallet instance sent back - // 3. XCM program completed - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { - id: id == &USDT_ID, - from: from == &treasury_account, - to: to == &alice, - amount: amount == &SPEND_AMOUNT, - }, - RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - // beneficiary received the assets from the treasury. - assert_eq!(>::balance(USDT_ID, &alice,), SPEND_AMOUNT,); - }); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Treasury = ::Treasury; - - // check the payment status to ensure the response from the AssetHub was received. - assert_ok!(Treasury::check_status(bob_signed, 0)); - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs deleted file mode 100644 index 50fe578dde..0000000000 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests for XCM fee estimation in the runtime. - -use crate::{ - assert_expected_events, bx, AssetHubPolkadot, Chain, ParaToParaThroughAHTest, PenpalA, - PenpalAPallet, PenpalAReceiver, PenpalAssetOwner, PenpalB, PenpalBPallet, PenpalBSender, - TestArgs, TestContext, TransferType, -}; -use emulated_integration_tests_common::impls::{Parachain, TestExt}; -use frame_support::{ - dispatch::RawOrigin, - sp_runtime::{traits::Dispatchable, DispatchResult}, - traits::fungibles::Inspect, -}; -use xcm::prelude::*; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -/// We are able to dry-run and estimate the fees for a multi-hop XCM journey. -/// Scenario: Alice on PenpalB has some DOTs and wants to send them to PenpalA. -/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`. -#[test] -fn multi_hop_works() { - let destination = PenpalB::sibling_location_of(PenpalA::para_id()); - let sender = PenpalBSender::get(); - let amount_to_send = 1_000_000_000_000; // One DOT is 10 decimals but it's configured in Penpal as 12. - let asset_owner = PenpalAssetOwner::get(); - let assets: Assets = (Parent, amount_to_send).into(); - let relay_native_asset_location = Location::parent(); - let sender_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_of_sender_on_ah = - AssetHubPolkadot::sovereign_account_id_of(sender_as_seen_by_ah.clone()); - - // fund Parachain's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - - // fund the Parachain Origin's SA on AssetHub with the native tokens held in reserve. - AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); - - // Init values for Parachain Destination - let beneficiary_id = PenpalAReceiver::get(); - - let test_args = TestContext { - sender: PenpalBSender::get(), // Bob in PenpalB. - receiver: PenpalAReceiver::get(), // Alice. - args: TestArgs::new_para( - destination, - beneficiary_id.clone(), - amount_to_send, - assets, - None, - 0, - ), - }; - let mut test = ParaToParaThroughAHTest::new(test_args); - - // We get them from the PenpalB closure. - let mut delivery_fees_amount = 0; - let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); - ::execute_with(|| { - type Runtime = ::Runtime; - type OriginCaller = ::OriginCaller; - - let call = transfer_assets_para_to_para_through_ah_call(test.clone()); - let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); - let result = Runtime::dry_run_call(origin, call).unwrap(); - // We filter the result to get only the messages we are interested in. - let (destination_to_query, messages_to_query) = &result - .forwarded_xcms - .iter() - .find(|(destination, _)| { - *destination == VersionedLocation::from(Location::new(1, [Parachain(1000)])) - }) - .unwrap(); - assert_eq!(messages_to_query.len(), 1); - remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); - delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); - }); - - // These are set in the AssetHub closure. - let mut intermediate_execution_fees = 0; - let mut intermediate_delivery_fees_amount = 0; - let mut intermediate_remote_message = VersionedXcm::from(Xcm::<()>(Vec::new())); - ::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - - // First we get the execution fees. - let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); - intermediate_execution_fees = Runtime::query_weight_to_asset_fee( - weight, - VersionedAssetId::from(AssetId(Location::parent())), - ) - .unwrap(); - - // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. - let xcm_program = VersionedXcm::from(Xcm::::from( - remote_message.clone().try_into().unwrap(), - )); - - // Now we get the delivery fees to the final destination. - let result = - Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); - let (destination_to_query, messages_to_query) = &result - .forwarded_xcms - .iter() - .find(|(destination, _)| { - *destination == VersionedLocation::from(Location::new(1, [Parachain(2000)])) - }) - .unwrap(); - // There's actually two messages here. - // One created when the message we sent from PenpalA arrived and was executed. - // The second one when we dry-run the xcm. - // We could've gotten the message from the queue without having to dry-run, but - // offchain applications would have to dry-run, so we do it here as well. - intermediate_remote_message = messages_to_query[0].clone(); - let delivery_fees = Runtime::query_delivery_fees( - destination_to_query.clone(), - intermediate_remote_message.clone(), - ) - .unwrap(); - intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); - }); - - // Get the final execution fees in the destination. - let mut final_execution_fees = 0; - ::execute_with(|| { - type Runtime = ::Runtime; - - let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); - final_execution_fees = Runtime::query_weight_to_asset_fee( - weight, - VersionedAssetId::from(AssetId(Location::parent())), - ) - .unwrap(); - }); - - // Dry-running is done. - PenpalB::reset_ext(); - AssetHubPolkadot::reset_ext(); - PenpalA::reset_ext(); - - // Fund accounts again. - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), - relay_native_asset_location.clone(), - sender.clone(), - amount_to_send * 2, - ); - AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]); - - // Actually run the extrinsic. - let sender_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &beneficiary_id) - }); - - test.set_assertion::(sender_assertions); - test.set_assertion::(hop_assertions); - test.set_assertion::(receiver_assertions); - test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); - test.assert(); - - let sender_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location.clone(), &sender) - }); - let receiver_assets_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(relay_native_asset_location, &beneficiary_id) - }); - - // We know the exact fees on every hop. - assert_eq!( - sender_assets_after, - sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly - * from the sender's - * account. */ - ); - assert_eq!( - receiver_assets_after, - receiver_assets_before + amount_to_send - - intermediate_execution_fees - - intermediate_delivery_fees_amount - - final_execution_fees - ); -} - -fn sender_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcm_pallet_attempted_complete(None); - - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Burned { asset_id, owner, balance } - ) => { - asset_id: *asset_id == Location::parent(), - owner: *owner == test.sender.account_id, - balance: *balance == test.args.amount, - }, - ] - ); -} - -fn hop_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcmp_queue_success(None); - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Balances( - pallet_balances::Event::Burned { amount, .. } - ) => { - amount: *amount == test.args.amount, - }, - ] - ); -} - -fn receiver_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcmp_queue_success(None); - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::ForeignAssets( - pallet_assets::Event::Issued { asset_id, owner, .. } - ) => { - asset_id: *asset_id == Location::parent(), - owner: *owner == test.receiver.account_id, - }, - ] - ); -} - -fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { - let latest_assets: Assets = assets.try_into().unwrap(); - let Fungible(amount) = latest_assets.inner()[0].fun else { - unreachable!("asset is non-fungible"); - }; - amount -} - -fn transfer_assets_para_to_para_through_ah_dispatchable( - test: ParaToParaThroughAHTest, -) -> DispatchResult { - let call = transfer_assets_para_to_para_through_ah_call(test.clone()); - match call.dispatch(test.signed_origin) { - Ok(_) => Ok(()), - Err(error_with_post_info) => Err(error_with_post_info.error), - } -} - -fn transfer_assets_para_to_para_through_ah_call( - test: ParaToParaThroughAHTest, -) -> ::RuntimeCall { - type RuntimeCall = ::RuntimeCall; - - let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(test.args.assets.len() as u32)), - beneficiary: test.args.beneficiary, - }]); - RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets_using_type_and_then { - dest: bx!(test.args.dest.into()), - assets: bx!(test.args.assets.clone().into()), - assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::parent()))), - fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), - custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), - weight_limit: test.args.weight_limit, - }) -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml deleted file mode 100644 index 2e017144eb..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "bridge-hub-kusama-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Kusama runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true } -hex-literal = { workspace = true } - -# Substrate -sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-asset-conversion = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } - -# Polkadot -xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -emulated-integration-tests-common = { workspace = true } -parachains-common = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } - -# Bridges -bp-messages = { workspace = true, default-features = true } -pallet-bridge-messages = { workspace = true, default-features = true } - -# Local -bp-bridge-hub-kusama = { workspace = true, default-features = true } -bridge-hub-kusama-runtime = { workspace = true } -asset-hub-kusama-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -kusama-polkadot-system-emulated-network = { workspace = true } -kusama-system-emulated-network = { workspace = true } -system-parachains-constants = { workspace = true, default-features = true } - -# Snowbridge -snowbridge-beacon-primitives = { workspace = true, default-features = true } -snowbridge-core = { workspace = true, default-features = true } -snowbridge-router-primitives = { workspace = true, default-features = true } -snowbridge-pallet-system = { workspace = true, default-features = true } -snowbridge-pallet-outbound-queue = { workspace = true, default-features = true } -snowbridge-pallet-inbound-queue-fixtures = { workspace = true } diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs deleted file mode 100644 index 9bdf33e39e..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -pub use codec::Encode; -pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; -pub use sp_runtime::{traits::Dispatchable, DispatchError}; - -// Polkadot -pub use xcm::{ - latest::ParentThen, - prelude::{AccountId32 as AccountId32Junction, *}, - v4::{ - self, Error, - NetworkId::{Kusama as KusamaId, Polkadot as PolkadotId}, - }, -}; -pub use xcm_executor::traits::TransferType; - -// Bridges -pub use bp_messages::LegacyLaneId; - -// Cumulus -pub use emulated_integration_tests_common::{ - accounts::{ALICE, BOB}, - impls::Inspect, - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - ASSETS_PALLET_ID, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V4, -}; -pub use kusama_polkadot_system_emulated_network::{ - asset_hub_kusama_emulated_chain::{ - genesis::ED as ASSET_HUB_KUSAMA_ED, AssetHubKusamaParaPallet as AssetHubKusamaPallet, - }, - asset_hub_polkadot_emulated_chain::{ - genesis::{AssetHubPolkadotAssetOwner, ED as ASSET_HUB_POLKADOT_ED}, - AssetHubPolkadotParaPallet as AssetHubPolkadotPallet, - }, - bridge_hub_kusama_emulated_chain::{ - genesis::ED as BRIDGE_HUB_KUSAMA_ED, BridgeHubKusamaParaPallet as BridgeHubKusamaPallet, - }, - kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, - penpal_emulated_chain::{ - penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, - UniversalLocation as PenpalUniversalLocation, - }, - PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, - }, - AssetHubKusamaPara as AssetHubKusama, AssetHubKusamaParaReceiver as AssetHubKusamaReceiver, - AssetHubKusamaParaSender as AssetHubKusamaSender, AssetHubPolkadotPara as AssetHubPolkadot, - AssetHubPolkadotParaReceiver as AssetHubPolkadotReceiver, - AssetHubPolkadotParaSender as AssetHubPolkadotSender, BridgeHubKusamaPara as BridgeHubKusama, - BridgeHubKusamaParaReceiver as BridgeHubKusamaReceiver, - BridgeHubKusamaParaSender as BridgeHubKusamaSender, BridgeHubPolkadotPara as BridgeHubPolkadot, - KusamaRelay as Kusama, KusamaRelayReceiver as KusamaReceiver, - KusamaRelaySender as KusamaSender, PenpalAPara as PenpalA, - PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender, -}; -pub use parachains_common::{AccountId, Balance}; - -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -pub const USDT_ID: u32 = 1984; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs deleted file mode 100644 index a9c7cc2748..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs +++ /dev/null @@ -1,555 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::tests::*; - -fn send_assets_over_bridge(send_fn: F) { - // fund the KAH's SA on BHR for paying bridge transport fees - BridgeHubKusama::fund_para_sovereign(AssetHubKusama::para_id(), 10_000_000_000_000u128); - - // set XCM versions - let local_asset_hub = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - PenpalA::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); - AssetHubKusama::force_xcm_version(asset_hub_polkadot_location(), XCM_VERSION); - BridgeHubKusama::force_xcm_version(bridge_hub_polkadot_location(), XCM_VERSION); - - // send message over bridge - send_fn(); - - // process and verify intermediary hops - assert_bridge_hub_kusama_message_accepted(true); - assert_bridge_hub_polkadot_message_received(); -} - -fn set_up_ksm_for_penpal_kusama_through_kah_to_pah( - sender: &AccountId, - amount: u128, -) -> (Location, v4::Location) { - let ksm_at_kusama_parachains = ksm_at_ah_kusama(); - let ksm_at_asset_hub_polkadot = bridged_ksm_at_ah_polkadot(); - create_foreign_on_ah_polkadot(ksm_at_asset_hub_polkadot.clone(), true); - - let penpal_location = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_kah = AssetHubKusama::sovereign_account_id_of(penpal_location); - // fund Penpal's sovereign account on AssetHub - AssetHubKusama::fund_accounts(vec![(sov_penpal_on_kah, amount * 2)]); - // fund Penpal's sender account - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), - ksm_at_kusama_parachains.clone(), - sender.clone(), - amount * 2, - ); - (ksm_at_kusama_parachains, ksm_at_asset_hub_polkadot) -} - -fn send_assets_from_penpal_kusama_through_kusama_ah_to_polkadot_ah( - destination: Location, - assets: (Assets, TransferType), - fees: (AssetId, TransferType), - custom_xcm_on_dest: Xcm<()>, -) { - send_assets_over_bridge(|| { - let sov_penpal_on_kah = AssetHubKusama::sovereign_account_id_of( - AssetHubKusama::sibling_location_of(PenpalA::para_id()), - ); - let sov_pah_on_kah = - AssetHubKusama::sovereign_account_of_parachain_on_other_global_consensus( - Polkadot, - AssetHubPolkadot::para_id(), - ); - // send message over bridge - assert_ok!(PenpalA::execute_with(|| { - let signed_origin = ::RuntimeOrigin::signed(PenpalASender::get()); - ::PolkadotXcm::transfer_assets_using_type_and_then( - signed_origin, - bx!(destination.into()), - bx!(assets.0.into()), - bx!(assets.1), - bx!(fees.0.into()), - bx!(fees.1), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify intermediary AH Kusama hop - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubKusama, - vec![ - // Amount to reserve transfer is withdrawn from Penpal's sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, .. } - ) => { - who: *who == sov_penpal_on_kah.clone(), - }, - // Amount deposited in PAH's sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == sov_pah_on_kah.clone(), - }, - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }); - }); -} - -#[test] -/// Test transfer of KSM from AssetHub Kusama to AssetHub Polkadot. -fn send_ksm_from_asset_hub_kusama_to_asset_hub_polkadot() { - let amount = ASSET_HUB_KUSAMA_ED * 1_000; - let sender = AssetHubKusamaSender::get(); - let receiver = AssetHubPolkadotReceiver::get(); - let ksm_at_asset_hub_kusama = ksm_at_ah_kusama(); - let bridged_ksm_at_ah_polkadot = bridged_ksm_at_ah_polkadot(); - - create_foreign_on_ah_polkadot(bridged_ksm_at_ah_polkadot.clone(), true); - set_up_pool_with_dot_on_ah_polkadot(bridged_ksm_at_ah_polkadot.clone(), true); - - let sov_ahp_on_ahk = AssetHubKusama::sovereign_account_of_parachain_on_other_global_consensus( - Polkadot, - AssetHubPolkadot::para_id(), - ); - let ksms_in_reserve_on_ahk_before = - ::account_data_of(sov_ahp_on_ahk.clone()).free; - let sender_ksms_before = ::account_data_of(sender.clone()).free; - let receiver_ksms_before = - foreign_balance_on_ah_polkadot(bridged_ksm_at_ah_polkadot.clone(), &receiver); - - let ksm_at_ah_kusama_latest = ksm_at_ah_kusama(); - - // send KSMs, use them for fees - send_assets_over_bridge(|| { - let destination = asset_hub_polkadot_location(); - let assets: Assets = (ksm_at_ah_kusama_latest, amount).into(); - let fee_idx = 0; - assert_ok!(send_assets_from_asset_hub_kusama(destination, assets, fee_idx)); - }); - - // verify expected events on final destination - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - // issue KSMs on PAH - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == ksm_at_asset_hub_kusama, - owner: *owner == AssetHubPolkadotReceiver::get(), - }, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_ksms_after = ::account_data_of(sender.clone()).free; - let receiver_ksms_after = foreign_balance_on_ah_polkadot(bridged_ksm_at_ah_polkadot, &receiver); - let ksms_in_reserve_on_ahk_after = - ::account_data_of(sov_ahp_on_ahk.clone()).free; - - // Sender's balance is reduced - assert!(sender_ksms_before > sender_ksms_after); - // Receiver's balance is increased - assert!(receiver_ksms_after > receiver_ksms_before); - // Reserve balance is reduced by sent amount - assert_eq!(ksms_in_reserve_on_ahk_after, ksms_in_reserve_on_ahk_before + amount); -} - -#[test] -/// Send bridged assets "back" from AssetHub Kusama to AssetHub Polkadot. -/// -/// This mix of assets should cover the whole range: -/// - bridged native assets: KSM, -/// - bridged trust-based assets: USDT (exists only on Polkadot, Kusama gets it from Polkadot over -/// bridge), -/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from -/// Ethereum to Polkadot over Snowbridge, then bridged over to Kusama through this bridge). -fn send_back_dot_usdt_and_weth_from_asset_hub_kusama_to_asset_hub_polkadot() { - let prefund_amount = 10_000_000_000_000u128; - let amount_to_send = ASSET_HUB_POLKADOT_ED * 1_000; - let sender = AssetHubKusamaSender::get(); - let receiver = AssetHubPolkadotReceiver::get(); - let bridged_dot_at_asset_hub_kusama = bridged_dot_at_ah_kusama(); - let prefund_accounts = vec![(sender.clone(), prefund_amount)]; - create_foreign_on_ah_kusama(bridged_dot_at_asset_hub_kusama.clone(), true, prefund_accounts); - - //////////////////////////////////////////////////////////// - // Let's first send back just some DOTs as a simple example - //////////////////////////////////////////////////////////// - - // fund the KAH's SA on PAH with the DOT tokens held in reserve - let sov_kah_on_pah = AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - Kusama, - AssetHubKusama::para_id(), - ); - AssetHubPolkadot::fund_accounts(vec![(sov_kah_on_pah.clone(), prefund_amount)]); - - let dot_in_reserve_on_pah_before = - ::account_data_of(sov_kah_on_pah.clone()).free; - assert_eq!(dot_in_reserve_on_pah_before, prefund_amount); - - let sender_dot_before = - foreign_balance_on_ah_kusama(bridged_dot_at_asset_hub_kusama.clone(), &sender); - assert_eq!(sender_dot_before, prefund_amount); - let receiver_dot_before = ::account_data_of(receiver.clone()).free; - - // send back DOTs, use them for fees - send_assets_over_bridge(|| { - let destination = asset_hub_polkadot_location(); - let assets: Assets = (bridged_dot_at_ah_kusama(), amount_to_send).into(); - let fee_idx = 0; - assert_ok!(send_assets_from_asset_hub_kusama(destination, assets, fee_idx)); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - // DOT is withdrawn from KAH's SA on PAH - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_kah_on_pah, - amount: *amount == amount_to_send, - }, - // DOTs deposited to beneficiary - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: who == &receiver, - }, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_dot_after = foreign_balance_on_ah_kusama(bridged_dot_at_asset_hub_kusama, &sender); - let receiver_dot_after = ::account_data_of(receiver.clone()).free; - let dot_in_reserve_on_pah_after = - ::account_data_of(sov_kah_on_pah).free; - - // Sender's balance is reduced - assert!(sender_dot_before > sender_dot_after); - // Receiver's balance is increased - assert!(receiver_dot_after > receiver_dot_before); - // Reserve balance is reduced by sent amount - assert_eq!(dot_in_reserve_on_pah_after, dot_in_reserve_on_pah_before - amount_to_send); - - ////////////////////////////////////////////////////////////////// - // Now let's send back over USDTs + wETH (and pay fees with USDT) - ////////////////////////////////////////////////////////////////// - - // wETH has same relative location on both Polkadot and Kusama AssetHubs - let bridged_weth_at_ah = weth_at_asset_hubs(); - let bridged_usdt_at_asset_hub_kusama = bridged_usdt_at_ah_kusama(); - - // set up destination chain AH Polkadot: - // create a DOT/USDT pool to be able to pay fees with USDT (USDT created in genesis) - set_up_pool_with_dot_on_ah_polkadot(usdt_at_ah_polkadot(), false); - // create wETH on Polkadot (IRL it's already created by Snowbridge) - create_foreign_on_ah_polkadot(bridged_weth_at_ah.clone(), true); - // prefund KAH's sovereign account on PAH to be able to withdraw USDT and wETH from reserves - let sov_kah_on_pah = AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - Kusama, - AssetHubKusama::para_id(), - ); - AssetHubPolkadot::mint_asset( - ::RuntimeOrigin::signed(AssetHubPolkadotAssetOwner::get()), - USDT_ID, - sov_kah_on_pah.clone(), - amount_to_send * 2, - ); - AssetHubPolkadot::mint_foreign_asset( - ::RuntimeOrigin::signed(AssetHubPolkadot::account_id_of(ALICE)), - bridged_weth_at_ah.clone(), - sov_kah_on_pah, - amount_to_send * 2, - ); - - // set up source chain AH Kusama: - // create wETH and USDT foreign assets on Kusama and prefund sender's account - let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)]; - create_foreign_on_ah_kusama(bridged_weth_at_ah.clone(), true, prefund_accounts.clone()); - create_foreign_on_ah_kusama(bridged_usdt_at_asset_hub_kusama.clone(), true, prefund_accounts); - - // check balances before - let receiver_usdts_before = AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - >::balance(USDT_ID, &receiver) - }); - let receiver_weth_before = - foreign_balance_on_ah_polkadot(bridged_weth_at_ah.clone(), &receiver); - - let usdt_id: AssetId = bridged_usdt_at_asset_hub_kusama.into(); - // send USDTs and wETHs - let assets: Assets = vec![ - (usdt_id.clone(), amount_to_send).into(), - (bridged_weth_at_ah.clone(), amount_to_send).into(), - ] - .into(); - // use USDT for fees - let fee = usdt_id; - - // use the more involved transfer extrinsic - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), - }]); - assert_ok!(AssetHubKusama::execute_with(|| { - ::PolkadotXcm::transfer_assets_using_type_and_then( - ::RuntimeOrigin::signed(sender), - bx!(asset_hub_polkadot_location().into()), - bx!(assets.into()), - bx!(TransferType::DestinationReserve), - bx!(fee.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify hops (also advances the message through the hops) - assert_bridge_hub_kusama_message_accepted(true); - assert_bridge_hub_polkadot_message_received(); - AssetHubPolkadot::execute_with(|| { - AssetHubPolkadot::assert_xcmp_queue_success(None); - }); - - let receiver_usdts_after = AssetHubPolkadot::execute_with(|| { - type Assets = ::Assets; - >::balance(USDT_ID, &receiver) - }); - let receiver_weth_after = foreign_balance_on_ah_polkadot(bridged_weth_at_ah, &receiver); - - // Receiver's USDT balance is increased by almost `amount_to_send` (minus fees) - assert!(receiver_usdts_after > receiver_usdts_before); - assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send); - // Receiver's wETH balance is increased by `amount_to_send` - assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send); -} - -#[test] -fn send_ksm_from_penpal_kusama_through_asset_hub_kusama_to_asset_hub_polkadot() { - let amount = ASSET_HUB_KUSAMA_ED * 10_000_000; - let sender = PenpalASender::get(); - let receiver = AssetHubPolkadotReceiver::get(); - let local_asset_hub = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let (ksm_at_kusama_parachains, ksm_at_asset_hub_polkadot) = - set_up_ksm_for_penpal_kusama_through_kah_to_pah(&sender, amount); - - let sov_pah_on_kah = AssetHubKusama::sovereign_account_of_parachain_on_other_global_consensus( - Polkadot, - AssetHubPolkadot::para_id(), - ); - let ksm_in_reserve_on_kah_before = - ::account_data_of(sov_pah_on_kah.clone()).free; - let sender_ksm_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_kusama_parachains.clone(), &sender) - }); - let receiver_ksm_before = - foreign_balance_on_ah_polkadot(ksm_at_asset_hub_polkadot.clone(), &receiver); - - // Send KSMs over bridge - { - let destination = asset_hub_polkadot_location(); - let assets: Assets = (ksm_at_kusama_parachains.clone(), amount).into(); - let asset_transfer_type = TransferType::RemoteReserve(local_asset_hub.clone().into()); - let fees_id: AssetId = ksm_at_kusama_parachains.clone().into(); - let fees_transfer_type = TransferType::RemoteReserve(local_asset_hub.into()); - let beneficiary: Location = - AccountId32Junction { network: None, id: receiver.clone().into() }.into(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary, - }]); - send_assets_from_penpal_kusama_through_kusama_ah_to_polkadot_ah( - destination, - (assets, asset_transfer_type), - (fees_id, fees_transfer_type), - custom_xcm_on_dest, - ); - } - - // process PAH incoming message and check events - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - // issue KSMs on PAH - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == ksm_at_kusama_parachains.clone(), - owner: owner == &receiver, - }, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_ksm_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_kusama_parachains, &sender) - }); - let receiver_ksm_after = foreign_balance_on_ah_polkadot(ksm_at_asset_hub_polkadot, &receiver); - let ksm_in_reserve_on_kah_after = - ::account_data_of(sov_pah_on_kah.clone()).free; - - // Sender's balance is reduced - assert!(sender_ksm_after < sender_ksm_before); - // Receiver's balance is increased - assert!(receiver_ksm_after > receiver_ksm_before); - // Reserve balance is increased by sent amount (less fess) - assert!(ksm_in_reserve_on_kah_after > ksm_in_reserve_on_kah_before); - assert!(ksm_in_reserve_on_kah_after <= ksm_in_reserve_on_kah_before + amount); -} - -#[test] -fn send_back_dot_from_penpal_kusama_through_asset_hub_kusama_to_asset_hub_polkadot() { - let dot_at_kusama_parachains = bridged_dot_at_ah_kusama(); - let amount = ASSET_HUB_KUSAMA_ED * 10_000_000; - let sender = PenpalASender::get(); - let receiver = AssetHubPolkadotReceiver::get(); - - // set up KSMs for transfer - let (ksm_at_kusama_parachains, _) = - set_up_ksm_for_penpal_kusama_through_kah_to_pah(&sender, amount); - - // set up DOTs for transfer - let penpal_location = AssetHubKusama::sibling_location_of(PenpalA::para_id()); - let sov_penpal_on_kah = AssetHubKusama::sovereign_account_id_of(penpal_location); - let prefund_accounts = vec![(sov_penpal_on_kah, amount * 2)]; - create_foreign_on_ah_kusama(dot_at_kusama_parachains.clone(), true, prefund_accounts); - let asset_owner: AccountId = AssetHubKusama::account_id_of(ALICE); - PenpalA::force_create_foreign_asset( - dot_at_kusama_parachains.clone(), - asset_owner.clone(), - true, - ASSET_MIN_BALANCE, - vec![(sender.clone(), amount * 2)], - ); - // Configure source Penpal chain to trust local AH as reserve of bridged KSM - PenpalA::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - dot_at_kusama_parachains.encode(), - )], - )); - }); - - // fund the KAH's SA on PAH with the DOT tokens held in reserve - let sov_kah_on_pah = AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - NetworkId::Kusama, - AssetHubKusama::para_id(), - ); - AssetHubPolkadot::fund_accounts(vec![(sov_kah_on_pah.clone(), amount * 2)]); - - // balances before - let sender_dot_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains.clone(), &sender) - }); - let receiver_dot_before = ::account_data_of(receiver.clone()).free; - - // send DOTs over the bridge, KSMs only used to pay fees on local AH, pay with DOT on remote AH - { - let final_destination = asset_hub_polkadot_location(); - let intermediary_hop = PenpalA::sibling_location_of(AssetHubKusama::para_id()); - let context = PenpalA::execute_with(PenpalUniversalLocation::get); - - // what happens at final destination - let beneficiary = AccountId32Junction { network: None, id: receiver.clone().into() }.into(); - // use DOT as fees on the final destination (PAH) - let remote_fees: Asset = (dot_at_kusama_parachains.clone(), amount).into(); - let remote_fees = remote_fees.reanchored(&final_destination, &context).unwrap(); - // buy execution using DOTs, then deposit all remaining DOTs - let xcm_on_final_dest = Xcm::<()>(vec![ - BuyExecution { fees: remote_fees, weight_limit: WeightLimit::Unlimited }, - DepositAsset { assets: Wild(AllCounted(1)), beneficiary }, - ]); - - // what happens at intermediary hop - // reanchor final dest (Asset Hub Polkadot) to the view of hop (Asset Hub Kusama) - let mut final_destination = final_destination.clone(); - final_destination.reanchor(&intermediary_hop, &context).unwrap(); - // reanchor DOTs to the view of hop (Asset Hub Kusama) - let asset: Asset = (dot_at_kusama_parachains.clone(), amount).into(); - let asset = asset.reanchored(&intermediary_hop, &context).unwrap(); - // on Asset Hub Kusama, forward a request to withdraw DOTs from reserve on Asset Hub - // Polkadot - let xcm_on_hop = Xcm::<()>(vec![InitiateReserveWithdraw { - assets: Definite(asset.into()), // DOTs - reserve: final_destination, // PAH - xcm: xcm_on_final_dest, // XCM to execute on PAH - }]); - // assets to send from Penpal and how they reach the intermediary hop - let assets: Assets = vec![ - (dot_at_kusama_parachains.clone(), amount).into(), - (ksm_at_kusama_parachains.clone(), amount).into(), - ] - .into(); - let asset_transfer_type = TransferType::DestinationReserve; - let fees_id: AssetId = ksm_at_kusama_parachains.into(); - let fees_transfer_type = TransferType::DestinationReserve; - - // initiate the transfer - send_assets_from_penpal_kusama_through_kusama_ah_to_polkadot_ah( - intermediary_hop, - (assets, asset_transfer_type), - (fees_id, fees_transfer_type), - xcm_on_hop, - ); - } - - // process PAH incoming message and check events - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - // issue KSMs on PAH - RuntimeEvent::Balances(pallet_balances::Event::Issued { .. }) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_dot_after = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_kusama_parachains, &sender) - }); - let receiver_dot_after = ::account_data_of(receiver).free; - - // Sender's balance is reduced by sent "amount" - assert_eq!(sender_dot_after, sender_dot_before - amount); - // Receiver's balance is increased by no more than "amount" - assert!(receiver_dot_after > receiver_dot_before); - assert!(receiver_dot_after <= receiver_dot_before + amount); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/claim_assets.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/claim_assets.rs deleted file mode 100644 index 976d90ebe5..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/claim_assets.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests related to claiming assets trapped during XCM execution. - -use crate::*; - -use bridge_hub_kusama_runtime::ExistentialDeposit; -use integration_tests_helpers::test_chain_can_claim_assets; -use xcm_executor::traits::DropAssets; - -#[test] -fn assets_can_be_claimed() { - let amount = ExistentialDeposit::get(); - let assets: Assets = (Parent, amount).into(); - - test_chain_can_claim_assets!(AssetHubKusama, RuntimeCall, NetworkId::Kusama, assets, amount); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs deleted file mode 100644 index b6edd6a076..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -mod asset_transfers; -mod claim_assets; -mod register_bridged_assets; -mod send_xcm; -mod teleport; - -mod snowbridge { - pub const CHAIN_ID: u64 = 1; - pub const WETH: [u8; 20] = hex_literal::hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); -} - -pub(crate) fn asset_hub_polkadot_location() -> Location { - Location::new(2, [GlobalConsensus(Polkadot), Parachain(AssetHubPolkadot::para_id().into())]) -} - -pub(crate) fn bridge_hub_polkadot_location() -> Location { - Location::new(2, [GlobalConsensus(Polkadot), Parachain(BridgeHubPolkadot::para_id().into())]) -} - -// KSM and wKSM -pub(crate) fn ksm_at_ah_kusama() -> Location { - Parent.into() -} -pub(crate) fn bridged_ksm_at_ah_polkadot() -> Location { - Location::new(2, [GlobalConsensus(Kusama)]) -} - -// wDOT -pub(crate) fn bridged_dot_at_ah_kusama() -> Location { - Location::new(2, [GlobalConsensus(Polkadot)]) -} - -// USDT and wUSDT -pub(crate) fn usdt_at_ah_polkadot() -> Location { - Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) -} -pub(crate) fn bridged_usdt_at_ah_kusama() -> Location { - Location::new( - 2, - [ - GlobalConsensus(Polkadot), - Parachain(AssetHubPolkadot::para_id().into()), - PalletInstance(ASSETS_PALLET_ID), - GeneralIndex(USDT_ID.into()), - ], - ) -} - -// wETH has same relative location on both Kusama and Polkadot AssetHubs -pub(crate) fn weth_at_asset_hubs() -> Location { - Location::new( - 2, - [ - GlobalConsensus(Ethereum { chain_id: snowbridge::CHAIN_ID }), - AccountKey20 { network: None, key: snowbridge::WETH }, - ], - ) -} - -pub(crate) fn create_foreign_on_ah_kusama( - id: v4::Location, - sufficient: bool, - prefund_accounts: Vec<(AccountId, u128)>, -) { - let owner = AssetHubKusama::account_id_of(ALICE); - let min = ASSET_MIN_BALANCE; - AssetHubKusama::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); -} - -pub(crate) fn create_foreign_on_ah_polkadot(id: v4::Location, sufficient: bool) { - let owner = AssetHubPolkadot::account_id_of(ALICE); - AssetHubPolkadot::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]); -} - -pub(crate) fn foreign_balance_on_ah_kusama(id: v4::Location, who: &AccountId) -> u128 { - AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(id, who) - }) -} -pub(crate) fn foreign_balance_on_ah_polkadot(id: v4::Location, who: &AccountId) -> u128 { - AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(id, who) - }) -} - -// set up pool -pub(crate) fn set_up_pool_with_dot_on_ah_polkadot(asset: v4::Location, is_foreign: bool) { - let dot: v4::Location = v4::Parent.into(); - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - let owner = AssetHubPolkadotSender::get(); - let signed_owner = ::RuntimeOrigin::signed(owner.clone()); - - if is_foreign { - assert_ok!(::ForeignAssets::mint( - signed_owner.clone(), - asset.clone(), - owner.clone().into(), - 3_000_000_000_000, - )); - } else { - let asset_id = match asset.interior.last() { - Some(v4::Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - assert_ok!(::Assets::mint( - signed_owner.clone(), - asset_id.into(), - owner.clone().into(), - 3_000_000_000_000, - )); - } - assert_ok!(::AssetConversion::create_pool( - signed_owner.clone(), - Box::new(dot.clone()), - Box::new(asset.clone()), - )); - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - assert_ok!(::AssetConversion::add_liquidity( - signed_owner.clone(), - Box::new(dot), - Box::new(asset), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - owner, - )); - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); -} - -pub(crate) fn send_assets_from_asset_hub_kusama( - destination: Location, - assets: Assets, - fee_idx: u32, -) -> DispatchResult { - let signed_origin = - ::RuntimeOrigin::signed(AssetHubKusamaSender::get()); - let beneficiary: Location = - AccountId32Junction { network: None, id: AssetHubPolkadotReceiver::get().into() }.into(); - - AssetHubKusama::execute_with(|| { - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_idx, - WeightLimit::Unlimited, - ) - }) -} - -pub(crate) fn assert_bridge_hub_kusama_message_accepted(expected_processed: bool) { - BridgeHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - if expected_processed { - assert_expected_events!( - BridgeHubKusama, - vec![ - // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Burned { .. }) => {}, - // message exported - RuntimeEvent::BridgePolkadotMessages( - pallet_bridge_messages::Event::MessageAccepted { .. } - ) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - } else { - assert_expected_events!( - BridgeHubKusama, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: false, - .. - }) => {}, - ] - ); - } - }); -} - -pub(crate) fn assert_bridge_hub_polkadot_message_received() { - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubPolkadot, - vec![ - // message sent to destination - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }) -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/register_bridged_assets.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/register_bridged_assets.rs deleted file mode 100644 index 2e42fcb4f7..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/register_bridged_assets.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::tests::*; - -const XCM_FEE: u128 = 40_000_000_000; - -/// Tests the registering of a Kusama Asset as a bridged asset on Polkadot Asset Hub. -#[test] -fn register_kusama_asset_on_pah_from_kah() { - let sa_of_kah_on_pah = - AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - Kusama, - AssetHubKusama::para_id(), - ); - - // Kusama Asset Hub asset when bridged to Polkadot Asset Hub. - let bridged_asset_at_pah = v4::Location::new( - 2, - [ - v4::Junction::GlobalConsensus(v4::NetworkId::Kusama), - v4::Junction::Parachain(AssetHubKusama::para_id().into()), - v4::Junction::PalletInstance(ASSETS_PALLET_ID), - v4::Junction::GeneralIndex(ASSET_ID.into()), - ], - ); - - // Encoded `create_asset` call to be executed in Polkadot Asset Hub ForeignAssets pallet. - let call = AssetHubPolkadot::create_foreign_asset_call( - bridged_asset_at_pah.clone(), - ASSET_MIN_BALANCE, - sa_of_kah_on_pah.clone(), - ); - - let origin_kind = OriginKind::Xcm; - let fee_amount = XCM_FEE; - let fees = (Parent, fee_amount).into(); - - let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_kah_on_pah.clone()); - - // SA-of-KAH-on-PAH needs to have balance to pay for fees and asset creation deposit - AssetHubPolkadot::fund_accounts(vec![( - sa_of_kah_on_pah.clone(), - ASSET_HUB_POLKADOT_ED * 10000000000, - )]); - - let destination = asset_hub_polkadot_location(); - - // fund the KAH's SA on KBH for paying bridge transport fees - BridgeHubKusama::fund_para_sovereign(AssetHubKusama::para_id(), 10_000_000_000_000u128); - - // set XCM versions - AssetHubKusama::force_xcm_version(destination.clone(), XCM_VERSION); - BridgeHubKusama::force_xcm_version(bridge_hub_polkadot_location(), XCM_VERSION); - - let root_origin = ::RuntimeOrigin::root(); - AssetHubKusama::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(destination.into()), - bx!(xcm), - )); - - AssetHubKusama::assert_xcm_pallet_sent(); - }); - - assert_bridge_hub_kusama_message_accepted(true); - assert_bridge_hub_polkadot_message_received(); - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - AssetHubPolkadot::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Burned the fee - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == sa_of_kah_on_pah.clone(), - amount: *amount == fee_amount, - }, - // Foreign Asset created - RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { - asset_id: *asset_id == bridged_asset_at_pah, - creator: *creator == sa_of_kah_on_pah.clone(), - owner: *owner == sa_of_kah_on_pah, - }, - // Unspent fee minted to origin - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == sa_of_kah_on_pah.clone(), - }, - ] - ); - type ForeignAssets = ::ForeignAssets; - assert!(ForeignAssets::asset_exists(bridged_asset_at_pah)); - }); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/send_xcm.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/send_xcm.rs deleted file mode 100644 index a166e9ac0d..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/send_xcm.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::tests::*; - -#[test] -fn send_xcm_from_kusama_relay_to_polkadot_asset_hub_should_fail_on_not_applicable() { - // Init tests variables - // XcmPallet send arguments - let sudo_origin = ::RuntimeOrigin::root(); - let destination = Kusama::child_location_of(BridgeHubKusama::para_id()).into(); - let weight_limit = WeightLimit::Unlimited; - let check_origin = None; - - let remote_xcm = Xcm(vec![ClearOrigin]); - - let xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit, check_origin }, - ExportMessage { - network: PolkadotId, - destination: [Parachain(AssetHubPolkadot::para_id().into())].into(), - xcm: remote_xcm, - }, - ])); - - // Kusama Global Consensus - // Send XCM message from Relay Chain to Bridge Hub source Parachain - Kusama::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(destination), - bx!(xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have - // opened bridge/lane. - assert_bridge_hub_kusama_message_accepted(false); -} - -#[test] -fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { - // Initially set only default version on all runtimes - let newer_xcm_version = xcm::prelude::XCM_VERSION; - let older_xcm_version = newer_xcm_version - 1; - - AssetHubKusama::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubKusama::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubPolkadot::force_default_xcm_version(Some(older_xcm_version)); - AssetHubPolkadot::force_default_xcm_version(Some(older_xcm_version)); - - // prepare data - let destination = asset_hub_polkadot_location(); - let native_token = Location::parent(); - let amount = ASSET_HUB_KUSAMA_ED * 1_000; - - // fund the AHK's SA on BHK for paying bridge transport fees - BridgeHubKusama::fund_para_sovereign(AssetHubKusama::para_id(), 10_000_000_000_000u128); - // fund sender - AssetHubKusama::fund_accounts(vec![(AssetHubKusamaSender::get(), amount * 10)]); - - // send XCM from AssetHubKusama - fails - destination version not known - assert_err!( - send_assets_from_asset_hub_kusama( - destination.clone(), - (native_token.clone(), amount).into(), - 0 - ), - DispatchError::Module(sp_runtime::ModuleError { - index: 31, - error: [1, 0, 0, 0], - message: Some("SendFailure") - }) - ); - - // set destination version - AssetHubKusama::force_xcm_version(destination.clone(), newer_xcm_version); - - // set version with `ExportMessage` for BridgeHubKusama - AssetHubKusama::force_xcm_version( - ParentThen(Parachain(BridgeHubKusama::para_id().into()).into()).into(), - newer_xcm_version, - ); - // send XCM from AssetHubKusama - ok - assert_ok!(send_assets_from_asset_hub_kusama( - destination.clone(), - (native_token.clone(), amount).into(), - 0 - )); - - // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known - assert_bridge_hub_kusama_message_accepted(false); - - // set version for remote BridgeHub on BridgeHubKusama - BridgeHubKusama::force_xcm_version(bridge_hub_polkadot_location(), newer_xcm_version); - // set version for AssetHubPolkadot on BridgeHubPolkadot - BridgeHubPolkadot::force_xcm_version( - ParentThen(Parachain(AssetHubPolkadot::para_id().into()).into()).into(), - newer_xcm_version, - ); - - // send XCM from AssetHubKusama - ok - assert_ok!(send_assets_from_asset_hub_kusama( - destination.clone(), - (native_token.clone(), amount).into(), - 0 - )); - assert_bridge_hub_kusama_message_accepted(true); - assert_bridge_hub_polkadot_message_received(); - // message delivered and processed at destination - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - // message processed with failure, but for this scenario it is ok, important is that was delivered - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: false, .. } - ) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs deleted file mode 100644 index 074244a418..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use bridge_hub_kusama_runtime::xcm_config::XcmConfig; -use frame_support::{ - dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_to_other_system_parachains_works() { - let amount = BRIDGE_HUB_KUSAMA_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - BridgeHubKusama, // Origin - XcmConfig, // XCM configuration - vec![AssetHubKusama], // Destinations - (native_asset, amount) - ); -} - -#[test] -fn teleport_from_and_to_relay() { - let amount = KUSAMA_ED * 1000; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Kusama, - KusamaXcmConfig, - vec![BridgeHubKusama], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - BridgeHubKusama, - BridgeHubKusamaXcmConfig, - Kusama, - amount - ); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml deleted file mode 100644 index 34fe19ad15..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "bridge-hub-polkadot-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Bridge Hub Polkadot runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true } -hex-literal = { workspace = true } - -# Substrate -sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-asset-conversion = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } - -# Polkadot -xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -emulated-integration-tests-common = { workspace = true } -parachains-common = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } - -# Bridges -bp-messages = { workspace = true, default-features = true } -pallet-bridge-messages = { workspace = true, default-features = true } - -# Local -bp-bridge-hub-polkadot = { workspace = true, default-features = true } -bridge-hub-polkadot-runtime = { workspace = true } -asset-hub-polkadot-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -kusama-polkadot-system-emulated-network = { workspace = true } -polkadot-system-emulated-network = { workspace = true } -system-parachains-constants = { workspace = true, default-features = true } - -# Snowbridge -snowbridge-beacon-primitives = { workspace = true, default-features = true } -snowbridge-core = { workspace = true, default-features = true } -snowbridge-router-primitives = { workspace = true, default-features = true } -snowbridge-pallet-system = { workspace = true, default-features = true } -snowbridge-pallet-outbound-queue = { workspace = true, default-features = true } -snowbridge-pallet-inbound-queue-fixtures = { workspace = true } diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs deleted file mode 100644 index 6a55e4c24c..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Substrate -pub use codec::Encode; -pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; -pub use sp_runtime::DispatchError; - -// Polkadot -pub use xcm::{ - latest::ParentThen, - prelude::{AccountId32 as AccountId32Junction, *}, - v4::{ - self, Error, - NetworkId::{Kusama as KusamaId, Polkadot as PolkadotId}, - }, -}; -pub use xcm_executor::traits::TransferType; - -// Bridges -pub use bp_messages::LegacyLaneId; - -// Cumulus -pub use emulated_integration_tests_common::{ - accounts::{ALICE, BOB}, - impls::Inspect, - test_parachain_is_trusted_teleporter, - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - ASSETS_PALLET_ID, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V4, -}; -pub use kusama_polkadot_system_emulated_network::{ - asset_hub_kusama_emulated_chain::{ - genesis::ED as ASSET_HUB_KUSAMA_ED, AssetHubKusamaParaPallet as AssetHubKusamaPallet, - }, - asset_hub_polkadot_emulated_chain::{ - genesis::{AssetHubPolkadotAssetOwner, ED as ASSET_HUB_POLKADOT_ED}, - AssetHubPolkadotParaPallet as AssetHubPolkadotPallet, - }, - bridge_hub_polkadot_emulated_chain::{ - genesis::ED as BRIDGE_HUB_POLKADOT_ED, - BridgeHubPolkadotParaPallet as BridgeHubPolkadotPallet, - }, - penpal_emulated_chain::{ - penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, - UniversalLocation as PenpalUniversalLocation, - }, - PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, - }, - polkadot_emulated_chain::{genesis::ED as POLKADOT_ED, PolkadotRelayPallet as PolkadotPallet}, - AssetHubKusamaPara as AssetHubKusama, AssetHubKusamaParaReceiver as AssetHubKusamaReceiver, - AssetHubKusamaParaSender as AssetHubKusamaSender, AssetHubPolkadotPara as AssetHubPolkadot, - AssetHubPolkadotParaReceiver as AssetHubPolkadotReceiver, - AssetHubPolkadotParaSender as AssetHubPolkadotSender, BridgeHubKusamaPara as BridgeHubKusama, - BridgeHubPolkadotPara as BridgeHubPolkadot, - BridgeHubPolkadotParaReceiver as BridgeHubPolkadotReceiver, - BridgeHubPolkadotParaSender as BridgeHubPolkadotSender, PenpalBPara as PenpalB, - PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender, - PolkadotRelay as Polkadot, PolkadotRelayReceiver as PolkadotReceiver, - PolkadotRelaySender as PolkadotSender, -}; -pub use parachains_common::{AccountId, Balance}; - -pub const ASSET_ID: u32 = 1; -pub const ASSET_MIN_BALANCE: u128 = 1000; -pub const USDT_ID: u32 = 1984; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/asset_transfers.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/asset_transfers.rs deleted file mode 100644 index 794144a549..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/asset_transfers.rs +++ /dev/null @@ -1,539 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::tests::*; - -fn send_assets_over_bridge(send_fn: F) { - // fund the PAH's SA on PBH for paying bridge transport fees - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), 10_000_000_000_000u128); - - // set XCM versions - let local_asset_hub = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - PenpalB::force_xcm_version(local_asset_hub.clone(), XCM_VERSION); - AssetHubPolkadot::force_xcm_version(asset_hub_kusama_location(), XCM_VERSION); - BridgeHubPolkadot::force_xcm_version(bridge_hub_kusama_location(), XCM_VERSION); - - // send message over bridge - send_fn(); - - // process and verify intermediary hops - assert_bridge_hub_polkadot_message_accepted(true); - assert_bridge_hub_kusama_message_received(); -} - -fn set_up_dot_for_penpal_polkadot_through_pah_to_kah( - sender: &AccountId, - amount: u128, -) -> (Location, v4::Location) { - let dot_at_polkadot_parachains = dot_at_ah_polkadot(); - let dot_at_asset_hub_kusama = bridged_dot_at_ah_kusama(); - create_foreign_on_ah_kusama(dot_at_asset_hub_kusama.clone(), true); - - let penpal_location = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_pah = AssetHubPolkadot::sovereign_account_id_of(penpal_location); - // fund Penpal's sovereign account on AssetHub - AssetHubPolkadot::fund_accounts(vec![(sov_penpal_on_pah, amount * 2)]); - // fund Penpal's sender account - PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), - dot_at_polkadot_parachains.clone(), - sender.clone(), - amount * 2, - ); - (dot_at_polkadot_parachains, dot_at_asset_hub_kusama) -} - -fn send_assets_from_penpal_polkadot_through_polkadot_ah_to_kusama_ah( - destination: Location, - assets: (Assets, TransferType), - fees: (AssetId, TransferType), - custom_xcm_on_dest: Xcm<()>, -) { - send_assets_over_bridge(|| { - let sov_penpal_on_pah = AssetHubPolkadot::sovereign_account_id_of( - AssetHubPolkadot::sibling_location_of(PenpalB::para_id()), - ); - let sov_kah_on_pah = - AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - Kusama, - AssetHubKusama::para_id(), - ); - - // send message over bridge - assert_ok!(PenpalB::execute_with(|| { - let signed_origin = ::RuntimeOrigin::signed(PenpalBSender::get()); - ::PolkadotXcm::transfer_assets_using_type_and_then( - signed_origin, - bx!(destination.into()), - bx!(assets.0.into()), - bx!(assets.1), - bx!(fees.0.into()), - bx!(fees.1), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify intermediary AH Polkadot hop - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - // Amount to reserve transfer is withdrawn from Penpal's sovereign account - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, .. } - ) => { - who: *who == sov_penpal_on_pah.clone(), - }, - // Amount deposited in KAH's sovereign account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == sov_kah_on_pah.clone(), - }, - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }); - }); -} - -#[test] -/// Test transfer of DOT, USDT and wETH from AssetHub Polkadot to AssetHub Kusama. -/// -/// This mix of assets should cover the whole range: -/// - native assets: DOT, -/// - trust-based assets: USDT (exists only on Polkadot, Kusama gets it from Polkadot over bridge), -/// - foreign asset / bridged asset (other bridge / Snowfork): wETH (bridged from Ethereum to -/// Polkadot over Snowbridge, then bridged over to Kusama through this bridge). -fn send_dot_usdt_and_weth_from_asset_hub_polkadot_to_asset_hub_kusama() { - let amount = ASSET_HUB_POLKADOT_ED * 1_000; - let sender = AssetHubPolkadotSender::get(); - let receiver = AssetHubKusamaReceiver::get(); - let dot_at_asset_hub_polkadot = dot_at_ah_polkadot(); - let bridged_dot_at_asset_hub_kusama = bridged_dot_at_ah_kusama(); - - create_foreign_on_ah_kusama(bridged_dot_at_asset_hub_kusama.clone(), true); - set_up_pool_with_ksm_on_ah_kusama(bridged_dot_at_asset_hub_kusama.clone(), true); - - //////////////////////////////////////////////////////////// - // Let's first send over just some DOTs as a simple example - //////////////////////////////////////////////////////////// - let sov_kah_on_pah = AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - Kusama, - AssetHubKusama::para_id(), - ); - let dot_in_reserve_on_pah_before = - ::account_data_of(sov_kah_on_pah.clone()).free; - let sender_dot_before = ::account_data_of(sender.clone()).free; - let receiver_dot_before = - foreign_balance_on_ah_kusama(bridged_dot_at_asset_hub_kusama.clone(), &receiver); - - // send DOTs, use them for fees - send_assets_over_bridge(|| { - let destination = asset_hub_kusama_location(); - let assets: Assets = (dot_at_asset_hub_polkadot, amount).into(); - let fee_idx = 0; - assert_ok!(send_assets_from_asset_hub_polkadot(destination, assets, fee_idx)); - }); - - // verify expected events on final destination - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubKusama, - vec![ - // issue DOTs on KAH - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == bridged_dot_at_asset_hub_kusama, - owner: *owner == receiver, - }, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_dot_after = ::account_data_of(sender.clone()).free; - let receiver_dot_after = - foreign_balance_on_ah_kusama(bridged_dot_at_asset_hub_kusama, &receiver); - let dot_in_reserve_on_pah_after = - ::account_data_of(sov_kah_on_pah).free; - - // Sender's balance is reduced - assert!(sender_dot_before > sender_dot_after); - // Receiver's balance is increased - assert!(receiver_dot_after > receiver_dot_before); - // Reserve balance is increased by sent amount - assert_eq!(dot_in_reserve_on_pah_after, dot_in_reserve_on_pah_before + amount); - - ///////////////////////////////////////////////////////////// - // Now let's send over USDTs + wETH (and pay fees with USDT) - ///////////////////////////////////////////////////////////// - let usdt_at_asset_hub_polkadot = usdt_at_ah_polkadot(); - let bridged_usdt_at_asset_hub_kusama = bridged_usdt_at_ah_kusama(); - // wETH has same relative location on both Polkadot and Kusama AssetHubs - let bridged_weth_at_ah = weth_at_asset_hubs(); - - // mint USDT in sender's account (USDT already created in genesis) - AssetHubPolkadot::mint_asset( - ::RuntimeOrigin::signed(AssetHubPolkadotAssetOwner::get()), - USDT_ID, - sender.clone(), - amount * 2, - ); - // create wETH at src and dest and prefund sender's account - create_foreign_on_ah_polkadot( - bridged_weth_at_ah.clone(), - true, - vec![(sender.clone(), amount * 2)], - ); - create_foreign_on_ah_kusama(bridged_weth_at_ah.clone(), true); - create_foreign_on_ah_kusama(bridged_usdt_at_asset_hub_kusama.clone(), true); - set_up_pool_with_ksm_on_ah_kusama(bridged_usdt_at_asset_hub_kusama.clone(), true); - - let receiver_usdts_before = - foreign_balance_on_ah_kusama(bridged_usdt_at_asset_hub_kusama.clone(), &receiver); - let receiver_weth_before = foreign_balance_on_ah_kusama(bridged_weth_at_ah.clone(), &receiver); - - // send USDTs and wETHs - let assets: Assets = vec![ - (usdt_at_asset_hub_polkadot.clone(), amount).into(), - (bridged_weth_at_ah.clone(), amount).into(), - ] - .into(); - // use USDT for fees - let fee: AssetId = usdt_at_asset_hub_polkadot.into(); - - // use the more involved transfer extrinsic - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), - }]); - assert_ok!(AssetHubPolkadot::execute_with(|| { - ::PolkadotXcm::transfer_assets_using_type_and_then( - ::RuntimeOrigin::signed(sender), - bx!(asset_hub_kusama_location().into()), - bx!(assets.into()), - bx!(TransferType::LocalReserve), - bx!(fee.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify hops (also advances the message through the hops) - assert_bridge_hub_polkadot_message_accepted(true); - assert_bridge_hub_kusama_message_received(); - AssetHubKusama::execute_with(|| { - AssetHubKusama::assert_xcmp_queue_success(None); - }); - - let receiver_usdts_after = - foreign_balance_on_ah_kusama(bridged_usdt_at_asset_hub_kusama, &receiver); - let receiver_weth_after = foreign_balance_on_ah_kusama(bridged_weth_at_ah, &receiver); - - // Receiver's USDT balance is increased by almost `amount` (minus fees) - assert!(receiver_usdts_after > receiver_usdts_before); - assert!(receiver_usdts_after < receiver_usdts_before + amount); - // Receiver's wETH balance is increased by sent amount - assert_eq!(receiver_weth_after, receiver_weth_before + amount); -} - -#[test] -/// Send bridged KSM "back" from AssetHub Polkadot to AssetHub Kusama. -fn send_back_ksm_from_asset_hub_polkadot_to_asset_hub_kusama() { - let prefund_amount = 10_000_000_000_000u128; - let amount_to_send = ASSET_HUB_KUSAMA_ED * 1_000; - let sender = AssetHubPolkadotSender::get(); - let receiver = AssetHubKusamaReceiver::get(); - let bridged_ksm_at_asset_hub_polkadot = bridged_ksm_at_ah_polkadot(); - let prefund_accounts = vec![(sender.clone(), prefund_amount)]; - create_foreign_on_ah_polkadot( - bridged_ksm_at_asset_hub_polkadot.clone(), - true, - prefund_accounts, - ); - - // fund the PAH's SA on KAH with the KSM tokens held in reserve - let sov_pah_on_kah = AssetHubKusama::sovereign_account_of_parachain_on_other_global_consensus( - Polkadot, - AssetHubPolkadot::para_id(), - ); - AssetHubKusama::fund_accounts(vec![(sov_pah_on_kah.clone(), prefund_amount)]); - - let ksm_in_reserve_on_kah_before = - ::account_data_of(sov_pah_on_kah.clone()).free; - assert_eq!(ksm_in_reserve_on_kah_before, prefund_amount); - - let sender_ksm_before = - foreign_balance_on_ah_polkadot(bridged_ksm_at_asset_hub_polkadot.clone(), &sender); - assert_eq!(sender_ksm_before, prefund_amount); - let receiver_ksm_before = ::account_data_of(receiver.clone()).free; - - // send back KSMs, use them for fees - send_assets_over_bridge(|| { - let destination = asset_hub_kusama_location(); - let assets: Assets = (bridged_ksm_at_asset_hub_polkadot.clone(), amount_to_send).into(); - let fee_idx = 0; - assert_ok!(send_assets_from_asset_hub_polkadot(destination, assets, fee_idx)); - }); - - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubKusama, - vec![ - // KSM is withdrawn from PAH's SA on KAH - RuntimeEvent::Balances( - pallet_balances::Event::Burned { who, amount } - ) => { - who: *who == sov_pah_on_kah, - amount: *amount == amount_to_send, - }, - // KSMs deposited to beneficiary - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == receiver, - }, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_ksm_after = - foreign_balance_on_ah_polkadot(bridged_ksm_at_asset_hub_polkadot, &sender); - let receiver_ksm_after = ::account_data_of(receiver.clone()).free; - let ksm_in_reserve_on_kah_after = - ::account_data_of(sov_pah_on_kah.clone()).free; - - // Sender's balance is reduced - assert!(sender_ksm_before > sender_ksm_after); - // Receiver's balance is increased - assert!(receiver_ksm_after > receiver_ksm_before); - // Reserve balance is reduced by sent amount - assert_eq!(ksm_in_reserve_on_kah_after, ksm_in_reserve_on_kah_before - amount_to_send); -} - -#[test] -fn send_dot_from_penpal_polkadot_through_asset_hub_polkadot_to_asset_hub_kusama() { - let amount = ASSET_HUB_POLKADOT_ED * 10_000_000; - let sender = PenpalBSender::get(); - let receiver = AssetHubKusamaReceiver::get(); - let local_asset_hub = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let (dot_at_polkadot_parachains, dot_at_asset_hub_kusama) = - set_up_dot_for_penpal_polkadot_through_pah_to_kah(&sender, amount); - - let sov_kah_on_pah = AssetHubPolkadot::sovereign_account_of_parachain_on_other_global_consensus( - Kusama, - AssetHubKusama::para_id(), - ); - let dot_in_reserve_on_pah_before = - ::account_data_of(sov_kah_on_pah.clone()).free; - let sender_dot_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_polkadot_parachains.clone(), &sender) - }); - let receiver_dot_before = - foreign_balance_on_ah_kusama(dot_at_asset_hub_kusama.clone(), &receiver); - - // Send DOTs over bridge - { - let destination = asset_hub_kusama_location(); - let assets: Assets = (dot_at_polkadot_parachains.clone(), amount).into(); - let asset_transfer_type = TransferType::RemoteReserve(local_asset_hub.clone().into()); - let fees_id: AssetId = dot_at_polkadot_parachains.clone().into(); - let fees_transfer_type = TransferType::RemoteReserve(local_asset_hub.into()); - let beneficiary: Location = - AccountId32Junction { network: None, id: receiver.clone().into() }.into(); - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary, - }]); - send_assets_from_penpal_polkadot_through_polkadot_ah_to_kusama_ah( - destination, - (assets, asset_transfer_type), - (fees_id, fees_transfer_type), - custom_xcm_on_dest, - ); - } - - // process KAH incoming message and check events - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubKusama, - vec![ - // issue DOTs on KAH - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { - asset_id: *asset_id == dot_at_polkadot_parachains.clone(), - owner: owner == &receiver, - }, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_dot_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(dot_at_polkadot_parachains, &sender) - }); - let receiver_dot_after = foreign_balance_on_ah_kusama(dot_at_asset_hub_kusama, &receiver); - let dot_in_reserve_on_pah_after = - ::account_data_of(sov_kah_on_pah.clone()).free; - - // Sender's balance is reduced - assert!(sender_dot_after < sender_dot_before); - // Receiver's balance is increased - assert!(receiver_dot_after > receiver_dot_before); - // Reserve balance is increased by sent amount (less fess) - assert!(dot_in_reserve_on_pah_after > dot_in_reserve_on_pah_before); - assert!(dot_in_reserve_on_pah_after <= dot_in_reserve_on_pah_before + amount); -} - -#[test] -fn send_back_ksm_from_penpal_polkadot_through_asset_hub_polkadot_to_asset_hub_kusama() { - let ksm_at_polkadot_parachains = bridged_ksm_at_ah_polkadot(); - let amount = ASSET_HUB_POLKADOT_ED * 10_000_000; - let sender = PenpalBSender::get(); - let receiver = AssetHubKusamaReceiver::get(); - - // set up DOTs for transfer - let (dot_at_polkadot_parachains, _) = - set_up_dot_for_penpal_polkadot_through_pah_to_kah(&sender, amount); - - // set up KSMs for transfer - let penpal_location = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); - let sov_penpal_on_kah = AssetHubPolkadot::sovereign_account_id_of(penpal_location); - let prefund_accounts = vec![(sov_penpal_on_kah, amount * 2)]; - create_foreign_on_ah_polkadot(ksm_at_polkadot_parachains.clone(), true, prefund_accounts); - let asset_owner: AccountId = AssetHubPolkadot::account_id_of(ALICE); - PenpalB::force_create_foreign_asset( - ksm_at_polkadot_parachains.clone(), - asset_owner.clone(), - true, - ASSET_MIN_BALANCE, - vec![(sender.clone(), amount * 2)], - ); - // Configure source Penpal chain to trust local AH as reserve of bridged KSM - PenpalB::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), - ksm_at_polkadot_parachains.encode(), - )], - )); - }); - - // fund the PAH's SA on KAH with the KSM tokens held in reserve - let sov_pah_on_kah = AssetHubKusama::sovereign_account_of_parachain_on_other_global_consensus( - Polkadot, - AssetHubPolkadot::para_id(), - ); - AssetHubKusama::fund_accounts(vec![(sov_pah_on_kah.clone(), amount * 2)]); - - // balances before - let sender_ksm_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains.clone(), &sender) - }); - let receiver_ksm_before = ::account_data_of(receiver.clone()).free; - - // send KSMs over the bridge, DOTs only used to pay fees on local AH, pay with KSM on remote AH - { - let final_destination = asset_hub_kusama_location(); - let intermediary_hop = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); - let context = PenpalB::execute_with(PenpalUniversalLocation::get); - - // what happens at final destination - let beneficiary = AccountId32Junction { network: None, id: receiver.clone().into() }.into(); - // use KSM as fees on the final destination (PAH) - let remote_fees: Asset = (ksm_at_polkadot_parachains.clone(), amount).into(); - let remote_fees = remote_fees.reanchored(&final_destination, &context).unwrap(); - // buy execution using KSMs, then deposit all remaining KSMs - let xcm_on_final_dest = Xcm::<()>(vec![ - BuyExecution { fees: remote_fees, weight_limit: WeightLimit::Unlimited }, - DepositAsset { assets: Wild(AllCounted(1)), beneficiary }, - ]); - - // what happens at intermediary hop - // reanchor final dest (Asset Hub Kusama) to the view of hop (Asset Hub Polkadot) - let mut final_destination = final_destination.clone(); - final_destination.reanchor(&intermediary_hop, &context).unwrap(); - // reanchor KSMs to the view of hop (Asset Hub Polkadot) - let asset: Asset = (ksm_at_polkadot_parachains.clone(), amount).into(); - let asset = asset.reanchored(&intermediary_hop, &context).unwrap(); - // on Asset Hub Polkadot, forward a request to withdraw KSMs from reserve on Asset Hub - // Kusama - let xcm_on_hop = Xcm::<()>(vec![InitiateReserveWithdraw { - assets: Definite(asset.into()), // KSMs - reserve: final_destination, // KAH - xcm: xcm_on_final_dest, // XCM to execute on KAH - }]); - // assets to send from Penpal and how they reach the intermediary hop - let assets: Assets = vec![ - (ksm_at_polkadot_parachains.clone(), amount).into(), - (dot_at_polkadot_parachains.clone(), amount).into(), - ] - .into(); - let asset_transfer_type = TransferType::DestinationReserve; - let fees_id: AssetId = dot_at_polkadot_parachains.into(); - let fees_transfer_type = TransferType::DestinationReserve; - - // initiate the transfer - send_assets_from_penpal_polkadot_through_polkadot_ah_to_kusama_ah( - intermediary_hop, - (assets, asset_transfer_type), - (fees_id, fees_transfer_type), - xcm_on_hop, - ); - } - - // process KAH incoming message and check events - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubKusama, - vec![ - // issue DOTs on KAH - RuntimeEvent::Balances(pallet_balances::Event::Issued { .. }) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - let sender_ksm_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; - >::balance(ksm_at_polkadot_parachains, &sender) - }); - let receiver_ksm_after = ::account_data_of(receiver).free; - - // Sender's balance is reduced by sent "amount" - assert_eq!(sender_ksm_after, sender_ksm_before - amount); - // Receiver's balance is increased by no more than "amount" - assert!(receiver_ksm_after > receiver_ksm_before); - assert!(receiver_ksm_after <= receiver_ksm_before + amount); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/claim_assets.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/claim_assets.rs deleted file mode 100644 index 450788b92b..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/claim_assets.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests related to claiming assets trapped during XCM execution. - -use crate::*; - -use bridge_hub_polkadot_runtime::ExistentialDeposit; -use integration_tests_helpers::test_chain_can_claim_assets; -use xcm_executor::traits::DropAssets; - -#[test] -fn assets_can_be_claimed() { - let amount = ExistentialDeposit::get(); - let assets: Assets = (Parent, amount).into(); - - test_chain_can_claim_assets!( - AssetHubPolkadot, - RuntimeCall, - NetworkId::Polkadot, - assets, - amount - ); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/mod.rs deleted file mode 100644 index 82556e1885..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; - -mod asset_transfers; -mod claim_assets; -mod register_bridged_assets; -mod send_xcm; -mod snowbridge; -mod teleport; - -pub(crate) fn asset_hub_kusama_location() -> Location { - Location::new(2, [GlobalConsensus(Kusama), Parachain(AssetHubKusama::para_id().into())]) -} - -pub(crate) fn bridge_hub_kusama_location() -> Location { - Location::new(2, [GlobalConsensus(Kusama), Parachain(BridgeHubKusama::para_id().into())]) -} - -// DOT and wDOT -pub(crate) fn dot_at_ah_polkadot() -> Location { - Parent.into() -} -pub(crate) fn bridged_dot_at_ah_kusama() -> Location { - Location::new(2, [GlobalConsensus(Polkadot)]) -} - -// wKSM -pub(crate) fn bridged_ksm_at_ah_polkadot() -> Location { - Location::new(2, [GlobalConsensus(Kusama)]) -} - -// USDT and wUSDT -pub(crate) fn usdt_at_ah_polkadot() -> Location { - Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) -} -pub(crate) fn bridged_usdt_at_ah_kusama() -> Location { - Location::new( - 2, - [ - GlobalConsensus(Polkadot), - Parachain(AssetHubPolkadot::para_id().into()), - PalletInstance(ASSETS_PALLET_ID), - GeneralIndex(USDT_ID.into()), - ], - ) -} - -// wETH has same relative location on both Kusama and Polkadot AssetHubs -pub(crate) fn weth_at_asset_hubs() -> Location { - Location::new( - 2, - [ - GlobalConsensus(Ethereum { chain_id: snowbridge::CHAIN_ID }), - AccountKey20 { network: None, key: snowbridge::WETH }, - ], - ) -} - -pub(crate) fn create_foreign_on_ah_kusama(id: v4::Location, sufficient: bool) { - let owner = AssetHubKusama::account_id_of(ALICE); - AssetHubKusama::force_create_foreign_asset(id, owner, sufficient, ASSET_MIN_BALANCE, vec![]); -} - -pub(crate) fn create_foreign_on_ah_polkadot( - id: v4::Location, - sufficient: bool, - prefund_accounts: Vec<(AccountId, u128)>, -) { - let owner = AssetHubPolkadot::account_id_of(ALICE); - let min = ASSET_MIN_BALANCE; - AssetHubPolkadot::force_create_foreign_asset(id, owner, sufficient, min, prefund_accounts); -} - -pub(crate) fn foreign_balance_on_ah_kusama(id: v4::Location, who: &AccountId) -> u128 { - AssetHubKusama::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(id, who) - }) -} -pub(crate) fn foreign_balance_on_ah_polkadot(id: v4::Location, who: &AccountId) -> u128 { - AssetHubPolkadot::execute_with(|| { - type Assets = ::ForeignAssets; - >::balance(id, who) - }) -} - -// set up pool -pub(crate) fn set_up_pool_with_ksm_on_ah_kusama(asset: v4::Location, is_foreign: bool) { - let ksm: v4::Location = v4::Parent.into(); - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - let owner = AssetHubKusamaSender::get(); - let signed_owner = ::RuntimeOrigin::signed(owner.clone()); - - if is_foreign { - assert_ok!(::ForeignAssets::mint( - signed_owner.clone(), - asset.clone(), - owner.clone().into(), - 3_000_000_000_000, - )); - } else { - let asset_id = match asset.interior.last() { - Some(v4::Junction::GeneralIndex(id)) => *id as u32, - _ => unreachable!(), - }; - assert_ok!(::Assets::mint( - signed_owner.clone(), - asset_id.into(), - owner.clone().into(), - 3_000_000_000_000, - )); - } - assert_ok!(::AssetConversion::create_pool( - signed_owner.clone(), - Box::new(ksm.clone()), - Box::new(asset.clone()), - )); - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, - ] - ); - assert_ok!(::AssetConversion::add_liquidity( - signed_owner.clone(), - Box::new(ksm), - Box::new(asset), - 1_000_000_000_000, - 2_000_000_000_000, - 1, - 1, - owner, - )); - assert_expected_events!( - AssetHubKusama, - vec![ - RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {..}) => {}, - ] - ); - }); -} - -pub(crate) fn send_assets_from_asset_hub_polkadot( - destination: Location, - assets: Assets, - fee_idx: u32, -) -> DispatchResult { - let signed_origin = - ::RuntimeOrigin::signed(AssetHubPolkadotSender::get()); - let beneficiary: Location = - AccountId32Junction { network: None, id: AssetHubKusamaReceiver::get().into() }.into(); - - AssetHubPolkadot::execute_with(|| { - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_idx, - WeightLimit::Unlimited, - ) - }) -} - -pub(crate) fn assert_bridge_hub_polkadot_message_accepted(expected_processed: bool) { - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - if expected_processed { - assert_expected_events!( - BridgeHubPolkadot, - vec![ - // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Burned { .. }) => {}, - // message exported - RuntimeEvent::BridgeKusamaMessages( - pallet_bridge_messages::Event::MessageAccepted { .. } - ) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - } else { - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: false, - .. - }) => {}, - ] - ); - } - }); -} - -pub(crate) fn assert_bridge_hub_kusama_message_received() { - BridgeHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubKusama, - vec![ - // message sent to destination - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }) -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/register_bridged_assets.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/register_bridged_assets.rs deleted file mode 100644 index 928b486fd4..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/register_bridged_assets.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::tests::{ - snowbridge::{CHAIN_ID, WETH}, - *, -}; - -const XCM_FEE: u128 = 40_000_000_000; - -/// Tests the registering of a Polkadot Asset as a bridged asset on Kusama Asset Hub. -#[test] -fn register_polkadot_asset_on_kah_from_pah() { - // Polkadot Asset Hub asset when bridged to Kusama Asset Hub. - let bridged_asset_at_kah = v4::Location::new( - 2, - [ - v4::Junction::GlobalConsensus(v4::NetworkId::Polkadot), - v4::Junction::Parachain(AssetHubPolkadot::para_id().into()), - v4::Junction::PalletInstance(ASSETS_PALLET_ID), - v4::Junction::GeneralIndex(ASSET_ID.into()), - ], - ); - // Register above asset on Kusama AH from Polkadot AH. - register_asset_on_kah_from_pah(bridged_asset_at_kah); -} - -/// Tests the registering of an Ethereum Asset as a bridged asset on Kusama Asset Hub. -#[test] -fn register_ethereum_asset_on_kah_from_pah() { - // Ethereum asset when bridged to Kusama Asset Hub. - let bridged_asset_at_kah = v4::Location::new( - 2, - [ - v4::Junction::GlobalConsensus(v4::NetworkId::Ethereum { chain_id: CHAIN_ID }), - v4::Junction::AccountKey20 { network: None, key: WETH }, - ], - ); - // Register above asset on Kusama AH from Polkadot AH. - register_asset_on_kah_from_pah(bridged_asset_at_kah); -} - -fn register_asset_on_kah_from_pah(bridged_asset_at_kah: v4::Location) { - let sa_of_pah_on_kah = AssetHubKusama::sovereign_account_of_parachain_on_other_global_consensus( - Polkadot, - AssetHubPolkadot::para_id(), - ); - - // Encoded `create_asset` call to be executed in Kusama Asset Hub ForeignAssets pallet. - let call = AssetHubKusama::create_foreign_asset_call( - bridged_asset_at_kah.clone(), - ASSET_MIN_BALANCE, - sa_of_pah_on_kah.clone(), - ); - - let origin_kind = OriginKind::Xcm; - let fee_amount = XCM_FEE; - let fees = (Parent, fee_amount).into(); - - let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_pah_on_kah.clone()); - - // SA-of-PAH-on-KAH needs to have balance to pay for fees and asset creation deposit - AssetHubKusama::fund_accounts(vec![( - sa_of_pah_on_kah.clone(), - ASSET_HUB_KUSAMA_ED * 10000000000, - )]); - - let destination = asset_hub_kusama_location(); - - // fund the PAH's SA on PBH for paying bridge transport fees - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), 10_000_000_000_000u128); - - // set XCM versions - AssetHubPolkadot::force_xcm_version(destination.clone(), XCM_VERSION); - BridgeHubPolkadot::force_xcm_version(bridge_hub_kusama_location(), XCM_VERSION); - - let root_origin = ::RuntimeOrigin::root(); - AssetHubPolkadot::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - root_origin, - bx!(destination.into()), - bx!(xcm), - )); - - AssetHubPolkadot::assert_xcm_pallet_sent(); - }); - - assert_bridge_hub_polkadot_message_accepted(true); - assert_bridge_hub_kusama_message_received(); - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - AssetHubKusama::assert_xcmp_queue_success(None); - assert_expected_events!( - AssetHubKusama, - vec![ - // Burned the fee - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == sa_of_pah_on_kah.clone(), - amount: *amount == fee_amount, - }, - // Foreign Asset created - RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { - asset_id: *asset_id == bridged_asset_at_kah, - creator: *creator == sa_of_pah_on_kah.clone(), - owner: *owner == sa_of_pah_on_kah, - }, - // Unspent fee minted to origin - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == sa_of_pah_on_kah.clone(), - }, - ] - ); - type ForeignAssets = ::ForeignAssets; - assert!(ForeignAssets::asset_exists(bridged_asset_at_kah)); - }); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/send_xcm.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/send_xcm.rs deleted file mode 100644 index 65a0dea677..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/send_xcm.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::tests::*; - -#[test] -fn send_xcm_from_polkadot_relay_to_kusama_asset_hub_should_fail_on_not_applicable() { - // Init tests variables - // XcmPallet send arguments - let sudo_origin = ::RuntimeOrigin::root(); - let destination = Polkadot::child_location_of(BridgeHubPolkadot::para_id()).into(); - let weight_limit = WeightLimit::Unlimited; - let check_origin = None; - - let remote_xcm = Xcm(vec![ClearOrigin]); - - let xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit, check_origin }, - ExportMessage { - network: KusamaId, - destination: [Parachain(AssetHubKusama::para_id().into())].into(), - xcm: remote_xcm, - }, - ])); - - // Polkadot Global Consensus - // Send XCM message from Relay Chain to Bridge Hub source Parachain - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(destination), - bx!(xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have - // opened bridge/lane. - assert_bridge_hub_polkadot_message_accepted(false); -} - -#[test] -fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { - // Initially set only default version on all runtimes - let newer_xcm_version = xcm::prelude::XCM_VERSION; - let older_xcm_version = newer_xcm_version - 1; - - AssetHubKusama::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubKusama::force_default_xcm_version(Some(older_xcm_version)); - BridgeHubPolkadot::force_default_xcm_version(Some(older_xcm_version)); - AssetHubPolkadot::force_default_xcm_version(Some(older_xcm_version)); - - // prepare data - let destination = asset_hub_kusama_location(); - let native_token = Location::parent(); - let amount = ASSET_HUB_POLKADOT_ED * 1_000; - - // fund the AHK's SA on BHK for paying bridge transport fees - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), 10_000_000_000_000u128); - // fund sender - AssetHubPolkadot::fund_accounts(vec![(AssetHubPolkadotSender::get(), amount * 10)]); - - // send XCM from AssetHubPolkadot - fails - destination version not known - assert_err!( - send_assets_from_asset_hub_polkadot( - destination.clone(), - (native_token.clone(), amount).into(), - 0 - ), - DispatchError::Module(sp_runtime::ModuleError { - index: 31, - error: [1, 0, 0, 0], - message: Some("SendFailure") - }) - ); - - // set destination version - AssetHubPolkadot::force_xcm_version(destination.clone(), newer_xcm_version); - - // set version with `ExportMessage` for BridgeHubPolkadot - AssetHubPolkadot::force_xcm_version( - ParentThen(Parachain(BridgeHubPolkadot::para_id().into()).into()).into(), - newer_xcm_version, - ); - // send XCM from AssetHubPolkadot - ok - assert_ok!(send_assets_from_asset_hub_polkadot( - destination.clone(), - (native_token.clone(), amount).into(), - 0 - )); - - // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known - assert_bridge_hub_polkadot_message_accepted(false); - - // set version for remote BridgeHub on BridgeHubPolkadot - BridgeHubPolkadot::force_xcm_version(bridge_hub_kusama_location(), newer_xcm_version); - // set version for AssetHubKusama on BridgeHubKusama - BridgeHubKusama::force_xcm_version( - ParentThen(Parachain(AssetHubKusama::para_id().into()).into()).into(), - newer_xcm_version, - ); - - // send XCM from AssetHubPolkadot - ok - assert_ok!(send_assets_from_asset_hub_polkadot( - destination.clone(), - (native_token.clone(), amount).into(), - 0 - )); - assert_bridge_hub_polkadot_message_accepted(true); - assert_bridge_hub_kusama_message_received(); - // message delivered and processed at destination - AssetHubKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubKusama, - vec![ - // message processed with failure, but for this scenario it is ok, important is that was delivered - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: false, .. } - ) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs deleted file mode 100644 index 4d94458662..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/snowbridge.rs +++ /dev/null @@ -1,1286 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -use crate::*; -use asset_hub_polkadot_runtime::xcm_config::{ - bridging::to_ethereum::{BridgeHubEthereumBaseFee, EthereumNetwork}, - RelayTreasuryPalletAccount, -}; -use bp_bridge_hub_polkadot::snowbridge::CreateAssetCall; -use bridge_hub_polkadot_runtime::{ - bridge_to_ethereum_config::EthereumGatewayAddress, EthereumBeaconClient, EthereumInboundQueue, - Runtime, RuntimeOrigin, -}; -use codec::{Decode, Encode}; -use emulated_integration_tests_common::{xcm_emulator::ConvertLocation, RESERVABLE_ASSET_ID}; -use frame_support::pallet_prelude::TypeInfo; -use hex_literal::hex; -use polkadot_system_emulated_network::{ - asset_hub_polkadot_emulated_chain::genesis::AssetHubPolkadotAssetOwner, - penpal_emulated_chain::CustomizableAssetFromSystemAssetHub, - BridgeHubPolkadotParaSender as BridgeHubPolkadotSender, -}; -use snowbridge_beacon_primitives::{ - types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, -}; -use snowbridge_core::{ - gwei, - inbound::{InboundQueueFixture, Log, Message, Proof}, - meth, - outbound::OperatingMode, - AssetMetadata, Rewards, TokenIdOf, -}; -use snowbridge_pallet_system::PricingParametersOf; -use snowbridge_router_primitives::inbound::{ - Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, -}; -use sp_core::{H160, H256, U256}; -use sp_runtime::{DispatchError::Token, FixedU128, TokenError::FundsUnavailable}; -use system_parachains_constants::polkadot::currency::UNITS; - -pub const CHAIN_ID: u64 = 1; -pub const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); -pub const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); -pub const GATEWAY_ADDRESS: [u8; 20] = hex!("EDa338E4dC46038493b885327842fD3E301CaB39"); - -const INITIAL_FUND: u128 = 5_000_000_000 * POLKADOT_ED; -const INSUFFICIENT_XCM_FEE: u128 = 1000; -const XCM_FEE: u128 = 4_000_000_000; -const TOKEN_AMOUNT: u128 = 100_000_000_000; -const AH_BASE_FEE: u128 = 2_750_872_500_000u128; - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum ControlCall { - #[codec(index = 3)] - CreateAgent, - #[codec(index = 4)] - CreateChannel { mode: OperatingMode }, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum SnowbridgeControl { - #[codec(index = 83)] - Control(ControlCall), -} - -pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { - EthereumBeaconClient::store_finalized_header( - fixture.finalized_header, - fixture.block_roots_root, - ) - .unwrap(); - - EthereumInboundQueue::submit( - RuntimeOrigin::signed(BridgeHubPolkadotSender::get()), - fixture.message, - ) -} - -/// Create an agent on Ethereum. An agent is a representation of an entity in the Polkadot -/// ecosystem (like a parachain) on Ethereum. -#[test] -fn create_agent() { - let origin_para: u32 = 1001; - // Fund the origin parachain sovereign account so that it can pay execution fees. - BridgeHubPolkadot::fund_para_sovereign(origin_para.into(), INITIAL_FUND); - // Fund Treasury account with ED so that when create agent fees are paid to treasury, - // the treasury account may exist. - BridgeHubPolkadot::fund_accounts(vec![(RelayTreasuryPalletAccount::get(), INITIAL_FUND)]); - - let sudo_origin = ::RuntimeOrigin::root(); - let destination = Polkadot::child_location_of(BridgeHubPolkadot::para_id()).into(); - - let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); - // Construct XCM to create an agent for para 1001 - let remote_xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - DescendOrigin(Parachain(origin_para).into()), - Transact { - require_weight_at_most: 3000000000.into(), - origin_kind: OriginKind::Xcm, - call: create_agent_call.encode().into(), - }, - ])); - - // Polkadot Global Consensus - // Send XCM message from Relay Chain to Bridge Hub source Parachain - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(destination), - bx!(remote_xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - // Check that the Transact message was sent - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - let events = BridgeHubPolkadot::events(); - assert!( - events.iter().any(|event| !matches!( - event, - RuntimeEvent::EthereumSystem(snowbridge_pallet_system::Event::CreateAgent { .. }) - )), - "Create agent event found while not expected." - ); - }); -} - -/// Create a channel for a consensus system. A channel is a bidirectional messaging channel -/// between BridgeHub and Ethereum. -#[test] -fn create_channel() { - let origin_para: u32 = 1001; - // Fund AssetHub sovereign account so that it can pay execution fees. - BridgeHubPolkadot::fund_para_sovereign(origin_para.into(), INITIAL_FUND); - // Fund Treasury account with ED so that when create agent fees are paid to treasury, - // the treasury account may exist. - BridgeHubPolkadot::fund_accounts(vec![(RelayTreasuryPalletAccount::get(), INITIAL_FUND)]); - - let sudo_origin = ::RuntimeOrigin::root(); - let destination: VersionedLocation = - Polkadot::child_location_of(BridgeHubPolkadot::para_id()).into(); - - let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); - // Construct XCM to create an agent for para 1001 - let create_agent_xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - DescendOrigin(Parachain(origin_para).into()), - Transact { - require_weight_at_most: 3000000000.into(), - origin_kind: OriginKind::Xcm, - call: create_agent_call.encode().into(), - }, - ])); - - let create_channel_call = - SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal }); - // Construct XCM to create a channel for para 1001 - let create_channel_xcm = VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - DescendOrigin(Parachain(origin_para).into()), - Transact { - require_weight_at_most: 3000000000.into(), - origin_kind: OriginKind::Xcm, - call: create_channel_call.encode().into(), - }, - ])); - - // Polkadot Global Consensus - // Send XCM message from Relay Chain to Bridge Hub source Parachain - Polkadot::execute_with(|| { - assert_ok!(::XcmPallet::send( - sudo_origin.clone(), - bx!(destination.clone()), - bx!(create_agent_xcm), - )); - - assert_ok!(::XcmPallet::send( - sudo_origin, - bx!(destination), - bx!(create_channel_xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - let events = BridgeHubPolkadot::events(); - assert!( - events.iter().any(|event| !matches!( - event, - RuntimeEvent::EthereumSystem(snowbridge_pallet_system::Event::CreateChannel { .. }) - )), - "Create channel event found while not expected." - ); - }); -} - -/// Tests the registering of a token as an asset on AssetHub. -#[test] -fn register_weth_token_from_ethereum_to_asset_hub() { - // Fund AH sovereign account on BH so that it can pay execution fees. - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), INITIAL_FUND); - // Fund ethereum sovereign account on AssetHub. - AssetHubPolkadot::fund_accounts(vec![(ethereum_sovereign_account(), INITIAL_FUND)]); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], - )); - // Construct RegisterToken message and sent to inbound queue - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert([0; 32].into(), message).unwrap(); - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { .. }) => {}, - ] - ); - }); -} - -/// Tests sending a token to a 3rd party parachain, called PenPal. The token reserve is -/// still located on AssetHub. -#[test] -fn send_token_from_ethereum_to_penpal() { - let asset_hub_sovereign = BridgeHubPolkadot::sovereign_account_id_of(Location::new( - 1, - [Parachain(AssetHubPolkadot::para_id().into())], - )); - - // The Weth asset location, identified by the contract address on Ethereum - let weth_asset_location: Location = - (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); - // Converts the Weth asset location into an asset ID - let weth_asset_id = weth_asset_location.clone(); - - // Fund ethereum sovereign on AssetHub - AssetHubPolkadot::fund_accounts(vec![(ethereum_sovereign_account(), INITIAL_FUND)]); - - // Create asset on the Penpal parachain. - PenpalB::execute_with(|| { - // Set the trusted asset location from AH, in this case, Ethereum. - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![( - CustomizableAssetFromSystemAssetHub::key().to_vec(), - Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]).encode(), - )], - )); - - assert_ok!(::ForeignAssets::create( - ::RuntimeOrigin::signed(PenpalBSender::get()), - weth_asset_location.clone(), - asset_hub_sovereign.clone().into(), - 1000, - )); - - assert!(::ForeignAssets::asset_exists(weth_asset_location)); - }); - - AssetHubPolkadot::execute_with(|| { - assert_ok!(::ForeignAssets::force_create( - ::RuntimeOrigin::root(), - weth_asset_id.clone(), - asset_hub_sovereign.clone().into(), - true, - 1000, - )); - - assert!(::ForeignAssets::asset_exists( - weth_asset_id - )); - }); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - type RuntimeOrigin = ::RuntimeOrigin; - - // Fund AssetHub sovereign account so it can pay execution fees for the asset transfer - assert_ok!(::Balances::force_set_balance( - RuntimeOrigin::root(), - asset_hub_sovereign.clone().into(), - INITIAL_FUND, - )); - - let message_id: H256 = [1; 32].into(); - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::SendToken { - token: WETH.into(), - destination: Destination::ForeignAccountId32 { - para_id: PenpalB::para_id().into(), - id: PenpalBReceiver::get().into(), - fee: 40_000_000_000, - }, - amount: 1_000_000, - fee: 40_000_000_000, - }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - // Check that the assets were issued on AssetHub - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - PenpalB::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - // Check that the assets were issued on PenPal - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - }); -} - -/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending -/// a token from Ethereum to AssetHub. -#[test] -fn send_token_from_ethereum_to_asset_hub() { - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), INITIAL_FUND); - // Fund ethereum sovereign account on AssetHub. - AssetHubPolkadot::fund_accounts(vec![(ethereum_sovereign_account(), INITIAL_FUND)]); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], - )); - - // Construct RegisterToken message and sent to inbound queue - let message_id: H256 = [1; 32].into(); - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - - // Construct SendToken message and sent to inbound queue - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::SendToken { - token: WETH.into(), - destination: Destination::AccountId32 { - id: AssetHubPolkadotReceiver::get().into(), - }, - amount: TOKEN_AMOUNT, - fee: XCM_FEE, - }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - // Check that the message was sent - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the token was received and issued as a foreign asset on AssetHub - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - }); -} - -/// Tests the full cycle of token transfers: -/// - registering a token on AssetHub -/// - sending a token to AssetHub -/// - returning the token to Ethereum -#[test] -fn send_weth_asset_from_asset_hub_to_ethereum() { - let assethub_sovereign = BridgeHubPolkadot::sovereign_account_id_of(Location::new( - 1, - [Parachain(AssetHubPolkadot::para_id().into())], - )); - - BridgeHubPolkadot::fund_accounts(vec![ - (assethub_sovereign.clone(), INITIAL_FUND), - (RelayTreasuryPalletAccount::get(), INITIAL_FUND), - ]); - AssetHubPolkadot::fund_accounts(vec![ - (AssetHubPolkadotReceiver::get(), INITIAL_FUND), - (ethereum_sovereign_account(), INITIAL_FUND), - ]); - - // Set base transfer fee to Ethereum on AH. - AssetHubPolkadot::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(BridgeHubEthereumBaseFee::key().to_vec(), AH_BASE_FEE.encode())], - )); - }); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!( - ::EthereumSystem::set_pricing_parameters( - ::RuntimeOrigin::root(), - PricingParametersOf:: { - exchange_rate: FixedU128::from_rational(1, 75), - fee_per_gas: gwei(20), - rewards: Rewards { - local: (UNITS / 100), // 0.01 DOT - remote: meth(1), - }, - multiplier: FixedU128::from_rational(1, 1), - } - ) - ); - - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], - )); - - let message_id: H256 = [1; 32].into(); - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - // Check that the register token message was sent using xcm - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - - // Construct SendToken message and sent to inbound queue - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::SendToken { - token: WETH.into(), - destination: Destination::AccountId32 { - id: AssetHubPolkadotReceiver::get().into(), - }, - amount: TOKEN_AMOUNT, - fee: XCM_FEE, - }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - // Check that the send token message was sent using xcm - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - // check treasury account balance on BH before - let treasury_account_before = BridgeHubPolkadot::execute_with(|| { - <::Balances as frame_support::traits::fungible::Inspect<_>>::balance(&RelayTreasuryPalletAccount::get()) - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeOrigin = ::RuntimeOrigin; - - // Check that AssetHub has issued the foreign asset - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - let assets = vec![Asset { - id: AssetId(Location::new( - 2, - [ - GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), - AccountKey20 { network: None, key: WETH }, - ], - )), - fun: Fungible(TOKEN_AMOUNT), - }]; - let versioned_assets = VersionedAssets::from(Assets::from(assets)); - - let destination = VersionedLocation::from(Location::new( - 2, - [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], - )); - - let beneficiary = VersionedLocation::from(Location::new( - 0, - [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS }], - )); - - let free_balance_before = - ::Balances::free_balance( - AssetHubPolkadotReceiver::get(), - ); - // Send the Weth back to Ethereum - assert_ok!( - ::PolkadotXcm::limited_reserve_transfer_assets( - RuntimeOrigin::signed(AssetHubPolkadotReceiver::get()), - Box::new(destination), - Box::new(beneficiary), - Box::new(versioned_assets), - 0, - Unlimited, - ) - ); - - let free_balance_after = - ::Balances::free_balance( - AssetHubPolkadotReceiver::get(), - ); - // Assert at least DefaultBridgeHubEthereumBaseFee charged from the sender - let free_balance_diff = free_balance_before - free_balance_after; - assert!(free_balance_diff > AH_BASE_FEE); - }); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - // Check that the transfer token back to Ethereum message was queue in the Ethereum - // Outbound Queue - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued {..}) => {}, - ] - ); - - // check treasury account balance on BH after (should receive some fees) - let treasury_account_after = <::Balances as frame_support::traits::fungible::Inspect<_>>::balance(&RelayTreasuryPalletAccount::get()); - let local_fee = treasury_account_after - treasury_account_before; - - let events = BridgeHubPolkadot::events(); - // Check that the local fee was credited to the Snowbridge sovereign account - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) - if *who == RelayTreasuryPalletAccount::get() && *amount == local_fee - )), - "Snowbridge sovereign takes local fee." - ); - // Check that the remote delivery fee was credited to the AssetHub sovereign account - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) - if *who == assethub_sovereign, - )), - "AssetHub sovereign takes remote fee." - ); - }); -} - -#[test] -fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), INITIAL_FUND); - - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], - )); - - let message_id: H256 = [1; 32].into(); - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::RegisterToken { token: WETH.into(), fee: INSUFFICIENT_XCM_FEE }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, - ] - ); - }); -} - -#[test] -fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { - // Insufficient fund - BridgeHubPolkadot::fund_para_sovereign(AssetHubPolkadot::para_id(), 1_000); - - BridgeHubPolkadot::execute_with(|| { - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(EthereumGatewayAddress::key().to_vec(), H160(GATEWAY_ADDRESS).encode())], - )); - - assert_err!(send_inbound_message(make_register_token_message()), Token(FundsUnavailable)); - }); -} - -/// Tests that the EthereumInboundQueue CreateAssetCall parameter on BridgeHub matches -/// the ForeignAssets::create call on AssetHub. -#[test] -fn asset_hub_foreign_assets_pallet_is_configured_correctly_in_bridge_hub() { - let assethub_sovereign = BridgeHubPolkadot::sovereign_account_id_of(Location::new( - 1, - [Parachain(AssetHubPolkadot::para_id().into())], - )); - - let call_create_foreign_assets = - ::RuntimeCall::ForeignAssets(pallet_assets::Call::< - ::Runtime, - pallet_assets::Instance2, - >::create { - id: v4::Location::default(), - min_balance: ASSET_MIN_BALANCE, - admin: assethub_sovereign.into(), - }) - .encode(); - - let bridge_hub_inbound_queue_assets_pallet_call_index = CreateAssetCall::get(); - - assert!( - call_create_foreign_assets.starts_with(&bridge_hub_inbound_queue_assets_pallet_call_index) - ); -} - -fn ethereum_sovereign_account() -> AccountId { - let origin_location = (Parent, Parent, EthereumNetwork::get()).into(); - GlobalConsensusEthereumConvertsFor::::convert_location(&origin_location).unwrap() -} - -fn make_register_token_message() -> InboundQueueFixture { - InboundQueueFixture{ - message: Message { - event_log: Log{ - address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), - topics: vec![ - hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), - hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), - ], - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e0001000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), - }, - proof: Proof { - receipt_proof: (vec![ - hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), - ], vec![ - hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e0001000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), - ]), - execution_proof: ExecutionProof { - header: BeaconHeader { - slot: 393, - proposer_index: 4, - parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), - state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), - body_root: hex!("308e4c20194c0c77155c65a2d2c7dcd0ec6a7b20bdeb002c065932149fe0aa1b").into(), - }, - ancestry_proof: Some(AncestryProof { - header_branch: vec![ - hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), - hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), - hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), - hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), - hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), - hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), - hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), - hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), - hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), - hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), - hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), - hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), - hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), - ], - finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), - }), - execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { - parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), - fee_recipient: hex!("0000000000000000000000000000000000000000").into(), - state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), - receipts_root: hex!("62d13e9a073dc7cf609005b5531bb208c8686f18f7c8ae02d76232d83ae41a21").into(), - logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), - prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), - block_number: 393, - gas_limit: 54492273, - gas_used: 199644, - timestamp: 1710552813, - extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), - base_fee_per_gas: U256::from(7u64), - block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), - transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), - withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), - blob_gas_used: 0, - excess_blob_gas: 0, - }), - execution_branch: vec![ - hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), - hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), - hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), - hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), - ], - } - } - }, - finalized_header: BeaconHeader { - slot: 864, - proposer_index: 4, - parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), - state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), - body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), - }, - block_roots_root: hex!("3adb5c78afd49ef17160ca7fc38b47228cbb13a317709c86bb6f51d799ba9ab6").into(), - } -} - -fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) { - let weth_asset_location: Location = Location::new( - 2, - [EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }], - ); - // Fund asset hub sovereign on bridge hub - let asset_hub_sovereign = BridgeHubPolkadot::sovereign_account_id_of(Location::new( - 1, - [Parachain(AssetHubPolkadot::para_id().into())], - )); - BridgeHubPolkadot::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); - - // Register WETH - AssetHubPolkadot::execute_with(|| { - type RuntimeOrigin = ::RuntimeOrigin; - - assert_ok!(::ForeignAssets::force_create( - RuntimeOrigin::root(), - weth_asset_location.clone(), - asset_hub_sovereign.into(), - false, - 1, - )); - - assert!(::ForeignAssets::asset_exists( - weth_asset_location.clone(), - )); - }); - - // Send WETH to an existent account on asset hub - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - type EthereumInboundQueue = - ::EthereumInboundQueue; - let message_id: H256 = [0; 32].into(); - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::SendToken { - token: WETH.into(), - destination: Destination::AccountId32 { id: account_id }, - amount: 1_000_000, - fee, - }, - }); - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - assert_ok!(EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id())); - - // Check that the message was sent - assert_expected_events!( - BridgeHubPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); -} - -#[test] -fn send_token_from_ethereum_to_existent_account_on_asset_hub() { - send_token_from_ethereum_to_asset_hub_with_fee(AssetHubPolkadotSender::get().into(), XCM_FEE); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the token was received and issued as a foreign asset on AssetHub - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - }); -} - -#[test] -fn send_token_from_ethereum_to_non_existent_account_on_asset_hub() { - send_token_from_ethereum_to_asset_hub_with_fee([1; 32], XCM_FEE); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the token was received and issued as a foreign asset on AssetHub - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - }); -} - -#[test] -fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficient_fee() { - send_token_from_ethereum_to_asset_hub_with_fee([1; 32], INSUFFICIENT_XCM_FEE); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the message was not processed successfully due to insufficient fee - - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, - ] - ); - }); -} - -#[test] -fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_sufficient_fee_but_do_not_satisfy_ed( -) { - // On AH the xcm fee is 26_789_690 and the ED is 3_300_000 - send_token_from_ethereum_to_asset_hub_with_fee([1; 32], 30_000_000); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the message was not processed successfully due to insufficient ED - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, - ] - ); - }); -} - -#[test] -fn transfer_relay_token() { - let assethub_sovereign = BridgeHubPolkadot::sovereign_account_id_of( - BridgeHubPolkadot::sibling_location_of(AssetHubPolkadot::para_id()), - ); - BridgeHubPolkadot::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); - - let asset_id: Location = Location { parents: 1, interior: [].into() }; - let expected_asset_id: Location = - Location { parents: 1, interior: [GlobalConsensus(Polkadot)].into() }; - - let expected_token_id = TokenIdOf::convert_location(&expected_asset_id).unwrap(); - - let ethereum_sovereign: AccountId = - GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(&Location::new( - 2, - [GlobalConsensus(EthereumNetwork::get())], - )) - .unwrap() - .into(); - - // Register token - BridgeHubPolkadot::execute_with(|| { - type RuntimeOrigin = ::RuntimeOrigin; - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Balances::force_set_balance( - RuntimeOrigin::root(), - sp_runtime::MultiAddress::Id(BridgeHubPolkadotSender::get()), - INITIAL_FUND * 10, - )); - - assert_ok!(::EthereumSystem::register_token( - RuntimeOrigin::root(), - Box::new(VersionedLocation::V4(asset_id.clone())), - AssetMetadata { - name: "wnd".as_bytes().to_vec().try_into().unwrap(), - symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), - decimals: 12, - }, - )); - // Check that a message was sent to Ethereum to create the agent - assert_expected_events!( - BridgeHubPolkadot, - vec![RuntimeEvent::EthereumSystem(snowbridge_pallet_system::Event::RegisterToken { .. }) => {},] - ); - }); - - // Send token to Ethereum - AssetHubPolkadot::execute_with(|| { - type RuntimeOrigin = ::RuntimeOrigin; - type RuntimeEvent = ::RuntimeEvent; - - // Set base transfer fee to Ethereum on AH. - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(BridgeHubEthereumBaseFee::key().to_vec(), AH_BASE_FEE.encode())], - )); - - let assets = vec![Asset { id: AssetId(Location::parent()), fun: Fungible(TOKEN_AMOUNT) }]; - let versioned_assets = VersionedAssets::V4(Assets::from(assets)); - - let destination = VersionedLocation::V4(Location::new( - 2, - [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], - )); - - let beneficiary = VersionedLocation::V4(Location::new( - 0, - [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS }], - )); - - assert_ok!(::PolkadotXcm::limited_reserve_transfer_assets( - RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - Box::new(destination), - Box::new(beneficiary), - Box::new(versioned_assets), - 0, - Unlimited, - )); - - let events = AssetHubPolkadot::events(); - // Check that the native asset transferred to some reserved account(sovereign of Ethereum) - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Balances(pallet_balances::Event::Transfer { amount, to, ..}) - if *amount == TOKEN_AMOUNT && *to == ethereum_sovereign.clone(), - )), - "native token reserved to Ethereum sovereign account." - ); - }); - - // Send token back from ethereum - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the transfer token back to Ethereum message was queue in the Ethereum - // Outbound Queue - assert_expected_events!( - BridgeHubPolkadot, - vec![RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued{ .. }) => {},] - ); - - // Send relay token back to AH - let message_id: H256 = [0; 32].into(); - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::SendNativeToken { - token_id: expected_token_id, - destination: Destination::AccountId32 { - id: AssetHubPolkadotReceiver::get().into(), - }, - amount: TOKEN_AMOUNT, - fee: XCM_FEE, - }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - assert_expected_events!( - BridgeHubPolkadot, - vec![RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - AssetHubPolkadot, - vec![RuntimeEvent::Balances(pallet_balances::Event::Burned{ .. }) => {},] - ); - - let events = AssetHubPolkadot::events(); - - // Check that the native token burnt from some reserved account - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, ..}) - if *who == ethereum_sovereign.clone(), - )), - "native token burnt from Ethereum sovereign account." - ); - - // Check that the token was minted to beneficiary - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) - if *amount >= TOKEN_AMOUNT && *who == AssetHubPolkadotReceiver::get() - )), - "Token minted to beneficiary." - ); - }); -} - -#[test] -fn transfer_ah_token() { - let assethub_sovereign = BridgeHubPolkadot::sovereign_account_id_of( - BridgeHubPolkadot::sibling_location_of(AssetHubPolkadot::para_id()), - ); - BridgeHubPolkadot::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); - - let ethereum_destination = Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]); - - let ethereum_sovereign: AccountId = - GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(ðereum_destination) - .unwrap() - .into(); - AssetHubPolkadot::fund_accounts(vec![(ethereum_sovereign.clone(), INITIAL_FUND)]); - - let asset_id: Location = - [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())].into(); - - let asset_id_in_bh: Location = Location::new( - 1, - [ - Parachain(AssetHubPolkadot::para_id().into()), - PalletInstance(ASSETS_PALLET_ID), - GeneralIndex(RESERVABLE_ASSET_ID.into()), - ], - ); - - let asset_id_after_reanchored = Location::new( - 1, - [GlobalConsensus(Polkadot), Parachain(AssetHubPolkadot::para_id().into())], - ) - .appended_with(asset_id.clone().interior) - .unwrap(); - - let token_id = TokenIdOf::convert_location(&asset_id_after_reanchored).unwrap(); - - // Register token - BridgeHubPolkadot::execute_with(|| { - type RuntimeOrigin = ::RuntimeOrigin; - - assert_ok!(::EthereumSystem::register_token( - RuntimeOrigin::root(), - Box::new(VersionedLocation::V4(asset_id_in_bh.clone())), - AssetMetadata { - name: "ah_asset".as_bytes().to_vec().try_into().unwrap(), - symbol: "ah_asset".as_bytes().to_vec().try_into().unwrap(), - decimals: 12, - }, - )); - }); - - // Mint some token - AssetHubPolkadot::mint_asset( - ::RuntimeOrigin::signed(AssetHubPolkadotAssetOwner::get()), - RESERVABLE_ASSET_ID, - AssetHubPolkadotSender::get(), - TOKEN_AMOUNT, - ); - - // Send token to Ethereum - AssetHubPolkadot::execute_with(|| { - type RuntimeOrigin = ::RuntimeOrigin; - type RuntimeEvent = ::RuntimeEvent; - - // Set base transfer fee to Ethereum on AH. - assert_ok!(::System::set_storage( - ::RuntimeOrigin::root(), - vec![(BridgeHubEthereumBaseFee::key().to_vec(), AH_BASE_FEE.encode())], - )); - - // Send partial of the token, will fail if send all - let assets = vec![Asset { id: AssetId(asset_id.clone()), fun: Fungible(TOKEN_AMOUNT / 2) }]; - let versioned_assets = VersionedAssets::V4(Assets::from(assets)); - - let beneficiary = VersionedLocation::V4(Location::new( - 0, - [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS }], - )); - - assert_ok!(::PolkadotXcm::limited_reserve_transfer_assets( - RuntimeOrigin::signed(AssetHubPolkadotSender::get()), - Box::new(VersionedLocation::from(ethereum_destination)), - Box::new(beneficiary), - Box::new(versioned_assets), - 0, - Unlimited, - )); - - assert_expected_events!( - AssetHubPolkadot, - vec![RuntimeEvent::Assets(pallet_assets::Event::Transferred{ .. }) => {},] - ); - - let events = AssetHubPolkadot::events(); - // Check that the native asset transferred to some reserved account(sovereign of Ethereum) - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id, to, ..}) - if *asset_id == RESERVABLE_ASSET_ID && *to == ethereum_sovereign.clone() - )), - "native token reserved to Ethereum sovereign account." - ); - }); - - // Send token back from Ethereum - BridgeHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the transfer token back to Ethereum message was queue in the Ethereum - // Outbound Queue - assert_expected_events!( - BridgeHubPolkadot, - vec![RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued{ .. }) => {},] - ); - - let message = VersionedMessage::V1(MessageV1 { - chain_id: CHAIN_ID, - command: Command::SendNativeToken { - token_id, - destination: Destination::AccountId32 { - id: AssetHubPolkadotReceiver::get().into(), - }, - amount: TOKEN_AMOUNT / 10, - fee: XCM_FEE, - }, - }); - // Convert the message to XCM - let (xcm, _) = EthereumInboundQueue::do_convert([0; 32].into(), message).unwrap(); - // Send the XCM - let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubPolkadot::para_id()).unwrap(); - - assert_expected_events!( - BridgeHubPolkadot, - vec![RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - AssetHubPolkadot, - vec![RuntimeEvent::Assets(pallet_assets::Event::Burned{..}) => {},] - ); - - let events = AssetHubPolkadot::events(); - - // Check that the native token burnt from some reserved account - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Assets(pallet_assets::Event::Burned { owner, .. }) - if *owner == ethereum_sovereign.clone(), - )), - "token burnt from Ethereum sovereign account." - ); - - // Check that the token was minted to beneficiary - assert!( - events.iter().any(|event| matches!( - event, - RuntimeEvent::Assets(pallet_assets::Event::Issued { owner, .. }) - if *owner == AssetHubPolkadotReceiver::get() - )), - "Token minted to beneficiary." - ); - }); -} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs deleted file mode 100644 index 996e9f203b..0000000000 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use bridge_hub_polkadot_runtime::xcm_config::XcmConfig; -use frame_support::{ - dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_to_other_system_parachains_works() { - let amount = BRIDGE_HUB_POLKADOT_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - BridgeHubPolkadot, // Origin - XcmConfig, // XCM Configuration - vec![AssetHubPolkadot], // Destination - (native_asset, amount) - ); -} - -#[test] -fn teleport_from_and_to_relay() { - let amount = BRIDGE_HUB_POLKADOT_ED * 1000; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Polkadot, - PolkadotXcmConfig, - vec![BridgeHubPolkadot], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - BridgeHubPolkadot, - BridgeHubPolkadotXcmConfig, - Polkadot, - amount - ); -} diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml b/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml deleted file mode 100644 index 55c82668fb..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "collectives-polkadot-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Collectives Polkadot runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } -assert_matches = { workspace = true } - -# Substrate -sp-core = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-asset-rate = { workspace = true, default-features = true } -pallet-assets = { workspace = true, default-features = true } -pallet-treasury = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } -pallet-utility = { workspace = true, default-features = true } -pallet-whitelist = { workspace = true, default-features = true } - -# Polkadot -polkadot-runtime-common = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true, default-features = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -asset-test-utils = { workspace = true } -emulated-integration-tests-common = { workspace = true } -parachains-common = { workspace = true, default-features = true } -cumulus-pallet-xcmp-queue = { workspace = true, default-features = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -asset-hub-polkadot-runtime = { workspace = true } -collectives-polkadot-runtime = { workspace = true } -collectives-polkadot-runtime-constants = { workspace = true } -integration-tests-helpers = { workspace = true } -polkadot-runtime = { workspace = true } -polkadot-runtime-constants = { workspace = true, default-features = true } -polkadot-system-emulated-network = { workspace = true } -system-parachains-constants = { workspace = true, default-features = true } diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs deleted file mode 100644 index 0cf2df8c40..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Polkadot -pub use xcm::{prelude::*, v3}; - -// Cumulus -pub use emulated_integration_tests_common::{ - accounts::ALICE, - test_parachain_is_trusted_teleporter, - xcm_emulator::{assert_expected_events, bx, Chain, Parachain, RelayChain as Relay, TestExt}, -}; -pub use polkadot_system_emulated_network::{ - asset_hub_polkadot_emulated_chain::{ - genesis::ED as ASSET_HUB_POLKADOT_ED, AssetHubPolkadotParaPallet as AssetHubPolkadotPallet, - }, - collectives_polkadot_emulated_chain::{ - genesis::ED as COLLECTIVES_POLKADOT_ED, - CollectivesPolkadotParaPallet as CollectivesPolkadotPallet, - }, - polkadot_emulated_chain::{genesis::ED as POLKADOT_ED, PolkadotRelayPallet as PolkadotPallet}, - AssetHubPolkadotPara as AssetHubPolkadot, - AssetHubPolkadotParaReceiver as AssetHubPolkadotReceiver, - AssetHubPolkadotParaSender as AssetHubPolkadotSender, - CollectivesPolkadotPara as CollectivesPolkadot, - CollectivesPolkadotParaReceiver as CollectivesPolkadotReceiver, - CollectivesPolkadotParaSender as CollectivesPolkadotSender, PolkadotRelay as Polkadot, - PolkadotRelayReceiver as PolkadotReceiver, PolkadotRelaySender as PolkadotSender, -}; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship.rs deleted file mode 100644 index bdee6c87b7..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use codec::Encode; -use collectives_polkadot_runtime::fellowship::pallet_fellowship_origins::Origin::Fellows as FellowsOrigin; -use frame_support::{assert_ok, sp_runtime::traits::Dispatchable}; - -#[test] -fn fellows_whitelist_call() { - CollectivesPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeCall = ::RuntimeCall; - type RuntimeOrigin = ::RuntimeOrigin; - type Runtime = ::Runtime; - type PolkadotCall = ::RuntimeCall; - type PolkadotRuntime = ::Runtime; - - let call_hash = [1u8; 32].into(); - - let whitelist_call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::parent())), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), - call: PolkadotCall::Whitelist( - pallet_whitelist::Call::::whitelist_call { call_hash } - ) - .encode() - .into(), - } - ]))), - }); - - let fellows_origin: RuntimeOrigin = FellowsOrigin.into(); - - assert_ok!(whitelist_call.dispatch(fellows_origin)); - - assert_expected_events!( - CollectivesPolkadot, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::Whitelist(pallet_whitelist::Event::CallWhitelisted { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_salary.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_salary.rs deleted file mode 100644 index 150163a6c9..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_salary.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_polkadot_runtime::xcm_config::LocationToAccountId; -use collectives_polkadot_runtime::fellowship::FellowshipSalaryPaymaster; -use frame_support::{ - assert_ok, - traits::{fungibles::Mutate, tokens::Pay}, -}; -use xcm_executor::traits::ConvertLocation; - -const FELLOWSHIP_SALARY_PALLET_ID: u8 = - collectives_polkadot_runtime_constants::FELLOWSHIP_SALARY_PALLET_INDEX; - -#[test] -fn pay_salary() { - const USDT_ID: u32 = 1984; - let fellowship_salary = ( - Parent, - Parachain(CollectivesPolkadot::para_id().into()), - PalletInstance(FELLOWSHIP_SALARY_PALLET_ID), - ); - let pay_from = LocationToAccountId::convert_location(&fellowship_salary.into()).unwrap(); - let pay_to = Polkadot::account_id_of(ALICE); - let pay_amount = 9_000_000_000; - - AssetHubPolkadot::execute_with(|| { - type AssetHubAssets = ::Assets; - // USDT registered in genesis, now mint some into the payer's account - assert_ok!(>::mint_into(USDT_ID, &pay_from, pay_amount * 2)); - }); - - CollectivesPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount)); - assert_expected_events!( - CollectivesPolkadot, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Assets(pallet_assets::Event::Transferred { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_treasury.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_treasury.rs deleted file mode 100644 index 9671ff9a5a..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/fellowship_treasury.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_polkadot_runtime::xcm_config::LocationToAccountId as AssetHubLocationToAccountId; -use emulated_integration_tests_common::accounts::ALICE; -use frame_support::{ - assert_ok, dispatch::RawOrigin, instances::Instance1, sp_runtime::traits::Dispatchable, - traits::fungible::Inspect, -}; -use polkadot_runtime::OriginCaller; -use polkadot_runtime_common::impls::VersionedLocatableAsset; -use polkadot_runtime_constants::currency::UNITS; -use xcm_executor::traits::ConvertLocation; - -// Fund Fellowship Treasury from Polkadot Treasury and spend from Fellowship Treasury. -#[test] -fn fellowship_treasury_spend() { - // initial treasury balance on Asset Hub in DOTs. - let treasury_balance = 20_000_000 * UNITS; - // target fellowship balance on Asset Hub in DOTs. - let fellowship_treasury_balance = 1_000_000 * UNITS; - // fellowship first spend balance in DOTs. - let fellowship_spend_balance = 10_000 * UNITS; - - let init_alice_balance = AssetHubPolkadot::execute_with(|| { - <::Balances as Inspect<_>>::balance( - &Polkadot::account_id_of(ALICE), - ) - }); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeCall = ::RuntimeCall; - type Runtime = ::Runtime; - type Balances = ::Balances; - type Treasury = ::Treasury; - - // Fund Treasury account on Asset Hub with DOTs. - - let root = ::RuntimeOrigin::root(); - let treasury_account = Treasury::account_id(); - - // Mint assets to Treasury account on Relay Chain. - assert_ok!(Balances::force_set_balance( - root.clone(), - treasury_account.clone().into(), - treasury_balance * 2, - )); - - let native_asset = Location::here(); - let asset_hub_location: Location = [Parachain(1000)].into(); - let treasury_location: Location = (Parent, PalletInstance(19)).into(); - - let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { - as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))), - call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { - dest: bx!(VersionedLocation::from(asset_hub_location.clone())), - beneficiary: bx!(VersionedLocation::from(treasury_location)), - assets: bx!(VersionedAssets::from(Assets::from(Asset { - id: native_asset.clone().into(), - fun: treasury_balance.into() - }))), - fee_asset_item: 0, - })), - }); - - // Dispatched from Root to `despatch_as` `Signed(treasury_account)`. - assert_ok!(teleport_call.dispatch(root)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - Polkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeCall = ::RuntimeCall; - type RuntimeOrigin = ::RuntimeOrigin; - type Runtime = ::Runtime; - type Treasury = ::Treasury; - - // Fund Fellowship Treasury from Polkadot Treasury. - - let treasury_origin: RuntimeOrigin = - polkadot_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); - let fellowship_treasury_location: Location = - Location::new(1, [Parachain(1001), PalletInstance(65)]); - let asset_hub_location: Location = [Parachain(1000)].into(); - let native_asset_on_asset_hub = Location::parent(); - - let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::::spend { - asset_kind: bx!(VersionedLocatableAsset::V4 { - location: asset_hub_location.clone(), - asset_id: native_asset_on_asset_hub.into(), - }), - amount: fellowship_treasury_balance, - beneficiary: bx!(VersionedLocation::from(fellowship_treasury_location)), - valid_from: None, - }); - - assert_ok!(treasury_spend_call.dispatch(treasury_origin)); - - // Claim the spend. - - let alice_signed = RuntimeOrigin::signed(Polkadot::account_id_of(ALICE)); - assert_ok!(Treasury::payout(alice_signed.clone(), 0)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, - RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Balances = ::Balances; - - // Ensure that the funds deposited to the Fellowship Treasury account. - - let fellowship_treasury_location: Location = - Location::new(1, [Parachain(1001), PalletInstance(65)]); - let fellowship_treasury_account = - AssetHubLocationToAccountId::convert_location(&fellowship_treasury_location).unwrap(); - - assert_eq!( - >::balance(&fellowship_treasury_account), - fellowship_treasury_balance - ); - - // Assert events triggered by xcm pay program: - // 1. treasury asset transferred to spend beneficiary; - // 2. response to Relay Chain Treasury pallet instance sent back; - // 3. XCM program completed; - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, - RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - }); - - CollectivesPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type RuntimeCall = ::RuntimeCall; - type RuntimeOrigin = ::RuntimeOrigin; - type Runtime = ::Runtime; - type FellowshipTreasury = - ::FellowshipTreasury; - - // Fund Alice account from Fellowship Treasury. - - let fellows_origin: RuntimeOrigin = - collectives_polkadot_runtime::fellowship::pallet_fellowship_origins::Origin::Fellows - .into(); - let asset_hub_location: Location = (Parent, Parachain(1000)).into(); - let native_asset_on_asset_hub = Location::parent(); - - let alice_location: Location = - [Junction::AccountId32 { network: None, id: Polkadot::account_id_of(ALICE).into() }] - .into(); - - let fellowship_treasury_spend_call = - RuntimeCall::FellowshipTreasury(pallet_treasury::Call::::spend { - asset_kind: bx!(VersionedLocatableAsset::V4 { - location: asset_hub_location, - asset_id: native_asset_on_asset_hub.into(), - }), - amount: fellowship_spend_balance, - beneficiary: bx!(VersionedLocation::from(alice_location)), - valid_from: None, - }); - - assert_ok!(fellowship_treasury_spend_call.dispatch(fellows_origin)); - - // Claim the spend. - - let alice_signed = RuntimeOrigin::signed(Polkadot::account_id_of(ALICE)); - assert_ok!(FellowshipTreasury::payout(alice_signed.clone(), 0)); - - assert_expected_events!( - CollectivesPolkadot, - vec![ - RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, - RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::Paid { .. }) => {}, - ] - ); - }); - - AssetHubPolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - type Balances = ::Balances; - - // Ensure that the funds deposited to Alice account. - - let alice_account = Polkadot::account_id_of(ALICE); - assert_eq!( - >::balance(&alice_account), - fellowship_spend_balance + init_alice_balance - ); - - // Assert events triggered by xcm pay program: - // 1. treasury asset transferred to spend beneficiary; - // 2. response to Relay Chain Treasury pallet instance sent back; - // 3. XCM program completed; - assert_expected_events!( - AssetHubPolkadot, - vec![ - RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/mod.rs deleted file mode 100644 index ef4e488518..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod fellowship; -mod fellowship_salary; -mod fellowship_treasury; -mod teleport; diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs deleted file mode 100644 index 00daa0440a..0000000000 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use asset_hub_polkadot_runtime::xcm_config::XcmConfig as AssetHubPolkadotXcmConfig; -use collectives_polkadot_runtime::xcm_config::XcmConfig as CollectivesPolkadotXcmConfig; -use frame_support::{ - assert_ok, dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_from_and_to_relay() { - let amount = POLKADOT_ED * 10; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Polkadot, // Origin - PolkadotXcmConfig, // XCM Configuration - vec![CollectivesPolkadot], // Destinations - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - CollectivesPolkadot, // Origin - CollectivesPolkadotXcmConfig, // XCM Configuration - Polkadot, // Destination - amount - ); -} - -#[test] -fn teleport_from_collectives_to_asset_hub() { - let amount = ASSET_HUB_POLKADOT_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - CollectivesPolkadot, // Origin - CollectivesPolkadotXcmConfig, // XCM Configuration - vec![AssetHubPolkadot], // Destinations - (native_asset, amount) - ); -} - -#[test] -fn teleport_from_asset_hub_to_collectives() { - let amount = COLLECTIVES_POLKADOT_ED * 100; - let native_asset: Assets = (Parent, amount).into(); - - test_parachain_is_trusted_teleporter!( - AssetHubPolkadot, // Origin - AssetHubPolkadotXcmConfig, // XCM Configuration - vec![CollectivesPolkadot], // Destinations - (native_asset, amount) - ); -} diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml b/integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml deleted file mode 100644 index 8371a02754..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "coretime-kusama-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Coretime Kusama runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } - -# Substrate -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-broker = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } -pallet-identity = { workspace = true, default-features = true } - -# Polkadot -polkadot-runtime-common = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -runtime-parachains = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -asset-test-utils = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -kusama-runtime-constants = { workspace = true, default-features = true } -kusama-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -coretime-kusama-runtime = { workspace = true } -kusama-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs deleted file mode 100644 index 0d3e3ac75c..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; - -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Kusama as KusamaId}, -}; - -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use kusama_system_emulated_network::{ - coretime_kusama_emulated_chain::{ - genesis::ED as CORETIME_KUSAMA_ED, CoretimeKusamaParaPallet as CoretimeKusamaPallet, - }, - kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, - CoretimeKusamaPara as CoretimeKusama, CoretimeKusamaParaReceiver as CoretimeKusamaReceiver, - CoretimeKusamaParaSender as CoretimeKusamaSender, KusamaRelay as Kusama, - KusamaRelayReceiver as KusamaReceiver, KusamaRelaySender as KusamaSender, - PenpalAPara as PenpalA, -}; -pub use parachains_common::{AccountId, Balance}; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/coretime_interface.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/coretime_interface.rs deleted file mode 100644 index 1f7d513829..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/coretime_interface.rs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::traits::OnInitialize; -use kusama_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; -use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; -use sp_runtime::Perbill; - -#[test] -fn transact_hardcoded_weights_are_sane() { - // There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay - // Chain across the CoretimeInterface which are triggered at various points in the sales cycle. - // - Request core count - triggered directly by `start_sales` or `request_core_count` - // extrinsics. - // - Request revenue info - triggered when each timeslice is committed. - // - Assign core - triggered when an entry is encountered in the workplan for the next - // timeslice. - - // RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to - // - type CoretimeEvent = ::RuntimeEvent; - type RelayEvent = ::RuntimeEvent; - - // Reserve a workload, configure broker and start sales. - CoretimeKusama::execute_with(|| { - // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things - // along and have no concept of time passing otherwise. - ::Broker::on_initialize( - ::System::block_number(), - ); - - let coretime_root_origin = ::RuntimeOrigin::root(); - - // Create and populate schedule with the worst case assignment on this core. - let mut schedule = Vec::new(); - for i in 0..80 { - schedule.push(ScheduleItem { - mask: CoreMask::void().set(i), - assignment: CoreAssignment::Task(2000 + i), - }) - } - - assert_ok!(::Broker::reserve( - coretime_root_origin.clone(), - schedule.try_into().expect("Vector is within bounds."), - )); - - // Configure broker and start sales. - let config = ConfigRecord { - advance_notice: 1, - interlude_length: 1, - leadin_length: 2, - region_length: 1, - ideal_bulk_proportion: Perbill::from_percent(40), - limit_cores_offered: None, - renewal_bump: Perbill::from_percent(2), - contribution_timeout: 1, - }; - assert_ok!(::Broker::configure( - coretime_root_origin.clone(), - config - )); - assert_ok!(::Broker::start_sales( - coretime_root_origin, - 100, - 0 - )); - assert_eq!( - pallet_broker::Status::<::Runtime>::get() - .unwrap() - .core_count, - 1 - ); - - assert_expected_events!( - CoretimeKusama, - vec![ - CoretimeEvent::Broker( - pallet_broker::Event::ReservationMade { .. } - ) => {}, - CoretimeEvent::Broker( - pallet_broker::Event::CoreCountRequested { core_count: 1 } - ) => {}, - CoretimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); - }); - - // Check that the request_core_count message was processed successfully. This will fail if the - // weights are misconfigured. - Kusama::execute_with(|| { - Kusama::assert_ump_queue_processed(true, Some(CoretimeKusama::para_id()), None); - - assert_expected_events!( - Kusama, - vec![ - RelayEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - // Keep track of the relay chain block number so we can fast forward while still checking the - // right block. - let mut block_number_cursor = Kusama::ext_wrapper(::System::block_number); - - let config = CoretimeKusama::ext_wrapper(|| { - Configuration::<::Runtime>::get() - .expect("Pallet was configured earlier.") - }); - - // Now run up to the block before the sale is rotated. - while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 { - CoretimeKusama::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - }); - - Kusama::ext_wrapper(|| { - block_number_cursor = ::System::block_number(); - }); - } - - // In this block we trigger assign core. - CoretimeKusama::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - - assert_expected_events!( - CoretimeKusama, - vec![ - CoretimeEvent::Broker( - pallet_broker::Event::SaleInitialized { .. } - ) => {}, - CoretimeEvent::Broker( - pallet_broker::Event::CoreAssigned { .. } - ) => {}, - CoretimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); - }); - - // In this block we trigger request revenue. - CoretimeKusama::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - - assert_expected_events!( - CoretimeKusama, - vec![ - CoretimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); - }); - - // Check that the assign_core and request_revenue_info_at messages were processed successfully. - // This will fail if the weights are misconfigured. - Kusama::execute_with(|| { - Kusama::assert_ump_queue_processed(true, Some(CoretimeKusama::para_id()), None); - - assert_expected_events!( - Kusama, - vec![ - RelayEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - RelayEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - RelayEvent::Coretime( - runtime_parachains::coretime::Event::CoreAssigned { .. } - ) => {}, - ] - ); - }); - - // Here we receive and process the notify_revenue XCM with zero revenue. - CoretimeKusama::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - - assert_expected_events!( - CoretimeKusama, - vec![ - CoretimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - // Zero revenue in first timeslice so history is immediately dropped. - CoretimeEvent::Broker( - pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 } - ) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs deleted file mode 100644 index 057dc87e71..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod coretime_interface; -mod teleport; diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs deleted file mode 100644 index b55b3c6469..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::{ - dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_from_and_to_relay() { - let amount = KUSAMA_ED * 1000; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Kusama, - KusamaXcmConfig, - vec![CoretimeKusama], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - CoretimeKusama, - CoretimeKusamaXcmConfig, - Kusama, - amount - ); -} diff --git a/integration-tests/emulated/tests/coretime/coretime-polkadot/Cargo.toml b/integration-tests/emulated/tests/coretime/coretime-polkadot/Cargo.toml deleted file mode 100644 index 919afe87e8..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-polkadot/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "coretime-polkadot-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "Coretime Polkadot runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } - -# Substrate -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-broker = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } - -# Polkadot -polkadot-runtime-common = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -runtime-parachains = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -asset-test-utils = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -polkadot-runtime-constants = { workspace = true, default-features = true } -polkadot-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -coretime-polkadot-runtime = { workspace = true } -polkadot-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/lib.rs b/integration-tests/emulated/tests/coretime/coretime-polkadot/src/lib.rs deleted file mode 100644 index 800260df74..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/lib.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; - -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Polkadot as PolkadotId}, -}; - -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use polkadot_system_emulated_network::{ - coretime_polkadot_emulated_chain::{ - genesis::ED as CORETIME_POLKADOT_ED, CoretimePolkadotParaPallet as CoretimePolkadotPallet, - }, - polkadot_emulated_chain::{genesis::ED as POLKADOT_ED, PolkadotRelayPallet as PolkadotPallet}, - CoretimePolkadotPara as CoretimePolkadot, - CoretimePolkadotParaReceiver as CoretimePolkadotReceiver, - CoretimePolkadotParaSender as CoretimePolkadotSender, PenpalAPara as PenpalA, - PolkadotRelay as Polkadot, PolkadotRelayReceiver as PolkadotReceiver, - PolkadotRelaySender as PolkadotSender, -}; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/coretime_interface.rs b/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/coretime_interface.rs deleted file mode 100644 index c0317301f2..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/coretime_interface.rs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::traits::OnInitialize; -use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; -use polkadot_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; -use sp_runtime::Perbill; - -#[test] -fn transact_hardcoded_weights_are_sane() { - // There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay - // Chain across the CoretimeInterface which are triggered at various points in the sales cycle. - // - Request core count - triggered directly by `start_sales` or `request_core_count` - // extrinsics. - // - Request revenue info - triggered when each timeslice is committed. - // - Assign core - triggered when an entry is encountered in the workplan for the next - // timeslice. - - // RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to - // - type CoretimeEvent = ::RuntimeEvent; - type RelayEvent = ::RuntimeEvent; - - // Reserve a workload, configure broker and start sales. - CoretimePolkadot::execute_with(|| { - // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things - // along and have no concept of time passing otherwise. - ::Broker::on_initialize( - ::System::block_number(), - ); - - let coretime_root_origin = ::RuntimeOrigin::root(); - - // Create and populate schedule with the worst case assignment on this core. - let mut schedule = Vec::new(); - for i in 0..80 { - schedule.push(ScheduleItem { - mask: CoreMask::void().set(i), - assignment: CoreAssignment::Task(2000 + i), - }) - } - - assert_ok!(::Broker::reserve( - coretime_root_origin.clone(), - schedule.try_into().expect("Vector is within bounds."), - )); - - // Configure broker and start sales. - let config = ConfigRecord { - advance_notice: 1, - interlude_length: 1, - leadin_length: 2, - region_length: 1, - ideal_bulk_proportion: Perbill::from_percent(40), - limit_cores_offered: None, - renewal_bump: Perbill::from_percent(2), - contribution_timeout: 1, - }; - assert_ok!(::Broker::configure( - coretime_root_origin.clone(), - config - )); - assert_ok!(::Broker::start_sales( - coretime_root_origin, - 100, - 0 - )); - assert_eq!( - pallet_broker::Status::<::Runtime>::get() - .unwrap() - .core_count, - 1 - ); - - assert_expected_events!( - CoretimePolkadot, - vec![ - CoretimeEvent::Broker( - pallet_broker::Event::ReservationMade { .. } - ) => {}, - CoretimeEvent::Broker( - pallet_broker::Event::CoreCountRequested { core_count: 1 } - ) => {}, - CoretimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); - }); - - // Check that the request_core_count message was processed successfully. This will fail if the - // weights are misconfigured. - Polkadot::execute_with(|| { - Polkadot::assert_ump_queue_processed(true, Some(CoretimePolkadot::para_id()), None); - - assert_expected_events!( - Polkadot, - vec![ - RelayEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - - // Keep track of the relay chain block number so we can fast forward while still checking the - // right block. - let mut block_number_cursor = Polkadot::ext_wrapper(::System::block_number); - - let config = CoretimePolkadot::ext_wrapper(|| { - Configuration::<::Runtime>::get() - .expect("Pallet was configured earlier.") - }); - - // Now run up to the block before the sale is rotated. - while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 { - CoretimePolkadot::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - }); - - Polkadot::ext_wrapper(|| { - block_number_cursor = ::System::block_number(); - }); - } - - // In this block we trigger assign core. - CoretimePolkadot::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - - assert_expected_events!( - CoretimePolkadot, - vec![ - CoretimeEvent::Broker( - pallet_broker::Event::SaleInitialized { .. } - ) => {}, - CoretimeEvent::Broker( - pallet_broker::Event::CoreAssigned { .. } - ) => {}, - CoretimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); - }); - - // In this block we trigger request revenue. - CoretimePolkadot::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - - assert_expected_events!( - CoretimePolkadot, - vec![ - CoretimeEvent::ParachainSystem( - cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } - ) => {}, - ] - ); - }); - - // Check that the assign_core and request_revenue_info_at messages were processed successfully. - // This will fail if the weights are misconfigured. - Polkadot::execute_with(|| { - Polkadot::assert_ump_queue_processed(true, Some(CoretimePolkadot::para_id()), None); - - assert_expected_events!( - Polkadot, - vec![ - RelayEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - RelayEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - RelayEvent::Coretime( - runtime_parachains::coretime::Event::CoreAssigned { .. } - ) => {}, - ] - ); - }); - - // Here we receive and process the notify_revenue XCM with zero revenue. - CoretimePolkadot::execute_with(|| { - // Hooks don't run in emulated tests - workaround. - ::Broker::on_initialize( - ::System::block_number(), - ); - - assert_expected_events!( - CoretimePolkadot, - vec![ - CoretimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - // Zero revenue in first timeslice so history is immediately dropped. - CoretimeEvent::Broker( - pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 } - ) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/mod.rs deleted file mode 100644 index 507652d07a..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod coretime_interface; -mod teleport; diff --git a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/teleport.rs deleted file mode 100644 index abedf63d5b..0000000000 --- a/integration-tests/emulated/tests/coretime/coretime-polkadot/src/tests/teleport.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md -// for a list of specific contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::{ - dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_from_and_to_relay() { - let amount = POLKADOT_ED * 1000; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Polkadot, - PolkadotXcmConfig, - vec![CoretimePolkadot], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - CoretimePolkadot, - CoretimePolkadotXcmConfig, - Polkadot, - amount - ); -} diff --git a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml deleted file mode 100644 index 9de616880d..0000000000 --- a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "people-kusama-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "People Kusama runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } - -# Substrate -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } -pallet-identity = { workspace = true, default-features = true } - -# Polkadot -polkadot-runtime-common = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -asset-test-utils = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -kusama-runtime-constants = { workspace = true, default-features = true } -kusama-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -people-kusama-runtime = { workspace = true } -kusama-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/people/people-kusama/src/lib.rs b/integration-tests/emulated/tests/people/people-kusama/src/lib.rs deleted file mode 100644 index b59472d2df..0000000000 --- a/integration-tests/emulated/tests/people/people-kusama/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; - -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Kusama as KusamaId}, -}; - -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use kusama_system_emulated_network::{ - kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, - people_kusama_emulated_chain::{ - genesis::ED as PEOPLE_KUSAMA_ED, PeopleKusamaParaPallet as PeopleKusamaPallet, - }, - KusamaRelay as Kusama, KusamaRelayReceiver as KusamaReceiver, - KusamaRelaySender as KusamaSender, PenpalAPara as PenpalA, PeopleKusamaPara as PeopleKusama, - PeopleKusamaParaReceiver as PeopleKusamaReceiver, PeopleKusamaParaSender as PeopleKusamaSender, -}; -pub use parachains_common::{AccountId, Balance}; -pub use people_kusama_runtime::ExistentialDeposit as PeopleKusamaExistentialDeposit; - -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/people/people-kusama/src/tests/claim_assets.rs b/integration-tests/emulated/tests/people/people-kusama/src/tests/claim_assets.rs deleted file mode 100644 index 919b6332b8..0000000000 --- a/integration-tests/emulated/tests/people/people-kusama/src/tests/claim_assets.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests related to claiming assets trapped during XCM execution. - -use crate::*; - -use integration_tests_helpers::test_chain_can_claim_assets; -use xcm_executor::traits::DropAssets; - -#[test] -fn assets_can_be_claimed() { - let amount = PeopleKusamaExistentialDeposit::get(); - let assets: Assets = (Parent, amount).into(); - - test_chain_can_claim_assets!(PeopleKusama, RuntimeCall, NetworkId::Kusama, assets, amount); -} diff --git a/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs b/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs deleted file mode 100644 index be3b18acf9..0000000000 --- a/integration-tests/emulated/tests/people/people-kusama/src/tests/governance.rs +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; - -use frame_support::{sp_runtime::traits::Dispatchable, traits::ProcessMessageError}; -use kusama_runtime::governance::pallet_custom_origins::Origin::GeneralAdmin as GeneralAdminOrigin; -use people_kusama_runtime::people::IdentityInfo; - -use pallet_identity::Data; - -#[test] -fn relay_commands_add_registrar() { - let origins = vec![ - (OriginKind::Xcm, GeneralAdminOrigin.into()), - (OriginKind::Superuser, ::RuntimeOrigin::root()), - ]; - for (origin_kind, origin) in origins { - let registrar: AccountId = [1; 32].into(); - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_registrar_call = - PeopleCall::Identity(pallet_identity::Call::::add_registrar { - account: registrar.into(), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - // TODO: - // This and the below weight data in the XCM can be removed once XCMv5 is - // used. - require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), - call: add_registrar_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::RegistrarAdded { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); - } -} - -#[test] -fn relay_commands_add_registrar_wrong_origin() { - let people_kusama_alice = PeopleKusama::account_id_of(ALICE); - - let (origin_kind, origin) = ( - OriginKind::SovereignAccount, - ::RuntimeOrigin::signed(people_kusama_alice), - ); - - let registrar: AccountId = [1; 32].into(); - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_registrar_call = - PeopleCall::Identity(pallet_identity::Call::::add_registrar { - account: registrar.into(), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), - call: add_registrar_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); -} - -#[test] -fn relay_commands_kill_identity() { - // To kill an identity, first one must be set - PeopleKusama::execute_with(|| { - type PeopleRuntime = ::Runtime; - type PeopleRuntimeEvent = ::RuntimeEvent; - - let people_kusama_alice = - ::RuntimeOrigin::signed(PeopleKusama::account_id_of(ALICE)); - - let identity_info = IdentityInfo { - email: Data::Raw(b"test@test.io".to_vec().try_into().unwrap()), - ..Default::default() - }; - let identity: Box<::IdentityInformation> = - Box::new(identity_info); - - assert_ok!(::Identity::set_identity( - people_kusama_alice, - identity - )); - - assert_expected_events!( - PeopleKusama, - vec![ - PeopleRuntimeEvent::Identity(pallet_identity::Event::IdentitySet { .. }) => {}, - ] - ); - }); - - let (origin_kind, origin) = (OriginKind::Superuser, ::RuntimeOrigin::root()); - - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type PeopleCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleRuntime = ::Runtime; - - let kill_identity_call = - PeopleCall::Identity(pallet_identity::Call::::kill_identity { - target: people_kusama_runtime::MultiAddress::Id(PeopleKusama::account_id_of(ALICE)), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - // Making the weight's ref time any lower will prevent the XCM from triggering - // execution of the intended extrinsic on the People chain - beware of spurious - // test failure due to this. - require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), - call: kill_identity_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::IdentityKilled { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); -} - -#[test] -fn relay_commands_kill_identity_wrong_origin() { - let people_kusama_alice = PeopleKusama::account_id_of(BOB); - - let (origin_kind, origin) = ( - OriginKind::SovereignAccount, - ::RuntimeOrigin::signed(people_kusama_alice), - ); - - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type PeopleCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleRuntime = ::Runtime; - - let kill_identity_call = - PeopleCall::Identity(pallet_identity::Call::::kill_identity { - target: people_kusama_runtime::MultiAddress::Id(PeopleKusama::account_id_of(ALICE)), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), - call: kill_identity_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); -} - -#[test] -fn relay_commands_add_remove_username_authority() { - let people_kusama_alice = PeopleKusama::account_id_of(ALICE); - let people_kusama_bob = PeopleKusama::account_id_of(BOB); - - let origins = vec![ - (OriginKind::Xcm, GeneralAdminOrigin.into(), "generaladmin"), - (OriginKind::Superuser, ::RuntimeOrigin::root(), "rootusername"), - ]; - for (origin_kind, origin, usr) in origins { - // First, add a username authority. - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_username_authority = PeopleCall::Identity(pallet_identity::Call::< - PeopleRuntime, - >::add_username_authority { - authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), - suffix: b"suffix1".into(), - allocation: 10, - }); - - let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: add_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(add_authority_xcm_msg.dispatch(origin.clone())); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Check events system-parachain-side - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::AuthorityAdded { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); - - // Now, use the previously added username authority to concede a username to an account. - PeopleKusama::execute_with(|| { - type PeopleRuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Identity::set_username_for( - ::RuntimeOrigin::signed(people_kusama_alice.clone()), - people_kusama_runtime::MultiAddress::Id(people_kusama_bob.clone()), - usr.to_owned().into_bytes(), - None, - )); - - assert_expected_events!( - PeopleKusama, - vec![ - PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameQueued { .. }) => {}, - ] - ); - }); - - // Accept the given username - PeopleKusama::execute_with(|| { - type PeopleRuntimeEvent = ::RuntimeEvent; - let full_username = [usr.to_owned(), ".suffix1".to_owned()].concat().into_bytes(); - - assert_ok!(::Identity::accept_username( - ::RuntimeOrigin::signed(people_kusama_bob.clone()), - full_username.try_into().unwrap(), - )); - - assert_expected_events!( - PeopleKusama, - vec![ - PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameSet { .. }) => {}, - ] - ); - }); - - // Now, remove the username authority with another privileged XCM call. - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< - PeopleRuntime, - >::remove_username_authority { - authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), - }); - - let remove_authority_xcm_msg = - RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - // TODO: - // this and all other references to `require_weight_at_most` can be - // removed once XCMv5 is in use. - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: remove_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(remove_authority_xcm_msg.dispatch(origin)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Final event check. - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::AuthorityRemoved { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); - } -} - -#[test] -fn relay_commands_add_remove_username_authority_wrong_origin() { - let people_kusama_alice = PeopleKusama::account_id_of(ALICE); - - let (origin_kind, origin) = ( - OriginKind::SovereignAccount, - ::RuntimeOrigin::signed(people_kusama_alice.clone()), - ); - - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_username_authority = - PeopleCall::Identity(pallet_identity::Call::::add_username_authority { - authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), - suffix: b"suffix1".into(), - allocation: 10, - }); - - let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: add_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(add_authority_xcm_msg.dispatch(origin)); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Check events system-parachain-side - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); - - // Since the origin check is the very first instruction in `remove_username_authority`, an - // authority need not exist to test the safety of the origin check. - Kusama::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< - PeopleRuntime, - >::remove_username_authority { - authority: people_kusama_runtime::MultiAddress::Id(people_kusama_alice.clone()), - }); - - let remove_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: remove_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(remove_authority_xcm_msg - .dispatch(::RuntimeOrigin::signed(people_kusama_alice))); - - assert_expected_events!( - Kusama, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeopleKusama::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeopleKusama, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/people/people-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/people/people-kusama/src/tests/mod.rs deleted file mode 100644 index b9ad9e3db4..0000000000 --- a/integration-tests/emulated/tests/people/people-kusama/src/tests/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod claim_assets; -mod governance; -mod teleport; diff --git a/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs deleted file mode 100644 index 279473dd3f..0000000000 --- a/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::{ - dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use people_kusama_runtime::xcm_config::XcmConfig as PeopleKusamaXcmConfig; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_from_and_to_relay() { - let amount = KUSAMA_ED * 1000; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Kusama, - KusamaXcmConfig, - vec![PeopleKusama], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - PeopleKusama, - PeopleKusamaXcmConfig, - Kusama, - amount - ); -} - -fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Kusama::assert_ump_queue_processed( - false, - Some(PeopleKusama::para_id()), - Some(Weight::from_parts(157_718_000, 3_593)), - ); -} - -fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - PeopleKusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 600_000_000, - 7_000, - ))); - - PeopleKusama::assert_parachain_system_ump_sent(); - - assert_expected_events!( - PeopleKusama, - vec![ - // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; - let destination = PeopleKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - // Fund a sender - PeopleKusama::fund_accounts(vec![(PeopleKusamaSender::get(), KUSAMA_ED * 2_000u128)]); - - let test_args = TestContext { - sender: PeopleKusamaSender::get(), - receiver: KusamaReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PeopleKusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >( - test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest - ) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} diff --git a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml b/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml deleted file mode 100644 index 7f614a85be..0000000000 --- a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "people-polkadot-integration-tests" -version.workspace = true -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -description = "People Polkadot runtime integration tests with xcm-emulator" -publish = false - -[dependencies] -codec = { workspace = true, default-features = true } - -# Substrate -sp-runtime = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-message-queue = { workspace = true, default-features = true } -pallet-identity = { workspace = true, default-features = true } - -# Polkadot -polkadot-runtime-common = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } -xcm-executor = { workspace = true } -xcm-runtime-apis = { workspace = true, default-features = true } - -# Cumulus -parachains-common = { workspace = true, default-features = true } -emulated-integration-tests-common = { workspace = true } -asset-test-utils = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true, default-features = true } - -# Local -polkadot-runtime-constants = { workspace = true, default-features = true } -polkadot-runtime = { workspace = true } -integration-tests-helpers = { workspace = true } -people-polkadot-runtime = { workspace = true } -polkadot-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/lib.rs b/integration-tests/emulated/tests/people/people-polkadot/src/lib.rs deleted file mode 100644 index 23144ab8f1..0000000000 --- a/integration-tests/emulated/tests/people/people-polkadot/src/lib.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use codec::Encode; - -// Substrate -pub use frame_support::{ - assert_err, assert_ok, - pallet_prelude::Weight, - sp_runtime::{AccountId32, DispatchError, DispatchResult}, - traits::fungibles::Inspect, -}; - -// Polkadot -pub use xcm::{ - prelude::{AccountId32 as AccountId32Junction, *}, - v3::{Error, NetworkId::Polkadot as PolkadotId}, -}; - -// Cumulus -pub use asset_test_utils::xcm_helpers; -pub use emulated_integration_tests_common::{ - xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, - RelayChain as Relay, Test, TestArgs, TestContext, TestExt, - }, - xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, - PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, -}; -pub use parachains_common::{AccountId, Balance}; -pub use people_polkadot_runtime::ExistentialDeposit as PeoplePolkadotExistentialDeposit; -pub use polkadot_system_emulated_network::{ - people_polkadot_emulated_chain::{ - genesis::ED as PEOPLE_KUSAMA_ED, PeoplePolkadotParaPallet as PeoplePolkadotPallet, - }, - polkadot_emulated_chain::{genesis::ED as POLKADOT_ED, PolkadotRelayPallet as PolkadotPallet}, - PenpalAPara as PenpalA, PeoplePolkadotPara as PeoplePolkadot, - PeoplePolkadotParaReceiver as PeoplePolkadotReceiver, - PeoplePolkadotParaSender as PeoplePolkadotSender, PolkadotRelay as Polkadot, - PolkadotRelayReceiver as PolkadotReceiver, PolkadotRelaySender as PolkadotSender, -}; - -pub type RelayToSystemParaTest = Test; -pub type RelayToParaTest = Test; -pub type SystemParaToRelayTest = Test; -pub type SystemParaToParaTest = Test; -pub type ParaToSystemParaTest = Test; - -#[cfg(test)] -mod tests; diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/tests/claim_assets.rs b/integration-tests/emulated/tests/people/people-polkadot/src/tests/claim_assets.rs deleted file mode 100644 index ff7de41858..0000000000 --- a/integration-tests/emulated/tests/people/people-polkadot/src/tests/claim_assets.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Tests related to claiming assets trapped during XCM execution. - -use crate::*; - -use integration_tests_helpers::test_chain_can_claim_assets; -use xcm_executor::traits::DropAssets; - -#[test] -fn assets_can_be_claimed() { - let amount = PeoplePolkadotExistentialDeposit::get(); - let assets: Assets = (Parent, amount).into(); - - test_chain_can_claim_assets!(PeoplePolkadot, RuntimeCall, NetworkId::Polkadot, assets, amount); -} diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs b/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs deleted file mode 100644 index 4c3ac649a9..0000000000 --- a/integration-tests/emulated/tests/people/people-polkadot/src/tests/governance.rs +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use emulated_integration_tests_common::accounts::{ALICE, BOB}; - -use frame_support::{sp_runtime::traits::Dispatchable, traits::ProcessMessageError}; -use people_polkadot_runtime::people::IdentityInfo; -use polkadot_runtime::governance::pallet_custom_origins::Origin::GeneralAdmin as GeneralAdminOrigin; - -use pallet_identity::Data; - -#[test] -fn relay_commands_add_registrar() { - let origins = vec![ - (OriginKind::Xcm, GeneralAdminOrigin.into()), - (OriginKind::Superuser, ::RuntimeOrigin::root()), - ]; - for (origin_kind, origin) in origins { - let registrar: AccountId = [1; 32].into(); - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_registrar_call = - PeopleCall::Identity(pallet_identity::Call::::add_registrar { - account: registrar.into(), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), - call: add_registrar_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::RegistrarAdded { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); - } -} - -#[test] -fn relay_commands_add_registrar_wrong_origin() { - let people_polkadot_alice = PeoplePolkadot::account_id_of(ALICE); - - let (origin_kind, origin) = ( - OriginKind::SovereignAccount, - ::RuntimeOrigin::signed(people_polkadot_alice), - ); - - let registrar: AccountId = [1; 32].into(); - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_registrar_call = - PeopleCall::Identity(pallet_identity::Call::::add_registrar { - account: registrar.into(), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(5_000_000_000, 500_000), - call: add_registrar_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); -} - -#[test] -fn relay_commands_kill_identity() { - // To kill an identity, first one must be set - PeoplePolkadot::execute_with(|| { - type PeopleRuntime = ::Runtime; - type PeopleRuntimeEvent = ::RuntimeEvent; - - let people_polkadot_alice = - ::RuntimeOrigin::signed(PeoplePolkadot::account_id_of(ALICE)); - - let identity_info = IdentityInfo { - email: Data::Raw(b"test@test.io".to_vec().try_into().unwrap()), - ..Default::default() - }; - let identity: Box<::IdentityInformation> = - Box::new(identity_info); - - assert_ok!(::Identity::set_identity( - people_polkadot_alice, - identity - )); - - assert_expected_events!( - PeoplePolkadot, - vec![ - PeopleRuntimeEvent::Identity(pallet_identity::Event::IdentitySet { .. }) => {}, - ] - ); - }); - - let (origin_kind, origin) = (OriginKind::Superuser, ::RuntimeOrigin::root()); - - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type PeopleCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleRuntime = ::Runtime; - - let kill_identity_call = - PeopleCall::Identity(pallet_identity::Call::::kill_identity { - target: people_polkadot_runtime::MultiAddress::Id(PeoplePolkadot::account_id_of( - ALICE, - )), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - // Making the weight's ref time any lower will prevent the XCM from triggering - // execution of the intended extrinsic on the People chain - beware of spurious - // test failure due to this. - require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), - call: kill_identity_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::IdentityKilled { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); -} - -#[test] -fn relay_commands_kill_identity_wrong_origin() { - let people_polkadot_alice = PeoplePolkadot::account_id_of(BOB); - - let (origin_kind, origin) = ( - OriginKind::SovereignAccount, - ::RuntimeOrigin::signed(people_polkadot_alice), - ); - - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type PeopleCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleRuntime = ::Runtime; - - let kill_identity_call = - PeopleCall::Identity(pallet_identity::Call::::kill_identity { - target: people_polkadot_runtime::MultiAddress::Id(PeoplePolkadot::account_id_of( - ALICE, - )), - }); - - let xcm_message = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(11_000_000_000, 500_000), - call: kill_identity_call.encode().into(), - } - ]))), - }); - - assert_ok!(xcm_message.dispatch(origin)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); -} - -#[test] -fn relay_commands_add_remove_username_authority() { - let people_polkadot_alice = PeoplePolkadot::account_id_of(ALICE); - let people_polkadot_bob = PeoplePolkadot::account_id_of(BOB); - - let origins = vec![ - (OriginKind::Xcm, GeneralAdminOrigin.into(), "generaladmin"), - (OriginKind::Superuser, ::RuntimeOrigin::root(), "rootusername"), - ]; - for (origin_kind, origin, usr) in origins { - // First, add a username authority. - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_username_authority = PeopleCall::Identity(pallet_identity::Call::< - PeopleRuntime, - >::add_username_authority { - authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), - suffix: b"suffix1".into(), - allocation: 10, - }); - - let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: add_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(add_authority_xcm_msg.dispatch(origin.clone())); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Check events system-parachain-side - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::AuthorityAdded { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); - - // Now, use the previously added username authority to concede a username to an account. - PeoplePolkadot::execute_with(|| { - type PeopleRuntimeEvent = ::RuntimeEvent; - - assert_ok!(::Identity::set_username_for( - ::RuntimeOrigin::signed(people_polkadot_alice.clone()), - people_polkadot_runtime::MultiAddress::Id(people_polkadot_bob.clone()), - usr.to_owned().into_bytes(), - None, - )); - - assert_expected_events!( - PeoplePolkadot, - vec![ - PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameQueued { .. }) => {}, - ] - ); - }); - - // Accept the given username - PeoplePolkadot::execute_with(|| { - type PeopleRuntimeEvent = ::RuntimeEvent; - let full_username = [usr.to_owned(), ".suffix1".to_owned()].concat().into_bytes(); - - assert_ok!(::Identity::accept_username( - ::RuntimeOrigin::signed(people_polkadot_bob.clone()), - full_username.try_into().unwrap(), - )); - - assert_expected_events!( - PeoplePolkadot, - vec![ - PeopleRuntimeEvent::Identity(pallet_identity::Event::UsernameSet { .. }) => {}, - ] - ); - }); - - // Now, remove the username authority with another privileged XCM call. - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< - PeopleRuntime, - >::remove_username_authority { - authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), - }); - - let remove_authority_xcm_msg = - RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: remove_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(remove_authority_xcm_msg.dispatch(origin)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Final event check. - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::Identity(pallet_identity::Event::AuthorityRemoved { .. }) => {}, - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true, .. }) => {}, - ] - ); - }); - } -} - -#[test] -fn relay_commands_add_remove_username_authority_wrong_origin() { - let people_polkadot_alice = PeoplePolkadot::account_id_of(ALICE); - - let (origin_kind, origin) = ( - OriginKind::SovereignAccount, - ::RuntimeOrigin::signed(people_polkadot_alice.clone()), - ); - - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let add_username_authority = - PeopleCall::Identity(pallet_identity::Call::::add_username_authority { - authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), - suffix: b"suffix1".into(), - allocation: 10, - }); - - let add_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: add_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(add_authority_xcm_msg.dispatch(origin)); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Check events system-parachain-side - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); - - // Since the origin check is the very first instruction in `remove_username_authority`, - // an authority need not exist to test the safety of the origin check. - Polkadot::execute_with(|| { - type Runtime = ::Runtime; - type RuntimeCall = ::RuntimeCall; - type RuntimeEvent = ::RuntimeEvent; - type PeopleCall = ::RuntimeCall; - type PeopleRuntime = ::Runtime; - - let remove_username_authority = PeopleCall::Identity(pallet_identity::Call::< - PeopleRuntime, - >::remove_username_authority { - authority: people_polkadot_runtime::MultiAddress::Id(people_polkadot_alice.clone()), - }); - - let remove_authority_xcm_msg = RuntimeCall::XcmPallet(pallet_xcm::Call::::send { - dest: bx!(VersionedLocation::from(Location::new(0, [Parachain(1004)]))), - message: bx!(VersionedXcm::from(Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(500_000_000, 500_000), - call: remove_username_authority.encode().into(), - } - ]))), - }); - - assert_ok!(remove_authority_xcm_msg - .dispatch(::RuntimeOrigin::signed(people_polkadot_alice))); - - assert_expected_events!( - Polkadot, - vec![ - RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - PeoplePolkadot::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PeoplePolkadot, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { error: ProcessMessageError::Unsupported, .. }) => {}, - ] - ); - }); -} diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/people/people-polkadot/src/tests/mod.rs deleted file mode 100644 index b9ad9e3db4..0000000000 --- a/integration-tests/emulated/tests/people/people-polkadot/src/tests/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod claim_assets; -mod governance; -mod teleport; diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs deleted file mode 100644 index 4d994d648d..0000000000 --- a/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::*; -use frame_support::{ - dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, -}; -use integration_tests_helpers::{ - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, -}; -use people_polkadot_runtime::xcm_config::XcmConfig as PeoplePolkadotXcmConfig; -use xcm_runtime_apis::{ - dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, -}; - -#[test] -fn teleport_from_and_to_relay() { - let amount = POLKADOT_ED * 1000; - let native_asset: Assets = (Here, amount).into(); - - test_relay_is_trusted_teleporter!( - Polkadot, - PolkadotXcmConfig, - vec![PeoplePolkadot], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - PeoplePolkadot, - PeoplePolkadotXcmConfig, - Polkadot, - amount - ); -} - -fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { - Polkadot::assert_ump_queue_processed( - false, - Some(PeoplePolkadot::para_id()), - Some(Weight::from_parts(157_718_000, 3_593)), - ); -} - -fn para_origin_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - PeoplePolkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( - 600_000_000, - 7_000, - ))); - - PeoplePolkadot::assert_parachain_system_ump_sent(); - - assert_expected_events!( - PeoplePolkadot, - vec![ - // Amount is withdrawn from Sender's account - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::limited_teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - t.args.weight_limit, - ) -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = POLKADOT_ED * 1000; - let destination = PeoplePolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - // Fund a sender - PeoplePolkadot::fund_accounts(vec![(PeoplePolkadotSender::get(), POLKADOT_ED * 2_000u128)]); - - let test_args = TestContext { - sender: PeoplePolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PeoplePolkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >( - test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest - ) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} diff --git a/integration-tests/zombienet/Cargo.toml b/integration-tests/zombienet/Cargo.toml deleted file mode 100644 index 93ce161b5b..0000000000 --- a/integration-tests/zombienet/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "zombienet-sdk-tests" -version = "0.1.0" -edition = "2021" - -[dependencies] -subxt = { features = ["native"], workspace = true } -tokio = { workspace = true } -tracing-subscriber = { workspace = true } -zombienet-sdk = { workspace = true } -log = { workspace = true, default-features = true } -anyhow = { workspace = true } diff --git a/integration-tests/zombienet/src/environment.rs b/integration-tests/zombienet/src/environment.rs deleted file mode 100644 index b060b8e20f..0000000000 --- a/integration-tests/zombienet/src/environment.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Helpers functions to get configuration (e.g. Provider and images) from the env vars -use std::{env, future::Future, pin::Pin}; - -use zombienet_sdk::{LocalFileSystem, Network, NetworkConfig, NetworkConfigExt, OrchestratorError}; - -const DEFAULT_POLKADOT_IMAGE: &str = "docker.io/parity/polkadot:latest"; -const DEFAULT_CUMULUS_IMAGE: &str = "docker.io/parity/polkadot-parachain:latest"; - -#[derive(Debug, Default)] -pub struct Images { - pub polkadot: String, - pub cumulus: String, -} - -pub enum Provider { - Native, - K8s, - Docker, -} - -// Use `docker` as default provider -impl From for Provider { - fn from(value: String) -> Self { - match value.to_ascii_lowercase().as_ref() { - "native" => Provider::Native, - "k8s" => Provider::K8s, - _ => Provider::Docker, // default provider - } - } -} - -pub fn get_images_from_env() -> Images { - let polkadot = env::var("POLKADOT_IMAGE").unwrap_or(DEFAULT_POLKADOT_IMAGE.into()); - let cumulus = env::var("CUMULUS_IMAGE").unwrap_or(DEFAULT_CUMULUS_IMAGE.into()); - Images { polkadot, cumulus } -} - -pub fn get_provider_from_env() -> Provider { - env::var("ZOMBIE_PROVIDER").unwrap_or_default().into() -} - -type SpawnResult = Result, OrchestratorError>; -pub fn get_spawn_fn() -> fn(NetworkConfig) -> Pin + Send>> { - let provider = get_provider_from_env(); - - match provider { - Provider::Native => zombienet_sdk::NetworkConfig::spawn_native, - Provider::K8s => zombienet_sdk::NetworkConfig::spawn_k8s, - Provider::Docker => zombienet_sdk::NetworkConfig::spawn_docker, - } -} diff --git a/integration-tests/zombienet/src/lib.rs b/integration-tests/zombienet/src/lib.rs deleted file mode 100644 index 3da344c952..0000000000 --- a/integration-tests/zombienet/src/lib.rs +++ /dev/null @@ -1,70 +0,0 @@ -use anyhow::anyhow; -use subxt::{OnlineClient, PolkadotConfig}; -use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder, NetworkNode}; - -pub mod environment; - -pub type Error = Box; - -// Chain generator command template -const CMD_TPL: &str = "chain-spec-generator {{chainName}}"; - -// Relaychain nodes -const ALICE: &str = "alice"; -const BOB: &str = "bob"; -// Collator -const COLLATOR: &str = "collator"; - -pub fn small_network() -> Result { - let images = environment::get_images_from_env(); - let config = NetworkConfigBuilder::new() - .with_relaychain(|r| { - r.with_chain("polkadot-local") - .with_default_command("polkadot") - .with_default_image(images.polkadot.as_str()) - .with_chain_spec_command(CMD_TPL) - .chain_spec_command_is_local(true) - .with_node(|node| node.with_name(ALICE)) - .with_node(|node| node.with_name(BOB)) - }) - .with_parachain(|p| { - p.with_id(2000).cumulus_based(true).with_collator(|n| { - n.with_name(COLLATOR) - .with_command("polkadot-parachain") - .with_image(images.cumulus.as_str()) - }) - }) - .build() - .map_err(|errs| { - let e = errs.iter().fold("".to_string(), |memo, err| format!("{memo} \n {err}")); - anyhow!(e) - })?; - - Ok(config) -} - -pub async fn wait_subxt_client( - node: &NetworkNode, -) -> Result, anyhow::Error> { - log::info!("trying to connect to: {}", node.ws_uri()); - loop { - match node.client::().await { - Ok(cli) => { - log::info!("returning client for: {}", node.ws_uri()); - return Ok(cli); - }, - Err(e) => { - log::trace!("{e:?}"); - if let subxt::Error::Rpc(subxt::error::RpcError::ClientError(ref inner)) = e { - log::trace!("inner: {inner}"); - if inner.to_string().contains("i/o error") { - // The node is not ready to accept connections yet - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - continue; - } - } - return Err(anyhow!("Cannot connect to node : {e:?}")); - }, - }; - } -} diff --git a/integration-tests/zombienet/tests/smoke.rs b/integration-tests/zombienet/tests/smoke.rs deleted file mode 100644 index 7614d3ea0a..0000000000 --- a/integration-tests/zombienet/tests/smoke.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::time::Instant; -use subxt::ext::futures::StreamExt; -use zombienet_sdk_tests::{environment::get_spawn_fn, small_network, wait_subxt_client}; - -#[tokio::test(flavor = "multi_thread")] -async fn smoke() { - tracing_subscriber::fmt::init(); - - // config and env - let spawn_fn = get_spawn_fn(); - let config = small_network().unwrap(); - - // spawn - let now = Instant::now(); - let network = spawn_fn(config).await.unwrap(); - let elapsed = now.elapsed(); - log::info!("🚀🚀🚀🚀 network deployed in {:.2?}", elapsed); - - let alice = network.get_node("alice").unwrap(); - // wait until the subxt client is ready - let client = wait_subxt_client(alice).await.unwrap(); - - // wait 10 blocks - let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(10); - - while let Some(block) = blocks.next().await { - log::info!("Block #{}", block.unwrap().header().number); - } - - // wait 10 blocks on the parachain - let collator = network.get_node("collator").unwrap(); - let collator_client = wait_subxt_client(collator).await.unwrap(); - - let mut blocks = collator_client.blocks().subscribe_finalized().await.unwrap().take(10); - - while let Some(block) = blocks.next().await { - log::info!("Parachain Block #{}", block.unwrap().header().number); - } -}

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