From 5c57678879cf8a25c730b3c8124f19bfde979779 Mon Sep 17 00:00:00 2001 From: Andrea Giacobino Date: Tue, 17 Sep 2024 01:36:14 +0300 Subject: [PATCH] Add tracing for runtime-3200 (#113) * Add tracing sources for runtime-3200 * Add tracing WASM for runtime-3200 --- ...nbase-runtime-3200-substitute-tracing.json | 1 + ...nbeam-runtime-3200-substitute-tracing.json | 1 + ...river-runtime-3200-substitute-tracing.json | 1 + tracing/3200/Cargo.lock | 9149 +++++++++++++++++ tracing/3200/Cargo.toml | 461 + tracing/3200/runtime/common/Cargo.toml | 168 + tracing/3200/runtime/common/src/apis.rs | 1123 ++ .../3200/runtime/common/src/benchmarking.rs | 30 + .../common/src/impl_moonbeam_xcm_call.rs | 51 + .../src/impl_moonbeam_xcm_call_tracing.rs | 119 + .../src/impl_on_charge_evm_transaction.rs | 62 + .../common/src/impl_self_contained_call.rs | 78 + .../runtime/common/src/impl_xcm_evm_runner.rs | 242 + tracing/3200/runtime/common/src/lib.rs | 30 + tracing/3200/runtime/common/src/migrations.rs | 308 + tracing/3200/runtime/common/src/timestamp.rs | 92 + .../cumulus_pallet_parachain_system.rs | 72 + .../src/weights/cumulus_pallet_xcmp_queue.rs | 154 + .../3200/runtime/common/src/weights/db/mod.rs | 17 + .../runtime/common/src/weights/db/rocksdb.rs | 117 + .../3200/runtime/common/src/weights/mod.rs | 54 + .../src/weights/pallet_asset_manager.rs | 100 + .../common/src/weights/pallet_assets.rs | 483 + .../src/weights/pallet_author_inherent.rs | 70 + .../src/weights/pallet_author_mapping.rs | 122 + .../src/weights/pallet_author_slot_filter.rs | 59 + .../common/src/weights/pallet_balances.rs | 151 + .../common/src/weights/pallet_collective.rs | 308 + .../src/weights/pallet_conviction_voting.rs | 192 + .../src/weights/pallet_crowdloan_rewards.rs | 163 + .../runtime/common/src/weights/pallet_evm.rs | 78 + .../common/src/weights/pallet_identity.rs | 411 + .../src/weights/pallet_message_queue.rs | 184 + .../weights/pallet_moonbeam_foreign_assets.rs | 173 + .../pallet_moonbeam_lazy_migrations.rs | 77 + .../src/weights/pallet_moonbeam_orbiters.rs | 203 + .../common/src/weights/pallet_multisig.rs | 160 + .../src/weights/pallet_parachain_staking.rs | 864 ++ .../common/src/weights/pallet_parameters.rs | 56 + .../weights/pallet_precompile_benchmarks.rs | 80 + .../common/src/weights/pallet_preimage.rs | 251 + .../common/src/weights/pallet_proxy.rs | 217 + .../common/src/weights/pallet_randomness.rs | 162 + .../common/src/weights/pallet_referenda.rs | 483 + .../src/weights/pallet_relay_storage_roots.rs | 64 + .../common/src/weights/pallet_scheduler.rs | 272 + .../runtime/common/src/weights/pallet_sudo.rs | 91 + .../common/src/weights/pallet_timestamp.rs | 67 + .../common/src/weights/pallet_treasury.rs | 189 + .../common/src/weights/pallet_utility.rs | 105 + .../common/src/weights/pallet_whitelist.rs | 118 + .../runtime/common/src/weights/pallet_xcm.rs | 336 + .../src/weights/pallet_xcm_transactor.rs | 204 + .../src/weights/pallet_xcm_weight_trader.rs | 104 + tracing/3200/runtime/moonbase/Cargo.toml | 444 + tracing/3200/runtime/moonbase/build.rs | 36 + .../3200/runtime/moonbase/src/asset_config.rs | 218 + .../moonbase/src/governance/councils.rs | 62 + .../runtime/moonbase/src/governance/mod.rs | 29 + .../moonbase/src/governance/origins.rs | 83 + .../moonbase/src/governance/referenda.rs | 101 + .../runtime/moonbase/src/governance/tracks.rs | 193 + tracing/3200/runtime/moonbase/src/lib.rs | 1855 ++++ .../3200/runtime/moonbase/src/migrations.rs | 28 + .../3200/runtime/moonbase/src/precompiles.rs | 352 + .../runtime/moonbase/src/runtime_params.rs | 44 + .../3200/runtime/moonbase/src/xcm_config.rs | 816 ++ .../3200/runtime/moonbase/tests/common/mod.rs | 405 + .../runtime/moonbase/tests/evm_tracing.rs | 144 + .../moonbase/tests/integration_test.rs | 3141 ++++++ .../runtime/moonbase/tests/runtime_apis.rs | 397 + .../runtime/moonbase/tests/xcm_mock/mod.rs | 273 + .../moonbase/tests/xcm_mock/parachain.rs | 1137 ++ .../moonbase/tests/xcm_mock/relay_chain.rs | 430 + .../moonbase/tests/xcm_mock/statemint_like.rs | 605 ++ .../3200/runtime/moonbase/tests/xcm_tests.rs | 4853 +++++++++ tracing/3200/runtime/moonbeam/Cargo.toml | 423 + tracing/3200/runtime/moonbeam/build.rs | 36 + .../3200/runtime/moonbeam/src/asset_config.rs | 216 + .../moonbeam/src/governance/councils.rs | 61 + .../runtime/moonbeam/src/governance/mod.rs | 29 + .../moonbeam/src/governance/origins.rs | 85 + .../moonbeam/src/governance/referenda.rs | 100 + .../runtime/moonbeam/src/governance/tracks.rs | 193 + tracing/3200/runtime/moonbeam/src/lib.rs | 1843 ++++ .../3200/runtime/moonbeam/src/migrations.rs | 27 + .../3200/runtime/moonbeam/src/precompiles.rs | 296 + .../3200/runtime/moonbeam/src/xcm_config.rs | 802 ++ .../3200/runtime/moonbeam/tests/common/mod.rs | 394 + .../runtime/moonbeam/tests/evm_tracing.rs | 144 + .../moonbeam/tests/integration_test.rs | 2899 ++++++ .../runtime/moonbeam/tests/runtime_apis.rs | 395 + .../runtime/moonbeam/tests/xcm_mock/mod.rs | 272 + .../moonbeam/tests/xcm_mock/parachain.rs | 1125 ++ .../moonbeam/tests/xcm_mock/relay_chain.rs | 430 + .../moonbeam/tests/xcm_mock/statemint_like.rs | 607 ++ .../3200/runtime/moonbeam/tests/xcm_tests.rs | 4584 +++++++++ tracing/3200/runtime/moonriver/Cargo.toml | 428 + tracing/3200/runtime/moonriver/build.rs | 36 + .../runtime/moonriver/src/asset_config.rs | 217 + .../moonriver/src/governance/councils.rs | 61 + .../runtime/moonriver/src/governance/mod.rs | 29 + .../moonriver/src/governance/origins.rs | 84 + .../moonriver/src/governance/referenda.rs | 100 + .../moonriver/src/governance/tracks.rs | 193 + tracing/3200/runtime/moonriver/src/lib.rs | 1844 ++++ .../3200/runtime/moonriver/src/migrations.rs | 31 + .../3200/runtime/moonriver/src/precompiles.rs | 269 + .../3200/runtime/moonriver/src/xcm_config.rs | 815 ++ .../runtime/moonriver/tests/common/mod.rs | 401 + .../runtime/moonriver/tests/evm_tracing.rs | 144 + .../moonriver/tests/integration_test.rs | 2808 +++++ .../runtime/moonriver/tests/runtime_apis.rs | 398 + .../runtime/moonriver/tests/xcm_mock/mod.rs | 274 + .../moonriver/tests/xcm_mock/parachain.rs | 1129 ++ .../moonriver/tests/xcm_mock/relay_chain.rs | 430 + .../tests/xcm_mock/statemine_like.rs | 607 ++ .../3200/runtime/moonriver/tests/xcm_tests.rs | 4882 +++++++++ tracing/3200/rust-toolchain | 5 + tracing/3200/shared/primitives/ext/Cargo.toml | 33 + tracing/3200/shared/primitives/ext/src/lib.rs | 82 + .../shared/primitives/rpc/debug/Cargo.toml | 45 + .../shared/primitives/rpc/debug/src/lib.rs | 129 + .../rpc/evm-tracing-events/Cargo.toml | 37 + .../rpc/evm-tracing-events/src/evm.rs | 272 + .../rpc/evm-tracing-events/src/gasometer.rs | 119 + .../rpc/evm-tracing-events/src/lib.rs | 287 + .../rpc/evm-tracing-events/src/runtime.rs | 156 + .../3200/shared/runtime/evm_tracer/Cargo.toml | 51 + .../3200/shared/runtime/evm_tracer/src/lib.rs | 117 + ...nbase-runtime-3200-substitute-tracing.wasm | Bin 0 -> 2227447 bytes ...nbeam-runtime-3200-substitute-tracing.wasm | Bin 0 -> 2179936 bytes ...river-runtime-3200-substitute-tracing.wasm | Bin 0 -> 2186809 bytes 133 files changed, 66047 insertions(+) create mode 100644 srtool-digest/moonbase-runtime-3200-substitute-tracing.json create mode 100644 srtool-digest/moonbeam-runtime-3200-substitute-tracing.json create mode 100644 srtool-digest/moonriver-runtime-3200-substitute-tracing.json create mode 100644 tracing/3200/Cargo.lock create mode 100644 tracing/3200/Cargo.toml create mode 100644 tracing/3200/runtime/common/Cargo.toml create mode 100644 tracing/3200/runtime/common/src/apis.rs create mode 100644 tracing/3200/runtime/common/src/benchmarking.rs create mode 100644 tracing/3200/runtime/common/src/impl_moonbeam_xcm_call.rs create mode 100644 tracing/3200/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs create mode 100644 tracing/3200/runtime/common/src/impl_on_charge_evm_transaction.rs create mode 100644 tracing/3200/runtime/common/src/impl_self_contained_call.rs create mode 100644 tracing/3200/runtime/common/src/impl_xcm_evm_runner.rs create mode 100644 tracing/3200/runtime/common/src/lib.rs create mode 100644 tracing/3200/runtime/common/src/migrations.rs create mode 100644 tracing/3200/runtime/common/src/timestamp.rs create mode 100644 tracing/3200/runtime/common/src/weights/cumulus_pallet_parachain_system.rs create mode 100644 tracing/3200/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs create mode 100644 tracing/3200/runtime/common/src/weights/db/mod.rs create mode 100644 tracing/3200/runtime/common/src/weights/db/rocksdb.rs create mode 100644 tracing/3200/runtime/common/src/weights/mod.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_asset_manager.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_assets.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_author_inherent.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_author_mapping.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_author_slot_filter.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_balances.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_collective.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_conviction_voting.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_crowdloan_rewards.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_evm.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_identity.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_message_queue.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_moonbeam_orbiters.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_multisig.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_parachain_staking.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_parameters.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_precompile_benchmarks.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_preimage.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_proxy.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_randomness.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_referenda.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_relay_storage_roots.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_scheduler.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_sudo.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_timestamp.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_treasury.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_utility.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_whitelist.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_xcm.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_xcm_transactor.rs create mode 100644 tracing/3200/runtime/common/src/weights/pallet_xcm_weight_trader.rs create mode 100644 tracing/3200/runtime/moonbase/Cargo.toml create mode 100644 tracing/3200/runtime/moonbase/build.rs create mode 100644 tracing/3200/runtime/moonbase/src/asset_config.rs create mode 100644 tracing/3200/runtime/moonbase/src/governance/councils.rs create mode 100644 tracing/3200/runtime/moonbase/src/governance/mod.rs create mode 100644 tracing/3200/runtime/moonbase/src/governance/origins.rs create mode 100644 tracing/3200/runtime/moonbase/src/governance/referenda.rs create mode 100644 tracing/3200/runtime/moonbase/src/governance/tracks.rs create mode 100644 tracing/3200/runtime/moonbase/src/lib.rs create mode 100644 tracing/3200/runtime/moonbase/src/migrations.rs create mode 100644 tracing/3200/runtime/moonbase/src/precompiles.rs create mode 100644 tracing/3200/runtime/moonbase/src/runtime_params.rs create mode 100644 tracing/3200/runtime/moonbase/src/xcm_config.rs create mode 100644 tracing/3200/runtime/moonbase/tests/common/mod.rs create mode 100644 tracing/3200/runtime/moonbase/tests/evm_tracing.rs create mode 100644 tracing/3200/runtime/moonbase/tests/integration_test.rs create mode 100644 tracing/3200/runtime/moonbase/tests/runtime_apis.rs create mode 100644 tracing/3200/runtime/moonbase/tests/xcm_mock/mod.rs create mode 100644 tracing/3200/runtime/moonbase/tests/xcm_mock/parachain.rs create mode 100644 tracing/3200/runtime/moonbase/tests/xcm_mock/relay_chain.rs create mode 100644 tracing/3200/runtime/moonbase/tests/xcm_mock/statemint_like.rs create mode 100644 tracing/3200/runtime/moonbase/tests/xcm_tests.rs create mode 100644 tracing/3200/runtime/moonbeam/Cargo.toml create mode 100644 tracing/3200/runtime/moonbeam/build.rs create mode 100644 tracing/3200/runtime/moonbeam/src/asset_config.rs create mode 100644 tracing/3200/runtime/moonbeam/src/governance/councils.rs create mode 100644 tracing/3200/runtime/moonbeam/src/governance/mod.rs create mode 100644 tracing/3200/runtime/moonbeam/src/governance/origins.rs create mode 100644 tracing/3200/runtime/moonbeam/src/governance/referenda.rs create mode 100644 tracing/3200/runtime/moonbeam/src/governance/tracks.rs create mode 100644 tracing/3200/runtime/moonbeam/src/lib.rs create mode 100644 tracing/3200/runtime/moonbeam/src/migrations.rs create mode 100644 tracing/3200/runtime/moonbeam/src/precompiles.rs create mode 100644 tracing/3200/runtime/moonbeam/src/xcm_config.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/common/mod.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/evm_tracing.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/integration_test.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/runtime_apis.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/xcm_mock/mod.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/xcm_mock/parachain.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/xcm_mock/relay_chain.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/xcm_mock/statemint_like.rs create mode 100644 tracing/3200/runtime/moonbeam/tests/xcm_tests.rs create mode 100644 tracing/3200/runtime/moonriver/Cargo.toml create mode 100644 tracing/3200/runtime/moonriver/build.rs create mode 100644 tracing/3200/runtime/moonriver/src/asset_config.rs create mode 100644 tracing/3200/runtime/moonriver/src/governance/councils.rs create mode 100644 tracing/3200/runtime/moonriver/src/governance/mod.rs create mode 100644 tracing/3200/runtime/moonriver/src/governance/origins.rs create mode 100644 tracing/3200/runtime/moonriver/src/governance/referenda.rs create mode 100644 tracing/3200/runtime/moonriver/src/governance/tracks.rs create mode 100644 tracing/3200/runtime/moonriver/src/lib.rs create mode 100644 tracing/3200/runtime/moonriver/src/migrations.rs create mode 100644 tracing/3200/runtime/moonriver/src/precompiles.rs create mode 100644 tracing/3200/runtime/moonriver/src/xcm_config.rs create mode 100644 tracing/3200/runtime/moonriver/tests/common/mod.rs create mode 100644 tracing/3200/runtime/moonriver/tests/evm_tracing.rs create mode 100644 tracing/3200/runtime/moonriver/tests/integration_test.rs create mode 100644 tracing/3200/runtime/moonriver/tests/runtime_apis.rs create mode 100644 tracing/3200/runtime/moonriver/tests/xcm_mock/mod.rs create mode 100644 tracing/3200/runtime/moonriver/tests/xcm_mock/parachain.rs create mode 100644 tracing/3200/runtime/moonriver/tests/xcm_mock/relay_chain.rs create mode 100644 tracing/3200/runtime/moonriver/tests/xcm_mock/statemine_like.rs create mode 100644 tracing/3200/runtime/moonriver/tests/xcm_tests.rs create mode 100644 tracing/3200/rust-toolchain create mode 100644 tracing/3200/shared/primitives/ext/Cargo.toml create mode 100644 tracing/3200/shared/primitives/ext/src/lib.rs create mode 100644 tracing/3200/shared/primitives/rpc/debug/Cargo.toml create mode 100644 tracing/3200/shared/primitives/rpc/debug/src/lib.rs create mode 100644 tracing/3200/shared/primitives/rpc/evm-tracing-events/Cargo.toml create mode 100644 tracing/3200/shared/primitives/rpc/evm-tracing-events/src/evm.rs create mode 100644 tracing/3200/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs create mode 100644 tracing/3200/shared/primitives/rpc/evm-tracing-events/src/lib.rs create mode 100644 tracing/3200/shared/primitives/rpc/evm-tracing-events/src/runtime.rs create mode 100644 tracing/3200/shared/runtime/evm_tracer/Cargo.toml create mode 100644 tracing/3200/shared/runtime/evm_tracer/src/lib.rs create mode 100644 wasm/moonbase-runtime-3200-substitute-tracing.wasm create mode 100644 wasm/moonbeam-runtime-3200-substitute-tracing.wasm create mode 100644 wasm/moonriver-runtime-3200-substitute-tracing.wasm diff --git a/srtool-digest/moonbase-runtime-3200-substitute-tracing.json b/srtool-digest/moonbase-runtime-3200-substitute-tracing.json new file mode 100644 index 00000000..738e190d --- /dev/null +++ b/srtool-digest/moonbase-runtime-3200-substitute-tracing.json @@ -0,0 +1 @@ +{"gen":"srtool v0.15.0","src":"zip","version":"0.8.4","commit":"","tag":"","branch":"","rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbase-runtime","tmsp":"2024-09-16T20:01:42Z","size":"2227447","prop":"0xefd27951852b5775da5ac63c79c7a45140360412288dae5a100be9482b954801","authorize_upgrade_prop":"0xe9714ef54b663cc0e69057a448dd7e1cdf666b40920c6452f41bc99123ce3321","ipfs":"QmPnGtn2LSha5FR3eEWHgS4pMRpMVcn91Zp8TAaemj2srB","sha256":"0x803ad5a1138043f50579b0d8307be11abfd526d605912bc7f7285a081fb49b6f","wasm":"runtime/moonbase/target/srtool/release/wbuild/moonbase-runtime/moonbase_runtime.compact.compressed.wasm","info":{"generator":{"name":"srtool","version":"0.15.0"},"src":"zip","version":"0.8.4","git":{"commit":"","tag":"","branch":""},"rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbase-runtime","profile":"release"},"context":{"package":"moonbase-runtime","runtime_dir":"runtime/moonbase","docker":{"image":"paritytech/srtool","tag":"1.77.0"},"profile":"release"},"runtimes":{"compact":{"tmsp":"2024-09-16T20:00:17Z","size":"10735540","prop":"0x8e64614db64132ed167303f7fc86365daaadd8a0bdd86972a468d9efa207048e","authorize_upgrade_prop":"0xf83dc681a5ef2628fd050cb4b1bf2a9df5959e4805ac1d46b20605b6170651b8","blake2_256":"0x1b5c86daf0c4525b922fb00bc0ddd62d40349dc91efa43c571f15f710790da45","ipfs":"Qmf7tFhqWCzHEjk1RLJgRq1CpQutyiaDqGuraLWqYreeiT","sha256":"0xb3c8fa69ab64f6032262806b0c130805900fb4dc3dd38627c9e79c4bfcb996c1","wasm":"runtime/moonbase/target/srtool/release/wbuild/moonbase-runtime/moonbase_runtime.compact.wasm","subwasm":{"size":10735540,"compression":{"size_compressed":10735540,"size_decompressed":10735540,"compressed":false},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbase","implName":"moonbase","authoringVersion":4,"specVersion":3200,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":3,"stateVersion":0},"proposal_hash":"0x8e64614db64132ed167303f7fc86365daaadd8a0bdd86972a468d9efa207048e","parachain_authorize_upgrade_hash":"0xf83dc681a5ef2628fd050cb4b1bf2a9df5959e4805ac1d46b20605b6170651b8","ipfs_hash":"Qmf7tFhqWCzHEjk1RLJgRq1CpQutyiaDqGuraLWqYreeiT","blake2_256":"0x1b5c86daf0c4525b922fb00bc0ddd62d40349dc91efa43c571f15f710790da45"}},"compressed":{"tmsp":"2024-09-16T19:45:04Z","size":"2227447","prop":"0xefd27951852b5775da5ac63c79c7a45140360412288dae5a100be9482b954801","authorize_upgrade_prop":"0xe9714ef54b663cc0e69057a448dd7e1cdf666b40920c6452f41bc99123ce3321","blake2_256":"0xbd9e09e39b532272dfbbbf94b1bbac6bdc5a31411a827d226061311816a92ecf","ipfs":"QmPnGtn2LSha5FR3eEWHgS4pMRpMVcn91Zp8TAaemj2srB","sha256":"0x803ad5a1138043f50579b0d8307be11abfd526d605912bc7f7285a081fb49b6f","wasm":"runtime/moonbase/target/srtool/release/wbuild/moonbase-runtime/moonbase_runtime.compact.compressed.wasm","subwasm":{"size":2227447,"compression":{"size_compressed":2227447,"size_decompressed":10735540,"compressed":true},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbase","implName":"moonbase","authoringVersion":4,"specVersion":3200,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":3,"stateVersion":0},"proposal_hash":"0xefd27951852b5775da5ac63c79c7a45140360412288dae5a100be9482b954801","parachain_authorize_upgrade_hash":"0xe9714ef54b663cc0e69057a448dd7e1cdf666b40920c6452f41bc99123ce3321","ipfs_hash":"QmPnGtn2LSha5FR3eEWHgS4pMRpMVcn91Zp8TAaemj2srB","blake2_256":"0xbd9e09e39b532272dfbbbf94b1bbac6bdc5a31411a827d226061311816a92ecf"}}}} diff --git a/srtool-digest/moonbeam-runtime-3200-substitute-tracing.json b/srtool-digest/moonbeam-runtime-3200-substitute-tracing.json new file mode 100644 index 00000000..be60a9ab --- /dev/null +++ b/srtool-digest/moonbeam-runtime-3200-substitute-tracing.json @@ -0,0 +1 @@ +{"gen":"srtool v0.15.0","src":"zip","version":"0.8.4","commit":"","tag":"","branch":"","rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbeam-runtime","tmsp":"2024-09-16T21:17:07Z","size":"2179936","prop":"0x652cbcd0a4ef065525908d74c9f5e3e9ffdb9fa325589f98c47b4128b4258489","authorize_upgrade_prop":"0xac7203007514a2016b5364af0ec8621d4c9ded151ff3dfabf71a37b9291625d3","ipfs":"QmaPWQFCmubiDf1aNApPiY3qPSidHZ3RZs1HsjipEJoeS7","sha256":"0xd938d35e670c402b4d49894fc16319574329d35a5fc8253932a8cced02e27139","wasm":"runtime/moonbeam/target/srtool/release/wbuild/moonbeam-runtime/moonbeam_runtime.compact.compressed.wasm","info":{"generator":{"name":"srtool","version":"0.15.0"},"src":"zip","version":"0.8.4","git":{"commit":"","tag":"","branch":""},"rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonbeam-runtime","profile":"release"},"context":{"package":"moonbeam-runtime","runtime_dir":"runtime/moonbeam","docker":{"image":"paritytech/srtool","tag":"1.77.0"},"profile":"release"},"runtimes":{"compact":{"tmsp":"2024-09-16T21:15:43Z","size":"10468982","prop":"0x6cb85839f5b674c192e02d28f31fed439c0935aedf299ac95037a1734150fa17","authorize_upgrade_prop":"0xa484f9ae1f47615ccc5b029bee30c383f1d8408a1a266fbe78420259d9fd774a","blake2_256":"0xd426bbdc0e308f4c68a2e1dca2545e6cc66b0075666333a2258f4875e6b6927e","ipfs":"QmcgoMJRJymrjJBybwuPEhuQNCLXz4GioDq2tifyJmdEbN","sha256":"0x1f9656759303000ff8a0cee29ab70e0bc358d9410fb00304128cac6530985495","wasm":"runtime/moonbeam/target/srtool/release/wbuild/moonbeam-runtime/moonbeam_runtime.compact.wasm","subwasm":{"size":10468982,"compression":{"size_compressed":10468982,"size_decompressed":10468982,"compressed":false},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbeam","implName":"moonbeam","authoringVersion":3,"specVersion":3200,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":3,"stateVersion":0},"proposal_hash":"0x6cb85839f5b674c192e02d28f31fed439c0935aedf299ac95037a1734150fa17","parachain_authorize_upgrade_hash":"0xa484f9ae1f47615ccc5b029bee30c383f1d8408a1a266fbe78420259d9fd774a","ipfs_hash":"QmcgoMJRJymrjJBybwuPEhuQNCLXz4GioDq2tifyJmdEbN","blake2_256":"0xd426bbdc0e308f4c68a2e1dca2545e6cc66b0075666333a2258f4875e6b6927e"}},"compressed":{"tmsp":"2024-09-16T20:54:49Z","size":"2179936","prop":"0x652cbcd0a4ef065525908d74c9f5e3e9ffdb9fa325589f98c47b4128b4258489","authorize_upgrade_prop":"0xac7203007514a2016b5364af0ec8621d4c9ded151ff3dfabf71a37b9291625d3","blake2_256":"0x0fbc56bd4e0633af1e9806d694cb715b536f3782fab102f7295529bfb807aa01","ipfs":"QmaPWQFCmubiDf1aNApPiY3qPSidHZ3RZs1HsjipEJoeS7","sha256":"0xd938d35e670c402b4d49894fc16319574329d35a5fc8253932a8cced02e27139","wasm":"runtime/moonbeam/target/srtool/release/wbuild/moonbeam-runtime/moonbeam_runtime.compact.compressed.wasm","subwasm":{"size":2179936,"compression":{"size_compressed":2179936,"size_decompressed":10468982,"compressed":true},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonbeam","implName":"moonbeam","authoringVersion":3,"specVersion":3200,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":3,"stateVersion":0},"proposal_hash":"0x652cbcd0a4ef065525908d74c9f5e3e9ffdb9fa325589f98c47b4128b4258489","parachain_authorize_upgrade_hash":"0xac7203007514a2016b5364af0ec8621d4c9ded151ff3dfabf71a37b9291625d3","ipfs_hash":"QmaPWQFCmubiDf1aNApPiY3qPSidHZ3RZs1HsjipEJoeS7","blake2_256":"0x0fbc56bd4e0633af1e9806d694cb715b536f3782fab102f7295529bfb807aa01"}}}} diff --git a/srtool-digest/moonriver-runtime-3200-substitute-tracing.json b/srtool-digest/moonriver-runtime-3200-substitute-tracing.json new file mode 100644 index 00000000..3d46e247 --- /dev/null +++ b/srtool-digest/moonriver-runtime-3200-substitute-tracing.json @@ -0,0 +1 @@ +{"gen":"srtool v0.15.0","src":"zip","version":"0.8.4","commit":"","tag":"","branch":"","rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonriver-runtime","tmsp":"2024-09-16T20:38:21Z","size":"2186809","prop":"0x741ba5c22b7ddc25a467916c97d385b9205d4593552c1468e3cf370fa7d6cc7f","authorize_upgrade_prop":"0xca84eb61d1346a7008bac8d5ac48714eb0f8c37b119cd2ab7892d14fb4dbc05b","ipfs":"Qmb8KewKBrNAWfDd939hqwePsN2dqVMeKoX35PNMMKRQcR","sha256":"0x45610b551dacf0ab322356322b1808c783dc5a7c29dbfab5a2260eb9b6b217c3","wasm":"runtime/moonriver/target/srtool/release/wbuild/moonriver-runtime/moonriver_runtime.compact.compressed.wasm","info":{"generator":{"name":"srtool","version":"0.15.0"},"src":"zip","version":"0.8.4","git":{"commit":"","tag":"","branch":""},"rustc":"rustc 1.77.0 (aedd173a2 2024-03-17)","pkg":"moonriver-runtime","profile":"release"},"context":{"package":"moonriver-runtime","runtime_dir":"runtime/moonriver","docker":{"image":"paritytech/srtool","tag":"1.77.0"},"profile":"release"},"runtimes":{"compact":{"tmsp":"2024-09-16T20:36:53Z","size":"10479855","prop":"0x863cde8ef7f2ba7c92caaa7648b6b6ed6dbf40fc5a72a23b658d61616e6e5744","authorize_upgrade_prop":"0x74d0c8d520d720a101a1b456486b87a5eac395519108accd7adbd362e1fc00ec","blake2_256":"0x676f57382514572f87604e2e9b747fdc87a1dd417d3953c05802b29fd9b193db","ipfs":"Qmb9Wg23kzvJLzJLym8w7yt4qXohwrXvQU3n9mTrobgQAc","sha256":"0x5972c6589de317dfa23bfc3bc003fcc27fb152c8fa72371be3bd1d4851063825","wasm":"runtime/moonriver/target/srtool/release/wbuild/moonriver-runtime/moonriver_runtime.compact.wasm","subwasm":{"size":10479855,"compression":{"size_compressed":10479855,"size_decompressed":10479855,"compressed":false},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonriver","implName":"moonriver","authoringVersion":3,"specVersion":3200,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":3,"stateVersion":0},"proposal_hash":"0x863cde8ef7f2ba7c92caaa7648b6b6ed6dbf40fc5a72a23b658d61616e6e5744","parachain_authorize_upgrade_hash":"0x74d0c8d520d720a101a1b456486b87a5eac395519108accd7adbd362e1fc00ec","ipfs_hash":"Qmb9Wg23kzvJLzJLym8w7yt4qXohwrXvQU3n9mTrobgQAc","blake2_256":"0x676f57382514572f87604e2e9b747fdc87a1dd417d3953c05802b29fd9b193db"}},"compressed":{"tmsp":"2024-09-16T20:17:44Z","size":"2186809","prop":"0x741ba5c22b7ddc25a467916c97d385b9205d4593552c1468e3cf370fa7d6cc7f","authorize_upgrade_prop":"0xca84eb61d1346a7008bac8d5ac48714eb0f8c37b119cd2ab7892d14fb4dbc05b","blake2_256":"0x70d1903b93112ca997d4eab67afba75093895db89c1eb3873b9c92fe24a1c77e","ipfs":"Qmb8KewKBrNAWfDd939hqwePsN2dqVMeKoX35PNMMKRQcR","sha256":"0x45610b551dacf0ab322356322b1808c783dc5a7c29dbfab5a2260eb9b6b217c3","wasm":"runtime/moonriver/target/srtool/release/wbuild/moonriver-runtime/moonriver_runtime.compact.compressed.wasm","subwasm":{"size":2186809,"compression":{"size_compressed":2186809,"size_decompressed":10479855,"compressed":true},"reserved_meta":[109,101,116,97],"reserved_meta_valid":true,"metadata_version":14,"core_version":{"specName":"moonriver","implName":"moonriver","authoringVersion":3,"specVersion":3200,"implVersion":0,"apis":[["0xd2bc9897eed08f15",3],["0xd0399cd053adda2b",1],["0xdf6acb689907609b",5],["0x37e397fc7c91f5e4",2],["0x40fe3ad401f8959a",6],["0xf78b278be53f454c",2],["0xab3c0572291feb8b",1],["0xfbc577b9d747efd6",1],["0xbc9d89904f5b923f",1],["0xbd78255d4feeea1f",6],["0xa33d43f58731ad84",2],["0x582211f65bb14b89",5],["0xe65b00e46cedd0aa",2],["0x37c8bb1350a9a2a8",4],["0x2aa62120049dd2d2",1],["0xea93e3f16f3d6962",2],["0xba8173bf23b2e6f8",1],["0x6ff52ee858e6c5bd",1]],"transactionVersion":3,"stateVersion":0},"proposal_hash":"0x741ba5c22b7ddc25a467916c97d385b9205d4593552c1468e3cf370fa7d6cc7f","parachain_authorize_upgrade_hash":"0xca84eb61d1346a7008bac8d5ac48714eb0f8c37b119cd2ab7892d14fb4dbc05b","ipfs_hash":"Qmb8KewKBrNAWfDd939hqwePsN2dqVMeKoX35PNMMKRQcR","blake2_256":"0x70d1903b93112ca997d4eab67afba75093895db89c1eb3873b9c92fe24a1c77e"}}}} diff --git a/tracing/3200/Cargo.lock b/tracing/3200/Cargo.lock new file mode 100644 index 00000000..be4df60b --- /dev/null +++ b/tracing/3200/Cargo.lock @@ -0,0 +1,9149 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "account" +version = "0.1.1" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "blake2-rfc", + "impl-serde 0.3.2", + "libsecp256k1", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sha3", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", +] + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli 0.27.3", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli 0.28.1", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.14", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.14", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "aquamarine" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "aquamarine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" +dependencies = [ + "include_dir", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "ark-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c7021f180a0cbea0380eba97c2af3c57074cdaffe0eef7e840e1c9f2841e55" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bls12-381-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1dc4b3d08f19e8ec06e949712f95b8361e43f1391d94f65e4234df03480631c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-models-ext", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bw6-761" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0605daf0cc5aa2034b78d008aaf159f56901d92a52ee4f6ecdfdac4f426700" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bw6-761-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccee5fba47266f460067588ee1bf070a9c760bf2050c1c509982c5719aadb4f2" +dependencies = [ + "ark-bw6-761", + "ark-ec", + "ark-ff", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ed-on-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10d901b9ac4b38f9c32beacedfadcdd64e46f8d7f8e88c1ae1060022cf6f6c6" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524a4fb7540df2e1a8c2e67a83ba1d1e6c3947f4f9342cc2359fc2e789ad731d" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ff", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15185f1acb49a07ff8cbe5f11a1adc5a93b19e211e325d826ae98e98e124346" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-models-ext", + "ark-std", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-models-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9eab5d4b5ff2f228b763d38442adc9b084b0a465409b059fac5c2308835ec2" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-scale" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f69c00b3b529be29528a6f2fd5fa7b1790f8bed81b9cdca17e326538545a179" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ark-secret-scalar" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "ark-transcript", + "digest 0.10.7", + "getrandom_or_panic", + "zeroize", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", + "rayon", +] + +[[package]] +name = "ark-transcript" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "digest 0.10.7", + "rand_core 0.6.4", + "sha3", +] + +[[package]] +name = "array-bytes" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" + +[[package]] +name = "arrayref" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-backing-primitives" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "sp-api", + "sp-consensus-slots", +] + +[[package]] +name = "async-trait" +version = "0.1.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line 0.21.0", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object 0.32.2", + "rustc-demangle", +] + +[[package]] +name = "bandersnatch_vrfs" +version = "0.0.4" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-serialize", + "ark-std", + "dleq_vrf", + "fflonk", + "merlin", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "ring", + "sha2 0.10.8", + "sp-ark-bls12-381", + "sp-ark-ed-on-bls12-381-bandersnatch", + "zeroize", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "serde", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "blake3" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "cc", + "cfg-if", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bounded-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32385ecb91a31bddaf908e8dcf4a15aef1bcd3913cc03ebfad02ff6d568abc1" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bp-xcm-bridge-hub-router" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata 0.1.10", +] + +[[package]] +name = "build-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" +dependencies = [ + "semver 0.6.0", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.22", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "case" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c" + +[[package]] +name = "cc" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-expr" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "common" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#665f5f51af5734c7b6d90b985dd6861d4c5b4752" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "fflonk", + "getrandom_or_panic", + "merlin", + "rand_chacha 0.3.1", +] + +[[package]] +name = "common-path" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.14", + "once_cell", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "constcat" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "cranelift-isle", + "gimli 0.27.3", + "hashbrown 0.13.2", + "log", + "regalloc2 0.6.1", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8" + +[[package]] +name = "cranelift-entity" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba" + +[[package]] +name = "cranelift-native" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.95.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff3220489a3d928ad91e59dd7aeaa8b3de18afb554a6211213673a71c90737ac" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "cumulus-pallet-dmp-queue" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "cumulus-pallet-parachain-system" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bytes", + "cumulus-pallet-parachain-system-proc-macro", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction", + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-message-queue", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "scale-info", + "sp-core", + "sp-externalities", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-version", + "staging-xcm", + "trie-db", +] + +[[package]] +name = "cumulus-pallet-parachain-system-proc-macro" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "cumulus-pallet-xcm" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "cumulus-pallet-xcmp-queue" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bounded-collections", + "bp-xcm-bridge-hub-router", + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-message-queue", + "parity-scale-codec", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "cumulus-primitives-core" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-primitives", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", + "sp-trie", + "staging-xcm", +] + +[[package]] +name = "cumulus-primitives-parachain-inherent" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "cumulus-primitives-proof-size-hostfunction" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "sp-externalities", + "sp-runtime-interface", + "sp-trie", +] + +[[package]] +name = "cumulus-primitives-storage-weight-reclaim" +version = "1.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "cumulus-primitives-proof-size-hostfunction", + "docify", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "cumulus-primitives-timestamp" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "futures", + "parity-scale-codec", + "sp-inherents", + "sp-std", + "sp-timestamp", +] + +[[package]] +name = "cumulus-primitives-utility" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "log", + "pallet-asset-conversion", + "parity-scale-codec", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + +[[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", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "cxx" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21db378d04296a84d8b7d047c36bb3954f0b46529db725d7e62fb02f9ba53ccc" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5262a7fa3f0bae2a55b767c223ba98032d7c328f5c13fa5cdc980b77fc0658" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.66", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8dcadd2e2fb4a501e1d9e93d6e88e6ea494306d8272069c92d5a9edf8855c0" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad08a837629ad949b73d032c637653d069e909cffe4ee7870b02301939ce39cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive-syn-parse" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dleq_vrf" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-scale", + "ark-secret-scalar", + "ark-serialize", + "ark-std", + "ark-transcript", + "arrayvec 0.7.4", + "zeroize", +] + +[[package]] +name = "docify" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce" +dependencies = [ + "docify_macros", +] + +[[package]] +name = "docify_macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad" +dependencies = [ + "common-path", + "derive-syn-parse 0.2.0", + "once_cell", + "proc-macro2", + "quote", + "regex", + "syn 2.0.66", + "termcolor", + "toml 0.8.12", + "walkdir", +] + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.2", + "ed25519", + "serde", + "sha2 0.10.8", + "subtle", + "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 = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "enumflags2" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "enumn" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04d24d20b8ff2235cffbf242d5092de3aa45f77c5270ddbfadd2778ca13fea" +dependencies = [ + "bytes", + "ethereum-types", + "hash-db", + "hash256-std-hasher", + "parity-scale-codec", + "rlp", + "scale-info", + "serde", + "sha3", + "trie-root", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "evm" +version = "0.41.1" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#25cf24198458187c96cdf1138c11b244f9e35f6f" +dependencies = [ + "auto_impl", + "environmental", + "ethereum", + "evm-core", + "evm-gasometer", + "evm-runtime", + "log", + "parity-scale-codec", + "primitive-types", + "rlp", + "scale-info", + "serde", + "sha3", +] + +[[package]] +name = "evm-core" +version = "0.41.0" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#25cf24198458187c96cdf1138c11b244f9e35f6f" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "scale-info", + "serde", +] + +[[package]] +name = "evm-gasometer" +version = "0.41.0" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#25cf24198458187c96cdf1138c11b244f9e35f6f" +dependencies = [ + "environmental", + "evm-core", + "evm-runtime", + "primitive-types", +] + +[[package]] +name = "evm-runtime" +version = "0.41.0" +source = "git+https://github.com/moonbeam-foundation/evm?branch=moonbeam-polkadot-v1.11.0#25cf24198458187c96cdf1138c11b244f9e35f6f" +dependencies = [ + "auto_impl", + "environmental", + "evm-core", + "primitive-types", + "sha3", +] + +[[package]] +name = "evm-tracing-events" +version = "0.1.0" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "evm", + "evm-gasometer", + "evm-runtime", + "parity-scale-codec", + "sp-runtime-interface", +] + +[[package]] +name = "expander" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "faster-hex" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fflonk" +version = "0.1.0" +source = "git+https://github.com/w3f/fflonk#1e854f35e9a65d08b11a86291405cdc95baa0a35" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "merlin", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" + +[[package]] +name = "file-per-thread-logger" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fp-account" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "hex", + "impl-serde 0.4.0", + "libsecp256k1", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", +] + +[[package]] +name = "fp-consensus" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "ethereum", + "parity-scale-codec", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "fp-ethereum" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-evm", + "frame-support", + "parity-scale-codec", +] + +[[package]] +name = "fp-evm" +version = "3.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "environmental", + "evm", + "frame-support", + "num_enum 0.7.2", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "fp-rpc" +version = "3.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "ethereum", + "ethereum-types", + "fp-evm", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-runtime", + "sp-state-machine", +] + +[[package]] +name = "fp-self-contained" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", +] + +[[package]] +name = "fp-storage" +version = "2.0.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "parity-scale-codec", + "serde", +] + +[[package]] +name = "frame-benchmarking" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-support-procedural", + "frame-system", + "linregress", + "log", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "static_assertions", +] + +[[package]] +name = "frame-election-provider-solution-type" +version = "13.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "frame-election-provider-support" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-election-provider-solution-type", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "frame-executive" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "aquamarine 0.3.3", + "frame-support", + "frame-system", + "frame-try-runtime", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "frame-metadata" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "frame-metadata-hash-extension" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "array-bytes", + "docify", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", +] + +[[package]] +name = "frame-support" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "aquamarine 0.5.0", + "array-bytes", + "bitflags 1.3.2", + "docify", + "environmental", + "frame-metadata", + "frame-support-procedural", + "impl-trait-for-tuples", + "k256", + "log", + "macro_magic", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "serde_json", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-crypto-hashing-proc-macro", + "sp-debug-derive", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-metadata-ir", + "sp-runtime", + "sp-staking", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-weights", + "static_assertions", + "tt-call", +] + +[[package]] +name = "frame-support-procedural" +version = "23.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "Inflector", + "cfg-expr", + "derive-syn-parse 0.2.0", + "expander", + "frame-support-procedural-tools", + "itertools", + "macro_magic", + "proc-macro-warning", + "proc-macro2", + "quote", + "sp-crypto-hashing", + "syn 2.0.66", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "10.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support-procedural-tools-derive", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "11.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "frame-system" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cfg-if", + "docify", + "frame-support", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-version", + "sp-weights", +] + +[[package]] +name = "frame-system-benchmarking" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "frame-system-rpc-runtime-api" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + +[[package]] +name = "frame-try-runtime" +version = "0.34.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "parity-scale-codec", + "sp-api", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom_or_panic" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" +dependencies = [ + "rand 0.8.5", + "rand_core 0.6.4", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +dependencies = [ + "fallible-iterator 0.2.0", + "indexmap 1.9.3", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator 0.3.0", + "stable_deref_trait", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hash-db" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.11", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2 0.10.8", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + +[[package]] +name = "linregress" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2" +dependencies = [ + "nalgebra", +] + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "macro_magic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e03844fc635e92f3a0067e25fa4bf3e3dbf3f2927bf3aa01bb7bc8f1c428949d" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "macro_magic_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d" +dependencies = [ + "const-random", + "derive-syn-parse 0.1.5", + "macro_magic_core_macros", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "macro_magic_core_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "macro_magic_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" +dependencies = [ + "macro_magic_core", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "memfd" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +dependencies = [ + "rustix 0.38.32", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory-db" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" +dependencies = [ + "hash-db", +] + +[[package]] +name = "merkleized-metadata" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f313fcff1d2a4bcaa2deeaa00bf7530d77d5f7bd0467a117dde2e29a75a7a17a" +dependencies = [ + "array-bytes", + "blake3", + "frame-metadata", + "parity-scale-codec", + "scale-decode", + "scale-info", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "moonbase-runtime" +version = "0.8.4" +dependencies = [ + "account", + "async-backing-primitives", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "evm-tracing-events", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "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 0.3.4", + "log", + "moonbeam-core-primitives", + "moonbeam-evm-tracer", + "moonbeam-relay-encoder", + "moonbeam-rpc-primitives-debug", + "moonbeam-rpc-primitives-txpool", + "moonbeam-runtime-common 0.8.0-dev", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "num_enum 0.5.11", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-emergency-para-xcm", + "pallet-erc20-xcm-bridge", + "pallet-ethereum", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-evm-precompile-author-mapping", + "pallet-evm-precompile-balances-erc20", + "pallet-evm-precompile-batch", + "pallet-evm-precompile-blake2", + "pallet-evm-precompile-bn128", + "pallet-evm-precompile-call-permit", + "pallet-evm-precompile-collective", + "pallet-evm-precompile-conviction-voting", + "pallet-evm-precompile-crowdloan-rewards", + "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-gmp", + "pallet-evm-precompile-identity", + "pallet-evm-precompile-modexp", + "pallet-evm-precompile-p256verify", + "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-preimage", + "pallet-evm-precompile-proxy", + "pallet-evm-precompile-randomness", + "pallet-evm-precompile-referenda", + "pallet-evm-precompile-registry", + "pallet-evm-precompile-relay-encoder", + "pallet-evm-precompile-relay-verifier", + "pallet-evm-precompile-sha3fips", + "pallet-evm-precompile-simple", + "pallet-evm-precompile-storage-cleaner", + "pallet-evm-precompile-xcm", + "pallet-evm-precompile-xcm-transactor", + "pallet-evm-precompile-xcm-utils", + "pallet-evm-precompile-xtokens", + "pallet-evm-precompileset-assets-erc20", + "pallet-identity", + "pallet-maintenance-mode", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-parameters", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-proxy-genesis-companion", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-root-testing", + "pallet-scheduler", + "pallet-society", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-transactor", + "pallet-xcm-weight-trader", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "precompile-foreign-asset-migrator", + "precompile-utils", + "rlp", + "scale-info", + "serde", + "session-keys-primitives", + "sha3", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-slots", + "sp-core", + "sp-debug-derive", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "strum 0.24.1", + "strum_macros 0.24.3", + "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.0", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-core-primitives" +version = "0.1.1" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "fp-self-contained", + "hex-literal 0.3.4", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "moonbeam-evm-tracer" +version = "0.1.0" +dependencies = [ + "ethereum-types", + "evm", + "evm-gasometer", + "evm-runtime", + "evm-tracing-events", + "fp-evm", + "moonbeam-primitives-ext", + "pallet-evm", + "parity-scale-codec", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "moonbeam-primitives-ext" +version = "0.1.0" +dependencies = [ + "ethereum-types", + "evm-tracing-events", + "parity-scale-codec", + "sp-externalities", + "sp-runtime-interface", + "sp-std", +] + +[[package]] +name = "moonbeam-relay-encoder" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "frame-system", + "pallet-evm-precompile-relay-encoder", + "pallet-staking", + "pallet-xcm-transactor", + "parity-scale-codec", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-rpc-primitives-debug" +version = "0.1.0" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "hex", + "parity-scale-codec", + "serde", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "moonbeam-rpc-primitives-txpool" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "ethereum", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "moonbeam-runtime" +version = "0.8.4" +dependencies = [ + "account", + "async-backing-primitives", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "evm-tracing-events", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "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 0.3.4", + "log", + "moonbeam-core-primitives", + "moonbeam-evm-tracer", + "moonbeam-relay-encoder", + "moonbeam-rpc-primitives-debug", + "moonbeam-rpc-primitives-txpool", + "moonbeam-runtime-common 0.8.0-dev", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "num_enum 0.5.11", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-emergency-para-xcm", + "pallet-erc20-xcm-bridge", + "pallet-ethereum", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-evm-precompile-author-mapping", + "pallet-evm-precompile-balances-erc20", + "pallet-evm-precompile-batch", + "pallet-evm-precompile-blake2", + "pallet-evm-precompile-bn128", + "pallet-evm-precompile-call-permit", + "pallet-evm-precompile-collective", + "pallet-evm-precompile-conviction-voting", + "pallet-evm-precompile-crowdloan-rewards", + "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-gmp", + "pallet-evm-precompile-identity", + "pallet-evm-precompile-modexp", + "pallet-evm-precompile-p256verify", + "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-preimage", + "pallet-evm-precompile-proxy", + "pallet-evm-precompile-randomness", + "pallet-evm-precompile-referenda", + "pallet-evm-precompile-registry", + "pallet-evm-precompile-relay-encoder", + "pallet-evm-precompile-relay-verifier", + "pallet-evm-precompile-sha3fips", + "pallet-evm-precompile-simple", + "pallet-evm-precompile-xcm-transactor", + "pallet-evm-precompile-xcm-utils", + "pallet-evm-precompile-xtokens", + "pallet-evm-precompileset-assets-erc20", + "pallet-identity", + "pallet-maintenance-mode", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-proxy-genesis-companion", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-root-testing", + "pallet-scheduler", + "pallet-society", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-transactor", + "pallet-xcm-weight-trader", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "precompile-utils", + "rlp", + "scale-info", + "serde", + "session-keys-primitives", + "sha3", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-slots", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "strum 0.24.1", + "strum_macros 0.24.3", + "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.0", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-runtime-common" +version = "0.8.0-dev" +dependencies = [ + "account", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", + "fp-ethereum", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "frame-try-runtime", + "hex-literal 0.3.4", + "impl-trait-for-tuples", + "log", + "moonbeam-core-primitives", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-identity", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-parameters", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-scheduler", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-transactor", + "pallet-xcm-weight-trader", + "parity-scale-codec", + "precompile-utils", + "sp-api", + "sp-consensus-slots", + "sp-core", + "sp-genesis-builder", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-runtime-common" +version = "0.8.0-dev" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", + "fp-ethereum", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "frame-try-runtime", + "hex-literal 0.3.4", + "impl-trait-for-tuples", + "log", + "moonbeam-core-primitives", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-identity", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-parameters", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-scheduler", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-transactor", + "pallet-xcm-weight-trader", + "parity-scale-codec", + "precompile-utils", + "sp-api", + "sp-consensus-slots", + "sp-core", + "sp-genesis-builder", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonbeam-xcm-benchmarks" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-erc20-xcm-bridge", + "pallet-moonbeam-foreign-assets", + "pallet-xcm-benchmarks", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "staging-xcm", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "moonriver-runtime" +version = "0.8.4" +dependencies = [ + "account", + "async-backing-primitives", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "evm-tracing-events", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "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 0.3.4", + "log", + "moonbeam-core-primitives", + "moonbeam-evm-tracer", + "moonbeam-relay-encoder", + "moonbeam-rpc-primitives-debug", + "moonbeam-rpc-primitives-txpool", + "moonbeam-runtime-common 0.8.0-dev", + "moonbeam-xcm-benchmarks", + "nimbus-primitives", + "num_enum 0.5.11", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-asset-manager", + "pallet-assets", + "pallet-async-backing", + "pallet-author-inherent", + "pallet-author-mapping", + "pallet-author-slot-filter", + "pallet-balances", + "pallet-collective", + "pallet-conviction-voting", + "pallet-crowdloan-rewards", + "pallet-emergency-para-xcm", + "pallet-erc20-xcm-bridge", + "pallet-ethereum", + "pallet-ethereum-xcm", + "pallet-evm", + "pallet-evm-chain-id", + "pallet-evm-precompile-author-mapping", + "pallet-evm-precompile-balances-erc20", + "pallet-evm-precompile-batch", + "pallet-evm-precompile-blake2", + "pallet-evm-precompile-bn128", + "pallet-evm-precompile-call-permit", + "pallet-evm-precompile-collective", + "pallet-evm-precompile-conviction-voting", + "pallet-evm-precompile-crowdloan-rewards", + "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-gmp", + "pallet-evm-precompile-identity", + "pallet-evm-precompile-modexp", + "pallet-evm-precompile-p256verify", + "pallet-evm-precompile-parachain-staking", + "pallet-evm-precompile-preimage", + "pallet-evm-precompile-proxy", + "pallet-evm-precompile-randomness", + "pallet-evm-precompile-referenda", + "pallet-evm-precompile-registry", + "pallet-evm-precompile-relay-encoder", + "pallet-evm-precompile-relay-verifier", + "pallet-evm-precompile-sha3fips", + "pallet-evm-precompile-simple", + "pallet-evm-precompile-xcm-transactor", + "pallet-evm-precompile-xcm-utils", + "pallet-evm-precompile-xtokens", + "pallet-evm-precompileset-assets-erc20", + "pallet-identity", + "pallet-maintenance-mode", + "pallet-message-queue", + "pallet-migrations", + "pallet-moonbeam-foreign-assets", + "pallet-moonbeam-lazy-migrations", + "pallet-moonbeam-orbiters", + "pallet-multisig", + "pallet-parachain-staking", + "pallet-precompile-benchmarks", + "pallet-preimage", + "pallet-proxy", + "pallet-proxy-genesis-companion", + "pallet-randomness", + "pallet-referenda", + "pallet-relay-storage-roots", + "pallet-root-testing", + "pallet-scheduler", + "pallet-society", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-whitelist", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-transactor", + "pallet-xcm-weight-trader", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "precompile-utils", + "rlp", + "scale-info", + "serde", + "session-keys-primitives", + "sha3", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-slots", + "sp-core", + "sp-debug-derive", + "sp-genesis-builder", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "strum 0.24.1", + "strum_macros 0.24.3", + "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", + "xcm-primitives 0.1.0", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "nalgebra" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "nimbus-primitives" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "async-trait", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-inherents", + "sp-runtime", + "sp-std", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec 0.7.4", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive 0.7.2", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "crc32fast", + "hashbrown 0.13.2", + "indexmap 1.9.3", + "memchr", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "orml-traits" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#f653f239532bd72b6bc4a7290db10790a38b0b92" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "num-traits", + "orml-utilities", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "orml-utilities" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#f653f239532bd72b6bc4a7290db10790a38b0b92" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "orml-xcm-support" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#f653f239532bd72b6bc4a7290db10790a38b0b92" +dependencies = [ + "frame-support", + "orml-traits", + "parity-scale-codec", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "orml-xtokens" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/open-runtime-module-library?branch=moonbeam-polkadot-v1.11.0#f653f239532bd72b6bc4a7290db10790a38b0b92" +dependencies = [ + "frame-support", + "frame-system", + "log", + "orml-traits", + "orml-xcm-support", + "pallet-xcm", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "pallet-asset-conversion" +version = "10.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-asset-manager" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-asset-rate" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-asset-tx-payment" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-assets" +version = "29.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-async-backing" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-consensus-slots", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-author-inherent" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-inherents", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-author-mapping" +version = "2.0.5" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "session-keys-primitives", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-author-slot-filter" +version = "0.9.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-authority-discovery" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-system", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-authority-discovery", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-authorship" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-babe" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-balances" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-broker" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-collator-selection" +version = "9.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-balances", + "pallet-session", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-collective" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-conviction-voting" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-crowdloan-rewards" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/crowdloan-rewards?branch=moonbeam-polkadot-v1.11.0#35d34816f5b4655d2192633d0d69531e4ed35f66" +dependencies = [ + "ed25519-dalek", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-utility", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-trie", +] + +[[package]] +name = "pallet-election-provider-multi-phase" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-election-provider-support-benchmarking", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", + "strum 0.26.2", +] + +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-system", + "parity-scale-codec", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-emergency-para-xcm" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "pallet-message-queue", + "parity-scale-codec", + "polkadot-parachain-primitives", + "scale-info", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-erc20-xcm-bridge" +version = "1.0.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "environmental", + "ethereum-types", + "fp-evm", + "frame-support", + "frame-system", + "log", + "pallet-evm", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "pallet-ethereum" +version = "4.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "evm", + "fp-consensus", + "fp-ethereum", + "fp-evm", + "fp-rpc", + "fp-storage", + "frame-support", + "frame-system", + "pallet-evm", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", +] + +[[package]] +name = "pallet-ethereum-xcm" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "environmental", + "ethereum", + "ethereum-types", + "fp-ethereum", + "fp-evm", + "fp-rpc", + "fp-self-contained", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "rlp", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm" +version = "6.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "environmental", + "evm", + "fp-account", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "hash-db", + "hex", + "hex-literal 0.4.1", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "rlp", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + +[[package]] +name = "pallet-evm-chain-id" +version = "1.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "pallet-evm-precompile-author-mapping" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "num_enum 0.5.11", + "pallet-author-mapping", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-balances-erc20" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-balances", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-batch" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-blake2" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", +] + +[[package]] +name = "pallet-evm-precompile-bn128" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", + "sp-core", + "substrate-bn", +] + +[[package]] +name = "pallet-evm-precompile-call-permit" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-collective" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-collective", + "pallet-evm", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-conviction-voting" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-conviction-voting", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-crowdloan-rewards" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-crowdloan-rewards", + "pallet-evm", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-dispatch" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", + "frame-support", + "pallet-evm", + "parity-scale-codec", + "sp-runtime", +] + +[[package]] +name = "pallet-evm-precompile-gmp" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "orml-traits", + "orml-xtokens", + "pallet-evm", + "pallet-xcm", + "parity-scale-codec", + "paste", + "precompile-utils", + "slices", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-identity" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "enumflags2", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "pallet-evm", + "pallet-identity", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-modexp" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", + "num", +] + +[[package]] +name = "pallet-evm-precompile-p256verify" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "p256", +] + +[[package]] +name = "pallet-evm-precompile-parachain-staking" +version = "1.0.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-parachain-staking", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-consensus-slots", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-preimage" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-preimage", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-proxy" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-balances", + "pallet-evm", + "pallet-proxy", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-randomness" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "num_enum 0.5.11", + "pallet-evm", + "pallet-randomness", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-referenda" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-referenda", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-registry" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "log", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "pallet-evm-precompile-relay-encoder" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-staking", + "pallet-xcm-transactor", + "parity-scale-codec", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-relay-verifier" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "fp-evm", + "frame-support", + "frame-system", + "moonbeam-runtime-common 0.8.0-dev (git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200)", + "pallet-evm", + "pallet-precompile-benchmarks", + "pallet-relay-storage-roots", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "sp-core", + "sp-std", + "storage-proof-primitives", +] + +[[package]] +name = "pallet-evm-precompile-sha3fips" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", + "tiny-keccak", +] + +[[package]] +name = "pallet-evm-precompile-simple" +version = "2.0.0-dev" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", + "ripemd", + "sp-io", +] + +[[package]] +name = "pallet-evm-precompile-storage-cleaner" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "pallet-evm-precompile-xcm" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.7.2", + "pallet-evm", + "pallet-xcm", + "precompile-utils", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-evm-precompile-xcm-transactor" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-evm", + "pallet-xcm-transactor", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-xcm-utils" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "num_enum 0.5.11", + "pallet-evm", + "pallet-xcm", + "parity-scale-codec", + "precompile-utils", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompile-xtokens" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "orml-xtokens", + "pallet-evm", + "precompile-utils", + "rustc-hex", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-evm-precompileset-assets-erc20" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-assets", + "pallet-balances", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-fast-unstake" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-identity" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "enumflags2", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-maintenance-mode" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-message-queue" +version = "31.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", +] + +[[package]] +name = "pallet-migrations" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "pallet-moonbeam-foreign-assets" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "ethereum-types", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "log", + "pallet-evm", + "parity-scale-codec", + "precompile-utils", + "precompile-utils-macro", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "pallet-moonbeam-lazy-migrations" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-evm", + "pallet-scheduler", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-moonbeam-orbiters" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-multisig" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-parachain-staking" +version = "3.0.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-slots", + "sp-runtime", + "sp-std", + "substrate-fixed", +] + +[[package]] +name = "pallet-parameters" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-storage-weight-reclaim", + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-precompile-benchmarks" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "evm", + "fp-evm", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-evm-precompile-p256verify", + "pallet-relay-storage-roots", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "sp-core", + "sp-std", + "storage-proof-primitives", +] + +[[package]] +name = "pallet-preimage" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-proxy" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-proxy-genesis-companion" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-support", + "frame-system", + "pallet-proxy", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-randomness" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "log", + "nimbus-primitives", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "schnorrkel", + "serde", + "session-keys-primitives", + "sp-consensus-babe", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-referenda" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-relay-storage-roots" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "cumulus-pallet-parachain-system", + "cumulus-primitives-core", + "environmental", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "log", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-root-testing" +version = "4.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-scheduler" +version = "29.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", +] + +[[package]] +name = "pallet-session" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "pallet-society" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "rand_chacha 0.2.2", + "scale-info", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-staking" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "rand_chacha 0.2.2", + "scale-info", + "serde", + "sp-application-crypto", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-staking-reward-fn" +version = "19.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "log", + "sp-arithmetic", +] + +[[package]] +name = "pallet-sudo" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-timestamp" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-std", + "sp-storage", + "sp-timestamp", +] + +[[package]] +name = "pallet-transaction-payment" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-transaction-payment-rpc-runtime-api" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "pallet-transaction-payment", + "parity-scale-codec", + "sp-api", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "pallet-treasury" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-utility" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-vesting" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-whitelist" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-xcm" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bounded-collections", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", +] + +[[package]] +name = "pallet-xcm-benchmarks" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + +[[package]] +name = "pallet-xcm-transactor" +version = "0.2.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "orml-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-primitives 0.1.1", +] + +[[package]] +name = "pallet-xcm-weight-trader" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", +] + +[[package]] +name = "parachains-common" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-support", + "frame-system", + "log", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-message-queue", + "pallet-xcm", + "parity-scale-codec", + "polkadot-primitives", + "scale-info", + "sp-consensus-aura", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-executor", + "substrate-wasm-builder", +] + +[[package]] +name = "parity-bip39" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" +dependencies = [ + "bitcoin_hashes", + "rand 0.7.3", + "rand_core 0.5.1", + "serde", + "unicode-normalization", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parity-wasm" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "password-hash", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + +[[package]] +name = "polkadot-core-primitives" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "polkadot-parachain-primitives" +version = "6.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bounded-collections", + "derive_more", + "parity-scale-codec", + "polkadot-core-primitives", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", + "sp-weights", +] + +[[package]] +name = "polkadot-primitives" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bitvec", + "hex-literal 0.4.1", + "log", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-authority-discovery", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "polkadot-runtime-common" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "libsecp256k1", + "log", + "pallet-asset-rate", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-broker", + "pallet-election-provider-multi-phase", + "pallet-fast-unstake", + "pallet-identity", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-fn", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "pallet-vesting", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-parachains", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "slot-range-helper", + "sp-api", + "sp-core", + "sp-inherents", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "static_assertions", +] + +[[package]] +name = "polkadot-runtime-metrics" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bs58", + "frame-benchmarking", + "parity-scale-codec", + "polkadot-primitives", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "polkadot-runtime-parachains" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bitflags 1.3.2", + "bitvec", + "derive_more", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-broker", + "pallet-message-queue", + "pallet-session", + "pallet-staking", + "pallet-timestamp", + "pallet-vesting", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-primitives", + "polkadot-runtime-metrics", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rustc-hex", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "staging-xcm", + "staging-xcm-executor", + "static_assertions", +] + +[[package]] +name = "polkavm" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3693e5efdb2bf74e449cd25fd777a28bd7ed87e41f5d5da75eb31b4de48b94" +dependencies = [ + "libc", + "log", + "polkavm-assembler", + "polkavm-common", + "polkavm-linux-raw", +] + +[[package]] +name = "polkavm-assembler" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa96d6d868243acc12de813dd48e756cbadcc8e13964c70d272753266deadc1" +dependencies = [ + "log", +] + +[[package]] +name = "polkavm-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9428a5cfcc85c5d7b9fc4b6a18c4b802d0173d768182a51cc7751640f08b92" +dependencies = [ + "log", +] + +[[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", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" +dependencies = [ + "polkavm-common", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[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", + "syn 2.0.66", +] + +[[package]] +name = "polkavm-linker" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" +dependencies = [ + "gimli 0.28.1", + "hashbrown 0.14.3", + "log", + "object 0.32.2", + "polkavm-common", + "regalloc2 0.9.3", + "rustc-demangle", +] + +[[package]] +name = "polkavm-linux-raw" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precompile-foreign-asset-migrator" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "account", + "fp-evm", + "frame-support", + "frame-system", + "log", + "num_enum 0.5.11", + "pallet-asset-manager", + "pallet-assets", + "pallet-balances", + "pallet-evm", + "pallet-moonbeam-foreign-assets", + "pallet-timestamp", + "parity-scale-codec", + "paste", + "precompile-utils", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "xcm-primitives 0.1.0", +] + +[[package]] +name = "precompile-utils" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "derive_more", + "environmental", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "hex", + "hex-literal 0.4.1", + "impl-trait-for-tuples", + "log", + "num_enum 0.7.2", + "pallet-evm", + "parity-scale-codec", + "precompile-utils-macro", + "scale-info", + "serde", + "similar-asserts", + "sp-core", + "sp-io", + "sp-runtime", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "precompile-utils-macro" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/frontier?branch=moonbeam-polkadot-v1.11.0#42a7a8e179bb96401daf6c71728e6c71e38c8293" +dependencies = [ + "case", + "num_enum 0.7.2", + "prettyplease", + "proc-macro2", + "quote", + "sp-crypto-hashing", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.66", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-warning" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.14", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom 0.2.14", + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "regalloc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regalloc2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#665f5f51af5734c7b6d90b985dd6861d4c5b4752" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "arrayvec 0.7.4", + "blake2", + "common", + "fflonk", + "merlin", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.22", +] + +[[package]] +name = "rustix" +version = "0.36.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sc-allocator" +version = "23.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "log", + "sp-core", + "sp-wasm-interface", + "thiserror", +] + +[[package]] +name = "sc-executor" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "log", + "parity-scale-codec", + "parking_lot", + "sc-executor-common", + "sc-executor-polkavm", + "sc-executor-wasmtime", + "schnellru", + "sp-api", + "sp-core", + "sp-externalities", + "sp-io", + "sp-panic-handler", + "sp-runtime-interface", + "sp-trie", + "sp-version", + "sp-wasm-interface", + "tracing", +] + +[[package]] +name = "sc-executor-common" +version = "0.29.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "polkavm", + "sc-allocator", + "sp-maybe-compressed-blob", + "sp-wasm-interface", + "thiserror", + "wasm-instrument", +] + +[[package]] +name = "sc-executor-polkavm" +version = "0.29.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "log", + "polkavm", + "sc-executor-common", + "sp-wasm-interface", +] + +[[package]] +name = "sc-executor-wasmtime" +version = "0.29.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "log", + "parity-scale-codec", + "parking_lot", + "rustix 0.36.17", + "sc-allocator", + "sc-executor-common", + "sp-core", + "sp-runtime-interface", + "sp-wasm-interface", + "wasmtime", +] + +[[package]] +name = "scale-bits" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57b1e7f6b65ed1f04e79a85a57d755ad56d76fdf1e9bddcc9ae14f71fcdcf54" +dependencies = [ + "parity-scale-codec", + "scale-type-resolver", +] + +[[package]] +name = "scale-decode" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12ebca36cec2a3f983c46295b282b35e5f8496346fb859a8776dad5389e5389" +dependencies = [ + "derive_more", + "parity-scale-codec", + "scale-bits", + "scale-type-resolver", + "smallvec", +] + +[[package]] +name = "scale-info" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-type-resolver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.11", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "schnorrkel" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" +dependencies = [ + "aead", + "arrayref", + "arrayvec 0.7.4", + "curve25519-dalek 4.1.2", + "getrandom_or_panic", + "merlin", + "rand_core 0.6.4", + "serde_bytes", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "session-keys-primitives" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "async-trait", + "frame-support", + "nimbus-primitives", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "similar" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +dependencies = [ + "bstr", + "unicode-segmentation", +] + +[[package]] +name = "similar-asserts" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e041bb827d1bfca18f213411d51b665309f1afb37a04a5d1464530e13779fc0f" +dependencies = [ + "console", + "similar", +] + +[[package]] +name = "simple-mermaid" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "620a1d43d70e142b1d46a929af51d44f383db9c7a2ec122de2cd992ccfcf3c18" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "slices" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2086e458a369cdca838e9f6ed04b4cc2e3ce636d99abb80c9e2eada107749cf" +dependencies = [ + "faster-hex", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "slot-range-helper" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "enumn", + "parity-scale-codec", + "paste", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "sp-api" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "scale-info", + "sp-api-proc-macro", + "sp-core", + "sp-externalities", + "sp-metadata-ir", + "sp-runtime", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-version", + "thiserror", +] + +[[package]] +name = "sp-api-proc-macro" +version = "15.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "Inflector", + "blake2", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-application-crypto" +version = "30.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-arithmetic" +version = "23.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "static_assertions", +] + +[[package]] +name = "sp-ark-bls12-381" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-bls12-381-ext", + "sp-crypto-ec-utils", +] + +[[package]] +name = "sp-ark-ed-on-bls12-381-bandersnatch" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-ed-on-bls12-381-bandersnatch-ext", + "sp-crypto-ec-utils", +] + +[[package]] +name = "sp-authority-discovery" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-runtime", +] + +[[package]] +name = "sp-block-builder" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "sp-api", + "sp-inherents", + "sp-runtime", +] + +[[package]] +name = "sp-consensus-aura" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-consensus-slots", + "sp-inherents", + "sp-runtime", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-babe" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-slots" +version = "0.32.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-timestamp", +] + +[[package]] +name = "sp-core" +version = "28.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "array-bytes", + "bandersnatch_vrfs", + "bitflags 1.3.2", + "blake2", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde 0.4.0", + "itertools", + "k256", + "libsecp256k1", + "log", + "merlin", + "parity-bip39", + "parity-scale-codec", + "parking_lot", + "paste", + "primitive-types", + "rand 0.8.5", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-crypto-hashing", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tracing", + "w3f-bls", + "zeroize", +] + +[[package]] +name = "sp-crypto-ec-utils" +version = "0.10.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "ark-bls12-377", + "ark-bls12-377-ext", + "ark-bls12-381", + "ark-bls12-381-ext", + "ark-bw6-761", + "ark-bw6-761-ext", + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ed-on-bls12-377-ext", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", + "ark-scale", + "sp-runtime-interface", +] + +[[package]] +name = "sp-crypto-hashing" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.7", + "sha2 0.10.8", + "sha3", + "twox-hash", +] + +[[package]] +name = "sp-crypto-hashing-proc-macro" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "quote", + "sp-crypto-hashing", + "syn 2.0.66", +] + +[[package]] +name = "sp-debug-derive" +version = "14.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-externalities" +version = "0.25.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-storage", +] + +[[package]] +name = "sp-genesis-builder" +version = "0.8.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde_json", + "sp-api", + "sp-runtime", +] + +[[package]] +name = "sp-inherents" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sp-io" +version = "30.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bytes", + "ed25519-dalek", + "libsecp256k1", + "log", + "parity-scale-codec", + "polkavm-derive", + "rustversion", + "secp256k1", + "sp-core", + "sp-crypto-hashing", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-trie", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-keystore" +version = "0.34.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "parking_lot", + "sp-core", + "sp-externalities", +] + +[[package]] +name = "sp-maybe-compressed-blob" +version = "11.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "thiserror", + "zstd 0.12.4", +] + +[[package]] +name = "sp-metadata-ir" +version = "0.6.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp-npos-elections" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-offchain" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "sp-api", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-panic-handler" +version = "13.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + +[[package]] +name = "sp-runtime" +version = "31.0.1" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "docify", + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand 0.8.5", + "scale-info", + "serde", + "simple-mermaid", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-std", + "sp-weights", +] + +[[package]] +name = "sp-runtime-interface" +version = "24.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "17.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "Inflector", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-session" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-staking", +] + +[[package]] +name = "sp-staking" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-state-machine" +version = "0.35.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot", + "rand 0.8.5", + "smallvec", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-trie", + "thiserror", + "tracing", + "trie-db", +] + +[[package]] +name = "sp-std" +version = "14.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" + +[[package]] +name = "sp-storage" +version = "19.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", +] + +[[package]] +name = "sp-timestamp" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "async-trait", + "parity-scale-codec", + "sp-inherents", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sp-tracing" +version = "16.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-transaction-pool" +version = "26.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "sp-api", + "sp-runtime", +] + +[[package]] +name = "sp-trie" +version = "29.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "ahash 0.8.11", + "hash-db", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot", + "rand 0.8.5", + "scale-info", + "schnellru", + "sp-core", + "sp-externalities", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "29.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-crypto-hashing-proc-macro", + "sp-runtime", + "sp-std", + "sp-version-proc-macro", + "thiserror", +] + +[[package]] +name = "sp-version-proc-macro" +version = "13.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "parity-scale-codec", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "sp-wasm-interface" +version = "20.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "wasmtime", +] + +[[package]] +name = "sp-weights" +version = "27.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "bounded-collections", + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-debug-derive", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "ss58-registry" +version = "1.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4743ce898933fbff7bbf414f497c459a782d496269644b3d650a398ae6a487ba" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "staging-parachain-info" +version = "0.7.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "staging-xcm" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "array-bytes", + "bounded-collections", + "derivative", + "environmental", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-weights", + "xcm-procedural", +] + +[[package]] +name = "staging-xcm-builder" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-transaction-payment", + "parity-scale-codec", + "polkadot-parachain-primitives", + "scale-info", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", + "staging-xcm-executor", +] + +[[package]] +name = "staging-xcm-executor" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "storage-proof-primitives" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.66", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.7" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "schnorrkel", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.5", + "rustc-hex", +] + +[[package]] +name = "substrate-fixed" +version = "0.5.9" +source = "git+https://github.com/encointer/substrate-fixed#879c58bcc6fd676a74315dcd38b598f28708b0b5" +dependencies = [ + "parity-scale-codec", + "scale-info", + "substrate-typenum", +] + +[[package]] +name = "substrate-typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f0091e93c2c75b233ae39424c52cb8a662c0811fb68add149e20e5d7e8a788" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "substrate-wasm-builder" +version = "17.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "array-bytes", + "build-helper", + "cargo_metadata", + "console", + "filetime", + "frame-metadata", + "merkleized-metadata", + "parity-scale-codec", + "parity-wasm", + "polkavm-linker", + "sc-executor", + "sp-core", + "sp-io", + "sp-maybe-compressed-blob", + "sp-tracing", + "sp-version", + "strum 0.26.2", + "tempfile", + "toml 0.8.12", + "walkdir", + "wasm-opt", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix 0.38.32", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.9", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.5", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "trie-db" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c992b4f40c234a074d48a757efeabb1a6be88af84c0c23f7ca158950cb0ae7f" +dependencies = [ + "hash-db", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" +dependencies = [ + "hash-db", +] + +[[package]] +name = "tt-call" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.7", + "rand 0.7.3", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "w3f-bls" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-serialize-derive", + "arrayref", + "constcat", + "digest 0.10.7", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "sha2 0.10.8", + "sha3", + "thiserror", + "zeroize", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-instrument" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a47ecb37b9734d1085eaa5ae1a81e60801fd8c28d4cabdd8aedb982021918bc" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasm-opt" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" +dependencies = [ + "anyhow", + "libc", + "strum 0.24.1", + "strum_macros 0.24.3", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe" +dependencies = [ + "anyhow", + "cc", + "cxx", + "cxx-build", +] + +[[package]] +name = "wasmparser" +version = "0.102.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b" +dependencies = [ + "indexmap 1.9.3", + "url", +] + +[[package]] +name = "wasmtime" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f907fdead3153cb9bfb7a93bbd5b62629472dc06dee83605358c64c52ed3dda9" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "indexmap 1.9.3", + "libc", + "log", + "object 0.30.4", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-cache", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.45.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b9daa7c14cd4fa3edbf69de994408d5f4b7b0959ac13fa69d465f6597f810d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" +dependencies = [ + "anyhow", + "base64 0.21.7", + "bincode", + "directories-next", + "file-per-thread-logger", + "log", + "rustix 0.36.17", + "serde", + "sha2 0.10.8", + "toml 0.5.11", + "windows-sys 0.45.0", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "wasmtime-cranelift" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1cefde0cce8cb700b1b21b6298a3837dba46521affd7b8c38a9ee2c869eee04" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli 0.27.3", + "log", + "object 0.30.4", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd041e382ef5aea1b9fc78442394f1a4f6d676ce457e7076ca4cb3f397882f8b" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-native", + "gimli 0.27.3", + "object 0.30.4", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a990198cee4197423045235bf89d3359e69bd2ea031005f4c2d901125955c949" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli 0.27.3", + "indexmap 1.9.3", + "log", + "object 0.30.4", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de48df552cfca1c9b750002d3e07b45772dd033b0b206d5c0968496abf31244" +dependencies = [ + "addr2line 0.19.0", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli 0.27.3", + "log", + "object 0.30.4", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.45.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" +dependencies = [ + "object 0.30.4", + "once_cell", + "rustix 0.36.17", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658cf6f325232b6760e202e5255d823da5e348fdea827eff0a2a22319000b441" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap 1.9.3", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "rand 0.8.5", + "rustix 0.36.17", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "windows-sys 0.45.0", +] + +[[package]] +name = "wasmtime-types" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f6fffd2a1011887d57f07654dd112791e872e3ff4a2e626aee8059ee17f06f" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wide" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89beec544f246e679fc25490e3f8e08003bc4bf612068f325120dad4cea02c1c" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xcm-fee-payment-runtime-api" +version = "0.1.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "frame-support", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "xcm-primitives" +version = "0.1.0" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-v1.11.0#597e9e5fcbffa1b2436eaf4b9dc436c0b96708f6" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-core", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "xcm-primitives" +version = "0.1.1" +source = "git+https://github.com/moonbeam-foundation/moonbeam?rev=runtime-3200#55688c4e60e1176cdd712f79dc42ba509052b3e7" +dependencies = [ + "cumulus-primitives-core", + "ethereum", + "ethereum-types", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "impl-trait-for-tuples", + "log", + "orml-traits", + "pallet-staking", + "parity-scale-codec", + "polkadot-runtime-common", + "scale-info", + "serde", + "sha3", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + +[[package]] +name = "xcm-procedural" +version = "7.0.0" +source = "git+https://github.com/moonbeam-foundation/polkadot-sdk?branch=moonbeam-polkadot-v1.11.0#125e709e299d83556c21d668660fe37e2e3962cb" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe 6.0.6", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/tracing/3200/Cargo.toml b/tracing/3200/Cargo.toml new file mode 100644 index 00000000..27768611 --- /dev/null +++ b/tracing/3200/Cargo.toml @@ -0,0 +1,461 @@ +[workspace] +members = [ + "runtime/moonbase", + "runtime/moonbeam", + "runtime/moonriver", +] +resolver = "2" + +[workspace.package] +authors = ["PureStake"] +repository = "https://github.com/PureStake/moonbeam" + +[workspace.dependencies] +# Dependencies are split into 2 groups: wasm and client. +# - "wasm" dependencies requires to be no_std compatible, which often requires +# `default-features = false`. When used in a client-side crate the "std" feature should be enabled +# there if it exists. +# - "client" dependencies are only used in the client, and thus don't need to be no_std compatible. + +# Moonbeam (wasm) +account = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +evm-tracing-events = { path = "shared/primitives/rpc/evm-tracing-events", default-features = false , features = ["runtime-1600"] } +moonbeam-core-primitives = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-primitives-ext = { path = "shared/primitives/ext", default-features = false } +moonbeam-rpc-primitives-debug = { path = "shared/primitives/rpc/debug", default-features = false, features = [ + "runtime-3000", +] } +moonbeam-rpc-primitives-txpool = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +storage-proof-primitives = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } + +moonbeam-evm-tracer = { path = "shared/runtime/evm_tracer", default-features = false } +moonbeam-relay-encoder = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-runtime-common = { path = "runtime/common", default-features = false } + +moonbeam-xcm-benchmarks = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-asset-manager = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-erc20-xcm-bridge = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-ethereum-xcm = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-moonbeam-foreign-assets = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-moonbeam-lazy-migrations = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } + +pallet-evm-precompile-author-mapping = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-balances-erc20 = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-batch = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-call-permit = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-collective = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-conviction-voting = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-crowdloan-rewards = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-gmp = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-identity = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-parachain-staking = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-preimage = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-proxy = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-randomness = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-referenda = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-registry = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-relay-encoder = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-relay-verifier = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-xcm-transactor = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-xcm-utils = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-xtokens = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompile-p256verify = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-evm-precompileset-assets-erc20 = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-moonbeam-orbiters = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-parachain-staking = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-precompile-benchmarks = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-proxy-genesis-companion = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-xcm-transactor = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +pallet-xcm-weight-trader = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +precompile-foreign-asset-migrator = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +xcm-primitives = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } + +pallet-crowdloan-rewards = { git = "https://github.com/moonbeam-foundation/crowdloan-rewards", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Moonbeam (client) +moonbeam-cli = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-cli-opt = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-service = { default-features = false , git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } + +moonbeam-client-evm-tracing = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-dev-rpc = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-finality-rpc = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-core-debug = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-core-trace = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-core-txpool = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-core-types = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-debug = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-trace = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-rpc-txpool = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } +moonbeam-vrf = { git = "https://github.com/moonbeam-foundation/moonbeam", rev = "runtime-3200" } + +moonbase-runtime = { path = "runtime/moonbase" } +moonbeam-runtime = { path = "runtime/moonbeam" } +moonriver-runtime = { path = "runtime/moonriver" } + +frame-benchmarking = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-executive = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-support = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-system = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-system-benchmarking = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-system-rpc-runtime-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +frame-try-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-assets = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-balances = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-collective = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-conviction-voting = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-identity = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-message-queue = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-multisig = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-preimage = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-parameters = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-proxy = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-referenda = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-root-testing = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-scheduler = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-society = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-staking = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-sudo = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-transaction-payment = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-treasury = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-utility = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-whitelist = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +parity-scale-codec = { version = "3.2.2", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.0", default-features = false, features = [ + "derive", +] } +sp-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-application-crypto = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-block-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-consensus-babe = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-consensus-slots = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-core = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-debug-derive = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-externalities = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-inherents = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-io = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-keystore = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-offchain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-runtime-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-session = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-std = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-state-machine = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-tracing = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-transaction-pool = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-trie = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-version = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-weights = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +sp-genesis-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", default-features = false } + +# Substrate (client) +frame-benchmarking-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +pallet-transaction-payment-rpc = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-basic-authorship = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-block-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-chain-spec = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-client-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-client-db = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-consensus = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-consensus-grandpa = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-consensus-manual-seal = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-executor = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-informant = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-network = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-network-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-network-sync = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-offchain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-rpc = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-rpc-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-service = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-sysinfo = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-telemetry = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-tracing = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-transaction-pool = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-transaction-pool-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sc-utils = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-blockchain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-consensus = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-storage = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-wasm-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +sp-rpc = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-build-script-utils = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-frame-rpc-system = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-prometheus-endpoint = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-test-client = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-test-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-test-runtime-client = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-wasm-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +substrate-rpc-client = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } + +# Frontier (wasm) + +ethereum = { version = "0.15.0", default-features = false, features = [ + "with-codec", +] } +ethereum-types = { version = "0.14", default-features = false } +evm = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +evm-gasometer = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +evm-runtime = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-ethereum = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-evm = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-rpc = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +fp-self-contained = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-ethereum = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false, features = [ + "forbid-evm-reentrancy", +] } +pallet-evm = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false, features = [ + "forbid-evm-reentrancy", +] } +pallet-evm-chain-id = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-blake2 = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-bn128 = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-dispatch = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-modexp = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-sha3fips = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-simple = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-storage-cleaner = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +precompile-utils = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +precompile-utils-macro = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + + +# Frontier (client) +fc-consensus = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-db = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-api = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-mapping-sync = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-rpc = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0", features = [ + "rpc-binary-search-estimate", +] } +fc-rpc-core = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fc-storage = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fp-consensus = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } +fp-storage = { git = "https://github.com/moonbeam-foundation/frontier", branch = "moonbeam-polkadot-v1.11.0" } + +# Cumulus (wasm) + +cumulus-pallet-dmp-queue = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-pallet-parachain-system = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false, features = [ + "parameterized-consensus-hook", +] } +cumulus-pallet-xcm = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-pallet-xcmp-queue = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-core = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-parachain-inherent = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-test-relay-sproof-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +cumulus-primitives-storage-weight-reclaim = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +parachain-info = { package = "staging-parachain-info", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +parachains-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Cumulus (client) +cumulus-client-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-collator = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-consensus-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-consensus-proposer = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-consensus-relay-chain = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-network = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-service = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-client-parachain-inherent = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-inprocess-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-minimal-node = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +cumulus-relay-chain-rpc-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } + +# Polkadot / XCM (wasm) +orml-traits = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +orml-xcm-support = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +orml-xtokens = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-xcm = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-xcm-benchmarks = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-core-primitives = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-parachain = { package = "polkadot-parachain-primitives", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-runtime-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +polkadot-runtime-parachains = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm = { package = "staging-xcm", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +xcm-fee-payment-runtime-api = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Polkadot / XCM (client) +#kusama-runtime = { package = "staging-kusama-runtime", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +polkadot-cli = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +polkadot-primitives = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +#polkadot-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +polkadot-service = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +rococo-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +westend-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } +xcm-simulator = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } + +# Moonkit (wasm) +async-backing-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +moonkit-xcm-primitives = { package = "xcm-primitives", git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +nimbus-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-async-backing = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-author-inherent = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-author-mapping = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-author-slot-filter = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-emergency-para-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-evm-precompile-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-maintenance-mode = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-migrations = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-randomness = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +pallet-relay-storage-roots = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +session-keys-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0", default-features = false } + +# Moonkit (client) +nimbus-consensus = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-v1.11.0" } + +# Other (wasm) +async-trait = { version = "0.1.42" } +blake2-rfc = { version = "0.2.18", default-features = false } +derive_more = "0.99" +environmental = { version = "1.1.2", default-features = false } +frame-metadata = { version = "16.0.0", default-features = false, features = [ + "current", +] } +frame-metadata-hash-extension = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false } +hex = { version = "0.4.3", default-features = false } +hex-literal = { version = "0.3.4" } +impl-serde = { version = "0.3.1", default-features = false } +impl-trait-for-tuples = "0.2.1" +libsecp256k1 = { version = "0.7", default-features = false } +log = { version = "0.4", default-features = false } +num_enum = { version = "0.5.3", default-features = false } +paste = "1.0.6" +rlp = { version = "0.5", default-features = false } +rustc-hex = { version = "2.0.1", default-features = false } +serde = { version = "1.0.101", default-features = false } +sha3 = { version = "0.10", default-features = false } +slices = "0.2.0" +smallvec = "1.8.0" +strum = { version = "0.24", default-features = false, features = ["derive"] } +strum_macros = "0.24" +p256 = { version = "0.13.2", default-features = false, features = ["ecdsa"] } + +# Other (client) + +assert_cmd = "2.0.10" +async-io = "1.3" +bip32 = { version = "0.5.1", default-features = false, features = ["bip39"] } +clap = { version = "4.0.9", features = ["derive"] } +clap-num = "=1.1.1" +exit-future = "0.2" +flume = "0.10.9" +futures = { version = "0.3.21" } +jsonrpsee = { version = "0.22.5", default-features = false } +maplit = "1.0.2" +nix = "0.23" +parking_lot = "0.12.0" +primitive-types = "0.12.0" +prometheus = { version = "0.13.0", default-features = false } +rand = "0.8.5" +serde_json = { version = "1.0" } +similar-asserts = "1.1.0" +tempfile = "3.2.0" +tiny-bip39 = { version = "0.8", default-features = false } +schnorrkel = { version = "0.11.4", default-features = false, features = [ + "preaudit_deprecated", +] } +tokio = { version = "1.36" } +tokio-retry = { version = "0.3.0" } +tracing = "0.1.34" +tracing-core = "0.1.29" +trie-root = "0.15.2" +url = "2.2.2" +thiserror = "1.0.63" + +# The list of dependencies below (which can be both direct and indirect dependencies) are crates +# that are suspected to be CPU-intensive, and that are unlikely to require debugging (as some of +# their debug info might be missing) or to require to be frequently recompiled. We compile these +# dependencies with `opt-level=3` even in "dev" mode in order to make "dev" mode more usable. +# The majority of these crates are cryptographic libraries. +# +# Note that this does **not** affect crates that depend on Moonbeam. In other words, if you add +# a dependency on Moonbeam, you have to copy-paste this list in your own `Cargo.toml` (assuming +# that you want the same list). This list is only relevant when running `cargo build` from within +# the Moonbeam workspace. +# +# If you see an error mentioning "profile package spec ... did not match any packages", it +# probably concerns this list. +# +# This list is ordered alphabetically. +[profile.dev.package] +blake2 = { opt-level = 3 } +blake2b_simd = { opt-level = 3 } +chacha20poly1305 = { opt-level = 3 } +cranelift-codegen = { opt-level = 3 } +cranelift-wasm = { opt-level = 3 } +crc32fast = { opt-level = 3 } +crossbeam-deque = { opt-level = 3 } +crypto-mac = { opt-level = 3 } +curve25519-dalek = { opt-level = 3 } +ed25519-zebra = { opt-level = 3 } +flate2 = { opt-level = 3 } +futures-channel = { opt-level = 3 } +hash-db = { opt-level = 3 } +hashbrown = { opt-level = 3 } +hmac = { opt-level = 3 } +httparse = { opt-level = 3 } +integer-sqrt = { opt-level = 3 } +k256 = { opt-level = 3 } +keccak = { opt-level = 3 } +libm = { opt-level = 3 } +librocksdb-sys = { opt-level = 3 } +libsecp256k1 = { opt-level = 3 } +libz-sys = { opt-level = 3 } +mio = { opt-level = 3 } +nalgebra = { opt-level = 3 } +num-bigint = { opt-level = 3 } +parking_lot = { opt-level = 3 } +parking_lot_core = { opt-level = 3 } +percent-encoding = { opt-level = 3 } +primitive-types = { opt-level = 3 } +ring = { opt-level = 3 } +rustls = { opt-level = 3 } +secp256k1 = { opt-level = 3 } +sha2 = { opt-level = 3 } +sha3 = { opt-level = 3 } +smallvec = { opt-level = 3 } +snow = { opt-level = 3 } +twox-hash = { opt-level = 3 } +uint = { opt-level = 3 } +wasmi = { opt-level = 3 } +x25519-dalek = { opt-level = 3 } +yamux = { opt-level = 3 } +zeroize = { opt-level = 3 } + +# make sure dev builds with backtrace do +# not slow us down +[profile.dev.package.backtrace] +inherits = "release" + +[profile.production] +codegen-units = 1 +incremental = false +inherits = "release" +lto = true + +[profile.release] +debug-assertions = true # Enable debug-assert! for non-production profiles +opt-level = 3 +# Moonbeam runtime requires unwinding. +panic = "unwind" + +[profile.testnet] +debug = 1 # debug symbols are useful for profilers +debug-assertions = true # Enable debug-assert! for non-production profiles +inherits = "release" +overflow-checks = true + +[patch."https://github.com/paritytech/polkadot-sdk"] +sp-crypto-ec-utils = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" } diff --git a/tracing/3200/runtime/common/Cargo.toml b/tracing/3200/runtime/common/Cargo.toml new file mode 100644 index 00000000..66f0f925 --- /dev/null +++ b/tracing/3200/runtime/common/Cargo.toml @@ -0,0 +1,168 @@ +[package] +authors = { workspace = true } +description = "Common code shared between runtimes" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonbeam-runtime-common" +version = "0.8.0-dev" + +[dependencies] +hex-literal = "0.3.4" +impl-trait-for-tuples = "0.2.1" +log = "0.4" + +# Moonbeam +moonbeam-core-primitives = { workspace = true } +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-migrations = { workspace = true } +pallet-moonbeam-foreign-assets = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-randomness = { workspace = true } +pallet-relay-storage-roots = { workspace = true } +pallet-xcm-transactor = { workspace = true } +pallet-xcm-weight-trader = { workspace = true } +xcm-primitives = { workspace = true } + +# Substrate +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +pallet-message-queue = { workspace = true } +frame-benchmarking = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true } +pallet-collective = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-identity = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-parameters = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +pallet-xcm = { workspace = true } +sp-api = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-genesis-builder = { workspace = true } +frame-try-runtime = { workspace = true } + +# Frontier +fp-ethereum = { workspace = true } +fp-evm = { workspace = true } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-chain-id = { workspace = true } +precompile-utils = { workspace = true } + +# Moonkit +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } + +# Polkadot +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } + +# Parity +parity-scale-codec = { workspace = true } + +account = { workspace = true } + +[features] +std = [ + "cumulus-pallet-parachain-system/std", + "fp-ethereum/std", + "fp-evm/std", + "frame-support/std", + "moonbeam-core-primitives/std", + "pallet-asset-manager/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-ethereum-xcm/std", + "pallet-evm/std", + "pallet-migrations/std", + "pallet-parachain-staking/std", + "pallet-parameters/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-scheduler/std", + "pallet-xcm-transactor/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-identity/std", + "pallet-transaction-payment/std", + "pallet-xcm-weight-trader/std", + "pallet-message-queue/std", + "parity-scale-codec/std", + "precompile-utils/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", + "sp-genesis-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm/std", + "account/std", +] +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-parameters/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", +] +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "frame-support/try-runtime", + "pallet-migrations/try-runtime", +] diff --git a/tracing/3200/runtime/common/src/apis.rs b/tracing/3200/runtime/common/src/apis.rs new file mode 100644 index 00000000..f7df98d1 --- /dev/null +++ b/tracing/3200/runtime/common/src/apis.rs @@ -0,0 +1,1123 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_runtime_apis_plus_common { + {$($custom:tt)*} => { + + #[cfg(feature = "evm-tracing")] + // Helper function to replay the "on_idle" hook for all pallets, we need this for + // evm-tracing because some ethereum-xcm transactions might be executed at on_idle. + // + // We need to make sure that we replay on_idle exactly the same way as the + // original block execution, but unfortunatly frame executive diosn't provide a function + // to replay only on_idle, so we need to copy here some code inside frame executive. + fn replay_on_idle() { + use frame_system::pallet_prelude::BlockNumberFor; + use frame_support::traits::OnIdle; + + let weight = >::block_weight(); + let max_weight = < + ::BlockWeights as + frame_support::traits::Get<_> + >::get().max_block; + let remaining_weight = max_weight.saturating_sub(weight.total()); + if remaining_weight.all_gt(Weight::zero()) { + let _ = >>::on_idle( + >::block_number(), + remaining_weight, + ); + } + } + + impl_runtime_apis! { + $($custom)* + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> Vec { + Runtime::metadata_versions() + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics( + data: sp_inherents::InherentData, + ) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn decode_session_keys( + encoded: Vec, + ) -> Option, sp_core::crypto::KeyTypeId)>> { + opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + } + + fn generate_session_keys(seed: Option>) -> Vec { + opaque::SessionKeys::generate(seed) + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn build_state(config: Vec) -> sp_genesis_builder::Result { + frame_support::genesis_builder_helper::build_state::(config) + } + + fn get_preset(id: &Option) -> Option> { + frame_support::genesis_builder_helper::get_preset::(id, |_| None) + } + + fn preset_names() -> Vec { + vec![] + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl moonbeam_rpc_primitives_debug::DebugRuntimeApi for Runtime { + fn trace_transaction( + extrinsics: Vec<::Extrinsic>, + traced_transaction: &EthereumTransaction, + header: &::Header, + ) -> Result< + (), + sp_runtime::DispatchError, + > { + #[cfg(feature = "evm-tracing")] + { + use moonbeam_evm_tracer::tracer::EvmTracer; + use xcm_primitives::{ + ETHEREUM_XCM_TRACING_STORAGE_KEY, + EthereumXcmTracingStatus + }; + use frame_support::storage::unhashed; + use frame_system::pallet_prelude::BlockNumberFor; + + // Tell the CallDispatcher we are tracing a specific Transaction. + unhashed::put::( + ETHEREUM_XCM_TRACING_STORAGE_KEY, + &EthereumXcmTracingStatus::Transaction(traced_transaction.hash()), + ); + + // Initialize block: calls the "on_initialize" hook on every pallet + // in AllPalletsWithSystem. + // After pallet message queue was introduced, this must be done only after + // enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY + // in the storage + Executive::initialize_block(header); + + // Apply the a subset of extrinsics: all the substrate-specific or ethereum + // transactions that preceded the requested transaction. + for ext in extrinsics.into_iter() { + let _ = match &ext.0.function { + RuntimeCall::Ethereum(transact { transaction }) => { + if transaction == traced_transaction { + EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); + return Ok(()); + } else { + Executive::apply_extrinsic(ext) + } + } + _ => Executive::apply_extrinsic(ext), + }; + if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + return Ok(()); + } + } + + if let Some(EthereumXcmTracingStatus::Transaction(_)) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // If the transaction was not found, it might be + // an eth-xcm transaction that was executed at on_idle + replay_on_idle(); + } + + if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // The transaction was found + Ok(()) + } else { + // The transaction was not-found + Err(sp_runtime::DispatchError::Other( + "Failed to find Ethereum transaction among the extrinsics.", + )) + } + } + #[cfg(not(feature = "evm-tracing"))] + Err(sp_runtime::DispatchError::Other( + "Missing `evm-tracing` compile time feature flag.", + )) + } + + fn trace_block( + extrinsics: Vec<::Extrinsic>, + known_transactions: Vec, + header: &::Header, + ) -> Result< + (), + sp_runtime::DispatchError, + > { + #[cfg(feature = "evm-tracing")] + { + use moonbeam_evm_tracer::tracer::EvmTracer; + use frame_system::pallet_prelude::BlockNumberFor; + use xcm_primitives::EthereumXcmTracingStatus; + + // Tell the CallDispatcher we are tracing a full Block. + frame_support::storage::unhashed::put::( + xcm_primitives::ETHEREUM_XCM_TRACING_STORAGE_KEY, + &EthereumXcmTracingStatus::Block, + ); + + let mut config = ::config().clone(); + config.estimate = true; + + // Initialize block: calls the "on_initialize" hook on every pallet + // in AllPalletsWithSystem. + // After pallet message queue was introduced, this must be done only after + // enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY + // in the storage + Executive::initialize_block(header); + + // Apply all extrinsics. Ethereum extrinsics are traced. + for ext in extrinsics.into_iter() { + match &ext.0.function { + RuntimeCall::Ethereum(transact { transaction }) => { + if known_transactions.contains(&transaction.hash()) { + // Each known extrinsic is a new call stack. + EvmTracer::emit_new(); + EvmTracer::new().trace(|| Executive::apply_extrinsic(ext)); + } else { + let _ = Executive::apply_extrinsic(ext); + } + } + _ => { + let _ = Executive::apply_extrinsic(ext); + } + }; + } + + // Replay on_idle + // Some XCM messages with eth-xcm transaction might be executed at on_idle + replay_on_idle(); + + Ok(()) + } + #[cfg(not(feature = "evm-tracing"))] + Err(sp_runtime::DispatchError::Other( + "Missing `evm-tracing` compile time feature flag.", + )) + } + + fn trace_call( + header: &::Header, + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + access_list: Option)>>, + ) -> Result<(), sp_runtime::DispatchError> { + #[cfg(feature = "evm-tracing")] + { + use moonbeam_evm_tracer::tracer::EvmTracer; + + // Initialize block: calls the "on_initialize" hook on every pallet + // in AllPalletsWithSystem. + Executive::initialize_block(header); + + EvmTracer::new().trace(|| { + let is_transactional = false; + let validate = true; + let without_base_extrinsic_weight = true; + + + // Estimated encoded transaction size must be based on the heaviest transaction + // type (EIP1559Transaction) to be compatible with all transaction types. + let mut estimated_transaction_len = data.len() + + // pallet ethereum index: 1 + // transact call index: 1 + // Transaction enum variant: 1 + // chain_id 8 bytes + // nonce: 32 + // max_priority_fee_per_gas: 32 + // max_fee_per_gas: 32 + // gas_limit: 32 + // action: 21 (enum varianrt + call address) + // value: 32 + // access_list: 1 (empty vec size) + // 65 bytes signature + 258; + + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + let _ = ::Runner::call( + from, + to, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + ::config(), + ); + }); + Ok(()) + } + #[cfg(not(feature = "evm-tracing"))] + Err(sp_runtime::DispatchError::Other( + "Missing `evm-tracing` compile time feature flag.", + )) + } + } + + impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi for Runtime { + fn extrinsic_filter( + xts_ready: Vec<::Extrinsic>, + xts_future: Vec<::Extrinsic>, + ) -> TxPoolResponse { + TxPoolResponse { + ready: xts_ready + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + future: xts_future + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + } + } + } + + impl fp_rpc::EthereumRuntimeRPCApi for Runtime { + fn chain_id() -> u64 { + ::ChainId::get() + } + + fn account_basic(address: H160) -> EVMAccount { + let (account, _) = EVM::account_basic(&address); + account + } + + fn gas_price() -> U256 { + let (gas_price, _) = ::FeeCalculator::min_gas_price(); + gas_price + } + + fn account_code_at(address: H160) -> Vec { + pallet_evm::AccountCodes::::get(address) + } + + fn author() -> H160 { + >::find_author() + } + + fn storage_at(address: H160, index: U256) -> H256 { + let mut tmp = [0u8; 32]; + index.to_big_endian(&mut tmp); + pallet_evm::AccountStorages::::get(address, H256::from_slice(&tmp[..])) + } + + fn call( + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + let is_transactional = false; + let validate = true; + + // Estimated encoded transaction size must be based on the heaviest transaction + // type (EIP1559Transaction) to be compatible with all transaction types. + let mut estimated_transaction_len = data.len() + + // pallet ethereum index: 1 + // transact call index: 1 + // Transaction enum variant: 1 + // chain_id 8 bytes + // nonce: 32 + // max_priority_fee_per_gas: 32 + // max_fee_per_gas: 32 + // gas_limit: 32 + // action: 21 (enum varianrt + call address) + // value: 32 + // access_list: 1 (empty vec size) + // 65 bytes signature + 258; + + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = gas_limit.min(u64::MAX.into()).low_u64(); + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + ::Runner::call( + from, + to, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn create( + from: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + estimate: bool, + access_list: Option)>>, + ) -> Result { + let config = if estimate { + let mut config = ::config().clone(); + config.estimate = true; + Some(config) + } else { + None + }; + let is_transactional = false; + let validate = true; + + let mut estimated_transaction_len = data.len() + + // from: 20 + // value: 32 + // gas_limit: 32 + // nonce: 32 + // 1 byte transaction action variant + // chain id 8 bytes + // 65 bytes signature + 190; + + if max_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if max_priority_fee_per_gas.is_some() { + estimated_transaction_len += 32; + } + if access_list.is_some() { + estimated_transaction_len += access_list.encoded_size(); + } + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + u64::MAX + } else { + gas_limit.low_u64() + }; + let without_base_extrinsic_weight = true; + + let (weight_limit, proof_size_base_cost) = + match ::GasWeightMapping::gas_to_weight( + gas_limit, + without_base_extrinsic_weight + ) { + weight_limit if weight_limit.proof_size() > 0 => { + (Some(weight_limit), Some(estimated_transaction_len as u64)) + } + _ => (None, None), + }; + + #[allow(clippy::or_fun_call)] // suggestion not helpful here + ::Runner::create( + from, + data, + value, + gas_limit, + max_fee_per_gas, + max_priority_fee_per_gas, + nonce, + access_list.unwrap_or_default(), + is_transactional, + validate, + weight_limit, + proof_size_base_cost, + config.as_ref().unwrap_or(::config()), + ).map_err(|err| err.error.into()) + } + + fn current_transaction_statuses() -> Option> { + pallet_ethereum::CurrentTransactionStatuses::::get() + } + + fn current_block() -> Option { + pallet_ethereum::CurrentBlock::::get() + } + + fn current_receipts() -> Option> { + pallet_ethereum::CurrentReceipts::::get() + } + + fn current_all() -> ( + Option, + Option>, + Option>, + ) { + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentReceipts::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get(), + ) + } + + fn extrinsic_filter( + xts: Vec<::Extrinsic>, + ) -> Vec { + xts.into_iter().filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None + }).collect::>() + } + + fn elasticity() -> Option { + None + } + + fn gas_limit_multiplier_support() {} + + fn pending_block( + xts: Vec<::Extrinsic> + ) -> ( + Option, Option> + ) { + for ext in xts.into_iter() { + let _ = Executive::apply_extrinsic(ext); + } + + Ethereum::on_finalize(System::block_number() + 1); + + ( + pallet_ethereum::CurrentBlock::::get(), + pallet_ethereum::CurrentTransactionStatuses::::get() + ) + } + + fn initialize_pending_block(header: &::Header) { + pallet_randomness::vrf::using_fake_vrf(|| { + let _ = Executive::initialize_block(header); + }) + } + } + + impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { + fn convert_transaction( + transaction: pallet_ethereum::Transaction + ) -> ::Extrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl nimbus_primitives::NimbusApi for Runtime { + fn can_author( + author: nimbus_primitives::NimbusId, + slot: u32, + parent_header: &::Header + ) -> bool { + use pallet_parachain_staking::Config as PalletParachainStakingConfig; + + let block_number = parent_header.number + 1; + + // The Moonbeam runtimes use an entropy source that needs to do some accounting + // work during block initialization. Therefore we initialize it here to match + // the state it will be in when the next block is being executed. + use frame_support::traits::OnInitialize; + System::initialize( + &block_number, + &parent_header.hash(), + &parent_header.digest, + ); + + // Because the staking solution calculates the next staking set at the beginning + // of the first block in the new round, the only way to accurately predict the + // authors is to compute the selection during prediction. + if pallet_parachain_staking::Pallet::::round() + .should_update(block_number) { + // get author account id + use nimbus_primitives::AccountLookup; + let author_account_id = if let Some(account) = + pallet_author_mapping::Pallet::::lookup_account(&author) { + account + } else { + // return false if author mapping not registered like in can_author impl + return false + }; + let candidates = pallet_parachain_staking::Pallet::::compute_top_candidates(); + if candidates.is_empty() { + // If there are zero selected candidates, we use the same eligibility + // as the previous round + return AuthorInherent::can_author(&author, &slot); + } + + // predict eligibility post-selection by computing selection results now + let (eligible, _) = + pallet_author_slot_filter::compute_pseudo_random_subset::( + candidates, + &slot + ); + eligible.contains(&author_account_id) + } else { + AuthorInherent::can_author(&author, &slot) + } + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info( + header: &::Header + ) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + impl session_keys_primitives::VrfApi for Runtime { + fn get_last_vrf_output() -> Option<::Hash> { + // TODO: remove in future runtime upgrade along with storage item + if pallet_randomness::Pallet::::not_first_block().is_none() { + return None; + } + pallet_randomness::Pallet::::local_vrf_output() + } + fn vrf_key_lookup( + nimbus_id: nimbus_primitives::NimbusId + ) -> Option { + use session_keys_primitives::KeysLookup; + AuthorMapping::lookup_keys(&nimbus_id) + } + } + + impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets( + xcm_version: xcm::Version + ) -> Result, XcmPaymentApiError> { + XcmWeightTrader::query_acceptable_payment_assets(xcm_version) + } + + fn query_weight_to_asset_fee( + weight: Weight, asset: VersionedAssetId + ) -> Result { + XcmWeightTrader::query_weight_to_asset_fee(weight, asset) + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees( + destination: VersionedLocation, message: VersionedXcm<()> + ) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; + use moonbeam_xcm_benchmarks::generic::benchmarking as MoonbeamXcmBenchmarks; + use frame_support::traits::StorageInfoTrait; + use MoonbeamXcmBenchmarks::XcmGenericBenchmarks as MoonbeamXcmGenericBench; + + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + + return (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig, + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{add_benchmark, BenchmarkBatch, Benchmarking}; + use frame_support::traits::TrackedStorageKey; + use cumulus_primitives_core::ParaId; + + use xcm::latest::prelude::{ + GeneralIndex, Junction, Junctions, Location, Response, NetworkId, AssetId, + Assets as XcmAssets, Fungible, Asset, ParentThen, Parachain, Parent + }; + use xcm_config::SelfReserve; + use frame_benchmarking::BenchmarkError; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime {} + + impl moonbeam_xcm_benchmarks::Config for Runtime {} + impl moonbeam_xcm_benchmarks::generic::Config for Runtime {} + + use pallet_asset_manager::Config as PalletAssetManagerConfig; + + use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; + parameter_types! { + pub const RandomParaId: ParaId = ParaId::new(43211234); + } + + pub struct TestDeliveryHelper; + impl xcm_builder::EnsureDelivery for TestDeliveryHelper { + fn ensure_successful_delivery( + origin_ref: &Location, + _dest: &Location, + _fee_reason: xcm_executor::traits::FeeReason, + ) -> (Option, Option) { + use xcm_executor::traits::ConvertLocation; + let account = xcm_config::LocationToH160::convert_location(origin_ref) + .expect("Invalid location"); + // Give the existential deposit at least + let balance = ExistentialDeposit::get(); + let _ = >:: + make_free_balance_be(&account.into(), balance); + + (None, None) + } + } + + impl pallet_xcm::benchmarking::Config for Runtime { + type DeliveryHelper = TestDeliveryHelper; + + fn get_asset() -> Asset { + Asset { + id: AssetId(SelfReserve::get()), + fun: Fungible(ExistentialDeposit::get()), + } + } + + fn reachable_dest() -> Option { + Some(Parent.into()) + } + + fn teleportable_asset_and_dest() -> Option<(Asset, Location)> { + None + } + + fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { + use xcm_config::SelfReserve; + + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( + RandomParaId::get().into() + ); + + Some(( + Asset { + fun: Fungible(ExistentialDeposit::get()), + id: AssetId(SelfReserve::get().into()) + }, + // Moonbeam can reserve transfer native token to + // some random parachain. + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), + )) + } + + fn set_up_complex_asset_transfer( + ) -> Option<(XcmAssets, u32, Location, Box)> { + use xcm_config::SelfReserve; + + let destination: xcm::v4::Location = Parent.into(); + + let fee_amount: u128 = ::ExistentialDeposit::get(); + let fee_asset: Asset = (SelfReserve::get(), fee_amount).into(); + + // Give some multiple of transferred amount + let balance = fee_amount * 1000; + let who = frame_benchmarking::whitelisted_caller(); + let _ = + >::make_free_balance_be(&who, balance); + + // verify initial balance + assert_eq!(Balances::free_balance(&who), balance); + + // set up local asset + let asset_amount: u128 = 10u128; + let initial_asset_amount: u128 = asset_amount * 10; + + let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::< + Runtime, + () + >(true, initial_asset_amount); + let transfer_asset: Asset = (SelfReserve::get(), asset_amount).into(); + + let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into(); + let fee_index: u32 = 0; + + let verify: Box = Box::new(move || { + // verify balance after transfer, decreased by + // transferred amount (and delivery fees) + assert!(Balances::free_balance(&who) <= balance - fee_amount); + }); + + Some((assets, fee_index, destination, verify)) + } + } + + impl pallet_xcm_benchmarks::Config for Runtime { + type XcmConfig = xcm_config::XcmExecutorConfig; + type AccountIdConverter = xcm_config::LocationToAccountId; + type DeliveryHelper = (); + fn valid_destination() -> Result { + Ok(Location::parent()) + } + fn worst_case_holding(_depositable_count: u32) -> XcmAssets { + // 100 fungibles + const HOLDING_FUNGIBLES: u32 = 100; + let fungibles_amount: u128 = 100; + let assets = (0..HOLDING_FUNGIBLES).map(|i| { + let location: Location = GeneralIndex(i as u128).into(); + Asset { + id: AssetId(location), + fun: Fungible(fungibles_amount * i as u128), + } + .into() + }) + .chain( + core::iter::once( + Asset { + id: AssetId(Location::parent()), + fun: Fungible(u128::MAX) + } + ) + ) + .collect::>(); + + + for (i, asset) in assets.iter().enumerate() { + if let Asset { + id: AssetId(location), + fun: Fungible(_) + } = asset { + EvmForeignAssets::set_asset( + location.clone(), + i as u128 + ); + XcmWeightTrader::set_asset_price( + location.clone(), + 1u128.pow(18) + ); + } + } + assets.into() + } + } + + impl pallet_xcm_benchmarks::generic::Config for Runtime { + type RuntimeCall = RuntimeCall; + type TransactAsset = Balances; + + fn worst_case_response() -> (u64, Response) { + (0u64, Response::Version(Default::default())) + } + + fn worst_case_asset_exchange() + -> Result<(XcmAssets, XcmAssets), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn universal_alias() -> Result<(Location, Junction), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn export_message_origin_and_destination() + -> Result<(Location, NetworkId, Junctions), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn transact_origin_and_runtime_call() + -> Result<(Location, RuntimeCall), BenchmarkError> { + Ok((Location::parent(), frame_system::Call::remark_with_event { + remark: vec![] + }.into())) + } + + fn subscribe_origin() -> Result { + Ok(Location::parent()) + } + + fn claimable_asset() + -> Result<(Location, Location, XcmAssets), BenchmarkError> { + let origin = Location::parent(); + let assets: XcmAssets = (AssetId(Location::parent()), 1_000u128) + .into(); + let ticket = Location { parents: 0, interior: [].into() /* Here */ }; + Ok((origin, ticket, assets)) + } + + fn fee_asset() -> Result { + Err(BenchmarkError::Skip) + } + + fn unlockable_asset() + -> Result<(Location, Location, Asset), BenchmarkError> { + Err(BenchmarkError::Skip) + } + + fn alias_origin() -> Result<(Location, Location), BenchmarkError> { + Err(BenchmarkError::Skip) + } + } + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "02a5c1b19ab7a04f536c519aca4983ac") + .to_vec().into(), + // Total Issuance + hex_literal::hex!( "c2261276cc9d1f8598ea4b6a74b15c2f" + "57c875e4cff74148e4628f264b974c80") + .to_vec().into(), + // Execution Phase + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "ff553b5a9862a516939d82b3d3d8661a") + .to_vec().into(), + // Event Count + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "0a98fdbe9ce6c55837576c60c7af3850") + .to_vec().into(), + // System Events + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "80d41e5e16056765bc8461851072c9d7") + .to_vec().into(), + // System BlockWeight + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "34abf5cb34d6244378cddbf18e849d96") + .to_vec().into(), + // ParachainStaking Round + hex_literal::hex!( "a686a3043d0adcf2fa655e57bc595a78" + "13792e785168f725b60e2969c7fc2552") + .to_vec().into(), + // Treasury Account (py/trsry) + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "b99d880ec681799c0cf30e8886371da9" + "7be2919ac397ba499ea5e57132180ec6" + "6d6f646c70792f747273727900000000" + "00000000" + ).to_vec().into(), + // Treasury Account (pc/trsry) + hex_literal::hex!( "26aa394eea5630e07c48ae0c9558cef7" + "b99d880ec681799c0cf30e8886371da9" + "7be2919ac397ba499ea5e57132180ec6" + "6d6f646c70632f747273727900000000" + "00000000" + ).to_vec().into(), + // ParachainInfo ParachainId + hex_literal::hex!( "0d715f2646c8f85767b5d2764bb27826" + "04a74d81251e398fd8a0a4d55023bb3f") + .to_vec().into(), + // Parameters Parameters + hex_literal::hex!( "c63bdd4a39095ccf55623a6f2872bf8a" // Pallet: "Parameters" + "c63bdd4a39095ccf55623a6f2872bf8a" // Storage Prefix: "Parameters" + // MoonbaseRuntimeRuntimeParamsRuntimeParametersKey(FeesTreasuryProportion) + "71d0aacb690b61280d0c97c6b6a666640000" + ) + .to_vec().into(), + + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + add_benchmarks!(params, batches); + + if batches.is_empty() { + return Err("Benchmark not found for this pallet.".into()); + } + Ok(batches) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade()"); + // NOTE: intentional expect: we don't want to propagate the error backwards, + // and want to have a backtrace here. If any of the pre/post migration checks + // fail, we shall stop right here and right now. + let weight = Executive::try_runtime_upgrade(checks) + .expect("runtime upgrade logic *must* be infallible"); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect + ) -> Weight { + log::info!( + "try-runtime: executing block {:?} / root checks: {:?} / try-state-select: {:?}", + block.header.hash(), + state_root_check, + select, + ); + // NOTE: intentional unwrap: we don't want to propagate the error backwards, + // and want to have a backtrace here. + Executive::try_execute_block( + block, + state_root_check, + signature_check, + select, + ).expect("execute-block failed") + } + } + } + }; +} diff --git a/tracing/3200/runtime/common/src/benchmarking.rs b/tracing/3200/runtime/common/src/benchmarking.rs new file mode 100644 index 00000000..b6985b5b --- /dev/null +++ b/tracing/3200/runtime/common/src/benchmarking.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use account::AccountId20; +use pallet_treasury::ArgumentsFactory; + +pub struct BenchmarkHelper; + +impl ArgumentsFactory<(), AccountId20> for BenchmarkHelper { + fn create_asset_kind(_seed: u32) -> () { + () + } + + fn create_beneficiary(seed: [u8; 32]) -> AccountId20 { + AccountId20::from(seed) + } +} diff --git a/tracing/3200/runtime/common/src/impl_moonbeam_xcm_call.rs b/tracing/3200/runtime/common/src/impl_moonbeam_xcm_call.rs new file mode 100644 index 00000000..112c457c --- /dev/null +++ b/tracing/3200/runtime/common/src/impl_moonbeam_xcm_call.rs @@ -0,0 +1,51 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_moonbeam_xcm_call { + {} => { + + pub struct MoonbeamCall; + impl CallDispatcher for MoonbeamCall { + fn dispatch( + call: RuntimeCall, + origin: RuntimeOrigin, + ) -> Result< + PostDispatchInfoOf, + DispatchErrorWithPostInfo> + > { + if let Ok(raw_origin) = TryInto::>::try_into(origin.clone().caller) { + match (call.clone(), raw_origin) { + ( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { .. }) | + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact_through_proxy { .. }), + RawOrigin::Signed(account_id) + ) => { + return RuntimeCall::dispatch( + call, + pallet_ethereum_xcm::Origin::XcmEthereumTransaction( + account_id.into() + ).into() + ); + }, + _ => {} + } + } + RuntimeCall::dispatch(call, origin) + } + } + } +} diff --git a/tracing/3200/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs b/tracing/3200/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs new file mode 100644 index 00000000..ffddb3b8 --- /dev/null +++ b/tracing/3200/runtime/common/src/impl_moonbeam_xcm_call_tracing.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_moonbeam_xcm_call_tracing { + {} => { + + type CallResult = + Result< + PostDispatchInfoOf, + DispatchErrorWithPostInfo> + >; + + pub struct MoonbeamCall; + impl CallDispatcher for MoonbeamCall { + fn dispatch( + call: RuntimeCall, + origin: RuntimeOrigin, + ) -> CallResult { + if let Ok(raw_origin) = TryInto::>::try_into(origin.clone().caller) { + match (call.clone(), raw_origin) { + ( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { xcm_transaction }) | + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact_through_proxy { + xcm_transaction, .. + }), + RawOrigin::Signed(account_id) + ) => { + use crate::EthereumXcm; + use moonbeam_evm_tracer::tracer::EvmTracer; + use xcm_primitives::{ + XcmToEthereum, + EthereumXcmTracingStatus, + ETHEREUM_XCM_TRACING_STORAGE_KEY + }; + use frame_support::storage::unhashed; + use frame_support::traits::Get; + + let dispatch_call = || { + RuntimeCall::dispatch( + call, + pallet_ethereum_xcm::Origin::XcmEthereumTransaction( + account_id.into() + ).into() + ) + }; + + return match unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // This runtime instance is used for tracing. + Some(tracing_status) => match tracing_status { + // Tracing a block, all calls are done using environmental. + EthereumXcmTracingStatus::Block => { + // Each known extrinsic is a new call stack. + EvmTracer::emit_new(); + let mut res: Option = None; + EvmTracer::new().trace(|| { + res = Some(dispatch_call()); + }); + res.expect("Invalid dispatch result") + }, + // Tracing a transaction, the one matching the trace request + // is done using environmental, the rest dispatched normally. + EthereumXcmTracingStatus::Transaction(traced_transaction_hash) => { + let transaction_hash = xcm_transaction.into_transaction_v2( + EthereumXcm::nonce(), + ::ChainId::get(), + false + ) + .expect("Invalid transaction conversion") + .hash(); + if transaction_hash == traced_transaction_hash { + let mut res: Option = None; + EvmTracer::new().trace(|| { + res = Some(dispatch_call()); + }); + // Tracing runtime work is done, just signal instance exit. + unhashed::put::( + xcm_primitives::ETHEREUM_XCM_TRACING_STORAGE_KEY, + &EthereumXcmTracingStatus::TransactionExited, + ); + return res.expect("Invalid dispatch result"); + } + dispatch_call() + }, + // Tracing a transaction that has already been found and + // executed. There's no need to dispatch the rest of the + // calls. + EthereumXcmTracingStatus::TransactionExited => Ok(crate::PostDispatchInfo { + actual_weight: None, + pays_fee: frame_support::pallet_prelude::Pays::No, + }), + }, + // This runtime instance is importing a block. + None => dispatch_call() + }; + }, + _ => {} + } + } + RuntimeCall::dispatch(call, origin) + } + } + } +} diff --git a/tracing/3200/runtime/common/src/impl_on_charge_evm_transaction.rs b/tracing/3200/runtime/common/src/impl_on_charge_evm_transaction.rs new file mode 100644 index 00000000..baa4777e --- /dev/null +++ b/tracing/3200/runtime/common/src/impl_on_charge_evm_transaction.rs @@ -0,0 +1,62 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_on_charge_evm_transaction { + {} => { + type FungibleAccountId = ::AccountId; + + type BalanceFor = + <::Currency as Inspect>>::Balance; + + pub struct OnChargeEVMTransaction(sp_std::marker::PhantomData); + + impl OnChargeEVMTransactionT for OnChargeEVMTransaction + where + T: pallet_evm::Config, + T::Currency: Balanced, + OU: OnUnbalanced>, + U256: UniqueSaturatedInto> + { + type LiquidityInfo = Option>; + + fn withdraw_fee(who: &H160, fee: U256) -> Result> { + EVMFungibleAdapter::<::Currency, ()>::withdraw_fee(who, fee) + } + + fn can_withdraw(who: &H160, amount: U256) -> Result<(), pallet_evm::Error> { + EVMFungibleAdapter::<::Currency, ()>::can_withdraw(who, amount) + } + + fn correct_and_deposit_fee( + who: &H160, + corrected_fee: U256, + base_fee: U256, + already_withdrawn: Self::LiquidityInfo, + ) -> Self::LiquidityInfo { + ::Currency, OU> as OnChargeEVMTransactionT< + T, + >>::correct_and_deposit_fee(who, corrected_fee, base_fee, already_withdrawn) + } + + fn pay_priority_fee(tip: Self::LiquidityInfo) { + if let Some(tip) = tip { + OU::on_unbalanced(tip); + } + } + } + } +} diff --git a/tracing/3200/runtime/common/src/impl_self_contained_call.rs b/tracing/3200/runtime/common/src/impl_self_contained_call.rs new file mode 100644 index 00000000..0dbce052 --- /dev/null +++ b/tracing/3200/runtime/common/src/impl_self_contained_call.rs @@ -0,0 +1,78 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_self_contained_call { + {} => { + impl fp_self_contained::SelfContainedCall for RuntimeCall { + type SignedInfo = H160; + + fn is_self_contained(&self) -> bool { + match self { + RuntimeCall::Ethereum(call) => call.is_self_contained(), + _ => false, + } + } + + fn check_self_contained( + &self + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.check_self_contained(), + _ => None, + } + } + + fn validate_self_contained( + &self, + signed_info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { + match self { + RuntimeCall::Ethereum(call) => call.validate_self_contained(signed_info, dispatch_info, len), + _ => None, + } + } + + fn pre_dispatch_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option> { + match self { + RuntimeCall::Ethereum(call) => call.pre_dispatch_self_contained(info, dispatch_info, len), + _ => None, + } + } + + fn apply_self_contained( + self, + info: Self::SignedInfo, + ) -> Option>> { + match self { + call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => Some( + call.dispatch(RuntimeOrigin::from( + pallet_ethereum::RawOrigin::EthereumTransaction(info) + )) + ), + _ => None, + } + } + } + } +} diff --git a/tracing/3200/runtime/common/src/impl_xcm_evm_runner.rs b/tracing/3200/runtime/common/src/impl_xcm_evm_runner.rs new file mode 100644 index 00000000..07102147 --- /dev/null +++ b/tracing/3200/runtime/common/src/impl_xcm_evm_runner.rs @@ -0,0 +1,242 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#[macro_export] +macro_rules! impl_evm_runner_precompile_or_eth_xcm { + {} => { + use fp_evm::{CallInfo, CallOrCreateInfo, Context, Transfer}; + use frame_support::dispatch::CallableCallFor; + use pallet_evm::{Runner, RunnerError}; + use precompile_utils::{prelude::*, evm::handle::with_precompile_handle}; + use sp_core::U256; + use sp_runtime::DispatchError; + use sp_std::vec::Vec; + use xcm_primitives::{EthereumXcmTransaction, EthereumXcmTransactionV2}; + + pub struct EvmRunnerPrecompileOrEthXcm( + core::marker::PhantomData<(CallDispatcher, Runtime)>, + ); + + impl Runner + for EvmRunnerPrecompileOrEthXcm + where + CallDispatcher: xcm_executor::traits::CallDispatcher, + Runtime: pallet_evm::Config + pallet_ethereum_xcm::Config, + Runtime::RuntimeOrigin: From, + { + type Error = DispatchError; + + fn call( + source: H160, + target: H160, + input: Vec, + value: U256, + gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _validate: bool, + _weight_limit: Option, + _transaction_len: Option, + _config: &fp_evm::Config, + ) -> Result> { + // The `with_precompile_handle` function will execute the closure (and return the + // result in a Some) if and only if there is an available EVM context. Otherwise, + // it will return None. + if let Some((exit_reason, value)) = with_precompile_handle(|precompile_handle| { + let transfer = if value.is_zero() { + None + } else { + Some(Transfer { + source, + target, + value, + }) + }; + + precompile_handle.call( + target, + transfer, + input.clone(), + Some(gas_limit), + false, + &Context { + address: target, + caller: source, + apparent_value: value, + }, + ) + }) { + Ok(CallInfo { + exit_reason, + value, + used_gas: fp_evm::UsedGas { + standard: U256::default(), + effective: U256::default(), + }, + logs: Default::default(), + weight_info: None, + }) + } else { + let xcm_transaction = EthereumXcmTransaction::V2(EthereumXcmTransactionV2 { + gas_limit: gas_limit.into(), + action: pallet_ethereum_xcm::TransactionAction::Call(target), + value, + input: input.try_into().map_err(|_| RunnerError { + error: DispatchError::Exhausted, + weight: Default::default(), + })?, + access_list: Some(access_list), + }); + + let mut execution_info: Option = None; + pallet_ethereum::catch_exec_info(&mut execution_info, || { + CallDispatcher::dispatch( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { xcm_transaction }), + RawOrigin::Signed(source.into()).into(), + ) + .map_err(|DispatchErrorWithPostInfo { error, .. }| RunnerError { + error, + weight: Default::default(), + }) + })?; + + if let Some(CallOrCreateInfo::Call(call_info))= execution_info { + Ok(call_info) + } else { + // `execution_info` must have been filled in + Err(RunnerError { + error: DispatchError::Unavailable, + weight: Default::default(), + }) + } + } + } + + fn create( + _source: H160, + _init: Vec, + _value: U256, + _gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + _access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _validate: bool, + _weight_limit: Option, + _transaction_len: Option, + _config: &fp_evm::Config, + ) -> Result> { + unimplemented!() + } + + fn create2( + _source: H160, + _init: Vec, + _salt: H256, + _value: U256, + _gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + _access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _validate: bool, + _weight_limit: Option, + _transaction_len: Option, + _config: &fp_evm::Config, + ) -> Result> { + unimplemented!() + } + + fn create_force_address( + source: H160, + init: Vec, + value: U256, + gas_limit: u64, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + access_list: Vec<(H160, Vec)>, + is_transactional: bool, + validate: bool, + weight_limit: Option, + transaction_len: Option, + config: &fp_evm::Config, + force_address: H160, + ) -> Result> { + let xcm_transaction = EthereumXcmTransaction::V2(EthereumXcmTransactionV2 { + gas_limit: gas_limit.into(), + action: pallet_ethereum_xcm::TransactionAction::Create, + value, + input: init.try_into().map_err(|_| RunnerError { + error: DispatchError::Exhausted, + weight: Default::default(), + })?, + access_list: Some(access_list), + }); + + let mut execution_info: Option = None; + pallet_ethereum::catch_exec_info(&mut execution_info, || { + CallDispatcher::dispatch( + RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::force_transact_as { + transact_as: source, + xcm_transaction, + force_create_address: Some(force_address), + }), + RawOrigin::Root.into(), + ) + .map_err(|DispatchErrorWithPostInfo { error, .. }| RunnerError { + error, + weight: Default::default(), + }) + })?; + + if let Some(CallOrCreateInfo::Create(create_info))= execution_info { + Ok(create_info) + } else { + // `execution_info` must have been filled in + Err(RunnerError { + error: DispatchError::Unavailable, + weight: Default::default(), + }) + } + } + + fn validate( + _source: H160, + _target: Option, + _input: Vec, + _value: U256, + _gas_limit: u64, + _max_fee_per_gas: Option, + _max_priority_fee_per_gas: Option, + _nonce: Option, + _access_list: Vec<(H160, Vec)>, + _is_transactional: bool, + _weight_limit: Option, + _transaction_len: Option, + _evm_config: &fp_evm::Config, + ) -> Result<(), RunnerError> { + unimplemented!() + } + } + + } +} diff --git a/tracing/3200/runtime/common/src/lib.rs b/tracing/3200/runtime/common/src/lib.rs new file mode 100644 index 00000000..747a8a32 --- /dev/null +++ b/tracing/3200/runtime/common/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +mod apis; +mod impl_moonbeam_xcm_call; +mod impl_moonbeam_xcm_call_tracing; +mod impl_on_charge_evm_transaction; +mod impl_self_contained_call; +mod impl_xcm_evm_runner; +pub mod migrations; +pub mod timestamp; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; diff --git a/tracing/3200/runtime/common/src/migrations.rs b/tracing/3200/runtime/common/src/migrations.rs new file mode 100644 index 00000000..ef94f52b --- /dev/null +++ b/tracing/3200/runtime/common/src/migrations.rs @@ -0,0 +1,308 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Migrations +//! +//! This module acts as a registry where each migration is defined. Each migration should implement +//! the "Migration" trait declared in the pallet-migrations crate. + +use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{marker::PhantomData, prelude::*, vec}; + +pub struct MigrateToLatestXcmVersion(PhantomData); +impl Migration for MigrateToLatestXcmVersion +where + pallet_xcm::migration::MigrateToLatestXcmVersion: OnRuntimeUpgrade, +{ + fn friendly_name(&self) -> &str { + "MM_MigrateToLatestXcmVersion" + } + + fn migrate(&self, _available_weight: Weight) -> Weight { + pallet_xcm::migration::MigrateToLatestXcmVersion::::on_runtime_upgrade() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade(&self) -> Result, sp_runtime::DispatchError> { + pallet_xcm::migration::MigrateToLatestXcmVersion::::pre_upgrade() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(&self, state: Vec) -> Result<(), sp_runtime::DispatchError> { + pallet_xcm::migration::MigrateToLatestXcmVersion::::post_upgrade(state) + } +} + +#[derive(parity_scale_codec::Decode, Eq, Ord, PartialEq, PartialOrd)] +enum OldAssetType { + Xcm(xcm::v3::Location), +} + +pub struct MigrateXcmFeesAssetsMeatdata(PhantomData); +impl Migration for MigrateXcmFeesAssetsMeatdata +where + Runtime: pallet_transaction_payment::Config, + Runtime: pallet_xcm_weight_trader::Config, +{ + fn friendly_name(&self) -> &str { + "MM_MigrateXcmFeesAssetsMetadata" + } + + fn migrate(&self, _available_weight: Weight) -> Weight { + let supported_assets = + if let Some(supported_assets) = frame_support::storage::migration::get_storage_value::< + Vec, + >(b"AssetManager", b"SupportedFeePaymentAssets", &[]) + { + sp_std::collections::btree_set::BTreeSet::from_iter( + supported_assets + .into_iter() + .map(|OldAssetType::Xcm(location_v3)| location_v3), + ) + } else { + return Weight::default(); + }; + + let mut assets: Vec<(xcm::v4::Location, (bool, u128))> = Vec::new(); + + for (OldAssetType::Xcm(location_v3), units_per_seconds) in + frame_support::storage::migration::storage_key_iter::< + OldAssetType, + u128, + frame_support::Blake2_128Concat, + >(b"AssetManager", b"AssetTypeUnitsPerSecond") + { + let enabled = supported_assets.get(&location_v3).is_some(); + + if let Ok(location_v4) = location_v3.try_into() { + assets.push((location_v4, (enabled, units_per_seconds))); + } + } + + //***** Start mutate storage *****// + + // Write asset metadata in new pallet_xcm_weight_trader + use frame_support::weights::WeightToFee as _; + for (asset_location, (enabled, units_per_second)) in assets { + let native_amount_per_second: u128 = + ::WeightToFee::weight_to_fee( + &Weight::from_parts( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + 0, + ), + ) + .try_into() + .unwrap_or(u128::MAX); + let relative_price: u128 = native_amount_per_second + .saturating_mul(10u128.pow(pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS)) + .saturating_div(units_per_second); + pallet_xcm_weight_trader::SupportedAssets::::insert( + asset_location, + (enabled, relative_price), + ); + } + + // Remove storage value AssetManager::SupportedFeePaymentAssets + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + b"AssetManager", + b"SupportedFeePaymentAssets", + )); + + // Remove storage map AssetManager::AssetTypeUnitsPerSecond + let _ = frame_support::storage::migration::clear_storage_prefix( + b"AssetManager", + b"AssetTypeUnitsPerSecond", + &[], + None, + None, + ); + + Weight::default() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade(&self) -> Result, sp_runtime::DispatchError> { + Ok(Default::default()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(&self, state: Vec) -> Result<(), sp_runtime::DispatchError> { + assert!(frame_support::storage::migration::storage_key_iter::< + OldAssetType, + u128, + frame_support::Blake2_128Concat, + >(b"AssetManager", b"AssetTypeUnitsPerSecond") + .next() + .is_none()); + + Ok(()) + } +} + +pub struct CommonMigrations(PhantomData); + +impl GetMigrations for CommonMigrations +where + Runtime: + pallet_xcm::Config + pallet_transaction_payment::Config + pallet_xcm_weight_trader::Config, + Runtime::AccountId: Default, + BlockNumberFor: Into, +{ + fn get_migrations() -> Vec> { + // let migration_author_mapping_twox_to_blake = AuthorMappingTwoXToBlake:: { + // 0: Default::default(), + // }; + + // let migration_parachain_staking_purge_stale_storage = + // ParachainStakingPurgeStaleStorage::(Default::default()); + // let migration_parachain_staking_manual_exits = + // ParachainStakingManualExits::(Default::default()); + // let migration_parachain_staking_increase_max_delegations_per_candidate = + // ParachainStakingIncreaseMaxDelegationsPerCandidate::(Default::default()); + // let migration_parachain_staking_split_candidate_state = + // ParachainStakingSplitCandidateState::(Default::default()); + // let migration_parachain_staking_patch_incorrect_delegation_sums = + // ParachainStakingPatchIncorrectDelegationSums::(Default::default()); + + // let migration_scheduler_v3 = SchedulerMigrationV3::(Default::default()); + + // let migration_base_fee = MigrateBaseFeePerGas::(Default::default()); + + // TODO: this is a lot of allocation to do upon every get() call. this *should* be avoided + // except when pallet_migrations undergoes a runtime upgrade -- but TODO: review + + // let migration_author_slot_filter_eligible_ratio_to_eligibility_count = + // AuthorSlotFilterEligibleRatioToEligiblityCount::(Default::default()); + // let migration_author_mapping_add_keys_to_registration_info = + // AuthorMappingAddKeysToRegistrationInfo::(Default::default()); + // let staking_delegator_state_requests = + // ParachainStakingSplitDelegatorStateIntoDelegationScheduledRequests::( + // Default::default(), + // ); + // let migration_author_mapping_add_account_id_to_nimbus_lookup = + // AuthorMappingAddAccountIdToNimbusLookup::(Default::default()); + + // let xcm_transactor_max_weight = + // XcmTransactorMaxTransactWeight::(Default::default()); + + // let asset_manager_units_with_asset_type = + // AssetManagerUnitsWithAssetType::(Default::default()); + + // let asset_manager_populate_asset_type_id_storage = + // AssetManagerPopulateAssetTypeIdStorage::(Default::default()); + + // let asset_manager_change_statemine_prefixes = AssetManagerChangeStateminePrefixes::< + // Runtime, + // StatemineParaIdInfo, + // StatemineAssetsInstanceInfo, + // >(Default::default()); + + // let xcm_supported_assets = XcmPaymentSupportedAssets::(Default::default()); + + // let migration_elasticity = MigrateBaseFeeElasticity::(Default::default()); + //let staking_at_stake_auto_compound = + // ParachainStakingMigrateAtStakeAutoCompound::(Default::default()); + + //let scheduler_to_v4 = SchedulerMigrationV4::(Default::default()); + //let democracy_migration_hash_to_bounded_call = + // DemocracryMigrationHashToBoundedCall::(Default::default()); + //let preimage_migration_hash_to_bounded_call = + // PreimageMigrationHashToBoundedCall::(Default::default()); + //let asset_manager_to_xcm_v3 = + // PalletAssetManagerMigrateXcmV2ToV3::(Default::default()); + //let xcm_transactor_to_xcm_v3 = + // PalletXcmTransactorMigrateXcmV2ToV3::(Default::default()); + //let remove_min_bond_for_old_orbiter_collators = + // RemoveMinBondForOrbiterCollators::(Default::default()); + // let missing_balances_migrations = MissingBalancesMigrations::(Default::default()); + // let fix_pallet_versions = + // FixIncorrectPalletVersions::(Default::default()); + // let pallet_referenda_migrate_v0_to_v1 = + // PalletReferendaMigrateV0ToV1::(Default::default()); + //let pallet_collective_drop_gov_v1_collectives = + // PalletCollectiveDropGovV1Collectives::(Default::default()); + //let pallet_staking_round = PalletStakingRoundMigration::(Default::default()); + + vec![ + // completed in runtime 800 + // Box::new(migration_author_mapping_twox_to_blake), + // completed in runtime 900 + // completed in runtime 1000 + // Box::new(migration_parachain_staking_purge_stale_storage), + // completed in runtime 1000 + // Box::new(migration_parachain_staking_manual_exits), + // completed in runtime 1101 + // Box::new(migration_parachain_staking_increase_max_delegations_per_candidate), + // completed in runtime 1201 + // Box::new(migration_parachain_staking_split_candidate_state), + // completed in runtime 1201 + // Box::new(xcm_transactor_max_weight), + // completed in runtime 1201 + // Box::new(asset_manager_units_with_asset_type), + // completed in runtime 1201 + // Box::new(asset_manager_change_statemine_prefixes), + // completed in runtime 1201 + // Box::new(asset_manager_populate_asset_type_id_storage), + // completed in runtime 1300 + // Box::new(migration_scheduler_v3), + // completed in runtime 1300 + // Box::new(migration_parachain_staking_patch_incorrect_delegation_sums), + // completed in runtime 1300 + // Box::new(migration_base_fee), + // completed in runtime 1300 + // Box::new(xcm_supported_assets), + // completed in runtime 1500 + // Box::new(migration_author_slot_filter_eligible_ratio_to_eligibility_count), + // Box::new(migration_author_mapping_add_keys_to_registration_info), + // Box::new(staking_delegator_state_requests), + // completed in runtime 1600 + // Box::new(migration_author_mapping_add_account_id_to_nimbus_lookup), + // completed in runtime 1600 + // Box::new(xcm_transactor_transact_signed), + // completed in runtime 1700 + //Box::new(migration_elasticity), + // completed in runtime 1900 + //Box::new(staking_at_stake_auto_compound), + // completed in runtime 2000 + //Box::new(scheduler_to_v4), + //Box::new(democracy_migration_hash_to_bounded_call), + //Box::new(preimage_migration_hash_to_bounded_call), + // completed in runtime 2100 + //Box::new(asset_manager_to_xcm_v3), + //Box::new(xcm_transactor_to_xcm_v3), + // completed in runtime 2600 + //Box::new(remove_min_bond_for_old_orbiter_collators), + // completed in runtime 2700 + // Box::new(missing_balances_migrations), + // Box::new(fix_pallet_versions), + // Box::new(pallet_referenda_migrate_v0_to_v1), + // completed in runtime 2800 + //Box::new(pallet_collective_drop_gov_v1_collectives), + // completed in runtime 2801 + // Box::new(pallet_staking_round), + // Box::new(pallet_collective_drop_gov_v1_collectives), + // completed in runtime 2900 + // Box::new(remove_pallet_democracy), + // Box::new(remove_collectives_addresses), + // completed in runtime 3200 + Box::new(MigrateXcmFeesAssetsMeatdata::(Default::default())), + // permanent migrations + Box::new(MigrateToLatestXcmVersion::(Default::default())), + ] + } +} diff --git a/tracing/3200/runtime/common/src/timestamp.rs b/tracing/3200/runtime/common/src/timestamp.rs new file mode 100644 index 00000000..82a67ef3 --- /dev/null +++ b/tracing/3200/runtime/common/src/timestamp.rs @@ -0,0 +1,92 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! A way to get a relyable timestamp + +use cumulus_pallet_parachain_system::{ + consensus_hook::UnincludedSegmentCapacity, + relay_state_snapshot::{self, ReadEntryErr}, + ConsensusHook, RelayChainStateProof, +}; +use frame_support::pallet_prelude::*; +use frame_support::storage::types::{StorageValue, ValueQuery}; +use frame_support::traits::{StorageInstance, Time}; +pub use moonbeam_core_primitives::well_known_relay_keys; + +/// Get the relay timestamp. +/// Noe that the relay timestamp is populated at the parachain system inherent. +/// If you fetch the timestamp before, you will get the timestamp of the parent block. +pub struct RelayTimestamp; +impl Time for RelayTimestamp { + type Moment = u64; + + fn now() -> Self::Moment { + RelayTimestampNow::get() + } +} + +/// A wrapper around the consensus hook to get the relay timestamp from the relay storage proof +pub struct ConsensusHookWrapperForRelayTimestamp( + core::marker::PhantomData<(Runtime, Inner)>, +); +impl ConsensusHook for ConsensusHookWrapperForRelayTimestamp +where + Runtime: frame_system::Config, + Inner: ConsensusHook, +{ + fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) { + let relay_timestamp: u64 = + match state_proof.read_entry(well_known_relay_keys::TIMESTAMP_NOW, None) { + Ok(relay_timestamp) => relay_timestamp, + // Log the read entry error + Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Proof)) => { + log::error!("Invalid relay storage proof: fail to read key TIMESTAMP_NOW"); + panic!("Invalid realy storage proof: fail to read key TIMESTAMP_NOW"); + } + Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Decode)) => { + log::error!("Corrupted relay storage: fail to decode value TIMESTAMP_NOW"); + panic!("Corrupted relay storage: fail to decode value TIMESTAMP_NOW"); + } + Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Absent)) => { + log::error!("Corrupted relay storage: value TIMESTAMP_NOW is absent!"); + panic!("Corrupted relay storage: value TIMESTAMP_NOW is absent!"); + } + // Can't return another kind of error, the blokc is invalid anyway, so we should panic + _ => unreachable!(), + }; + + let wrapper_weight = ::DbWeight::get().writes(1); + + RelayTimestampNow::put(relay_timestamp); + + let (weight, capacity) = Inner::on_state_proof(state_proof); + + (weight.saturating_add(wrapper_weight), capacity) + } +} + +// Prefix for storage value RelayTimestampNow +struct RelayTimestampNowPrefix; +impl StorageInstance for RelayTimestampNowPrefix { + const STORAGE_PREFIX: &'static str = "RelayTimestampNow"; + + fn pallet_prefix() -> &'static str { + "runtime" + } +} + +// Storage type used to store the last current relay timestamp +type RelayTimestampNow = StorageValue; diff --git a/tracing/3200/runtime/common/src/weights/cumulus_pallet_parachain_system.rs b/tracing/3200/runtime/common/src/weights/cumulus_pallet_parachain_system.rs new file mode 100644 index 00000000..fce7282c --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/cumulus_pallet_parachain_system.rs @@ -0,0 +1,72 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `cumulus_pallet_parachain_system` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=cumulus_pallet_parachain_system +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `cumulus_pallet_parachain_system`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_parachain_system::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::LastDmqMqcHead` (r:1 w:1) + /// Proof: `ParachainSystem::LastDmqMqcHead` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::ProcessedDownwardMessages` (r:0 w:1) + /// Proof: `ParachainSystem::ProcessedDownwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1000) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 1000]`. + fn enqueue_inbound_downward_messages(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3517` + // Minimum execution time: 2_185_000 picoseconds. + Weight::from_parts(2_274_000, 3517) + // Standard Error: 22_952 + .saturating_add(Weight::from_parts(286_056_967, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + } +} diff --git a/tracing/3200/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs b/tracing/3200/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs new file mode 100644 index 00000000..cef9b901 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/cumulus_pallet_xcmp_queue.rs @@ -0,0 +1,154 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `cumulus_pallet_xcmp_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=cumulus_pallet_xcmp_queue +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `cumulus_pallet_xcmp_queue`. +pub struct WeightInfo(PhantomData); +impl cumulus_pallet_xcmp_queue::WeightInfo for WeightInfo { + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:1) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_config_with_u32() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `1627` + // Minimum execution time: 3_960_000 picoseconds. + Weight::from_parts(4_114_000, 1627) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn enqueue_xcmp_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `148` + // Estimated: `3517` + // Minimum execution time: 11_194_000 picoseconds. + Weight::from_parts(12_119_000, 3517) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn suspend_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `1627` + // Minimum execution time: 2_460_000 picoseconds. + Weight::from_parts(2_628_000, 1627) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn resume_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `177` + // Estimated: `1662` + // Minimum execution time: 3_364_000 picoseconds. + Weight::from_parts(3_543_000, 1662) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn take_first_concatenated_xcm() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_984_000 picoseconds. + Weight::from_parts(8_167_000, 0) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn on_idle_good_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `105713` + // Estimated: `109178` + // Minimum execution time: 153_649_000 picoseconds. + Weight::from_parts(155_782_000, 109178) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6b345d8e88afa015075c945637c07e8f20` (r:1 w:1) + /// Storage: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Proof: UNKNOWN KEY `0x7b3237373ffdfeb1cab4222e3b520d6bedc49980ba3aa32b0a189290fd036649` (r:1 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::QueueConfig` (r:1 w:0) + /// Proof: `XcmpQueue::QueueConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn on_idle_large_msg() -> Weight { + // Proof Size summary in bytes: + // Measured: `65782` + // Estimated: `69247` + // Minimum execution time: 104_439_000 picoseconds. + Weight::from_parts(105_300_000, 69247) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/db/mod.rs b/tracing/3200/runtime/common/src/weights/db/mod.rs new file mode 100644 index 00000000..64793abc --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/db/mod.rs @@ -0,0 +1,17 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +pub mod rocksdb; diff --git a/tracing/3200/runtime/common/src/weights/db/rocksdb.rs b/tracing/3200/runtime/common/src/weights/db/rocksdb.rs new file mode 100644 index 00000000..3d0dee09 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/db/rocksdb.rs @@ -0,0 +1,117 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-04-27 (Y/M/D) +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! +//! DATABASE: `RocksDb`, RUNTIME: `Moonbeam` +//! BLOCK-NUM: `BlockId::Number(5962022)` +//! SKIP-WRITE: `false`, SKIP-READ: `false`, WARMUPS: `1` +//! STATE-VERSION: `V0`, STATE-CACHE-SIZE: `` +//! WEIGHT-PATH: `/home/ubuntu/projects/moonbeam/weights-rocksdb-moonbeam.rs` +//! METRIC: `Average`, WEIGHT-MUL: `1.1`, WEIGHT-ADD: `0` + +// Executed Command: +// /home/ubuntu/projects/moonbeam/target/release/moonbeam +// benchmark +// storage +// --db=rocksdb +// --state-version=0 +// --mul=1.1 +// --weight-path +// /home/ubuntu/projects/moonbeam/weights-rocksdb-moonbeam.rs +// --chain +// moonbeam +// --base-path +// /var/lib/rocksdb-moonbeam-data +// --keys-limit +// 10000000 +// --random-seed +// 1024 + +/// Storage DB weights for the `Moonbeam` runtime and `RocksDb`. +pub mod constants { + use frame_support::weights::{constants, RuntimeDbWeight}; + use sp_core::parameter_types; + + parameter_types! { + /// By default, Substrate uses `RocksDB`, so this will be the weight used throughout + /// the runtime. + pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { + // Time to read one storage item. + // Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. + // + // Stats nanoseconds: + // Min, Max: 2_300, 2_841_169 + // Average: 37_947 + // Median: 38_669 + // Std-Dev: 7331.86 + // + // Percentiles nanoseconds: + // 99th: 55_974 + // 95th: 49_824 + // 75th: 42_570 + read: 41_742 * constants::WEIGHT_REF_TIME_PER_NANOS, + + // Time to write one storage item. + // Calculated by multiplying the *Average* of all values with `1.1` and adding `0`. + // + // Stats nanoseconds: + // Min, Max: 18_981, 16_772_373 + // Average: 73_893 + // Median: 72_807 + // Std-Dev: 24543.58 + // + // Percentiles nanoseconds: + // 99th: 97_152 + // 95th: 85_751 + // 75th: 77_392 + write: 81_283 * constants::WEIGHT_REF_TIME_PER_NANOS, + }; + } + + #[cfg(test)] + mod test_db_weights { + use super::constants::RocksDbWeight as W; + use frame_support::weights::constants; + + /// Checks that all weights exist and have sane values. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn bound() { + // At least 1 µs. + assert!( + W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, + "Read weight should be at least 1 µs." + ); + assert!( + W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, + "Write weight should be at least 1 µs." + ); + // At most 1 ms. + assert!( + W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, + "Read weight should be at most 1 ms." + ); + assert!( + W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, + "Write weight should be at most 1 ms." + ); + } + } +} diff --git a/tracing/3200/runtime/common/src/weights/mod.rs b/tracing/3200/runtime/common/src/weights/mod.rs new file mode 100644 index 00000000..68b8f2c9 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/mod.rs @@ -0,0 +1,54 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam common weights. + +pub mod cumulus_pallet_parachain_system; +pub mod cumulus_pallet_xcmp_queue; +pub mod db; +pub mod pallet_asset_manager; +pub mod pallet_assets; +pub mod pallet_author_inherent; +pub mod pallet_author_mapping; +pub mod pallet_author_slot_filter; +pub mod pallet_balances; +pub mod pallet_collective; +pub mod pallet_conviction_voting; +pub mod pallet_crowdloan_rewards; +pub mod pallet_evm; +pub mod pallet_identity; +pub mod pallet_message_queue; +pub mod pallet_moonbeam_foreign_assets; +pub mod pallet_moonbeam_lazy_migrations; +pub mod pallet_moonbeam_orbiters; +pub mod pallet_multisig; +pub mod pallet_parachain_staking; +pub mod pallet_parameters; +pub mod pallet_precompile_benchmarks; +pub mod pallet_preimage; +pub mod pallet_proxy; +pub mod pallet_randomness; +pub mod pallet_referenda; +pub mod pallet_relay_storage_roots; +pub mod pallet_scheduler; +pub mod pallet_sudo; +pub mod pallet_timestamp; +pub mod pallet_treasury; +pub mod pallet_utility; +pub mod pallet_whitelist; +pub mod pallet_xcm; +pub mod pallet_xcm_transactor; +pub mod pallet_xcm_weight_trader; diff --git a/tracing/3200/runtime/common/src/weights/pallet_asset_manager.rs b/tracing/3200/runtime/common/src/weights/pallet_asset_manager.rs new file mode 100644 index 00000000..f81f50d7 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_asset_manager.rs @@ -0,0 +1,100 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_asset_manager` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_asset_manager +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_asset_manager`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_manager::WeightInfo for WeightInfo { + /// Storage: `AssetManager::AssetIdType` (r:1 w:1) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + /// Storage: `AssetManager::AssetTypeId` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3639` + // Minimum execution time: 28_019_000 picoseconds. + Weight::from_parts(28_713_000, 3639) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:1) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:0 w:2) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[5, 100]`. + fn change_existing_asset_type() -> Weight { + // Proof Size summary in bytes: + // Measured: `447 + x * (4 ±0)` + // Estimated: `3909 + x * (5 ±0)` + // Minimum execution time: 16_395_000 picoseconds. + Weight::from_parts(18_250_914, 3909) + // Standard Error: 1_597 + .saturating_add(Weight::from_parts(80_983, 0)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 5)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:1) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:0 w:1) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[5, 100]`. + fn remove_existing_asset_type() -> Weight { + // Proof Size summary in bytes: + // Measured: `447 + x * (4 ±0)` + // Estimated: `3909 + x * (5 ±0)` + // Minimum execution time: 13_955_000 picoseconds. + Weight::from_parts(15_660_921, 3909) + // Standard Error: 1_442 + .saturating_add(Weight::from_parts(80_494, 0)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 5)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_assets.rs b/tracing/3200/runtime/common/src/weights/pallet_assets.rs new file mode 100644 index 00000000..5510504e --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_assets.rs @@ -0,0 +1,483 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_assets +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_assets::WeightInfo for WeightInfo { + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn force_create() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `3639` + // Minimum execution time: 8_496_000 picoseconds. + Weight::from_parts(8_663_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn start_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 9_868_000 picoseconds. + Weight::from_parts(10_228_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:657 w:656) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:656 w:656) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 656]`. + fn destroy_accounts(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1514 + c * (183 ±0)` + // Estimated: `3639 + c * (2597 ±0)` + // Minimum execution time: 14_621_000 picoseconds. + Weight::from_parts(14_857_000, 3639) + // Standard Error: 9_664 + .saturating_add(Weight::from_parts(15_608_598, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 2597).saturating_mul(c.into())) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:657 w:656) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 656]`. + fn destroy_approvals(a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `313 + a * (74 ±0)` + // Estimated: `3639 + a * (2611 ±0)` + // Minimum execution time: 14_982_000 picoseconds. + Weight::from_parts(15_198_000, 3639) + // Standard Error: 7_365 + .saturating_add(Weight::from_parts(8_221_915, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(a.into()))) + .saturating_add(Weight::from_parts(0, 2611).saturating_mul(a.into())) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn finish_destroy() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 10_726_000 picoseconds. + Weight::from_parts(11_073_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn mint() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 19_014_000 picoseconds. + Weight::from_parts(19_815_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn burn() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 26_126_000 picoseconds. + Weight::from_parts(27_097_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `6184` + // Minimum execution time: 38_290_000 picoseconds. + Weight::from_parts(39_111_000, 6184) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `6184` + // Minimum execution time: 33_787_000 picoseconds. + Weight::from_parts(34_524_000, 6184) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `420` + // Estimated: `6184` + // Minimum execution time: 37_978_000 picoseconds. + Weight::from_parts(39_072_000, 6184) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn freeze() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 13_171_000 picoseconds. + Weight::from_parts(13_970_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn thaw() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 13_308_000 picoseconds. + Weight::from_parts(13_860_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn freeze_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 9_506_000 picoseconds. + Weight::from_parts(9_974_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn thaw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 9_373_000 picoseconds. + Weight::from_parts(9_855_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:0) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn transfer_ownership() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 10_853_000 picoseconds. + Weight::from_parts(11_409_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn set_team() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 9_196_000 picoseconds. + Weight::from_parts(9_604_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(n: u32, _s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 24_866_000 picoseconds. + Weight::from_parts(25_868_832, 3639) + // Standard Error: 635 + .saturating_add(Weight::from_parts(1_069, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `3639` + // Minimum execution time: 25_906_000 picoseconds. + Weight::from_parts(26_471_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `3639` + // Minimum execution time: 10_149_000 picoseconds. + Weight::from_parts(10_607_656, 3639) + // Standard Error: 272 + .saturating_add(Weight::from_parts(1_805, 0).saturating_mul(n.into())) + // Standard Error: 272 + .saturating_add(Weight::from_parts(780, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Metadata` (r:1 w:1) + /// Proof: `Assets::Metadata` (`max_values`: None, `max_size`: Some(152), added: 2627, mode: `MaxEncodedLen`) + fn force_clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `3639` + // Minimum execution time: 25_774_000 picoseconds. + Weight::from_parts(26_462_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn force_asset_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 9_047_000 picoseconds. + Weight::from_parts(9_466_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + fn approve_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `241` + // Estimated: `3639` + // Minimum execution time: 15_231_000 picoseconds. + Weight::from_parts(15_876_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `513` + // Estimated: `6184` + // Minimum execution time: 47_230_000 picoseconds. + Weight::from_parts(48_290_000, 6184) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + fn cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `399` + // Estimated: `3639` + // Minimum execution time: 17_476_000 picoseconds. + Weight::from_parts(17_821_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Approvals` (r:1 w:1) + /// Proof: `Assets::Approvals` (`max_values`: None, `max_size`: Some(136), added: 2611, mode: `MaxEncodedLen`) + fn force_cancel_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `399` + // Estimated: `3639` + // Minimum execution time: 17_717_000 picoseconds. + Weight::from_parts(18_116_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn set_min_balance() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 10_090_000 picoseconds. + Weight::from_parts(10_348_000, 3639) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn touch() -> Weight { + // Proof Size summary in bytes: + // Measured: `435` + // Estimated: `3639` + // Minimum execution time: 30_608_000 picoseconds. + Weight::from_parts(31_459_000, 3639) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn touch_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `207` + // Estimated: `3639` + // Minimum execution time: 27_693_000 picoseconds. + Weight::from_parts(28_718_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn refund() -> Weight { + // Proof Size summary in bytes: + // Measured: `561` + // Estimated: `3639` + // Minimum execution time: 30_173_000 picoseconds. + Weight::from_parts(30_991_000, 3639) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn refund_other() -> Weight { + // Proof Size summary in bytes: + // Measured: `353` + // Estimated: `3639` + // Minimum execution time: 28_105_000 picoseconds. + Weight::from_parts(28_801_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(122), added: 2597, mode: `MaxEncodedLen`) + fn block() -> Weight { + // Proof Size summary in bytes: + // Measured: `315` + // Estimated: `3639` + // Minimum execution time: 13_487_000 picoseconds. + Weight::from_parts(13_807_000, 3639) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_author_inherent.rs b/tracing/3200/runtime/common/src/weights/pallet_author_inherent.rs new file mode 100644 index 00000000..2212244a --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_author_inherent.rs @@ -0,0 +1,70 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_author_inherent` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_author_inherent +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_author_inherent`. +pub struct WeightInfo(PhantomData); +impl pallet_author_inherent::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorInherent::Author` (r:1 w:0) + /// Proof: `AuthorInherent::Author` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::SelectedCandidates` (r:1 w:0) + /// Proof: `ParachainStaking::SelectedCandidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorFilter::EligibleCount` (r:1 w:0) + /// Proof: `AuthorFilter::EligibleCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::PreviousLocalVrfOutput` (r:1 w:0) + /// Proof: `Randomness::PreviousLocalVrfOutput` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorInherent::InherentIncluded` (r:0 w:1) + /// Proof: `AuthorInherent::InherentIncluded` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + fn kick_off_authorship_validation() -> Weight { + // Proof Size summary in bytes: + // Measured: `372` + // Estimated: `1857` + // Minimum execution time: 16_871_000 picoseconds. + Weight::from_parts(17_631_000, 1857) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_author_mapping.rs b/tracing/3200/runtime/common/src/weights/pallet_author_mapping.rs new file mode 100644 index 00000000..72d109ee --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_author_mapping.rs @@ -0,0 +1,122 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_author_mapping` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_author_mapping +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_author_mapping`. +pub struct WeightInfo(PhantomData); +impl pallet_author_mapping::WeightInfo for WeightInfo { + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `AuthorMapping::NimbusLookup` (r:0 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `376` + // Estimated: `3841` + // Minimum execution time: 28_197_000 picoseconds. + Weight::from_parts(29_064_000, 3841) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::MappingWithDeposit` (r:2 w:2) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::NimbusLookup` (r:0 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `325` + // Estimated: `6265` + // Minimum execution time: 18_034_000 picoseconds. + Weight::from_parts(18_413_000, 6265) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `AuthorMapping::NimbusLookup` (r:0 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn clear_association() -> Weight { + // Proof Size summary in bytes: + // Measured: `453` + // Estimated: `3918` + // Minimum execution time: 29_273_000 picoseconds. + Weight::from_parts(30_035_000, 3918) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::NimbusLookup` (r:1 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn remove_keys() -> Weight { + // Proof Size summary in bytes: + // Measured: `547` + // Estimated: `4012` + // Minimum execution time: 36_519_000 picoseconds. + Weight::from_parts(37_312_000, 4012) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `AuthorMapping::NimbusLookup` (r:1 w:1) + /// Proof: `AuthorMapping::NimbusLookup` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:1) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn set_keys() -> Weight { + // Proof Size summary in bytes: + // Measured: `432` + // Estimated: `3897` + // Minimum execution time: 31_466_000 picoseconds. + Weight::from_parts(32_161_000, 3897) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_author_slot_filter.rs b/tracing/3200/runtime/common/src/weights/pallet_author_slot_filter.rs new file mode 100644 index 00000000..157541af --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_author_slot_filter.rs @@ -0,0 +1,59 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_author_slot_filter` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_author_slot_filter +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_author_slot_filter`. +pub struct WeightInfo(PhantomData); +impl pallet_author_slot_filter::WeightInfo for WeightInfo { + /// Storage: `AuthorFilter::EligibleCount` (r:0 w:1) + /// Proof: `AuthorFilter::EligibleCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_eligible() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_371_000 picoseconds. + Weight::from_parts(4_610_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_balances.rs b/tracing/3200/runtime/common/src/weights/pallet_balances.rs new file mode 100644 index 00000000..4026d4b3 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_balances.rs @@ -0,0 +1,151 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_balances` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_balances +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_balances`. +pub struct WeightInfo(PhantomData); +impl pallet_balances::WeightInfo for WeightInfo { + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `3581` + // Minimum execution time: 44_360_000 picoseconds. + Weight::from_parts(45_277_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `3581` + // Minimum execution time: 37_989_000 picoseconds. + Weight::from_parts(38_706_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_set_balance_creating() -> Weight { + // Proof Size summary in bytes: + // Measured: `195` + // Estimated: `3581` + // Minimum execution time: 13_993_000 picoseconds. + Weight::from_parts(14_521_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_set_balance_killing() -> Weight { + // Proof Size summary in bytes: + // Measured: `195` + // Estimated: `3581` + // Minimum execution time: 18_896_000 picoseconds. + Weight::from_parts(19_404_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `267` + // Estimated: `6172` + // Minimum execution time: 46_601_000 picoseconds. + Weight::from_parts(47_438_000, 6172) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `3581` + // Minimum execution time: 47_496_000 picoseconds. + Weight::from_parts(48_347_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn force_unreserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `195` + // Estimated: `3581` + // Minimum execution time: 17_366_000 picoseconds. + Weight::from_parts(17_835_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:999 w:999) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1277 + u * (123 ±0)` + // Estimated: `990 + u * (2591 ±0)` + // Minimum execution time: 15_597_000 picoseconds. + Weight::from_parts(15_989_000, 990) + // Standard Error: 9_951 + .saturating_add(Weight::from_parts(13_355_931, 0).saturating_mul(u.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(u.into())) + } + /// Storage: `Balances::InactiveIssuance` (r:1 w:0) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + fn force_adjust_total_issuance() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `1501` + // Minimum execution time: 5_542_000 picoseconds. + Weight::from_parts(5_873_000, 1501) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_collective.rs b/tracing/3200/runtime/common/src/weights/pallet_collective.rs new file mode 100644 index 00000000..5c70e97f --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_collective.rs @@ -0,0 +1,308 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . +//! Autogenerated weights for `pallet_collective` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_collective +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_collective`. +pub struct WeightInfo(PhantomData); +impl pallet_collective::WeightInfo for WeightInfo { + /// Storage: CouncilCollective Members (r:1 w:1) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:0) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:100 w:100) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Prime (r:0 w:1) + /// Proof Skipped: CouncilCollective Prime (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `m` is `[0, 100]`. + /// The range of component `n` is `[0, 100]`. + /// The range of component `p` is `[0, 100]`. + fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + m * (2021 ±0) + p * (2026 ±0)` + // Estimated: `12238 + m * (1231 ±14) + p * (3660 ±14)` + // Minimum execution time: 13_785_000 picoseconds. + Weight::from_parts(14_085_000, 0) + .saturating_add(Weight::from_parts(0, 12238)) + // Standard Error: 34_315 + .saturating_add(Weight::from_parts(2_414_144, 0).saturating_mul(m.into())) + // Standard Error: 34_315 + .saturating_add(Weight::from_parts(5_345_562, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 1231).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 3660).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[1, 100]`. + fn execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + m * (20 ±0)` + // Estimated: `1634 + m * (20 ±0)` + // Minimum execution time: 12_726_000 picoseconds. + Weight::from_parts(12_294_605, 0) + .saturating_add(Weight::from_parts(0, 1634)) + // Standard Error: 18 + .saturating_add(Weight::from_parts(910, 0).saturating_mul(b.into())) + // Standard Error: 192 + .saturating_add(Weight::from_parts(13_235, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(m.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:0) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[1, 100]`. + fn propose_execute(b: u32, m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + m * (20 ±0)` + // Estimated: `3614 + m * (20 ±0)` + // Minimum execution time: 14_722_000 picoseconds. + Weight::from_parts(14_487_427, 0) + .saturating_add(Weight::from_parts(0, 3614)) + // Standard Error: 20 + .saturating_add(Weight::from_parts(944, 0).saturating_mul(b.into())) + // Standard Error: 215 + .saturating_add(Weight::from_parts(25_619, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(m.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalCount (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalCount (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:0 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[2, 100]`. + /// The range of component `p` is `[1, 100]`. + fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `395 + m * (20 ±0) + p * (36 ±0)` + // Estimated: `3789 + m * (21 ±0) + p * (36 ±0)` + // Minimum execution time: 17_107_000 picoseconds. + Weight::from_parts(15_172_014, 0) + .saturating_add(Weight::from_parts(0, 3789)) + // Standard Error: 104 + .saturating_add(Weight::from_parts(3_191, 0).saturating_mul(b.into())) + // Standard Error: 1_090 + .saturating_add(Weight::from_parts(31_145, 0).saturating_mul(m.into())) + // Standard Error: 1_077 + .saturating_add(Weight::from_parts(131_855, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 21).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[5, 100]`. + fn vote(m: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `870 + m * (40 ±0)` + // Estimated: `4334 + m * (40 ±0)` + // Minimum execution time: 21_423_000 picoseconds. + Weight::from_parts(22_311_906, 0) + .saturating_add(Weight::from_parts(0, 4334)) + // Standard Error: 415 + .saturating_add(Weight::from_parts(32_990, 0).saturating_mul(m.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(m.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:0 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `447 + m * (40 ±0) + p * (36 ±0)` + // Estimated: `3892 + m * (41 ±0) + p * (36 ±0)` + // Minimum execution time: 20_010_000 picoseconds. + Weight::from_parts(20_008_777, 0) + .saturating_add(Weight::from_parts(0, 3892)) + // Standard Error: 1_391 + .saturating_add(Weight::from_parts(39_960, 0).saturating_mul(m.into())) + // Standard Error: 1_356 + .saturating_add(Weight::from_parts(126_447, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 41).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `791 + b * (1 ±0) + m * (40 ±0) + p * (40 ±0)` + // Estimated: `4108 + b * (1 ±0) + m * (42 ±0) + p * (40 ±0)` + // Minimum execution time: 30_647_000 picoseconds. + Weight::from_parts(30_084_699, 0) + .saturating_add(Weight::from_parts(0, 4108)) + // Standard Error: 123 + .saturating_add(Weight::from_parts(2_876, 0).saturating_mul(b.into())) + // Standard Error: 1_307 + .saturating_add(Weight::from_parts(31_661, 0).saturating_mul(m.into())) + // Standard Error: 1_274 + .saturating_add(Weight::from_parts(154_567, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 42).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Prime (r:1 w:0) + /// Proof Skipped: CouncilCollective Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:0 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_disapproved(m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `516 + m * (30 ±0) + p * (36 ±0)` + // Estimated: `3958 + m * (31 ±0) + p * (36 ±0)` + // Minimum execution time: 20_735_000 picoseconds. + Weight::from_parts(22_649_363, 0) + .saturating_add(Weight::from_parts(0, 3958)) + // Standard Error: 1_082 + .saturating_add(Weight::from_parts(32_331, 0).saturating_mul(m.into())) + // Standard Error: 1_055 + .saturating_add(Weight::from_parts(122_034, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 31).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Voting (r:1 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective Members (r:1 w:0) + /// Proof Skipped: CouncilCollective Members (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Prime (r:1 w:0) + /// Proof Skipped: CouncilCollective Prime (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:1 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// Storage: MaintenanceMode MaintenanceMode (r:1 w:0) + /// Proof Skipped: MaintenanceMode MaintenanceMode (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `b` is `[2, 1024]`. + /// The range of component `m` is `[4, 100]`. + /// The range of component `p` is `[1, 100]`. + fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `811 + b * (1 ±0) + m * (40 ±0) + p * (40 ±0)` + // Estimated: `4128 + b * (1 ±0) + m * (42 ±0) + p * (40 ±0)` + // Minimum execution time: 32_927_000 picoseconds. + Weight::from_parts(32_086_367, 0) + .saturating_add(Weight::from_parts(0, 4128)) + // Standard Error: 122 + .saturating_add(Weight::from_parts(2_962, 0).saturating_mul(b.into())) + // Standard Error: 1_299 + .saturating_add(Weight::from_parts(32_167, 0).saturating_mul(m.into())) + // Standard Error: 1_266 + .saturating_add(Weight::from_parts(154_131, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(0, 42).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 40).saturating_mul(p.into())) + } + /// Storage: CouncilCollective Proposals (r:1 w:1) + /// Proof Skipped: CouncilCollective Proposals (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: CouncilCollective Voting (r:0 w:1) + /// Proof Skipped: CouncilCollective Voting (max_values: None, max_size: None, mode: Measured) + /// Storage: CouncilCollective ProposalOf (r:0 w:1) + /// Proof Skipped: CouncilCollective ProposalOf (max_values: None, max_size: None, mode: Measured) + /// The range of component `p` is `[1, 100]`. + fn disapprove_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `264 + p * (32 ±0)` + // Estimated: `1749 + p * (32 ±0)` + // Minimum execution time: 10_334_000 picoseconds. + Weight::from_parts(11_413_201, 0) + .saturating_add(Weight::from_parts(0, 1749)) + // Standard Error: 1_033 + .saturating_add(Weight::from_parts(95_458, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_conviction_voting.rs b/tracing/3200/runtime/common/src/weights/pallet_conviction_voting.rs new file mode 100644 index 00000000..2bdf1479 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_conviction_voting.rs @@ -0,0 +1,192 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_conviction_voting` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_conviction_voting +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_conviction_voting`. +pub struct WeightInfo(PhantomData); +impl pallet_conviction_voting::WeightInfo for WeightInfo { + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn vote_new() -> Weight { + // Proof Size summary in bytes: + // Measured: `1962` + // Estimated: `42428` + // Minimum execution time: 62_404_000 picoseconds. + Weight::from_parts(64_144_000, 42428) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn vote_existing() -> Weight { + // Proof Size summary in bytes: + // Measured: `2263` + // Estimated: `83866` + // Minimum execution time: 83_179_000 picoseconds. + Weight::from_parts(85_862_000, 83866) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn remove_vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `1841` + // Estimated: `83866` + // Minimum execution time: 56_798_000 picoseconds. + Weight::from_parts(58_788_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn remove_other_vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `1385` + // Estimated: `4617` + // Minimum execution time: 20_271_000 picoseconds. + Weight::from_parts(20_946_000, 4617) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:20 w:20) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:20) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 20]`. + fn delegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1621 + r * (248 ±0)` + // Estimated: `83866 + r * (3387 ±0)` + // Minimum execution time: 42_617_000 picoseconds. + Weight::from_parts(39_583_327, 83866) + // Standard Error: 73_078 + .saturating_add(Weight::from_parts(25_826_433, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 3387).saturating_mul(r.into())) + } + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:20 w:20) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:20) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `r` is `[0, 20]`. + fn undelegate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1340 + r * (248 ±0)` + // Estimated: `83866 + r * (3387 ±0)` + // Minimum execution time: 19_345_000 picoseconds. + Weight::from_parts(11_294_651, 83866) + // Standard Error: 81_442 + .saturating_add(Weight::from_parts(25_724_386, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 3387).saturating_mul(r.into())) + } + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(1152), added: 3627, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(137), added: 2612, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + fn unlock() -> Weight { + // Proof Size summary in bytes: + // Measured: `1228` + // Estimated: `4752` + // Minimum execution time: 46_949_000 picoseconds. + Weight::from_parts(48_420_000, 4752) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_crowdloan_rewards.rs b/tracing/3200/runtime/common/src/weights/pallet_crowdloan_rewards.rs new file mode 100644 index 00000000..72883175 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_crowdloan_rewards.rs @@ -0,0 +1,163 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_crowdloan_rewards` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_crowdloan_rewards +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_crowdloan_rewards`. +pub struct WeightInfo(PhantomData); +impl pallet_crowdloan_rewards::WeightInfo for WeightInfo { + /// Storage: `CrowdloanRewards::Initialized` (r:1 w:0) + /// Proof: `CrowdloanRewards::Initialized` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitializedRewardAmount` (r:1 w:1) + /// Proof: `CrowdloanRewards::InitializedRewardAmount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::TotalContributors` (r:1 w:1) + /// Proof: `CrowdloanRewards::TotalContributors` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:501 w:501) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `CrowdloanRewards::ClaimedRelayChainIds` (r:500 w:500) + /// Proof: `CrowdloanRewards::ClaimedRelayChainIds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::UnassociatedContributions` (r:500 w:0) + /// Proof: `CrowdloanRewards::UnassociatedContributions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::AccountsPayable` (r:500 w:500) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 500]`. + fn initialize_reward_vec(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `76347 + x * (550 ±0)` + // Estimated: `66242 + x * (3052 ±5)` + // Minimum execution time: 128_593_000 picoseconds. + Weight::from_parts(26_484_438, 66242) + // Standard Error: 33_958 + .saturating_add(Weight::from_parts(58_041_582, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3052).saturating_mul(x.into())) + } + /// Storage: `CrowdloanRewards::Initialized` (r:1 w:1) + /// Proof: `CrowdloanRewards::Initialized` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitRelayBlock` (r:1 w:0) + /// Proof: `CrowdloanRewards::InitRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitializedRewardAmount` (r:1 w:0) + /// Proof: `CrowdloanRewards::InitializedRewardAmount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `CrowdloanRewards::TotalContributors` (r:1 w:0) + /// Proof: `CrowdloanRewards::TotalContributors` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::EndRelayBlock` (r:0 w:1) + /// Proof: `CrowdloanRewards::EndRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn complete_initialization() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `3581` + // Minimum execution time: 14_606_000 picoseconds. + Weight::from_parts(14_891_000, 3581) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `CrowdloanRewards::Initialized` (r:1 w:0) + /// Proof: `CrowdloanRewards::Initialized` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::AccountsPayable` (r:1 w:1) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::InitRelayBlock` (r:1 w:0) + /// Proof: `CrowdloanRewards::InitRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::EndRelayBlock` (r:1 w:0) + /// Proof: `CrowdloanRewards::EndRelayBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn claim() -> Weight { + // Proof Size summary in bytes: + // Measured: `1100` + // Estimated: `6172` + // Minimum execution time: 64_132_000 picoseconds. + Weight::from_parts(66_251_000, 6172) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `CrowdloanRewards::AccountsPayable` (r:2 w:2) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn update_reward_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `397` + // Estimated: `6337` + // Minimum execution time: 17_236_000 picoseconds. + Weight::from_parts(17_683_000, 6337) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `CrowdloanRewards::UnassociatedContributions` (r:1 w:1) + /// Proof: `CrowdloanRewards::UnassociatedContributions` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::ClaimedRelayChainIds` (r:1 w:1) + /// Proof: `CrowdloanRewards::ClaimedRelayChainIds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CrowdloanRewards::AccountsPayable` (r:1 w:1) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn associate_native_identity() -> Weight { + // Proof Size summary in bytes: + // Measured: `934` + // Estimated: `6172` + // Minimum execution time: 123_261_000 picoseconds. + Weight::from_parts(125_823_000, 6172) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `CrowdloanRewards::AccountsPayable` (r:2 w:2) + /// Proof: `CrowdloanRewards::AccountsPayable` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 500]`. + fn change_association_with_relay_keys(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `366 + x * (32 ±0)` + // Estimated: `6306 + x * (32 ±0)` + // Minimum execution time: 76_316_000 picoseconds. + Weight::from_parts(77_028_000, 6306) + // Standard Error: 10_579 + .saturating_add(Weight::from_parts(57_150_227, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(x.into())) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_evm.rs b/tracing/3200/runtime/common/src/weights/pallet_evm.rs new file mode 100644 index 00000000..8e7e7fe5 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_evm.rs @@ -0,0 +1,78 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_evm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_evm +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_evm`. +pub struct WeightInfo(PhantomData); +impl pallet_evm::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountStorages` (r:1 w:0) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 10000000]`. + fn runner_execute(_x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1574` + // Estimated: `7514` + // Minimum execution time: 23_633_093_000 picoseconds. + Weight::from_parts(24_184_220_134, 7514) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + fn withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_688_000 picoseconds. + Weight::from_parts(1_807_000, 0) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_identity.rs b/tracing/3200/runtime/common/src/weights/pallet_identity.rs new file mode 100644 index 00000000..c07b1adf --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_identity.rs @@ -0,0 +1,411 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_identity` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_identity +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_identity`. +pub struct WeightInfo(PhantomData); +impl pallet_identity::WeightInfo for WeightInfo { + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn add_registrar(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 7_895_000 picoseconds. + Weight::from_parts(8_480_079, 2386) + // Standard Error: 1_248 + .saturating_add(Weight::from_parts(97_775, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + fn set_identity(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6966 + r * (5 ±0)` + // Estimated: `11025` + // Minimum execution time: 109_883_000 picoseconds. + Weight::from_parts(111_161_026, 11025) + // Standard Error: 9_723 + .saturating_add(Weight::from_parts(246_899, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:100 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 100]`. + fn set_subs_new(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `89` + // Estimated: `11025 + s * (2565 ±0)` + // Minimum execution time: 8_333_000 picoseconds. + Weight::from_parts(21_037_893, 11025) + // Standard Error: 4_396 + .saturating_add(Weight::from_parts(3_345_632, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_parts(0, 2565).saturating_mul(s.into())) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 100]`. + fn set_subs_old(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `169 + p * (20 ±0)` + // Estimated: `11025` + // Minimum execution time: 8_499_000 picoseconds. + Weight::from_parts(21_501_786, 11025) + // Standard Error: 3_254 + .saturating_add(Weight::from_parts(1_437_065, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) + } + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[0, 100]`. + fn clear_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7046 + r * (5 ±0) + s * (20 ±0)` + // Estimated: `11025` + // Minimum execution time: 56_575_000 picoseconds. + Weight::from_parts(53_973_814, 11025) + // Standard Error: 6_369 + .saturating_add(Weight::from_parts(315_528, 0).saturating_mul(r.into())) + // Standard Error: 1_242 + .saturating_add(Weight::from_parts(1_462_118, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: `Identity::Registrars` (r:1 w:0) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + fn request_judgement(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6956 + r * (45 ±0)` + // Estimated: `11025` + // Minimum execution time: 75_323_000 picoseconds. + Weight::from_parts(76_831_914, 11025) + // Standard Error: 3_812 + .saturating_add(Weight::from_parts(147_383, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + fn cancel_request(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `6987` + // Estimated: `11025` + // Minimum execution time: 73_338_000 picoseconds. + Weight::from_parts(74_725_767, 11025) + // Standard Error: 3_575 + .saturating_add(Weight::from_parts(96_638, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn set_fee(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 5_704_000 picoseconds. + Weight::from_parts(6_016_308, 2386) + // Standard Error: 846 + .saturating_add(Weight::from_parts(67_771, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn set_account_id(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 5_805_000 picoseconds. + Weight::from_parts(6_084_566, 2386) + // Standard Error: 790 + .saturating_add(Weight::from_parts(66_181, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn set_fields(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `77 + r * (45 ±0)` + // Estimated: `2386` + // Minimum execution time: 5_679_000 picoseconds. + Weight::from_parts(6_030_639, 2386) + // Standard Error: 856 + .saturating_add(Weight::from_parts(64_027, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::Registrars` (r:1 w:0) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(901), added: 1396, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 19]`. + fn provide_judgement(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7022 + r * (45 ±0)` + // Estimated: `11025` + // Minimum execution time: 94_966_000 picoseconds. + Weight::from_parts(96_178_664, 11025) + // Standard Error: 3_026 + .saturating_add(Weight::from_parts(140_817, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `r` is `[1, 20]`. + /// The range of component `s` is `[0, 100]`. + fn kill_identity(r: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `7436 + r * (5 ±0) + s * (20 ±0)` + // Estimated: `11025` + // Minimum execution time: 74_684_000 picoseconds. + Weight::from_parts(73_335_697, 11025) + // Standard Error: 9_256 + .saturating_add(Weight::from_parts(353_584, 0).saturating_mul(r.into())) + // Standard Error: 1_806 + .saturating_add(Weight::from_parts(1_462_160, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 99]`. + fn add_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `536 + s * (23 ±0)` + // Estimated: `11025` + // Minimum execution time: 24_836_000 picoseconds. + Weight::from_parts(31_312_526, 11025) + // Standard Error: 1_898 + .saturating_add(Weight::from_parts(93_908, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 100]`. + fn rename_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `615 + s * (4 ±0)` + // Estimated: `11025` + // Minimum execution time: 11_670_000 picoseconds. + Weight::from_parts(15_772_433, 11025) + // Standard Error: 1_248 + .saturating_add(Weight::from_parts(58_197, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 100]`. + fn remove_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `647 + s * (24 ±0)` + // Estimated: `11025` + // Minimum execution time: 31_290_000 picoseconds. + Weight::from_parts(34_048_357, 11025) + // Standard Error: 861 + .saturating_add(Weight::from_parts(92_998, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(2046), added: 4521, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 99]`. + fn quit_sub(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `620 + s * (24 ±0)` + // Estimated: `5511` + // Minimum execution time: 20_820_000 picoseconds. + Weight::from_parts(24_687_820, 5511) + // Standard Error: 952 + .saturating_add(Weight::from_parts(85_969, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) + /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn add_username_authority() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_025_000 picoseconds. + Weight::from_parts(6_377_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + fn remove_username_authority() -> Weight { + // Proof Size summary in bytes: + // Measured: `67` + // Estimated: `3505` + // Minimum execution time: 8_401_000 picoseconds. + Weight::from_parts(8_766_000, 3505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) + /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Identity::AccountOfUsername` (r:1 w:1) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Identity::PendingUsernames` (r:1 w:0) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + fn set_username_for() -> Weight { + // Proof Size summary in bytes: + // Measured: `67` + // Estimated: `11025` + // Minimum execution time: 66_336_000 picoseconds. + Weight::from_parts(68_233_000, 11025) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Identity::PendingUsernames` (r:1 w:1) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + /// Storage: `Identity::AccountOfUsername` (r:0 w:1) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + fn accept_username() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `11025` + // Minimum execution time: 19_140_000 picoseconds. + Weight::from_parts(19_618_000, 11025) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Identity::PendingUsernames` (r:1 w:1) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + fn remove_expired_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3538` + // Minimum execution time: 13_607_000 picoseconds. + Weight::from_parts(15_785_000, 3538) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::AccountOfUsername` (r:1 w:0) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + fn set_primary_username() -> Weight { + // Proof Size summary in bytes: + // Measured: `232` + // Estimated: `11025` + // Minimum execution time: 15_633_000 picoseconds. + Weight::from_parts(16_053_000, 11025) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Identity::AccountOfUsername` (r:1 w:1) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7560), added: 10035, mode: `MaxEncodedLen`) + fn remove_dangling_username() -> Weight { + // Proof Size summary in bytes: + // Measured: `86` + // Estimated: `11025` + // Minimum execution time: 11_045_000 picoseconds. + Weight::from_parts(11_181_000, 11025) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_message_queue.rs b/tracing/3200/runtime/common/src/weights/pallet_message_queue.rs new file mode 100644 index 00000000..24f9cb2c --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_message_queue.rs @@ -0,0 +1,184 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_message_queue` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_message_queue +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_message_queue`. +pub struct WeightInfo(PhantomData); +impl pallet_message_queue::WeightInfo for WeightInfo { + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn ready_ring_knit() -> Weight { + // Proof Size summary in bytes: + // Measured: `223` + // Estimated: `6044` + // Minimum execution time: 10_842_000 picoseconds. + Weight::from_parts(11_183_000, 6044) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + fn ready_ring_unknit() -> Weight { + // Proof Size summary in bytes: + // Measured: `218` + // Estimated: `6044` + // Minimum execution time: 9_683_000 picoseconds. + Weight::from_parts(10_013_000, 6044) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `EmergencyParaXcm::Mode` (r:1 w:0) + /// Proof: `EmergencyParaXcm::Mode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn service_queue_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `190` + // Estimated: `3517` + // Minimum execution time: 6_826_000 picoseconds. + Weight::from_parts(7_140_000, 3517) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn service_page_base_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `108986` + // Minimum execution time: 5_388_000 picoseconds. + Weight::from_parts(5_614_000, 108986) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn service_page_base_no_completion() -> Weight { + // Proof Size summary in bytes: + // Measured: `72` + // Estimated: `108986` + // Minimum execution time: 5_723_000 picoseconds. + Weight::from_parts(5_838_000, 108986) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn service_page_item() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 236_686_000 picoseconds. + Weight::from_parts(240_236_000, 0) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn bump_service_head() -> Weight { + // Proof Size summary in bytes: + // Measured: `171` + // Estimated: `3517` + // Minimum execution time: 5_964_000 picoseconds. + Weight::from_parts(6_152_000, 3517) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn reap_page() -> Weight { + // Proof Size summary in bytes: + // Measured: `105609` + // Estimated: `108986` + // Minimum execution time: 68_421_000 picoseconds. + Weight::from_parts(71_340_000, 108986) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `EmergencyParaXcm::Mode` (r:1 w:0) + /// Proof: `EmergencyParaXcm::Mode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn execute_overweight_page_removed() -> Weight { + // Proof Size summary in bytes: + // Measured: `105793` + // Estimated: `108986` + // Minimum execution time: 147_979_000 picoseconds. + Weight::from_parts(159_979_000, 108986) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `EmergencyParaXcm::Mode` (r:1 w:0) + /// Proof: `EmergencyParaXcm::Mode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(105521), added: 107996, mode: `MaxEncodedLen`) + fn execute_overweight_page_updated() -> Weight { + // Proof Size summary in bytes: + // Measured: `105793` + // Estimated: `108986` + // Minimum execution time: 199_723_000 picoseconds. + Weight::from_parts(212_361_000, 108986) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs b/tracing/3200/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs new file mode 100644 index 00000000..942b78f1 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_moonbeam_foreign_assets.rs @@ -0,0 +1,173 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_moonbeam_foreign_assets` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_moonbeam_foreign_assets +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_moonbeam_foreign_assets`. +pub struct WeightInfo(PhantomData); +impl pallet_moonbeam_foreign_assets::WeightInfo for WeightInfo { + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::CounterForAssetsById` (r:1 w:1) + /// Proof: `EvmForeignAssets::CounterForAssetsById` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::EthereumXcmSuspended` (r:1 w:0) + /// Proof: `EthereumXcm::EthereumXcmSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::Nonce` (r:1 w:1) + /// Proof: `EthereumXcm::Nonce` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:1) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodesMetadata` (r:1 w:1) + /// Proof: `EVM::AccountCodesMetadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountStorages` (r:4 w:4) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::Suicided` (r:1 w:0) + /// Proof: `EVM::Suicided` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Ethereum::Pending` (r:1 w:1) + /// Proof: `Ethereum::Pending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn create_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `3272387` + // Estimated: `3283277` + // Minimum execution time: 4_500_002_000 picoseconds. + Weight::from_parts(4_589_472_000, 3283277) + .saturating_add(T::DbWeight::get().reads(19_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:2 w:2) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn change_xcm_location() -> Weight { + // Proof Size summary in bytes: + // Measured: `2461` + // Estimated: `8401` + // Minimum execution time: 62_933_000 picoseconds. + Weight::from_parts(68_319_000, 8401) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::EthereumXcmSuspended` (r:1 w:0) + /// Proof: `EthereumXcm::EthereumXcmSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::Nonce` (r:1 w:1) + /// Proof: `EthereumXcm::Nonce` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountCodesMetadata` (r:1 w:0) + /// Proof: `EVM::AccountCodesMetadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountStorages` (r:1 w:1) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Ethereum::Pending` (r:1 w:1) + /// Proof: `Ethereum::Pending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn freeze_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `3294569` + // Estimated: `3300509` + // Minimum execution time: 4_072_974_000 picoseconds. + Weight::from_parts(4_130_842_000, 3300509) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:1) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::EthereumXcmSuspended` (r:1 w:0) + /// Proof: `EthereumXcm::EthereumXcmSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumXcm::Nonce` (r:1 w:1) + /// Proof: `EthereumXcm::Nonce` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EthereumChainId::ChainId` (r:1 w:0) + /// Proof: `EthereumChainId::ChainId` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountCodes` (r:2 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountCodesMetadata` (r:1 w:0) + /// Proof: `EVM::AccountCodesMetadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + /// Storage: `EVM::AccountStorages` (r:1 w:1) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Ethereum::Pending` (r:1 w:1) + /// Proof: `Ethereum::Pending` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn unfreeze_foreign_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `3295628` + // Estimated: `3301568` + // Minimum execution time: 4_050_175_000 picoseconds. + Weight::from_parts(4_136_121_000, 3301568) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs b/tracing/3200/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs new file mode 100644 index 00000000..ff32f678 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_moonbeam_lazy_migrations.rs @@ -0,0 +1,77 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_moonbeam_lazy_migrations` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_moonbeam_lazy_migrations +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_moonbeam_lazy_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_moonbeam_lazy_migrations::WeightInfo for WeightInfo { + /// Storage: `EVM::Suicided` (r:100 w:0) + /// Proof: `EVM::Suicided` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountCodes` (r:100 w:0) + /// Proof: `EVM::AccountCodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EVM::AccountStorages` (r:1000 w:900) + /// Proof: `EVM::AccountStorages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamLazyMigrations::SuicidedContractsRemoved` (r:1 w:1) + /// Proof: `MoonbeamLazyMigrations::SuicidedContractsRemoved` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `a` is `[1, 100]`. + /// The range of component `l` is `[1, 1000]`. + fn clear_suicided_storage(a: u32, l: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `4251 + a * (12 ±0) + l * (84 ±0)` + // Estimated: `37759 + a * (2229 ±19) + l * (2536 ±1)` + // Minimum execution time: 48_290_000 picoseconds. + Weight::from_parts(49_165_000, 37759) + // Standard Error: 2_583_524 + .saturating_add(Weight::from_parts(41_638_192, 0).saturating_mul(a.into())) + // Standard Error: 258_077 + .saturating_add(Weight::from_parts(27_201_472, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(a.into()))) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(l.into()))) + .saturating_add(T::DbWeight::get().writes(41_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(l.into()))) + .saturating_add(Weight::from_parts(0, 2229).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2536).saturating_mul(l.into())) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_moonbeam_orbiters.rs b/tracing/3200/runtime/common/src/weights/pallet_moonbeam_orbiters.rs new file mode 100644 index 00000000..ea2a3f1b --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_moonbeam_orbiters.rs @@ -0,0 +1,203 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_moonbeam_orbiters` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_moonbeam_orbiters +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_moonbeam_orbiters`. +pub struct WeightInfo(PhantomData); +impl pallet_moonbeam_orbiters::WeightInfo for WeightInfo { + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Reserves` (r:1 w:0) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1037), added: 3512, mode: `MaxEncodedLen`) + fn collator_add_orbiter() -> Weight { + // Proof Size summary in bytes: + // Measured: `562` + // Estimated: `4502` + // Minimum execution time: 19_808_000 picoseconds. + Weight::from_parts(20_238_000, 4502) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn collator_remove_orbiter() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `3831` + // Minimum execution time: 15_412_000 picoseconds. + Weight::from_parts(16_392_000, 3831) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn orbiter_leave_collator_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `3831` + // Minimum execution time: 15_807_000 picoseconds. + Weight::from_parts(16_494_000, 3831) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MoonbeamOrbiters::MinOrbiterDeposit` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::MinOrbiterDeposit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1037), added: 3512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::RegisteredOrbiter` (r:0 w:1) + /// Proof: `MoonbeamOrbiters::RegisteredOrbiter` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn orbiter_register() -> Weight { + // Proof Size summary in bytes: + // Measured: `282` + // Estimated: `4502` + // Minimum execution time: 28_936_000 picoseconds. + Weight::from_parts(29_752_000, 4502) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `MoonbeamOrbiters::CounterForCollatorsPool` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::CounterForCollatorsPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:101 w:0) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Reserves` (r:1 w:1) + /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1037), added: 3512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::RegisteredOrbiter` (r:0 w:1) + /// Proof: `MoonbeamOrbiters::RegisteredOrbiter` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `n` is `[0, 100]`. + fn orbiter_unregister(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `391 + n * (48 ±0)` + // Estimated: `4502 + n * (2524 ±0)` + // Minimum execution time: 36_235_000 picoseconds. + Weight::from_parts(36_686_015, 4502) + // Standard Error: 8_456 + .saturating_add(Weight::from_parts(7_100_126, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 2524).saturating_mul(n.into())) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CounterForCollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CounterForCollatorsPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn add_collator() -> Weight { + // Proof Size summary in bytes: + // Measured: `82` + // Estimated: `3547` + // Minimum execution time: 10_237_000 picoseconds. + Weight::from_parts(10_886_000, 3547) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CounterForCollatorsPool` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::CounterForCollatorsPool` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `MoonbeamOrbiters::AccountLookupOverride` (r:0 w:9) + /// Proof: `MoonbeamOrbiters::AccountLookupOverride` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_collator() -> Weight { + // Proof Size summary in bytes: + // Measured: `366` + // Estimated: `3831` + // Minimum execution time: 22_288_000 picoseconds. + Weight::from_parts(23_569_000, 3831) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(11_u64)) + } + /// Storage: `MoonbeamOrbiters::CurrentRound` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::CurrentRound` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:100 w:100) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 100]`. + fn on_initialize(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `140 + x * (61 ±0)` + // Estimated: `1624 + x * (2537 ±0)` + // Minimum execution time: 6_275_000 picoseconds. + Weight::from_parts(6_444_708, 1624) + // Standard Error: 1_217 + .saturating_add(Weight::from_parts(861_814, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 2537).saturating_mul(x.into())) + } + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn distribute_rewards() -> Weight { + // Proof Size summary in bytes: + // Measured: `298` + // Estimated: `3763` + // Minimum execution time: 20_451_000 picoseconds. + Weight::from_parts(20_995_000, 3763) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MoonbeamOrbiters::ForceRotation` (r:1 w:1) + /// Proof: `MoonbeamOrbiters::ForceRotation` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CollatorsPool` (r:2 w:1) + /// Proof: `MoonbeamOrbiters::CollatorsPool` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:0 w:3) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::AccountLookupOverride` (r:0 w:3) + /// Proof: `MoonbeamOrbiters::AccountLookupOverride` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::CurrentRound` (r:0 w:1) + /// Proof: `MoonbeamOrbiters::CurrentRound` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_new_round() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6196` + // Minimum execution time: 28_935_000 picoseconds. + Weight::from_parts(29_646_000, 6196) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_multisig.rs b/tracing/3200/runtime/common/src/weights/pallet_multisig.rs new file mode 100644 index 00000000..1f8ba6ad --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_multisig.rs @@ -0,0 +1,160 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_multisig` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_multisig +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_multisig`. +pub struct WeightInfo(PhantomData); +impl pallet_multisig::WeightInfo for WeightInfo { + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 14_135_000 picoseconds. + Weight::from_parts(14_963_477, 1527) + // Standard Error: 3 + .saturating_add(Weight::from_parts(492, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_create(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `304` + // Estimated: `5587` + // Minimum execution time: 40_005_000 picoseconds. + Weight::from_parts(30_775_591, 5587) + // Standard Error: 735 + .saturating_add(Weight::from_parts(105_651, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_approve(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312` + // Estimated: `5587` + // Minimum execution time: 25_708_000 picoseconds. + Weight::from_parts(17_223_261, 5587) + // Standard Error: 424 + .saturating_add(Weight::from_parts(93_873, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_423, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. + fn as_multi_complete(s: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `475 + s * (20 ±0)` + // Estimated: `5587 + s * (20 ±0)` + // Minimum execution time: 51_624_000 picoseconds. + Weight::from_parts(38_977_604, 5587) + // Standard Error: 845 + .saturating_add(Weight::from_parts(146_636, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_462, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 20).saturating_mul(s.into())) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_create(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `304` + // Estimated: `5587` + // Minimum execution time: 28_091_000 picoseconds. + Weight::from_parts(29_260_231, 5587) + // Standard Error: 785 + .saturating_add(Weight::from_parts(107_501, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + fn approve_as_multi_approve(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `312` + // Estimated: `5587` + // Minimum execution time: 15_175_000 picoseconds. + Weight::from_parts(15_799_453, 5587) + // Standard Error: 496 + .saturating_add(Weight::from_parts(95_369, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(2122), added: 4597, mode: `MaxEncodedLen`) + /// The range of component `s` is `[2, 100]`. + fn cancel_as_multi(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `474` + // Estimated: `5587` + // Minimum execution time: 29_244_000 picoseconds. + Weight::from_parts(30_313_817, 5587) + // Standard Error: 647 + .saturating_add(Weight::from_parts(108_554, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_parachain_staking.rs b/tracing/3200/runtime/common/src/weights/pallet_parachain_staking.rs new file mode 100644 index 00000000..9c8685b7 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_parachain_staking.rs @@ -0,0 +1,864 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_parachain_staking` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_parachain_staking +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_parachain_staking`. +pub struct WeightInfo(PhantomData); +impl pallet_parachain_staking::WeightInfo for WeightInfo { + /// Storage: `ParachainStaking::InflationConfig` (r:1 w:1) + /// Proof: `ParachainStaking::InflationConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_staking_expectations() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 7_605_000 picoseconds. + Weight::from_parts(7_892_000, 1573) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::InflationConfig` (r:1 w:1) + /// Proof: `ParachainStaking::InflationConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_inflation() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 35_547_000 picoseconds. + Weight::from_parts(36_154_000, 1573) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::ParachainBondInfo` (r:1 w:1) + /// Proof: `ParachainStaking::ParachainBondInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_parachain_bond_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `7` + // Estimated: `1492` + // Minimum execution time: 6_027_000 picoseconds. + Weight::from_parts(6_458_000, 1492) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::ParachainBondInfo` (r:1 w:1) + /// Proof: `ParachainStaking::ParachainBondInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_parachain_bond_reserve_percent() -> Weight { + // Proof Size summary in bytes: + // Measured: `7` + // Estimated: `1492` + // Minimum execution time: 6_144_000 picoseconds. + Weight::from_parts(6_473_000, 1492) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:1) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_total_selected() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `1513` + // Minimum execution time: 6_990_000 picoseconds. + Weight::from_parts(7_275_000, 1513) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::CollatorCommission` (r:1 w:1) + /// Proof: `ParachainStaking::CollatorCommission` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_collator_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `27` + // Estimated: `1512` + // Minimum execution time: 6_233_000 picoseconds. + Weight::from_parts(6_584_000, 1512) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:0) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::InflationConfig` (r:1 w:1) + /// Proof: `ParachainStaking::InflationConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_blocks_per_round() -> Weight { + // Proof Size summary in bytes: + // Measured: `116` + // Estimated: `1601` + // Minimum execution time: 37_593_000 picoseconds. + Weight::from_parts(38_296_000, 1601) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:0) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:0 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:0 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 200]`. + fn join_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1417 + x * (38 ±0)` + // Estimated: `4752 + x * (41 ±0)` + // Minimum execution time: 46_754_000 picoseconds. + Weight::from_parts(54_914_434, 4752) + // Standard Error: 1_488 + .saturating_add(Weight::from_parts(110_141, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 41).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 200]`. + fn schedule_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `665 + x * (37 ±0)` + // Estimated: `4023 + x * (38 ±0)` + // Minimum execution time: 14_857_000 picoseconds. + Weight::from_parts(18_697_005, 4023) + // Standard Error: 824 + .saturating_add(Weight::from_parts(95_265, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 38).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegatorState` (r:349 w:349) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:350 w:350) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:350 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:350 w:350) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[2, 350]`. + fn execute_leave_candidates_worst_case(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1700 + x * (431 ±0)` + // Estimated: `4948 + x * (3762 ±0)` + // Minimum execution time: 96_853_000 picoseconds. + Weight::from_parts(100_169_000, 4948) + // Standard Error: 75_583 + .saturating_add(Weight::from_parts(35_658_586, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3762).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegatorState` (r:349 w:349) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:350 w:350) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:350 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:350 w:350) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[2, 350]`. + /// The range of component `y` is `[2, 350]`. + fn execute_leave_candidates_ideal(x: u32, _y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1695 + x * (431 ±0)` + // Estimated: `4907 + x * (3762 ±0)` + // Minimum execution time: 88_884_000 picoseconds. + Weight::from_parts(90_079_000, 4907) + // Standard Error: 33_913 + .saturating_add(Weight::from_parts(37_230_313, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3762).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 200]`. + fn cancel_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `633 + x * (37 ±0)` + // Estimated: `3991 + x * (38 ±0)` + // Minimum execution time: 14_558_000 picoseconds. + Weight::from_parts(18_665_113, 3991) + // Standard Error: 728 + .saturating_add(Weight::from_parts(70_199, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 38).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn go_offline(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `530 + x * (38 ±0)` + // Estimated: `3931 + x * (39 ±0)` + // Minimum execution time: 14_032_000 picoseconds. + Weight::from_parts(18_118_102, 3931) + // Standard Error: 1_057 + .saturating_add(Weight::from_parts(73_062, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn go_online(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `494 + x * (38 ±0)` + // Estimated: `3895 + x * (39 ±0)` + // Minimum execution time: 13_512_000 picoseconds. + Weight::from_parts(17_732_954, 3895) + // Standard Error: 818 + .saturating_add(Weight::from_parts(71_101, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn candidate_bond_more(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1233 + x * (42 ±0)` + // Estimated: `4752 + x * (44 ±0)` + // Minimum execution time: 41_622_000 picoseconds. + Weight::from_parts(48_808_924, 4752) + // Standard Error: 1_538 + .saturating_add(Weight::from_parts(104_559, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_parts(0, 44).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn schedule_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `171` + // Estimated: `3636` + // Minimum execution time: 12_236_000 picoseconds. + Weight::from_parts(12_471_000, 3636) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn execute_candidate_bond_less(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1322 + x * (42 ±0)` + // Estimated: `4752 + x * (43 ±0)` + // Minimum execution time: 45_309_000 picoseconds. + Weight::from_parts(52_618_430, 4752) + // Standard Error: 1_276 + .saturating_add(Weight::from_parts(92_735, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 200]`. + fn set_candidate_bond_to_zero(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1302 + x * (42 ±0)` + // Estimated: `4752 + x * (43 ±0)` + // Minimum execution time: 41_712_000 picoseconds. + Weight::from_parts(48_418_838, 4752) + // Standard Error: 1_162 + .saturating_add(Weight::from_parts(90_480, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn cancel_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `191` + // Estimated: `3656` + // Minimum execution time: 11_442_000 picoseconds. + Weight::from_parts(11_799_000, 3656) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[3, 100]`. + /// The range of component `y` is `[2, 300]`. + fn delegate(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2461 + x * (79 ±0) + y * (38 ±0)` + // Estimated: `5710 + x * (81 ±0) + y * (39 ±0)` + // Minimum execution time: 90_395_000 picoseconds. + Weight::from_parts(72_898_619, 5710) + // Standard Error: 2_645 + .saturating_add(Weight::from_parts(225_923, 0).saturating_mul(x.into())) + // Standard Error: 867 + .saturating_add(Weight::from_parts(82_123, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 81).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(y.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn schedule_revoke_delegation(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `567 + x * (42 ±0)` + // Estimated: `4013 + x * (43 ±0)` + // Minimum execution time: 14_980_000 picoseconds. + Weight::from_parts(21_164_970, 4013) + // Standard Error: 896 + .saturating_add(Weight::from_parts(93_739, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn delegator_bond_more(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2016 + x * (79 ±0)` + // Estimated: `5438 + x * (79 ±0)` + // Minimum execution time: 59_785_000 picoseconds. + Weight::from_parts(73_580_149, 5438) + // Standard Error: 1_151 + .saturating_add(Weight::from_parts(142_269, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 79).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn schedule_delegator_bond_less(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `567 + x * (42 ±0)` + // Estimated: `4013 + x * (43 ±0)` + // Minimum execution time: 15_317_000 picoseconds. + Weight::from_parts(21_959_219, 4013) + // Standard Error: 976 + .saturating_add(Weight::from_parts(89_414, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:0) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `998` + // Estimated: `4752` + // Minimum execution time: 71_618_000 picoseconds. + Weight::from_parts(73_885_000, 4752) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_delegator_revoke_delegation_worst() -> Weight { + // Proof Size summary in bytes: + // Measured: `37342` + // Estimated: `40807` + // Minimum execution time: 145_916_000 picoseconds. + Weight::from_parts(150_941_000, 40807) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_delegator_bond_less_worst() -> Weight { + // Proof Size summary in bytes: + // Measured: `29964` + // Estimated: `33429` + // Minimum execution time: 121_602_000 picoseconds. + Weight::from_parts(125_406_000, 33429) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + fn cancel_delegation_request(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `664 + x * (42 ±0)` + // Estimated: `4093 + x * (43 ±0)` + // Minimum execution time: 19_257_000 picoseconds. + Weight::from_parts(27_516_619, 4093) + // Standard Error: 791 + .saturating_add(Weight::from_parts(73_849, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 43).saturating_mul(x.into())) + } + /// Storage: `ParachainStaking::Points` (r:1 w:0) + /// Proof: `ParachainStaking::Points` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn prepare_staking_payouts() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3468` + // Minimum execution time: 2_593_000 picoseconds. + Weight::from_parts(2_673_000, 3468) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:0) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `y` is `[0, 100]`. + fn get_rewardable_delegators(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `73 + y * (36 ±0)` + // Estimated: `3537 + y * (36 ±0)` + // Minimum execution time: 5_882_000 picoseconds. + Weight::from_parts(7_266_012, 3537) + // Standard Error: 596 + .saturating_add(Weight::from_parts(46_898, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(y.into())) + } + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:0) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:0) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:51 w:0) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:51 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:51 w:0) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:51 w:0) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::SelectedCandidates` (r:0 w:1) + /// Proof: `ParachainStaking::SelectedCandidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AtStake` (r:0 w:51) + /// Proof: `ParachainStaking::AtStake` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 50]`. + /// The range of component `y` is `[0, 100]`. + fn select_top_candidates(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (3816 ±0) + y * (1800 ±0)` + // Estimated: `3693 + x * (3975 ±39) + y * (639 ±19)` + // Minimum execution time: 19_219_000 picoseconds. + Weight::from_parts(19_845_000, 3693) + // Standard Error: 92_798 + .saturating_add(Weight::from_parts(17_413_979, 0).saturating_mul(x.into())) + // Standard Error: 46_276 + .saturating_add(Weight::from_parts(1_575_283, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 3975).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 639).saturating_mul(y.into())) + } + /// Storage: `System::Account` (r:349 w:349) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:349 w:349) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:349 w:349) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:349 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 349]`. + /// The range of component `y` is `[0, 349]`. + /// The range of component `z` is `[0, 349]`. + fn pay_one_collator_reward_best(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (396 ±0) + y * (156 ±0) + z * (41 ±0)` + // Estimated: `126467 + x * (2591 ±28) + y * (2234 ±28) + z * (28 ±0)` + // Minimum execution time: 211_000 picoseconds. + Weight::from_parts(218_000, 126467) + // Standard Error: 519_254 + .saturating_add(Weight::from_parts(49_020_535, 0).saturating_mul(x.into())) + // Standard Error: 519_254 + .saturating_add(Weight::from_parts(30_229_813, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(y.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 2234).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 28).saturating_mul(z.into())) + } + /// Storage: `ParachainStaking::DelayedPayouts` (r:1 w:0) + /// Proof: `ParachainStaking::DelayedPayouts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Points` (r:1 w:0) + /// Proof: `ParachainStaking::Points` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AtStake` (r:2 w:1) + /// Proof: `ParachainStaking::AtStake` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AwardedPts` (r:1 w:1) + /// Proof: `ParachainStaking::AwardedPts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:0) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:301 w:301) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `y` is `[0, 300]`. + fn pay_one_collator_reward(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1764 + y * (161 ±0)` + // Estimated: `7437 + y * (2591 ±0)` + // Minimum execution time: 46_483_000 picoseconds. + Weight::from_parts(36_905_544, 7437) + // Standard Error: 7_521 + .saturating_add(Weight::from_parts(14_153_051, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(y.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(y.into())) + } + fn base_on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(722_000, 0) + } + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:0) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 300]`. + /// The range of component `y` is `[0, 100]`. + fn set_auto_compound(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `672 + x * (22 ±0) + y * (36 ±0)` + // Estimated: `4028 + x * (23 ±0) + y * (36 ±0)` + // Minimum execution time: 25_963_000 picoseconds. + Weight::from_parts(26_612_109, 4028) + // Standard Error: 685 + .saturating_add(Weight::from_parts(57_307, 0).saturating_mul(x.into())) + // Standard Error: 2_052 + .saturating_add(Weight::from_parts(64_959, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 23).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 36).saturating_mul(y.into())) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:1 w:1) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[0, 350]`. + /// The range of component `y` is `[0, 349]`. + /// The range of component `z` is `[0, 99]`. + fn delegate_with_auto_compound(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (60 ±0) + y * (21 ±0) + z * (78 ±0)` + // Estimated: `26250 + x * (44 ±0) + y * (19 ±0) + z * (76 ±1)` + // Minimum execution time: 100_869_000 picoseconds. + Weight::from_parts(79_778_917, 26250) + // Standard Error: 1_854 + .saturating_add(Weight::from_parts(153_339, 0).saturating_mul(x.into())) + // Standard Error: 6_546 + .saturating_add(Weight::from_parts(324_002, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + .saturating_add(Weight::from_parts(0, 44).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 19).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 76).saturating_mul(z.into())) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegatorState` (r:2 w:2) + /// Proof: `ParachainStaking::DelegatorState` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AutoCompoundingDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::AutoCompoundingDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TopDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::TopDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::BottomDelegations` (r:1 w:1) + /// Proof: `ParachainStaking::BottomDelegations` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Balances::Locks` (r:2 w:2) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1287), added: 3762, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:2 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(37), added: 2512, mode: `MaxEncodedLen`) + /// Storage: `ParachainStaking::DelegationScheduledRequests` (r:1 w:1) + /// Proof: `ParachainStaking::DelegationScheduledRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::Total` (r:1 w:1) + /// Proof: `ParachainStaking::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn delegate_with_auto_compound_worst() -> Weight { + // Proof Size summary in bytes: + // Measured: `48131` + // Estimated: `54071` + // Minimum execution time: 232_546_000 picoseconds. + Weight::from_parts(239_665_000, 54071) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(13_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn mint_collator_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `128` + // Estimated: `3581` + // Minimum execution time: 15_426_000 picoseconds. + Weight::from_parts(15_776_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `ParachainStaking::EnableMarkingOffline` (r:1 w:0) + /// Proof: `ParachainStaking::EnableMarkingOffline` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::TotalSelected` (r:1 w:0) + /// Proof: `ParachainStaking::TotalSelected` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::SelectedCandidates` (r:1 w:0) + /// Proof: `ParachainStaking::SelectedCandidates` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AtStake` (r:2 w:0) + /// Proof: `ParachainStaking::AtStake` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::AwardedPts` (r:2 w:0) + /// Proof: `ParachainStaking::AwardedPts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MoonbeamOrbiters::OrbiterPerRound` (r:1 w:0) + /// Proof: `MoonbeamOrbiters::OrbiterPerRound` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidateInfo` (r:1 w:1) + /// Proof: `ParachainStaking::CandidateInfo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainStaking::CandidatePool` (r:1 w:1) + /// Proof: `ParachainStaking::CandidatePool` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn notify_inactive_collator() -> Weight { + // Proof Size summary in bytes: + // Measured: `11566` + // Estimated: `17506` + // Minimum execution time: 70_732_000 picoseconds. + Weight::from_parts(73_054_000, 17506) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_parameters.rs b/tracing/3200/runtime/common/src/weights/pallet_parameters.rs new file mode 100644 index 00000000..5f242077 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_parameters.rs @@ -0,0 +1,56 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_parameters` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_parameters +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_parameters`. +pub struct WeightInfo(PhantomData); +impl pallet_parameters::WeightInfo for WeightInfo { + fn set_parameter() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_024_000 picoseconds. + Weight::from_parts(6_401_000, 0) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_precompile_benchmarks.rs b/tracing/3200/runtime/common/src/weights/pallet_precompile_benchmarks.rs new file mode 100644 index 00000000..8176f360 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_precompile_benchmarks.rs @@ -0,0 +1,80 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_precompile_benchmarks` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_precompile_benchmarks +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_precompile_benchmarks`. +pub struct WeightInfo(PhantomData); +impl pallet_precompile_benchmarks::WeightInfo for WeightInfo { + /// The range of component `x` is `[100, 2000]`. + fn verify_entry(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 73_369_000 picoseconds. + Weight::from_parts(73_842_000, 0) + // Standard Error: 2_347 + .saturating_add(Weight::from_parts(649_594, 0).saturating_mul(x.into())) + } + /// Storage: `RelayStorageRoots::RelayStorageRootKeys` (r:1 w:0) + /// Proof: `RelayStorageRoots::RelayStorageRootKeys` (`max_values`: Some(1), `max_size`: Some(121), added: 616, mode: `MaxEncodedLen`) + fn latest_relay_block() -> Weight { + // Proof Size summary in bytes: + // Measured: `227` + // Estimated: `1606` + // Minimum execution time: 4_152_000 picoseconds. + Weight::from_parts(4_383_000, 1606) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn p256_verify() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_569_886_000 picoseconds. + Weight::from_parts(1_580_721_000, 0) + // TODO: Remove this multiplication once we are comfortable with the weight estimation + // Double the weight just to mitigate the possibility of having a signature that + // takes longer to verify + .saturating_mul(1u64) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_preimage.rs b/tracing/3200/runtime/common/src/weights/pallet_preimage.rs new file mode 100644 index 00000000..85dd957f --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_preimage.rs @@ -0,0 +1,251 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_preimage` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_preimage +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_preimage`. +pub struct WeightInfo(PhantomData); +impl pallet_preimage::WeightInfo for WeightInfo { + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 4194304]`. + fn note_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3544` + // Minimum execution time: 46_975_000 picoseconds. + Weight::from_parts(47_859_000, 3544) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_489, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 4194304]`. + fn note_requested_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 14_663_000 picoseconds. + Weight::from_parts(14_911_000, 3544) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_510, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 4194304]`. + fn note_no_deposit_preimage(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 13_981_000 picoseconds. + Weight::from_parts(14_247_000, 3544) + // Standard Error: 5 + .saturating_add(Weight::from_parts(2_525, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn unnote_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `220` + // Estimated: `3544` + // Minimum execution time: 63_566_000 picoseconds. + Weight::from_parts(65_145_000, 3544) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn unnote_no_deposit_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `3544` + // Minimum execution time: 30_640_000 picoseconds. + Weight::from_parts(33_217_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `176` + // Estimated: `3544` + // Minimum execution time: 25_884_000 picoseconds. + Weight::from_parts(29_095_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_no_deposit_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `3544` + // Minimum execution time: 19_445_000 picoseconds. + Weight::from_parts(20_860_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_unnoted_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3544` + // Minimum execution time: 16_603_000 picoseconds. + Weight::from_parts(17_707_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn request_requested_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_450_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) + fn unrequest_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `3544` + // Minimum execution time: 24_822_000 picoseconds. + Weight::from_parts(28_189_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn unrequest_unnoted_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 10_264_000 picoseconds. + Weight::from_parts(10_796_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn unrequest_multi_referenced_preimage() -> Weight { + // Proof Size summary in bytes: + // Measured: `106` + // Estimated: `3544` + // Minimum execution time: 9_508_000 picoseconds. + Weight::from_parts(10_274_000, 3544) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Preimage::StatusFor` (r:1023 w:1023) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1023 w:1023) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1023 w:1023) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1024]`. + fn ensure_updated(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1461 + n * (203 ±0)` + // Estimated: `990 + n * (2591 ±0)` + // Minimum execution time: 57_983_000 picoseconds. + Weight::from_parts(59_722_000, 990) + // Standard Error: 48_752 + .saturating_add(Weight::from_parts(56_684_716, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2591).saturating_mul(n.into())) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_proxy.rs b/tracing/3200/runtime/common/src/weights/pallet_proxy.rs new file mode 100644 index 00000000..ae62f6c6 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_proxy.rs @@ -0,0 +1,217 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_proxy +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `191 + p * (25 ±0)` + // Estimated: `4310 + p * (25 ±0)` + // Minimum execution time: 14_516_000 picoseconds. + Weight::from_parts(15_238_209, 4310) + // Standard Error: 984 + .saturating_add(Weight::from_parts(37_395, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(0, 25).saturating_mul(p.into())) + // 1 DB read that happen when filtering the proxy call transaction + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `443 + a * (56 ±0) + p * (25 ±0)` + // Estimated: `5302 + a * (60 ±0) + p * (22 ±0)` + // Minimum execution time: 37_391_000 picoseconds. + Weight::from_parts(38_087_056, 5302) + // Standard Error: 2_252 + .saturating_add(Weight::from_parts(154_615, 0).saturating_mul(a.into())) + // Standard Error: 2_327 + .saturating_add(Weight::from_parts(17_070, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 60).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 22).saturating_mul(p.into())) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, _p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `329 + a * (56 ±0)` + // Estimated: `5302` + // Minimum execution time: 21_747_000 picoseconds. + Weight::from_parts(24_754_603, 5302) + // Standard Error: 3_972 + .saturating_add(Weight::from_parts(208_296, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, _p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `329 + a * (56 ±0)` + // Estimated: `5302` + // Minimum execution time: 21_639_000 picoseconds. + Weight::from_parts(24_746_374, 5302) + // Standard Error: 4_127 + .saturating_add(Weight::from_parts(209_178, 0).saturating_mul(a.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(1837), added: 4312, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `345 + a * (56 ±0) + p * (25 ±0)` + // Estimated: `5302` + // Minimum execution time: 31_646_000 picoseconds. + Weight::from_parts(32_005_044, 5302) + // Standard Error: 1_899 + .saturating_add(Weight::from_parts(161_454, 0).saturating_mul(a.into())) + // Standard Error: 1_963 + .saturating_add(Weight::from_parts(12_822, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 21_468_000 picoseconds. + Weight::from_parts(22_504_555, 4310) + // Standard Error: 1_112 + .saturating_add(Weight::from_parts(42_496, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 21_344_000 picoseconds. + Weight::from_parts(22_514_605, 4310) + // Standard Error: 1_796 + .saturating_add(Weight::from_parts(41_075, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `149 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 20_829_000 picoseconds. + Weight::from_parts(21_669_942, 4310) + // Standard Error: 1_161 + .saturating_add(Weight::from_parts(37_472, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `161` + // Estimated: `4310` + // Minimum execution time: 22_495_000 picoseconds. + Weight::from_parts(23_705_178, 4310) + // Standard Error: 1_185 + .saturating_add(Weight::from_parts(11_031, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(845), added: 3320, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `174 + p * (25 ±0)` + // Estimated: `4310` + // Minimum execution time: 21_651_000 picoseconds. + Weight::from_parts(22_471_734, 4310) + // Standard Error: 993 + .saturating_add(Weight::from_parts(34_387, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_randomness.rs b/tracing/3200/runtime/common/src/weights/pallet_randomness.rs new file mode 100644 index 00000000..0cc99a0d --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_randomness.rs @@ -0,0 +1,162 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_randomness` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_randomness +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_randomness`. +pub struct WeightInfo(PhantomData); +impl pallet_randomness::WeightInfo for WeightInfo { + /// Storage: `Randomness::RelayEpoch` (r:1 w:1) + /// Proof: `Randomness::RelayEpoch` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelayStateProof` (r:1 w:0) + /// Proof: `ParachainSystem::RelayStateProof` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::InherentIncluded` (r:0 w:1) + /// Proof: `Randomness::InherentIncluded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_babe_randomness_results() -> Weight { + // Proof Size summary in bytes: + // Measured: `297` + // Estimated: `3762` + // Minimum execution time: 12_307_000 picoseconds. + Weight::from_parts(12_673_000, 3762) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Randomness::NotFirstBlock` (r:1 w:0) + /// Proof: `Randomness::NotFirstBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Digest` (r:1 w:0) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AuthorMapping::MappingWithDeposit` (r:1 w:0) + /// Proof: `AuthorMapping::MappingWithDeposit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::LocalVrfOutput` (r:1 w:1) + /// Proof: `Randomness::LocalVrfOutput` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `719` + // Estimated: `4184` + // Minimum execution time: 520_990_000 picoseconds. + Weight::from_parts(523_311_000, 4184) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Randomness::RequestCount` (r:1 w:1) + /// Proof: `Randomness::RequestCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::Requests` (r:0 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn request_randomness() -> Weight { + // Proof Size summary in bytes: + // Measured: `549` + // Estimated: `6172` + // Minimum execution time: 51_094_000 picoseconds. + Weight::from_parts(52_292_000, 6172) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Randomness::Requests` (r:1 w:0) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:0) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `x` is `[1, 100]`. + fn prepare_fulfillment(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `3877` + // Minimum execution time: 9_055_000 picoseconds. + Weight::from_parts(9_553_442, 3877) + // Standard Error: 354 + .saturating_add(Weight::from_parts(270_997, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Randomness::Requests` (r:0 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn finish_fulfillment() -> Weight { + // Proof Size summary in bytes: + // Measured: `739` + // Estimated: `6172` + // Minimum execution time: 51_211_000 picoseconds. + Weight::from_parts(52_028_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Randomness::Requests` (r:1 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn increase_fee() -> Weight { + // Proof Size summary in bytes: + // Measured: `825` + // Estimated: `6172` + // Minimum execution time: 48_050_000 picoseconds. + Weight::from_parts(49_451_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Randomness::Requests` (r:1 w:1) + /// Proof: `Randomness::Requests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Randomness::RandomnessResults` (r:1 w:1) + /// Proof: `Randomness::RandomnessResults` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn execute_request_expiration() -> Weight { + // Proof Size summary in bytes: + // Measured: `868` + // Estimated: `6172` + // Minimum execution time: 52_951_000 picoseconds. + Weight::from_parts(53_757_000, 6172) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_referenda.rs b/tracing/3200/runtime/common/src/weights/pallet_referenda.rs new file mode 100644 index 00000000..86a5e611 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_referenda.rs @@ -0,0 +1,483 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_referenda` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_referenda +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_referenda`. +pub struct WeightInfo(PhantomData); +impl pallet_referenda::WeightInfo for WeightInfo { + /// Storage: `Referenda::ReferendumCount` (r:1 w:1) + /// Proof: `Referenda::ReferendumCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:0 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn submit() -> Weight { + // Proof Size summary in bytes: + // Measured: `269` + // Estimated: `42428` + // Minimum execution time: 30_958_000 picoseconds. + Weight::from_parts(31_691_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `83866` + // Minimum execution time: 41_428_000 picoseconds. + Weight::from_parts(43_244_000, 83866) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3303` + // Estimated: `42428` + // Minimum execution time: 58_921_000 picoseconds. + Weight::from_parts(61_299_000, 42428) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `3323` + // Estimated: `42428` + // Minimum execution time: 58_021_000 picoseconds. + Weight::from_parts(60_860_000, 42428) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `83866` + // Minimum execution time: 53_327_000 picoseconds. + Weight::from_parts(54_224_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn place_decision_deposit_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `510` + // Estimated: `83866` + // Minimum execution time: 48_094_000 picoseconds. + Weight::from_parts(49_279_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn refund_decision_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `453` + // Estimated: `4377` + // Minimum execution time: 27_453_000 picoseconds. + Weight::from_parts(28_127_000, 4377) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn refund_submission_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `378` + // Estimated: `4377` + // Minimum execution time: 26_631_000 picoseconds. + Weight::from_parts(27_180_000, 4377) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn cancel() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `83866` + // Minimum execution time: 28_842_000 picoseconds. + Weight::from_parts(29_442_000, 83866) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:0) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn kill() -> Weight { + // Proof Size summary in bytes: + // Measured: `1007` + // Estimated: `83866` + // Minimum execution time: 91_639_000 picoseconds. + Weight::from_parts(93_395_000, 83866) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:0) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + fn one_fewer_deciding_queue_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `102` + // Estimated: `5477` + // Minimum execution time: 8_972_000 picoseconds. + Weight::from_parts(9_340_000, 5477) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3090` + // Estimated: `42428` + // Minimum execution time: 40_298_000 picoseconds. + Weight::from_parts(41_761_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn one_fewer_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `3090` + // Estimated: `42428` + // Minimum execution time: 43_023_000 picoseconds. + Weight::from_parts(44_831_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_insertion() -> Weight { + // Proof Size summary in bytes: + // Measured: `2915` + // Estimated: `5477` + // Minimum execution time: 23_753_000 picoseconds. + Weight::from_parts(24_879_000, 5477) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_requeued_slide() -> Weight { + // Proof Size summary in bytes: + // Measured: `2915` + // Estimated: `5477` + // Minimum execution time: 23_344_000 picoseconds. + Weight::from_parts(24_526_000, 5477) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2919` + // Estimated: `5477` + // Minimum execution time: 27_283_000 picoseconds. + Weight::from_parts(28_398_000, 5477) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:0) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Referenda::TrackQueue` (r:1 w:1) + /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) + fn nudge_referendum_not_queued() -> Weight { + // Proof Size summary in bytes: + // Measured: `2939` + // Estimated: `5477` + // Minimum execution time: 27_303_000 picoseconds. + Weight::from_parts(28_966_000, 5477) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_no_deposit() -> Weight { + // Proof Size summary in bytes: + // Measured: `249` + // Estimated: `42428` + // Minimum execution time: 18_172_000 picoseconds. + Weight::from_parts(18_665_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_preparing() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `42428` + // Minimum execution time: 18_919_000 picoseconds. + Weight::from_parts(19_405_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + fn nudge_referendum_timed_out() -> Weight { + // Proof Size summary in bytes: + // Measured: `194` + // Estimated: `4377` + // Minimum execution time: 12_180_000 picoseconds. + Weight::from_parts(12_589_000, 4377) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_failing() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `42428` + // Minimum execution time: 24_811_000 picoseconds. + Weight::from_parts(25_485_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::DecidingCount` (r:1 w:1) + /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_deciding_passing() -> Weight { + // Proof Size summary in bytes: + // Measured: `285` + // Estimated: `42428` + // Minimum execution time: 26_577_000 picoseconds. + Weight::from_parts(27_201_000, 42428) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_begin_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `42428` + // Minimum execution time: 21_535_000 picoseconds. + Weight::from_parts(22_366_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_end_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `321` + // Estimated: `42428` + // Minimum execution time: 21_969_000 picoseconds. + Weight::from_parts(22_600_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_not_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `42428` + // Minimum execution time: 20_623_000 picoseconds. + Weight::from_parts(21_157_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_continue_confirming() -> Weight { + // Proof Size summary in bytes: + // Measured: `342` + // Estimated: `42428` + // Minimum execution time: 20_012_000 picoseconds. + Weight::from_parts(20_512_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn nudge_referendum_approved() -> Weight { + // Proof Size summary in bytes: + // Measured: `342` + // Estimated: `83866` + // Minimum execution time: 31_287_000 picoseconds. + Weight::from_parts(32_081_000, 83866) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + fn nudge_referendum_rejected() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `42428` + // Minimum execution time: 21_895_000 picoseconds. + Weight::from_parts(22_431_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:0 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `338` + // Estimated: `4377` + // Minimum execution time: 18_162_000 picoseconds. + Weight::from_parts(18_594_000, 4377) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(912), added: 3387, mode: `MaxEncodedLen`) + /// Storage: `Referenda::MetadataOf` (r:1 w:1) + /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `271` + // Estimated: `4377` + // Minimum execution time: 13_769_000 picoseconds. + Weight::from_parts(14_307_000, 4377) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_relay_storage_roots.rs b/tracing/3200/runtime/common/src/weights/pallet_relay_storage_roots.rs new file mode 100644 index 00000000..ece0cc8a --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_relay_storage_roots.rs @@ -0,0 +1,64 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_relay_storage_roots` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_relay_storage_roots +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_relay_storage_roots`. +pub struct WeightInfo(PhantomData); +impl pallet_relay_storage_roots::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::ValidationData` (r:1 w:0) + /// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `RelayStorageRoots::RelayStorageRoot` (r:1 w:2) + /// Proof: `RelayStorageRoots::RelayStorageRoot` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `RelayStorageRoots::RelayStorageRootKeys` (r:1 w:1) + /// Proof: `RelayStorageRoots::RelayStorageRootKeys` (`max_values`: Some(1), `max_size`: Some(121), added: 616, mode: `MaxEncodedLen`) + fn set_relay_storage_root() -> Weight { + // Proof Size summary in bytes: + // Measured: `972` + // Estimated: `3509` + // Minimum execution time: 16_771_000 picoseconds. + Weight::from_parts(17_356_000, 3509) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_scheduler.rs b/tracing/3200/runtime/common/src/weights/pallet_scheduler.rs new file mode 100644 index 00000000..c48e7467 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_scheduler.rs @@ -0,0 +1,272 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_scheduler` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_scheduler +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_scheduler`. +pub struct WeightInfo(PhantomData); +impl pallet_scheduler::WeightInfo for WeightInfo { + /// Storage: `Scheduler::IncompleteSince` (r:1 w:1) + /// Proof: `Scheduler::IncompleteSince` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn service_agendas_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `31` + // Estimated: `1489` + // Minimum execution time: 2_720_000 picoseconds. + Weight::from_parts(2_818_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 50]`. + fn service_agenda_base(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `78 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 3_189_000 picoseconds. + Weight::from_parts(6_019_354, 42428) + // Standard Error: 1_447 + .saturating_add(Weight::from_parts(349_380, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn service_task_base() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_180_000 picoseconds. + Weight::from_parts(3_314_000, 0) + } + /// Storage: `Preimage::PreimageFor` (r:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `179 + s * (1 ±0)` + // Estimated: `3644 + s * (1 ±0)` + // Minimum execution time: 16_845_000 picoseconds. + Weight::from_parts(17_000_000, 3644) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_178, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) + } + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + fn service_task_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_636_000 picoseconds. + Weight::from_parts(4_794_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn service_task_periodic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_189_000 picoseconds. + Weight::from_parts(3_304_000, 0) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn execute_dispatch_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 3_765_000 picoseconds. + Weight::from_parts(3_988_000, 1527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn execute_dispatch_unsigned() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_937_000 picoseconds. + Weight::from_parts(2_151_000, 0) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 49]`. + fn schedule(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `78 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 9_372_000 picoseconds. + Weight::from_parts(12_299_592, 42428) + // Standard Error: 1_404 + .saturating_add(Weight::from_parts(376_522, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Lookup` (r:0 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. + fn cancel(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `78 + s * (177 ±0)` + // Estimated: `42428` + // Minimum execution time: 14_631_000 picoseconds. + Weight::from_parts(14_493_098, 42428) + // Standard Error: 975 + .saturating_add(Weight::from_parts(577_889, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 49]`. + fn schedule_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `255 + s * (185 ±0)` + // Estimated: `42428` + // Minimum execution time: 12_594_000 picoseconds. + Weight::from_parts(16_202_190, 42428) + // Standard Error: 2_304 + .saturating_add(Weight::from_parts(404_922, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:1) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. + fn cancel_named(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `281 + s * (185 ±0)` + // Estimated: `42428` + // Minimum execution time: 16_826_000 picoseconds. + Weight::from_parts(17_330_248, 42428) + // Standard Error: 1_400 + .saturating_add(Weight::from_parts(600_950, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// The range of component `s` is `[1, 50]`. + fn schedule_retry(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `42428` + // Minimum execution time: 8_600_000 picoseconds. + Weight::from_parts(8_889_255, 42428) + // Standard Error: 414 + .saturating_add(Weight::from_parts(24_121, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `8928` + // Estimated: `42428` + // Minimum execution time: 23_926_000 picoseconds. + Weight::from_parts(24_965_000, 42428) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn set_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `9606` + // Estimated: `42428` + // Minimum execution time: 29_100_000 picoseconds. + Weight::from_parts(30_149_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn cancel_retry() -> Weight { + // Proof Size summary in bytes: + // Measured: `8940` + // Estimated: `42428` + // Minimum execution time: 22_767_000 picoseconds. + Weight::from_parts(23_423_000, 42428) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Scheduler::Lookup` (r:1 w:0) + /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:0) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + fn cancel_retry_named() -> Weight { + // Proof Size summary in bytes: + // Measured: `9618` + // Estimated: `42428` + // Minimum execution time: 28_421_000 picoseconds. + Weight::from_parts(29_035_000, 42428) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_sudo.rs b/tracing/3200/runtime/common/src/weights/pallet_sudo.rs new file mode 100644 index 00000000..9e662761 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_sudo.rs @@ -0,0 +1,91 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_sudo` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_sudo +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_sudo`. +pub struct WeightInfo(PhantomData); +impl pallet_sudo::WeightInfo for WeightInfo { + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn set_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 8_460_000 picoseconds. + Weight::from_parts(8_649_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn sudo() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 9_479_000 picoseconds. + Weight::from_parts(9_819_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn sudo_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 9_464_000 picoseconds. + Weight::from_parts(9_747_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `Sudo::Key` (r:1 w:1) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) + fn remove_key() -> Weight { + // Proof Size summary in bytes: + // Measured: `153` + // Estimated: `1505` + // Minimum execution time: 7_631_000 picoseconds. + Weight::from_parts(8_078_000, 1505) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_timestamp.rs b/tracing/3200/runtime/common/src/weights/pallet_timestamp.rs new file mode 100644 index 00000000..f0493a53 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_timestamp.rs @@ -0,0 +1,67 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_timestamp` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_timestamp +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_timestamp`. +pub struct WeightInfo(PhantomData); +impl pallet_timestamp::WeightInfo for WeightInfo { + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn set() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1493` + // Minimum execution time: 4_371_000 picoseconds. + Weight::from_parts(4_733_000, 1493) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_finalize() -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `0` + // Minimum execution time: 3_353_000 picoseconds. + Weight::from_parts(3_482_000, 0) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_treasury.rs b/tracing/3200/runtime/common/src/weights/pallet_treasury.rs new file mode 100644 index 00000000..6725da85 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_treasury.rs @@ -0,0 +1,189 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_treasury` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_treasury +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_treasury`. +pub struct WeightInfo(PhantomData); +impl pallet_treasury::WeightInfo for WeightInfo { + /// Storage: `Treasury::ProposalCount` (r:1 w:1) + /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + fn spend_local() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `1887` + // Minimum execution time: 11_052_000 picoseconds. + Weight::from_parts(11_473_000, 1887) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Treasury::ProposalCount` (r:1 w:1) + /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + fn propose_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `479` + // Estimated: `1489` + // Minimum execution time: 24_623_000 picoseconds. + Weight::from_parts(25_147_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Treasury::Proposals` (r:1 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn reject_proposal() -> Weight { + // Proof Size summary in bytes: + // Measured: `775` + // Estimated: `6172` + // Minimum execution time: 41_462_000 picoseconds. + Weight::from_parts(43_692_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Treasury::Proposals` (r:1 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 99]`. + fn approve_proposal(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `608 + p * (8 ±0)` + // Estimated: `3549` + // Minimum execution time: 8_537_000 picoseconds. + Weight::from_parts(11_089_847, 3549) + // Standard Error: 2_302 + .saturating_add(Weight::from_parts(99_612, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn remove_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `265` + // Estimated: `1887` + // Minimum execution time: 6_645_000 picoseconds. + Weight::from_parts(6_943_000, 1887) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Deactivated` (r:1 w:1) + /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:1) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:99 w:0) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(84), added: 2559, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 99]`. + fn on_initialize_proposals(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `389 + p * (97 ±0)` + // Estimated: `3581 + p * (2559 ±0)` + // Minimum execution time: 19_078_000 picoseconds. + Weight::from_parts(19_681_138, 3581) + // Standard Error: 6_880 + .saturating_add(Weight::from_parts(3_247_708, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 2559).saturating_mul(p.into())) + } + /// Storage: `Treasury::SpendCount` (r:1 w:1) + /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Spends` (r:0 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `1489` + // Minimum execution time: 9_832_000 picoseconds. + Weight::from_parts(10_164_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `586` + // Estimated: `6172` + // Minimum execution time: 53_252_000 picoseconds. + Weight::from_parts(54_469_000, 6172) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3522` + // Minimum execution time: 11_987_000 picoseconds. + Weight::from_parts(12_454_000, 3522) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3522` + // Minimum execution time: 10_718_000 picoseconds. + Weight::from_parts(11_160_000, 3522) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_utility.rs b/tracing/3200/runtime/common/src/weights/pallet_utility.rs new file mode 100644 index 00000000..781d70ec --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_utility.rs @@ -0,0 +1,105 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_utility` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_utility +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_utility`. +pub struct WeightInfo(PhantomData); +impl pallet_utility::WeightInfo for WeightInfo { + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1000]`. + fn batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 4_192_000 picoseconds. + Weight::from_parts(6_679_403, 1527) + // Standard Error: 3_644 + .saturating_add(Weight::from_parts(3_997_128, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn as_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 6_410_000 picoseconds. + Weight::from_parts(6_685_000, 1527) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1000]`. + fn batch_all(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 4_142_000 picoseconds. + Weight::from_parts(6_126_307, 1527) + // Standard Error: 3_450 + .saturating_add(Weight::from_parts(4_209_528, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + fn dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_114_000 picoseconds. + Weight::from_parts(6_360_000, 0) + } + /// Storage: `MaintenanceMode::MaintenanceMode` (r:1 w:0) + /// Proof: `MaintenanceMode::MaintenanceMode` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 1000]`. + fn force_batch(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1527` + // Minimum execution time: 4_301_000 picoseconds. + Weight::from_parts(3_549_785, 1527) + // Standard Error: 3_240 + .saturating_add(Weight::from_parts(4_010_017, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_whitelist.rs b/tracing/3200/runtime/common/src/weights/pallet_whitelist.rs new file mode 100644 index 00000000..ab1ff273 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_whitelist.rs @@ -0,0 +1,118 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_whitelist` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_whitelist +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_whitelist`. +pub struct WeightInfo(PhantomData); +impl pallet_whitelist::WeightInfo for WeightInfo { + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn whitelist_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `46` + // Estimated: `3544` + // Minimum execution time: 15_951_000 picoseconds. + Weight::from_parts(16_432_000, 3544) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + fn remove_whitelisted_call() -> Weight { + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `3544` + // Minimum execution time: 15_715_000 picoseconds. + Weight::from_parts(16_228_000, 3544) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:1 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 4194294]`. + fn dispatch_whitelisted_call(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `251 + n * (1 ±0)` + // Estimated: `3715 + n * (1 ±0)` + // Minimum execution time: 26_625_000 picoseconds. + Weight::from_parts(27_069_000, 3715) + // Standard Error: 12 + .saturating_add(Weight::from_parts(1_316, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) + } + /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) + /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(79), added: 2554, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 10000]`. + fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `175` + // Estimated: `3544` + // Minimum execution time: 19_716_000 picoseconds. + Weight::from_parts(20_404_324, 3544) + // Standard Error: 2 + .saturating_add(Weight::from_parts(1_372, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_xcm.rs b/tracing/3200/runtime/common/src/weights/pallet_xcm.rs new file mode 100644 index 00000000..3267ab38 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_xcm.rs @@ -0,0 +1,336 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_xcm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn send() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 19_301_000 picoseconds. + Weight::from_parts(19_851_000, 3610) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Benchmark::Override` (r:0 w:0) + /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn teleport_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. + Weight::from_parts(18_446_744_073_709_551_000, 0) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn reserve_transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `519` + // Estimated: `3984` + // Minimum execution time: 87_834_000 picoseconds. + Weight::from_parts(89_873_000, 3984) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `217` + // Estimated: `3682` + // Minimum execution time: 76_760_000 picoseconds. + Weight::from_parts(78_960_000, 3682) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + fn execute() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_933_000 picoseconds. + Weight::from_parts(7_285_000, 0) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_xcm_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_631_000 picoseconds. + Weight::from_parts(7_031_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:0 w:1) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn force_default_xcm_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_060_000 picoseconds. + Weight::from_parts(2_180_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_subscribe_version_notify() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 24_580_000 picoseconds. + Weight::from_parts(25_066_000, 3610) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_unsubscribe_version_notify() -> Weight { + // Proof Size summary in bytes: + // Measured: `328` + // Estimated: `3793` + // Minimum execution time: 26_378_000 picoseconds. + Weight::from_parts(26_875_000, 3793) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) + /// Proof: `PolkadotXcm::XcmExecutionSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_935_000 picoseconds. + Weight::from_parts(2_180_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::SupportedVersion` (r:5 w:2) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_supported_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `125` + // Estimated: `13490` + // Minimum execution time: 25_540_000 picoseconds. + Weight::from_parts(26_459_000, 13490) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifiers` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_version_notifiers() -> Weight { + // Proof Size summary in bytes: + // Measured: `129` + // Estimated: `13494` + // Minimum execution time: 26_060_000 picoseconds. + Weight::from_parts(26_830_000, 13494) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:6 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn already_notified_target() -> Weight { + // Proof Size summary in bytes: + // Measured: `178` + // Estimated: `16018` + // Minimum execution time: 31_955_000 picoseconds. + Weight::from_parts(32_791_000, 16018) + .saturating_add(T::DbWeight::get().reads(6_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn notify_current_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `6152` + // Minimum execution time: 25_863_000 picoseconds. + Weight::from_parts(26_772_000, 6152) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:0) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn notify_target_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `172` + // Estimated: `11062` + // Minimum execution time: 18_701_000 picoseconds. + Weight::from_parts(19_378_000, 11062) + .saturating_add(T::DbWeight::get().reads(4_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn migrate_version_notify_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `136` + // Estimated: `13501` + // Minimum execution time: 26_001_000 picoseconds. + Weight::from_parts(26_438_000, 13501) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:5 w:2) + /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn migrate_and_notify_old_targets() -> Weight { + // Proof Size summary in bytes: + // Measured: `212` + // Estimated: `13577` + // Minimum execution time: 40_652_000 picoseconds. + Weight::from_parts(41_560_000, 13577) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn new_query() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `1554` + // Minimum execution time: 4_140_000 picoseconds. + Weight::from_parts(4_346_000, 1554) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn take_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `7706` + // Estimated: `11171` + // Minimum execution time: 25_629_000 picoseconds. + Weight::from_parts(26_213_000, 11171) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) + /// Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `126` + // Estimated: `3591` + // Minimum execution time: 37_818_000 picoseconds. + Weight::from_parts(38_367_000, 3591) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_xcm_transactor.rs b/tracing/3200/runtime/common/src/weights/pallet_xcm_transactor.rs new file mode 100644 index 00000000..142b00f2 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_xcm_transactor.rs @@ -0,0 +1,204 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_xcm_transactor` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm_transactor +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm_transactor`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_transactor::WeightInfo for WeightInfo { + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `3579` + // Minimum execution time: 9_019_000 picoseconds. + Weight::from_parts(9_455_000, 3579) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::IndexToAccount` (r:0 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_623_000 picoseconds. + Weight::from_parts(5_822_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_984_000 picoseconds. + Weight::from_parts(7_245_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_369_000 picoseconds. + Weight::from_parts(6_593_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:0 w:1) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_fee_per_second() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_487_000 picoseconds. + Weight::from_parts(7_019_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:0) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `493` + // Estimated: `3958` + // Minimum execution time: 34_510_000 picoseconds. + Weight::from_parts(35_293_000, 3958) + .saturating_add(T::DbWeight::get().reads(9_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsByLocation` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsByLocation` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_sovereign() -> Weight { + // Proof Size summary in bytes: + // Measured: `427` + // Estimated: `3892` + // Minimum execution time: 28_949_000 picoseconds. + Weight::from_parts(29_771_000, 3892) + .saturating_add(T::DbWeight::get().reads(7_u64)) + } + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transact_through_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `471` + // Estimated: `3936` + // Minimum execution time: 42_008_000 picoseconds. + Weight::from_parts(42_748_000, 3936) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `EvmForeignAssets::AssetsById` (r:1 w:0) + /// Proof: `EvmForeignAssets::AssetsById` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn hrmp_manage() -> Weight { + // Proof Size summary in bytes: + // Measured: `475` + // Estimated: `3940` + // Minimum execution time: 45_199_000 picoseconds. + Weight::from_parts(46_239_000, 3940) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} diff --git a/tracing/3200/runtime/common/src/weights/pallet_xcm_weight_trader.rs b/tracing/3200/runtime/common/src/weights/pallet_xcm_weight_trader.rs new file mode 100644 index 00000000..93d88a64 --- /dev/null +++ b/tracing/3200/runtime/common/src/weights/pallet_xcm_weight_trader.rs @@ -0,0 +1,104 @@ +// Copyright 2024 Moonbeam foundation +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Autogenerated weights for `pallet_xcm_weight_trader` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("moonbase-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/production/moonbeam +// benchmark +// pallet +// --chain=moonbase-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm_weight_trader +// --extrinsic=* +// --wasm-execution=compiled +// --header=./file_header.txt +// --template=./benchmarking/frame-weight-template.hbs +// --output=./runtime/common/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm_weight_trader`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_weight_trader::WeightInfo for WeightInfo { + /// Storage: `XcmWeightTrader::SupportedAssets` (r:1 w:1) + /// Proof: `XcmWeightTrader::SupportedAssets` (`max_values`: None, `max_size`: Some(635), added: 3110, mode: `MaxEncodedLen`) + fn add_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `4100` + // Minimum execution time: 9_432_000 picoseconds. + Weight::from_parts(9_644_000, 4100) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmWeightTrader::SupportedAssets` (r:1 w:1) + /// Proof: `XcmWeightTrader::SupportedAssets` (`max_values`: None, `max_size`: Some(635), added: 3110, mode: `MaxEncodedLen`) + fn edit_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `102` + // Estimated: `4100` + // Minimum execution time: 10_261_000 picoseconds. + Weight::from_parts(10_540_000, 4100) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmWeightTrader::SupportedAssets` (r:1 w:1) + /// Proof: `XcmWeightTrader::SupportedAssets` (`max_values`: None, `max_size`: Some(635), added: 3110, mode: `MaxEncodedLen`) + fn resume_asset_support() -> Weight { + // Proof Size summary in bytes: + // Measured: `102` + // Estimated: `4100` + // Minimum execution time: 10_153_000 picoseconds. + Weight::from_parts(10_537_000, 4100) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmWeightTrader::SupportedAssets` (r:1 w:1) + /// Proof: `XcmWeightTrader::SupportedAssets` (`max_values`: None, `max_size`: Some(635), added: 3110, mode: `MaxEncodedLen`) + fn pause_asset_support() -> Weight { + // Proof Size summary in bytes: + // Measured: `102` + // Estimated: `4100` + // Minimum execution time: 10_029_000 picoseconds. + Weight::from_parts(10_456_000, 4100) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmWeightTrader::SupportedAssets` (r:1 w:1) + /// Proof: `XcmWeightTrader::SupportedAssets` (`max_values`: None, `max_size`: Some(635), added: 3110, mode: `MaxEncodedLen`) + fn remove_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `102` + // Estimated: `4100` + // Minimum execution time: 9_844_000 picoseconds. + Weight::from_parts(10_218_000, 4100) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} diff --git a/tracing/3200/runtime/moonbase/Cargo.toml b/tracing/3200/runtime/moonbase/Cargo.toml new file mode 100644 index 00000000..f4958f5c --- /dev/null +++ b/tracing/3200/runtime/moonbase/Cargo.toml @@ -0,0 +1,444 @@ +[package] +authors = { workspace = true } +build = "build.rs" +description = "Moonbase Runtime" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonbase-runtime" +version = "0.8.4" + +[dependencies] +hex-literal = { workspace = true, optional = true } +log = { workspace = true } +num_enum = { workspace = true } +rlp = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +sha3 = { workspace = true, optional = true } +smallvec = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +# Moonbeam +account = { workspace = true } +moonbeam-core-primitives = { workspace = true } +moonbeam-relay-encoder = { workspace = true } +moonbeam-runtime-common = { workspace = true } +session-keys-primitives = { workspace = true } +xcm-primitives = { workspace = true } + +# Moonbeam pallets +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-erc20-xcm-bridge = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-evm-chain-id = { workspace = true } +pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] } +pallet-migrations = { workspace = true } +pallet-moonbeam-foreign-assets = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-proxy-genesis-companion = { workspace = true } +pallet-randomness = { workspace = true } +pallet-xcm-transactor = { workspace = true } +pallet-xcm-weight-trader = { workspace = true } + +# Moonbeam precompiles +pallet-evm-precompile-author-mapping = { workspace = true } +pallet-evm-precompile-balances-erc20 = { workspace = true } +pallet-evm-precompile-batch = { workspace = true } +pallet-evm-precompile-call-permit = { workspace = true } +pallet-evm-precompile-collective = { workspace = true } +pallet-evm-precompile-conviction-voting = { workspace = true } +pallet-evm-precompile-crowdloan-rewards = { workspace = true } +pallet-evm-precompile-gmp = { workspace = true } +pallet-evm-precompile-identity = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } +pallet-evm-precompile-preimage = { workspace = true } +pallet-evm-precompile-proxy = { workspace = true } +pallet-evm-precompile-randomness = { workspace = true } +pallet-evm-precompile-referenda = { workspace = true } +pallet-evm-precompile-registry = { workspace = true } +pallet-evm-precompile-relay-encoder = { workspace = true } +pallet-evm-precompile-relay-verifier = { workspace = true } +pallet-evm-precompile-xcm-transactor = { workspace = true } +pallet-evm-precompile-xcm-utils = { workspace = true } +pallet-evm-precompile-xtokens = { workspace = true } +pallet-evm-precompileset-assets-erc20 = { workspace = true } +pallet-evm-precompile-p256verify = { workspace = true } +precompile-foreign-asset-migrator = { workspace = true } + +# Moonbeam tracing +evm-tracing-events = { workspace = true, optional = true } +moonbeam-evm-tracer = { workspace = true, optional = true } +moonbeam-rpc-primitives-debug = { workspace = true } +moonbeam-rpc-primitives-txpool = { workspace = true } + +# Substrate +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-identity = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-parameters = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-society = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +parity-scale-codec = { workspace = true, features = [ + "derive", + "max-encoded-len", + "chain-error", +] } +scale-info = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-debug-derive = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true, features = ["improved_panic_error_reporting"] } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } +sp-genesis-builder = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde"] } +pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-precompile-blake2 = { workspace = true } +pallet-evm-precompile-bn128 = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } +pallet-evm-precompile-modexp = { workspace = true } +pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-simple = { workspace = true } +pallet-evm-precompile-storage-cleaner = { workspace = true } +precompile-utils = { workspace = true } + + +# Polkadot / XCM +orml-traits = { workspace = true } +orml-xcm-support = { workspace = true } +orml-xtokens = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { workspace = true, optional = true } +pallet-message-queue = { workspace = true } +polkadot-core-primitives = { workspace = true } +polkadot-parachain = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } + +# Cumulus +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } + +# Moonkit +async-backing-primitives = { workspace = true } +moonkit-xcm-primitives = { workspace = true } +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } +pallet-emergency-para-xcm = { workspace = true } +pallet-evm-precompile-xcm = { workspace = true } +pallet-relay-storage-roots = { workspace = true } + +# Benchmarking +frame-benchmarking = { workspace = true, optional = true } +frame-system-benchmarking = { workspace = true, optional = true } +frame-try-runtime = { workspace = true, optional = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true } + +[features] +default = ["std", "evm-tracing"] +std = [ + "account/std", + "async-backing-primitives/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "cumulus-primitives-storage-weight-reclaim/std", + "evm-tracing-events/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-metadata-hash-extension/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "moonbeam-core-primitives/std", + "moonbeam-evm-tracer/std", + "moonbeam-relay-encoder/std", + "moonbeam-rpc-primitives-debug/std", + "moonbeam-rpc-primitives-txpool/std", + "moonbeam-runtime-common/std", + "moonkit-xcm-primitives/std", + "nimbus-primitives/std", + "orml-xtokens/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-author-slot-filter/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-conviction-voting/std", + "pallet-crowdloan-rewards/std", + "pallet-emergency-para-xcm/std", + "pallet-erc20-xcm-bridge/std", + "pallet-evm-chain-id/std", + "pallet-ethereum-xcm/std", + "pallet-ethereum/std", + "pallet-evm-precompile-author-mapping/std", + "pallet-evm-precompile-balances-erc20/std", + "pallet-evm-precompile-batch/std", + "pallet-evm-precompile-call-permit/std", + "pallet-evm-precompile-collective/std", + "pallet-evm-precompile-conviction-voting/std", + "pallet-evm-precompile-parachain-staking/std", + "pallet-evm-precompile-preimage/std", + "pallet-evm-precompile-randomness/std", + "pallet-evm-precompile-referenda/std", + "pallet-evm-precompile-registry/std", + "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm/std", + "pallet-evm-precompile-xcm-transactor/std", + "pallet-evm-precompile-xcm-utils/std", + "pallet-evm-precompile-xtokens/std", + "pallet-evm-precompileset-assets-erc20/std", + "pallet-evm-precompile-storage-cleaner/std", + "pallet-evm-precompile-p256verify/std", + "pallet-evm/std", + "pallet-identity/std", + "pallet-maintenance-mode/std", + "pallet-migrations/std", + "pallet-moonbeam-foreign-assets/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-moonbeam-orbiters/std", + "pallet-multisig/std", + "pallet-parachain-staking/std", + "pallet-precompile-benchmarks/std", + "pallet-preimage/std", + "pallet-parameters/std", + "pallet-proxy-genesis-companion/std", + "pallet-proxy/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-relay-storage-roots/std", + "pallet-root-testing/std", + "pallet-scheduler/std", + "pallet-society/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-treasury/std", + "pallet-utility/std", + "pallet-whitelist/std", + "pallet-xcm-transactor/std", + "pallet-xcm/std", + "pallet-xcm-weight-trader/std", + "parachain-info/std", + "parachains-common/std", + "parity-scale-codec/std", + "precompile-utils/std", + "scale-info/std", + "session-keys-primitives/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-genesis-builder/std", + "strum/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm-primitives/std", + "xcm/std", +] + +# Must be enabled for tracing runtimes only +evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"] + +# Allow to print logs details (no wasm:stripped) +force-debug = ["sp-debug-derive/force-debug"] + +# Will be enabled by the `wasm-builder` when building the runtime for WASM. +runtime-wasm = [] + +# Enable the metadata hash generation in the wasm builder. +metadata-hash = ["substrate-wasm-builder/metadata-hash"] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "moonbeam-relay-encoder/runtime-benchmarks", + "moonbeam-runtime-common/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", + "pallet-moonbeam-foreign-assets/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-precompile-benchmarks/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-parameters/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-relay-storage-roots/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-society/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-xcm-weight-trader/runtime-benchmarks", + "session-keys-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] + +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "fp-self-contained/try-runtime", + "frame-executive/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime", + "moonbeam-runtime-common/try-runtime", + "pallet-asset-manager/try-runtime", + "pallet-author-mapping/try-runtime", + "pallet-author-slot-filter/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-emergency-para-xcm/try-runtime", + "pallet-maintenance-mode/try-runtime", + "pallet-migrations/try-runtime", + "pallet-moonbeam-lazy-migrations/try-runtime", + "pallet-parachain-staking/try-runtime", + "pallet-preimage/try-runtime", + "pallet-parameters/try-runtime", + "pallet-referenda/try-runtime", + "pallet-relay-storage-roots/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-xcm/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-utility/try-runtime", + "pallet-sudo/try-runtime", + "pallet-transaction-payment/try-runtime", + "parachain-info/try-runtime", + "pallet-evm-chain-id/try-runtime", + "parachain-info/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum/try-runtime", + "pallet-treasury/try-runtime", + "pallet-author-inherent/try-runtime", + "pallet-crowdloan-rewards/try-runtime", + "pallet-proxy/try-runtime", + "pallet-identity/try-runtime", + "orml-xtokens/try-runtime", + "pallet-assets/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-proxy-genesis-companion/try-runtime", + "pallet-moonbeam-orbiters/try-runtime", + "pallet-ethereum-xcm/try-runtime", + "pallet-randomness/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-erc20-xcm-bridge/try-runtime", + "pallet-multisig/try-runtime", + "pallet-async-backing/try-runtime", + "pallet-precompile-benchmarks/try-runtime", +] + +moonbase-runtime-benchmarks = [] diff --git a/tracing/3200/runtime/moonbase/build.rs b/tracing/3200/runtime/moonbase/build.rs new file mode 100644 index 00000000..e6b9435b --- /dev/null +++ b/tracing/3200/runtime/moonbase/build.rs @@ -0,0 +1,36 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +#[cfg(not(feature = "metadata-hash"))] +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} + +#[cfg(feature = "metadata-hash")] +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .enable_metadata_hash("UNIT", 18) + .build() +} diff --git a/tracing/3200/runtime/moonbase/src/asset_config.rs b/tracing/3200/runtime/moonbase/src/asset_config.rs new file mode 100644 index 00000000..7238148b --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/asset_config.rs @@ -0,0 +1,218 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Asset configuration for Moonbase. +//! + +use crate::OpenTechCommitteeInstance; + +use super::{ + currency, governance, xcm_config, AccountId, AssetId, Assets, Balance, Balances, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use moonbeam_runtime_common::weights as moonbase_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; + +use frame_support::{ + dispatch::GetDispatchInfo, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, EitherOfDiverse}, + weights::Weight, +}; + +use frame_system::{EnsureNever, EnsureRoot}; +use parity_scale_codec::{Compact, Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::H160; + +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; + +// Number of items that can be destroyed with our configured max extrinsic proof size. +// x = (a - b) / c where: +// a: maxExtrinsic proof size +// b: base proof size for destroy_accounts in pallet_assets weights +// c: proof size for each item +// 656.87 = (3_407_872 - 8232) / 5180 +const REMOVE_ITEMS_LIMIT: u32 = 656; + +// Not to disrupt the previous asset instance, we assign () to Foreign +pub type ForeignAssetInstance = (); + +// For foreign assets, these parameters dont matter much +// as this will only be called by root with the forced arguments +// No deposit is substracted with those methods +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::UNIT * currency::SUPPLY_FACTOR; + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = currency::deposit(1,68); + pub const MetadataDepositPerByte: Balance = currency::deposit(0, 1); +} + +/// We allow Root and General Admin to execute privileged asset operations. +pub type AssetsForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +// Foreign assets +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>; + type WeightInfo = moonbase_weights::pallet_assets::WeightInfo; + type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>; + type AssetIdParameter = Compact; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::{pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + #[transactional] + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + crate::AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + // Lastly, the metadata + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + // For us both of them (Foreign and Local) have the same annotated weight for a given + // witness + // We need to take the dispatch info from the destroy call, which is already annotated in + // the assets pallet + + // This is the dispatch info of destroy + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} + +pub type ForeignAssetModifierOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type ForeignAssetType = xcm_config::AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = ForeignAssetModifierOrigin; + type WeightInfo = moonbase_weights::pallet_asset_manager::WeightInfo; +} + +// Instruct how to go from an H160 to an AssetID +// We just take the lowest 128 bits +impl AccountIdAssetIdConversion for Runtime { + /// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF + /// and by taking the lowest 128 bits as the assetId + fn account_to_asset_id(account: AccountId) -> Option<(Vec, AssetId)> { + let h160_account: H160 = account.into(); + let mut data = [0u8; 16]; + let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4); + if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX { + data.copy_from_slice(id_part); + let asset_id: AssetId = u128::from_be_bytes(data).into(); + Some((prefix_part.to_vec(), asset_id)) + } else { + None + } + } + + // The opposite conversion + fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(prefix); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + AccountId::from(data) + } +} diff --git a/tracing/3200/runtime/moonbase/src/governance/councils.rs b/tracing/3200/runtime/moonbase/src/governance/councils.rs new file mode 100644 index 00000000..e1fb3109 --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/governance/councils.rs @@ -0,0 +1,62 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Councils for Gov1 and Gov2 + +use super::*; +use moonbeam_runtime_common::weights as moonbase_weights; + +pub type TreasuryCouncilInstance = pallet_collective::Instance3; +pub type OpenTechCommitteeInstance = pallet_collective::Instance4; + +parameter_types! { + // TODO: Check value of this parameter + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * BlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for treasury council members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 3 * DAYS }>; + /// The maximum number of proposals that can be open in the treasury council at once. + type MaxProposals = ConstU32<20>; + /// The maximum number of treasury council members. + type MaxMembers = ConstU32<9>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbase_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for technical committee members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 14 * DAYS }>; + /// The maximum number of proposals that can be open in the technical committee at once. + type MaxProposals = ConstU32<100>; + /// The maximum number of technical committee members. + type MaxMembers = ConstU32<100>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbase_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} diff --git a/tracing/3200/runtime/moonbase/src/governance/mod.rs b/tracing/3200/runtime/moonbase/src/governance/mod.rs new file mode 100644 index 00000000..36a2c6be --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/governance/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Governance configurations + +pub mod councils; +pub mod referenda; + +use super::*; + +mod origins; +pub use origins::{ + custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; diff --git a/tracing/3200/runtime/moonbase/src/governance/origins.rs b/tracing/3200/runtime/moonbase/src/governance/origins.rs new file mode 100644 index 00000000..e8de3c35 --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/governance/origins.rs @@ -0,0 +1,83 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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. + +//! Custom origins for governance interventions. +pub use custom_origins::*; + +#[frame_support::pallet] +pub mod custom_origins { + use frame_support::pallet_prelude::*; + use strum_macros::EnumString; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive( + PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug, EnumString, + )] + #[strum(serialize_all = "snake_case")] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// General admin + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Fast General Admin + FastGeneralAdmin, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + GeneralAdmin, + FastGeneralAdmin, + ); +} diff --git a/tracing/3200/runtime/moonbase/src/governance/referenda.rs b/tracing/3200/runtime/moonbase/src/governance/referenda.rs new file mode 100644 index 00000000..36cd0420 --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/governance/referenda.rs @@ -0,0 +1,101 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Gov2 config +//! Includes runtime configs for these substrate pallets: +//! 1. pallet-conviction-voting +//! 2. pallet-whitelist +//! 3. pallet-referenda + +use super::*; +use crate::currency::*; +use frame_support::traits::{EitherOf, MapSuccess}; +use frame_system::EnsureRootWithSuccess; +use moonbeam_runtime_common::weights as moonbase_weights; +use sp_runtime::traits::Replace; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 1 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = moonbase_weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Polls = Referenda; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + // Maximum number of concurrent votes an account may have + type MaxVotes = ConstU32<20>; + // Minimum period of vote locking + type VoteLockingPeriod = VoteLockingPeriod; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 10 * UNIT * SUPPLY_FACTOR; + pub const UndecidingTimeout: BlockNumber = 21 * DAYS; +} + +pub type GeneralAdminOrRoot = EitherOf, origins::GeneralAdmin>; + +/// The policy allows for Root or FastGeneralAdmin. +pub type FastGeneralAdminOrRoot = EitherOf, origins::FastGeneralAdmin>; + +impl custom_origins::Config for Runtime {} + +// The purpose of this pallet is to queue calls to be dispatched as by root later => the Dispatch +// origin corresponds to the Gov2 Whitelist track. +impl pallet_whitelist::Config for Runtime { + type WeightInfo = moonbase_weights::pallet_whitelist::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WhitelistOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + pallet_collective::EnsureProportionAtLeast< + Self::AccountId, + OpenTechCommitteeInstance, + 5, + 9, + >, + Replace>, + >, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +impl pallet_referenda::Config for Runtime { + type WeightInfo = moonbase_weights::pallet_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/tracing/3200/runtime/moonbase/src/governance/tracks.rs b/tracing/3200/runtime/moonbase/src/governance/tracks.rs new file mode 100644 index 00000000..72e18b9f --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/governance/tracks.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{KILOUNIT, SUPPLY_FACTOR, UNIT}; +use sp_std::str::FromStr; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} +const fn permill(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 1000) +} + +use pallet_referenda::Curve; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + // Name of this track. + name: "root", + // A limit for the number of referenda on this track that can be being decided at once. + // For Root origin this should generally be just one. + max_deciding: 5, + // Amount that must be placed on deposit before a decision can be made. + decision_deposit: 100 * KILOUNIT * SUPPLY_FACTOR, + // Amount of time this must be submitted for before a decision can be made. + prepare_period: 1 * DAYS, + // Amount of time that a decision may take to be approved prior to cancellation. + decision_period: 14 * DAYS, + // Amount of time that the approval criteria must hold before it can be approved. + confirm_period: 1 * DAYS, + // Minimum amount of time that an approved proposal must be in the dispatch queue. + min_enactment_period: 1 * DAYS, + // Minimum aye votes as percentage of overall conviction-weighted votes needed for + // approval as a function of time into decision period. + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + // Minimum pre-conviction aye-votes ("support") as percentage of overall population that + // is needed for approval as a function of time into decision period. + min_support: Curve::make_linear(14, 14, permill(5), percent(25)), + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * KILOUNIT * SUPPLY_FACTOR, + prepare_period: 10 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)), + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 500 * UNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 1 * DAYS, + min_enactment_period: 1 * DAYS, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)), + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 20, + decision_deposit: 10 * KILOUNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(50)), + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 100, + decision_deposit: 20 * KILOUNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "fast_general_admin", + max_deciding: 10, + decision_deposit: 500 * UNIT * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)), + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => { + if let Some((track_id, _)) = Self::tracks() + .into_iter() + .find(|(_, track)| track.name == "root") + { + Ok(*track_id) + } else { + Err(()) + } + } + _ => Err(()), + } + } else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) { + if let Some((track_id, _)) = Self::tracks().into_iter().find(|(_, track)| { + if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track.name) { + track_custom_origin == custom_origin + } else { + false + } + }) { + Ok(*track_id) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +#[test] +/// To ensure voters are always locked into their vote +fn vote_locking_always_longer_than_enactment_period() { + for (_, track) in TRACKS_DATA { + assert!( + ::VoteLockingPeriod::get() + >= track.min_enactment_period, + "Track {} has enactment period {} < vote locking period {}", + track.name, + track.min_enactment_period, + ::VoteLockingPeriod::get(), + ); + } +} + +#[test] +fn all_tracks_have_origins() { + for (_, track) in TRACKS_DATA { + // check name.into() is successful either converts into "root" or custom origin + let track_is_root = track.name == "root"; + let track_has_custom_origin = custom_origins::Origin::from_str(track.name).is_ok(); + assert!(track_is_root || track_has_custom_origin); + } +} diff --git a/tracing/3200/runtime/moonbase/src/lib.rs b/tracing/3200/runtime/moonbase/src/lib.rs new file mode 100644 index 00000000..a99872c5 --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/lib.rs @@ -0,0 +1,1855 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! The Moonbase Runtime. +//! +//! Primary features of this runtime include: +//! * Ethereum compatibility +//! * Moonbase tokenomics + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "512"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod asset_config; +pub mod governance; +pub mod runtime_params; +pub mod xcm_config; + +mod migrations; +mod precompiles; + +// Re-export required by get! macro. +#[cfg(feature = "std")] +pub use fp_evm::GenesisAccount; +pub use frame_support::traits::Get; +pub use moonbeam_core_primitives::{ + AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, + Index, Signature, +}; +pub use pallet_author_slot_filter::EligibilityValue; +pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range}; +pub use precompiles::{ + MoonbasePrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use account::AccountId20; +use cumulus_pallet_parachain_system::{ + RelayChainStateProof, RelayStateProof, RelaychainDataProvider, ValidationData, +}; +use cumulus_primitives_core::{relay_chain, AggregateMessageOrigin}; +use fp_rpc::TransactionStatus; +use frame_support::{ + construct_runtime, + dispatch::{DispatchClass, GetDispatchInfo, PostDispatchInfo}, + ensure, + pallet_prelude::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Credit, HoldConsideration, Inspect}, + tokens::imbalance::ResolveTo, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, + EqualPrivilegeOnly, FindAuthor, Imbalance, InstanceFilter, LinearStoragePrice, OnFinalize, + OnUnbalanced, + }, + weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, + }, + PalletId, +}; + +use frame_system::{EnsureRoot, EnsureSigned}; +use governance::councils::*; +use moonbeam_rpc_primitives_txpool::TxPoolResponse; +use moonbeam_runtime_common::{ + timestamp::{ConsensusHookWrapperForRelayTimestamp, RelayTimestamp}, + weights as moonbase_weights, +}; +use nimbus_primitives::CanAuthor; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction}; +use pallet_evm::{ + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, GasWeightMapping, IdentityAddressMapping, + OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, +}; +use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_treasury::TreasuryAccountId; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_api::impl_runtime_apis; +use sp_consensus_slots::Slot; +use sp_core::{OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{ + BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentityLookup, + PostDispatchInfoOf, UniqueSaturatedInto, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, DispatchErrorWithPostInfo, FixedPointNumber, Perbill, Permill, + Perquintill, +}; +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; +use xcm::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; + +use runtime_params::*; + +use smallvec::smallvec; +use sp_runtime::serde::{Deserialize, Serialize}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +pub type Precompiles = MoonbasePrecompiles; + +/// UNIT, the native token, uses 18 decimals of precision. +pub mod currency { + use super::Balance; + + // Provide a common factor between runtimes based on a supply of 10_000_000 tokens. + pub const SUPPLY_FACTOR: Balance = 1; + + pub const WEI: Balance = 1; + pub const KILOWEI: Balance = 1_000; + pub const MEGAWEI: Balance = 1_000_000; + pub const GIGAWEI: Balance = 1_000_000_000; + pub const MICROUNIT: Balance = 1_000_000_000_000; + pub const MILLIUNIT: Balance = 1_000_000_000_000_000; + pub const UNIT: Balance = 1_000_000_000_000_000_000; + pub const KILOUNIT: Balance = 1_000_000_000_000_000_000_000; + + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; + pub const STORAGE_BYTE_FEE: Balance = 100 * MICROUNIT * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR / 4; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 1 * UNIT * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE + } +} + +/// Maximum weight per block +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX) + .saturating_mul(2) + .set_proof_size(relay_chain::MAX_POV_SIZE as u64); + +pub const MILLISECS_PER_BLOCK: u64 = 6_000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + pub type Block = generic::Block; + + impl_opaque_keys! { + pub struct SessionKeys { + pub nimbus: AuthorInherent, + pub vrf: session_keys_primitives::VrfSessionKey, + } + } +} + +/// This runtime version. +/// The spec_version is composed of 2x2 digits. The first 2 digits represent major changes +/// that can't be skipped, such as data migration upgrades. The last 2 digits represent minor +/// changes which can be skipped. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("moonbase"), + impl_name: create_runtime_str!("moonbase"), + authoring_version: 4, + spec_version: 3200, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 3, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we +// subtract roughly the cost of a balance transfer from it (about 1/3 the cost) +// and some cost to account for per-byte-fee. +// TODO: we should use benchmarking's overhead feature to measure this +pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_parts(10000 * WEIGHT_PER_GAS, 0); + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Provided BlockWeight definitions are valid, qed") + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + /// TODO: this is left here so that `impl_runtime_apis_plus_common` will find the same type for + /// `BlockWeights` in all runtimes. It can probably be removed once the custom + /// `RuntimeBlockWeights` has been pushed to each runtime. + pub BlockWeights: frame_system::limits::BlockWeights = RuntimeBlockWeights::get(); + /// We allow for 5 MB blocks. + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); +} + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Index; + /// The index type for blocks. + type Block = Block; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// The aggregated RuntimeTask type. + type RuntimeTask = RuntimeTask; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = ConstU32<256>; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type BlockWeights = RuntimeBlockWeights; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type BlockLength = BlockLength; + /// Runtime version. + type Version = Version; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = moonbase_weights::db::rocksdb::constants::RocksDbWeight; + type BaseCallFilter = MaintenanceMode; + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<1287>; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = moonbase_weights::pallet_utility::WeightInfo; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3000>; + type WeightInfo = moonbase_weights::pallet_timestamp::WeightInfo; +} + +#[cfg(not(feature = "runtime-benchmarks"))] +parameter_types! { + pub const ExistentialDeposit: Balance = 0; +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 4]; + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = moonbase_weights::pallet_balances::WeightInfo; +} + +pub struct DealWithFees(sp_std::marker::PhantomData); +impl OnUnbalanced>> for DealWithFees +where + R: pallet_balances::Config + pallet_treasury::Config, +{ + // this seems to be called for substrate-based transactions + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>>, + ) { + if let Some(fees) = fees_then_tips.next() { + let treasury_perbill = + runtime_params::dynamic_params::runtime_config::FeesTreasuryProportion::get(); + let treasury_part = treasury_perbill.deconstruct(); + let burn_part = Perbill::one().deconstruct() - treasury_part; + let (_, to_treasury) = fees.ration(burn_part, treasury_part); + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + + // handle tip if there is one + if let Some(tip) = fees_then_tips.next() { + // for now we use the same burn/treasury strategy used for regular fees + let (_, to_treasury) = tip.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + } + } + } + + // this is called from pallet_evm for Ethereum-based transactions + // (technically, it calls on_unbalanced, which calls this when non-zero) + fn on_nonzero_unbalanced(amount: Credit>) { + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + let (_, to_treasury) = amount.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced(to_treasury); + } +} + +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1 * currency::SUPPLY_FACTOR, + negative: false, + }, + ] + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = FungibleAdapter>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = ConstantMultiplier>; + type LengthToFee = LengthToFee; + type FeeMultiplierUpdate = FastAdjustingFeeUpdate; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = moonbase_weights::pallet_sudo::WeightInfo; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 2 sec Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; +/// The highest amount of new storage that can be created in a block (160KB). +pub const BLOCK_STORAGE_LIMIT: u64 = 160 * 1024; +parameter_types! { + pub BlockGasLimit: U256 + = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); + /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less + /// than this will decrease the weight and more will increase. + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); + /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to + /// change the fees more rapidly. This fast multiplier responds by doubling/halving in + /// approximately one hour at extreme block congestion levels. + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); + /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure + /// that combined with `AdjustmentVariable`, we can recover from the minimum. + /// See `multiplier_can_grow_from_zero` in integration_tests.rs. + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 10); + /// Maximum multiplier. We pick a value that is expensive but not impossibly so; it should act + /// as a safety net. + pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); + pub PrecompilesValue: MoonbasePrecompiles = MoonbasePrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 16 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + /// We should re-check `xcm_config::Erc20XcmBridgeTransferGasLimit` when changing this value + pub const GasLimitPovSizeRatio: u64 = 16; + /// The amount of gas per storage (in bytes): BLOCK_GAS_LIMIT / BLOCK_STORAGE_LIMIT + /// (60_000_000 / 160 kb) + pub GasLimitStorageGrowthRatio: u64 = 366; +} + +pub struct TransactionPaymentAsGasPrice; +impl FeeCalculator for TransactionPaymentAsGasPrice { + fn min_gas_price() -> (U256, Weight) { + // TODO: transaction-payment differs from EIP-1559 in that its tip and length fees are not + // scaled by the multiplier, which means its multiplier will be overstated when + // applied to an ethereum transaction + // note: transaction-payment uses both a congestion modifier (next_fee_multiplier, which is + // updated once per block in on_finalize) and a 'WeightToFee' implementation. Our + // runtime implements this as a 'ConstantModifier', so we can get away with a simple + // multiplication here. + // It is imperative that `saturating_mul_int` be performed as late as possible in the + // expression since it involves fixed point multiplication with a division by a fixed + // divisor. This leads to truncation and subsequent precision loss if performed too early. + // This can lead to min_gas_price being same across blocks even if the multiplier changes. + // There's still some precision loss when the final `gas_price` (used_gas * min_gas_price) + // is computed in frontier, but that's currently unavoidable. + let min_gas_price = TransactionPayment::next_fee_multiplier() + .saturating_mul_int((currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128)); + ( + min_gas_price.into(), + ::DbWeight::get().reads(1), + ) + } +} + +/// A "Fast" TargetedFeeAdjustment. Parameters chosen based on model described here: +/// https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#-1.-fast-adjusting-mechanism // editorconfig-checker-disable-line +/// +/// The adjustment algorithm boils down to: +/// +/// diff = (previous_block_weight - target) / maximum_block_weight +/// next_multiplier = prev_multiplier * (1 + (v * diff) + ((v * diff)^2 / 2)) +/// assert(next_multiplier > min) +/// where: v is AdjustmentVariable +/// target is TargetBlockFullness +/// min is MinimumMultiplier +pub type FastAdjustingFeeUpdate = TargetedFeeAdjustment< + R, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, +>; + +/// The author inherent provides an AccountId, but pallet evm needs an H160. +/// This simple adapter makes the conversion for any types T, U such that T: Into +pub struct FindAuthorAdapter(sp_std::marker::PhantomData<(T, U, Inner)>); + +impl FindAuthor for FindAuthorAdapter +where + T: Into, + Inner: FindAuthor, +{ + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + Inner::find_author(digests).map(Into::into) + } +} + +moonbeam_runtime_common::impl_on_charge_evm_transaction!(); + +impl pallet_evm::Config for Runtime { + type FeeCalculator = TransactionPaymentAsGasPrice; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = IdentityAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = MoonbasePrecompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EthereumChainId; + type OnChargeTransaction = OnChargeEVMTransaction>; + type BlockGasLimit = BlockGasLimit; + type FindAuthor = FindAuthorAdapter; + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = RelayTimestamp; + type WeightInfo = moonbase_weights::pallet_evm::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; + pub const NoPreimagePostponement: Option = Some(10); +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = moonbase_weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = 5 * currency::UNIT * currency::SUPPLY_FACTOR ; + pub const PreimageByteDeposit: Balance = currency::STORAGE_BYTE_FEE; + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = moonbase_weights::pallet_preimage::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +type TreasuryApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +type TreasuryRejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + // At least three-fifths majority of the council is required (or root) to approve a proposal + type ApproveOrigin = TreasuryApproveOrigin; + // More than half of the council is required (or root) to reject a proposal + type RejectOrigin = TreasuryRejectOrigin; + type RuntimeEvent = RuntimeEvent; + // If spending proposal rejected, transfer proposer bond to treasury + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type SpendPeriod = ConstU32<{ 6 * DAYS }>; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = moonbase_weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type ProposalBondMaximum = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Disabled, no spending + #[cfg(feature = "runtime-benchmarks")] + type SpendOrigin = + frame_system::EnsureWithSuccess, AccountId, benches::MaxBalance>; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +parameter_types! { + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; + pub const PendingUsernameExpiration: u32 = 7 * DAYS; + pub const MaxSuffixLength: u32 = 7; + pub const MaxUsernameLength: u32 = 32; +} + +type IdentityForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type IdentityRegistrarOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_identity::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + // Add one item in storage and take 258 bytes + type BasicDeposit = ConstU128<{ currency::deposit(1, 258) }>; + // Does not add any item to the storage but takes 1 bytes + type ByteDeposit = ConstU128<{ currency::deposit(0, 1) }>; + // Add one item in storage and take 53 bytes + type SubAccountDeposit = ConstU128<{ currency::deposit(1, 53) }>; + type MaxSubAccounts = MaxSubAccounts; + type IdentityInformation = pallet_identity::legacy::IdentityInfo; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = IdentityForceOrigin; + type RegistrarOrigin = IdentityRegistrarOrigin; + type OffchainSignature = Signature; + type SigningPublicKey = ::Signer; + type UsernameAuthorityOrigin = EnsureRoot; + type PendingUsernameExpiration = PendingUsernameExpiration; + type MaxSuffixLength = MaxSuffixLength; + type MaxUsernameLength = MaxUsernameLength; + type WeightInfo = moonbase_weights::pallet_identity::WeightInfo; +} + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will immediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook< + Runtime, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainInfo; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = EmergencyParaXcm; + type ConsensusHook = ConsensusHookWrapperForRelayTimestamp; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = moonbase_weights::cumulus_pallet_parachain_system::WeightInfo; +} + +impl parachain_info::Config for Runtime {} + +pub struct OnNewRound; +impl pallet_parachain_staking::OnNewRound for OnNewRound { + fn on_new_round(round_index: pallet_parachain_staking::RoundIndex) -> Weight { + MoonbeamOrbiters::on_new_round(round_index) + } +} +pub struct PayoutCollatorOrOrbiterReward; +impl pallet_parachain_staking::PayoutCollatorReward for PayoutCollatorOrOrbiterReward { + fn payout_collator_reward( + for_round: pallet_parachain_staking::RoundIndex, + collator_id: AccountId, + amount: Balance, + ) -> Weight { + let extra_weight = + if MoonbeamOrbiters::is_collator_pool_with_active_orbiter(for_round, collator_id) { + MoonbeamOrbiters::distribute_rewards(for_round, collator_id, amount) + } else { + ParachainStaking::mint_collator_reward(for_round, collator_id, amount) + }; + + ::DbWeight::get() + .reads(1) + .saturating_add(extra_weight) + } +} + +pub struct OnInactiveCollator; +impl pallet_parachain_staking::OnInactiveCollator for OnInactiveCollator { + fn on_inactive_collator( + collator_id: AccountId, + round: pallet_parachain_staking::RoundIndex, + ) -> Result> { + let extra_weight = if !MoonbeamOrbiters::is_collator_pool_with_active_orbiter( + round, + collator_id.clone(), + ) { + ParachainStaking::go_offline_inner(collator_id)?; + ::WeightInfo::go_offline( + pallet_parachain_staking::MAX_CANDIDATES, + ) + } else { + Weight::zero() + }; + + Ok(::DbWeight::get() + .reads(1) + .saturating_add(extra_weight)) + } +} + +type MonetaryGovernanceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +pub struct RelayChainSlotProvider; +impl Get for RelayChainSlotProvider { + fn get() -> Slot { + let slot_info = pallet_async_backing::pallet::Pallet::::slot_info(); + slot_info.unwrap_or_default().0 + } +} + +impl pallet_parachain_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = MonetaryGovernanceOrigin; + /// Minimum round length is 2 minutes (10 * 12 second block times) + type MinBlocksPerRound = ConstU32<10>; + /// If a collator doesn't produce any block on this number of rounds, it is notified as inactive + type MaxOfflineRounds = ConstU32<2>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<2>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<2>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<2>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<2>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<2>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after + type MinSelectedCandidates = ConstU32<8>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = ConstU128<{ 500 * currency::UNIT * currency::SUPPLY_FACTOR }>; + /// Minimum stake required to be reserved to be a delegator + type MinDelegation = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type BlockAuthor = AuthorInherent; + type OnCollatorPayout = (); + type PayoutCollatorReward = PayoutCollatorOrOrbiterReward; + type OnInactiveCollator = OnInactiveCollator; + type OnNewRound = OnNewRound; + type SlotProvider = RelayChainSlotProvider; + type WeightInfo = moonbase_weights::pallet_parachain_staking::WeightInfo; + type MaxCandidates = ConstU32<200>; + type SlotDuration = ConstU64<6_000>; + type BlockTime = ConstU64<6_000>; +} + +impl pallet_author_inherent::Config for Runtime { + type SlotBeacon = RelaychainDataProvider; + type AccountLookup = MoonbeamOrbiters; + type CanAuthor = AuthorFilter; + type AuthorId = AccountId; + type WeightInfo = moonbase_weights::pallet_author_inherent::WeightInfo; +} + +#[cfg(test)] +mod mock { + use super::*; + pub struct MockRandomness; + impl frame_support::traits::Randomness for MockRandomness { + fn random(subject: &[u8]) -> (H256, BlockNumber) { + (H256(sp_io::hashing::blake2_256(subject)), 0) + } + } +} + +impl pallet_author_slot_filter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(test))] + type RandomnessSource = Randomness; + #[cfg(test)] + type RandomnessSource = mock::MockRandomness; + type PotentialAuthors = ParachainStaking; + type WeightInfo = moonbase_weights::pallet_author_slot_filter::WeightInfo; +} + +impl pallet_async_backing::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type GetAndVerifySlot = pallet_async_backing::RelaySlot; + type ExpectedBlockTime = ConstU64<6000>; +} + +parameter_types! { + pub const InitializationPayment: Perbill = Perbill::from_percent(30); + pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100); + pub const SignatureNetworkIdentifier: &'static [u8] = b"moonbase-"; + +} + +impl pallet_crowdloan_rewards::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Initialized = ConstBool; + type InitializationPayment = InitializationPayment; + type MaxInitContributors = ConstU32<500>; + // TODO to be revisited + type MinimumReward = ConstU128<0>; + type RewardCurrency = Balances; + type RelayChainAccountId = [u8; 32]; + type RewardAddressAssociateOrigin = EnsureSigned; + type RewardAddressChangeOrigin = EnsureSigned; + type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold; + type SignatureNetworkIdentifier = SignatureNetworkIdentifier; + type VestingBlockNumber = relay_chain::BlockNumber; + type VestingBlockProvider = RelaychainDataProvider; + type WeightInfo = moonbase_weights::pallet_crowdloan_rewards::WeightInfo; +} + +// This is a simple session key manager. It should probably either work with, or be replaced +// entirely by pallet sessions +impl pallet_author_mapping::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DepositCurrency = Balances; + type DepositAmount = ConstU128<{ 100 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type Keys = session_keys_primitives::VrfId; + type WeightInfo = moonbase_weights::pallet_author_mapping::WeightInfo; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] +pub enum ProxyType { + /// All calls can be proxied. This is the trivial/most permissive filter. + Any = 0, + /// Only extrinsics that do not transfer funds. + NonTransfer = 1, + /// Only extrinsics related to governance (democracy and collectives). + Governance = 2, + /// Only extrinsics related to staking. + Staking = 3, + /// Allow to veto an announced proxy call. + CancelProxy = 4, + /// Allow extrinsic related to Balances. + Balances = 5, + /// Allow extrinsic related to AuthorMapping. + AuthorMapping = 6, + /// Allow extrinsic related to IdentityJudgement. + IdentityJudgement = 7, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +fn is_governance_precompile(precompile_name: &precompiles::PrecompileName) -> bool { + matches!( + precompile_name, + PrecompileName::TreasuryCouncilInstance + | PrecompileName::ReferendaPrecompile + | PrecompileName::ConvictionVotingPrecompile + | PrecompileName::PreimagePrecompile + | PrecompileName::OpenTechCommitteeInstance, + ) +} + +// Be careful: Each time this filter is modified, the substrate filter must also be modified +// consistently. +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType { + fn is_evm_proxy_call_allowed( + &self, + call: &pallet_evm_precompile_proxy::EvmSubCall, + recipient_has_code: bool, + gas: u64, + ) -> precompile_utils::EvmResult { + Ok(match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + call.value == U256::zero() + && match PrecompileName::from_address(call.to.0) { + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::IdentityPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + _ => false, + } + } + ProxyType::Governance => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(ref precompile) if is_governance_precompile(precompile) + ) + } + ProxyType::Staking => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile + ) + ) + } + // The proxy precompile does not contain method cancel_proxy + ProxyType::CancelProxy => false, + ProxyType::Balances => { + // Allow only "simple" accounts as recipient (no code nor precompile). + // Note: Checking the presence of the code is not enough because some precompiles + // have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + ProxyType::AuthorMapping => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(PrecompileName::AuthorMappingPrecompile) + ) + } + // There is no identity precompile + ProxyType::IdentityJudgement => false, + }) + } +} + +// Be careful: Each time this filter is modified, the EVM filter must also be modified consistently. +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::ParachainSystem(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::ParachainStaking(..) + | RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Identity(..) + | RuntimeCall::Utility(..) + | RuntimeCall::Proxy(..) | RuntimeCall::AuthorMapping(..) + | RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::claim { .. } + ) + ) + } + ProxyType::Governance => matches!( + c, + RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Utility(..) + ), + ProxyType::Staking => matches!( + c, + RuntimeCall::ParachainStaking(..) + | RuntimeCall::Utility(..) + | RuntimeCall::AuthorMapping(..) + | RuntimeCall::MoonbeamOrbiters(..) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ), + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + } + ProxyType::AuthorMapping => matches!(c, RuntimeCall::AuthorMapping(..)), + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) + | RuntimeCall::Utility(..) + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8 + type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)). + type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = moonbase_weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 56 bytes: + // - 20 bytes AccountId + // - 32 bytes Hasher (Blake2256) + // - 4 bytes BlockNumber (u32) + type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // TODO wire up our correct list of migrations here. Maybe this shouldn't be in + // `moonbeam_runtime_common`. + type MigrationsList = ( + moonbeam_runtime_common::migrations::CommonMigrations, + migrations::MoonbaseMigrations, + ); + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_moonbeam_lazy_migrations::Config for Runtime { + type WeightInfo = moonbase_weights::pallet_moonbeam_lazy_migrations::WeightInfo; +} + +/// Maintenance mode Call filter +pub struct MaintenanceFilter; +impl Contains for MaintenanceFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(_) => false, + RuntimeCall::Balances(_) => false, + RuntimeCall::CrowdloanRewards(_) => false, + RuntimeCall::Ethereum(_) => false, + RuntimeCall::EVM(_) => false, + RuntimeCall::Identity(_) => false, + RuntimeCall::XTokens(_) => false, + RuntimeCall::ParachainStaking(_) => false, + RuntimeCall::MoonbeamOrbiters(_) => false, + RuntimeCall::PolkadotXcm(_) => false, + RuntimeCall::Treasury(_) => false, + RuntimeCall::XcmTransactor(_) => false, + RuntimeCall::EthereumXcm(_) => false, + _ => true, + } + } +} + +/// Normal Call Filter +/// We dont allow to create nor mint assets, this for now is disabled +/// We only allow transfers. For now creation of assets will go through +/// asset-manager, while minting/burning only happens through xcm messages +/// This can change in the future +pub struct NormalFilter; +impl Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(method) => match method { + pallet_assets::Call::transfer { .. } => true, + pallet_assets::Call::transfer_keep_alive { .. } => true, + pallet_assets::Call::approve_transfer { .. } => true, + pallet_assets::Call::transfer_approved { .. } => true, + pallet_assets::Call::cancel_approval { .. } => true, + pallet_assets::Call::destroy_accounts { .. } => true, + pallet_assets::Call::destroy_approvals { .. } => true, + pallet_assets::Call::finish_destroy { .. } => true, + _ => false, + }, + // We filter anonymous proxy as they make "reserve" inconsistent + // See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line + RuntimeCall::Proxy(method) => match method { + pallet_proxy::Call::create_pure { .. } => false, + pallet_proxy::Call::kill_pure { .. } => false, + pallet_proxy::Call::proxy { real, .. } => { + !pallet_evm::AccountCodes::::contains_key(H160::from(*real)) + } + _ => true, + }, + // Filtering the EVM prevents possible re-entrancy from the precompiles which could + // lead to unexpected scenarios. + // See https://github.com/PureStake/sr-moonbeam/issues/30 + // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so + // this can be seen as an additional security + RuntimeCall::EVM(_) => false, + RuntimeCall::Treasury( + pallet_treasury::Call::spend { .. } + | pallet_treasury::Call::payout { .. } + | pallet_treasury::Call::check_status { .. } + | pallet_treasury::Call::void_spend { .. }, + ) => false, + _ => true, + } + } +} + +pub struct XcmExecutionManager; +impl moonkit_xcm_primitives::PauseXcmExecution for XcmExecutionManager { + fn suspend_xcm_execution() -> DispatchResult { + XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root()) + } + fn resume_xcm_execution() -> DispatchResult { + XcmpQueue::resume_xcm_execution(RuntimeOrigin::root()) + } +} + +impl pallet_maintenance_mode::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type NormalCallFilter = NormalFilter; + type MaintenanceCallFilter = MaintenanceFilter; + type MaintenanceOrigin = + pallet_collective::EnsureProportionAtLeast; + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_proxy_genesis_companion::Config for Runtime { + type ProxyType = ProxyType; +} + +parameter_types! { + pub OrbiterReserveIdentifier: [u8; 4] = [b'o', b'r', b'b', b'i']; +} + +type AddCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type DelCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_moonbeam_orbiters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountLookup = AuthorMapping; + type AddCollatorOrigin = AddCollatorOrigin; + type Currency = Balances; + type DelCollatorOrigin = DelCollatorOrigin; + /// Maximum number of orbiters per collator + type MaxPoolSize = ConstU32<8>; + /// Maximum number of round to keep on storage + type MaxRoundArchive = ConstU32<4>; + type OrbiterReserveIdentifier = OrbiterReserveIdentifier; + type RotatePeriod = ConstU32<3>; + /// Round index type. + type RoundIndex = pallet_parachain_staking::RoundIndex; + type WeightInfo = moonbase_weights::pallet_moonbeam_orbiters::WeightInfo; +} + +/// Only callable after `set_validation_data` is called which forms this proof the same way +fn relay_chain_state_proof() -> RelayChainStateProof +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + let relay_storage_root = ValidationData::::get() + .expect("set in `set_validation_data`") + .relay_parent_storage_root; + let relay_chain_state = + RelayStateProof::::get().expect("set in `set_validation_data`"); + RelayChainStateProof::new(ParachainInfo::get(), relay_storage_root, relay_chain_state) + .expect("Invalid relay chain state proof, already constructed in `set_validation_data`") +} + +pub struct BabeDataGetter(sp_std::marker::PhantomData); +impl pallet_randomness::GetBabeData> for BabeDataGetter +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + // Tolerate panic here because only ever called in inherent (so can be omitted) + fn get_epoch_index() -> u64 { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + const BENCHMARKING_NEW_EPOCH: u64 = 10u64; + return BENCHMARKING_NEW_EPOCH; + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::EPOCH_INDEX) + .ok() + .flatten() + .expect("expected to be able to read epoch index from relay chain state proof") + } + fn get_epoch_randomness() -> Option { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + let benchmarking_babe_output = Hash::default(); + return Some(benchmarking_babe_output); + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::ONE_EPOCH_AGO_RANDOMNESS) + .ok() + .flatten() + } +} + +impl pallet_randomness::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddressMapping = sp_runtime::traits::ConvertInto; + type Currency = Balances; + type BabeDataGetter = BabeDataGetter; + type VrfKeyLookup = AuthorMapping; + type Deposit = ConstU128<{ 1 * currency::UNIT * currency::SUPPLY_FACTOR }>; + type MaxRandomWords = ConstU8<100>; + type MinBlockDelay = ConstU32<2>; + type MaxBlockDelay = ConstU32<2_000>; + type BlockExpirationDelay = ConstU32<10_000>; + type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = moonbase_weights::pallet_randomness::WeightInfo; +} + +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + // One storage item; key size is 32 + 20; value is size 4+4+16+20 bytes = 44 bytes. + pub const DepositBase: Balance = currency::deposit(1, 96); + // Additional storage item size of 20 bytes. + pub const DepositFactor: Balance = currency::deposit(0, 20); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = moonbase_weights::pallet_multisig::WeightInfo; +} + +impl pallet_relay_storage_roots::Config for Runtime { + type MaxStorageRoots = ConstU32<30>; + type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider; + type WeightInfo = moonbase_weights::pallet_relay_storage_roots::WeightInfo; +} + +impl pallet_precompile_benchmarks::Config for Runtime { + type WeightInfo = moonbase_weights::pallet_precompile_benchmarks::WeightInfo; +} + +impl pallet_parameters::Config for Runtime { + type AdminOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type RuntimeParameters = RuntimeParameters; + type WeightInfo = moonbase_weights::pallet_parameters::WeightInfo; +} + +construct_runtime! { + pub enum Runtime + { + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + Utility: pallet_utility::{Pallet, Call, Event} = 1, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 2, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 3, + Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event} = 4, + // Previously 5: pallet_randomness_collective_flip + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 6, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Config, Event} = 7, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 8, + EthereumChainId: pallet_evm_chain_id::{Pallet, Storage, Config} = 9, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 10, + Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Origin, Config} = 11, + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 12, + Scheduler: pallet_scheduler::{Pallet, Storage, Event, Call} = 13, + // Previously 14: pallet_democracy::{Pallet, Storage, Config, Event, Call} = 14, + // Previously 15: CouncilCollective: pallet_collective:: + // Previously 16: TechCommitteeCollective: pallet_collective:: + Treasury: pallet_treasury::{Pallet, Storage, Config, Event, Call} = 17, + AuthorInherent: pallet_author_inherent::{Pallet, Call, Storage, Inherent} = 18, + AuthorFilter: pallet_author_slot_filter::{Pallet, Call, Storage, Event, Config} = 19, + CrowdloanRewards: pallet_crowdloan_rewards::{Pallet, Call, Config, Storage, Event} = 20, + AuthorMapping: pallet_author_mapping::{Pallet, Call, Config, Storage, Event} = 21, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 22, + MaintenanceMode: pallet_maintenance_mode::{Pallet, Call, Config, Storage, Event} = 23, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 24, + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 25, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 26, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 27, + PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 28, + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 29, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event} = 30, + AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event} = 31, + Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 32, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Config, Storage, Event} = 33, + ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 34, + // Previously 35: BaseFee + // Previously 36: pallet_assets:: + MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event, Config} = 37, + EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin, Event} = 38, + Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 39, + TreasuryCouncilCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 40, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 41, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 42, + Origins: governance::custom_origins::{Origin} = 43, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 44, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 45, + OpenTechCommitteeCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 46, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 47, + Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 48, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 49, + AsyncBacking: pallet_async_backing::{Pallet, Storage} = 50, + MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 51, + RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 52, + PrecompileBenchmarks: pallet_precompile_benchmarks::{Pallet} = 53, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 54, + EmergencyParaXcm: pallet_emergency_para_xcm::{Pallet, Call, Storage, Event} = 55, + EvmForeignAssets: pallet_moonbeam_foreign_assets::{Pallet, Call, Storage, Event} = 56, + Parameters: pallet_parameters = 57, + XcmWeightTrader: pallet_xcm_weight_trader::{Pallet, Call, Storage, Event} = 58, + } +} + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + frame_metadata_hash_extension::CheckMetadataHash, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// Executive: handles dispatch to the various pallets. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_support::parameter_types! { + pub const MaxBalance: crate::Balance = crate::Balance::max_value(); + } + + frame_benchmarking::define_benchmarks!( + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_balances, Balances] + [pallet_sudo, Sudo] + [pallet_evm, EVM] + [pallet_assets, Assets] + [pallet_parachain_staking, ParachainStaking] + [pallet_scheduler, Scheduler] + [pallet_treasury, Treasury] + [pallet_author_inherent, AuthorInherent] + [pallet_author_slot_filter, AuthorFilter] + [pallet_crowdloan_rewards, CrowdloanRewards] + [pallet_author_mapping, AuthorMapping] + [pallet_proxy, Proxy] + [pallet_identity, Identity] + [cumulus_pallet_parachain_system, ParachainSystem] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_message_queue, MessageQueue] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_asset_manager, AssetManager] + [pallet_xcm_transactor, XcmTransactor] + [pallet_moonbeam_foreign_assets, EvmForeignAssets] + [pallet_moonbeam_orbiters, MoonbeamOrbiters] + [pallet_randomness, Randomness] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_preimage, Preimage] + [pallet_whitelist, Whitelist] + [pallet_multisig, Multisig] + [pallet_relay_storage_roots, RelayStorageRoots] + [pallet_precompile_benchmarks, PrecompileBenchmarks] + [pallet_moonbeam_lazy_migrations, MoonbeamLazyMigrations] + [pallet_parameters, Parameters] + [pallet_xcm_weight_trader, XcmWeightTrader] + ); +} + +// All of our runtimes share most of their Runtime API implementations. +// We use a macro to implement this common part and add runtime-specific additional implementations. +// This macro expands to : +// ``` +// impl_runtime_apis! { +// // All impl blocks shared between all runtimes. +// +// // Specific impls provided to the `impl_runtime_apis_plus_common!` macro. +// } +// ``` +moonbeam_runtime_common::impl_runtime_apis_plus_common! { + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + xt: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + // Filtered calls should not enter the tx pool as they'll fail if inserted. + // If this call is not allowed, we return early. + if !::BaseCallFilter::contains(&xt.0.function) { + return InvalidTransaction::Call.into(); + } + + // This runtime uses Substrate's pallet transaction payment. This + // makes the chain feel like a standard Substrate chain when submitting + // frame transactions and using Substrate ecosystem tools. It has the downside that + // transaction are not prioritized by gas_price. The following code reprioritizes + // transactions to overcome this. + // + // A more elegant, ethereum-first solution is + // a pallet that replaces pallet transaction payment, and allows users + // to directly specify a gas price rather than computing an effective one. + // #HopefullySomeday + + // First we pass the transactions to the standard FRAME executive. This calculates all the + // necessary tags, longevity and other properties that we will leave unchanged. + // This also assigns some priority that we don't care about and will overwrite next. + let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?; + + let dispatch_info = xt.get_dispatch_info(); + + // If this is a pallet ethereum transaction, then its priority is already set + // according to effective priority fee from pallet ethereum. If it is any other kind of + // transaction, we modify its priority. The goal is to arrive at a similar metric used + // by pallet ethereum, which means we derive a fee-per-gas from the txn's tip and + // weight. + Ok(match &xt.0.function { + RuntimeCall::Ethereum(transact { .. }) => intermediate_valid, + _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid, + _ => { + let tip = match xt.0.signature { + None => 0, + Some((_, _, ref signed_extra)) => { + // Yuck, this depends on the index of charge transaction in Signed Extra + let charge_transaction = &signed_extra.7; + charge_transaction.tip() + } + }; + + let effective_gas = + ::GasWeightMapping::weight_to_gas( + dispatch_info.weight + ); + let tip_per_gas = if effective_gas > 0 { + tip.saturating_div(effective_gas as u128) + } else { + 0 + }; + + // Overwrite the original prioritization with this ethereum one + intermediate_valid.priority = tip_per_gas as u64; + intermediate_valid + } + }) + } + } + + impl async_backing_primitives::UnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: async_backing_primitives::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } +} + +struct CheckInherents; + +// Parity has decided to depreciate this trait, but does not offer a satisfactory replacement, +// see issue: https://github.com/paritytech/polkadot-sdk/issues/2841 +#[allow(deprecated)] +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + inherent_data.check_extrinsics(block) + } +} + +// Nimbus's Executive wrapper allows relay validators to verify the seal digest +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = pallet_author_inherent::BlockExecutor::, + CheckInherents = CheckInherents, +); + +moonbeam_runtime_common::impl_self_contained_call!(); + +// Shorthand for a Get field of a pallet Config. +#[macro_export] +macro_rules! get { + ($pallet:ident, $name:ident, $type:ty) => { + <<$crate::Runtime as $pallet::Config>::$name as $crate::Get<$type>>::get() + }; +} + +#[cfg(test)] +mod tests { + use super::{currency::*, *}; + + #[test] + // Helps us to identify a Pallet Call in case it exceeds the 1kb limit. + // Hint: this should be a rare case. If that happens, one or more of the dispatchable arguments + // need to be Boxed. + fn call_max_size() { + const CALL_ALIGN: u32 = 1024; + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + } + + #[test] + fn currency_constants_are_correct() { + assert_eq!(SUPPLY_FACTOR, 1); + + // txn fees + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(1 * GIGAWEI)); + assert_eq!( + get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), + 5_u8 + ); + assert_eq!(STORAGE_BYTE_FEE, Balance::from(100 * MICROUNIT)); + + // treasury minimums + assert_eq!( + get!(pallet_treasury, ProposalBondMinimum, u128), + Balance::from(1 * UNIT) + ); + + // pallet_identity deposits + assert_eq!( + get!(pallet_identity, BasicDeposit, u128), + Balance::from(1 * UNIT + 25800 * MICROUNIT) + ); + assert_eq!( + get!(pallet_identity, ByteDeposit, u128), + Balance::from(100 * MICROUNIT) + ); + assert_eq!( + get!(pallet_identity, SubAccountDeposit, u128), + Balance::from(1 * UNIT + 5300 * MICROUNIT) + ); + + // staking minimums + assert_eq!( + get!(pallet_parachain_staking, MinCandidateStk, u128), + Balance::from(500 * UNIT) + ); + assert_eq!( + get!(pallet_parachain_staking, MinDelegation, u128), + Balance::from(1 * UNIT) + ); + + // crowdloan min reward + assert_eq!( + get!(pallet_crowdloan_rewards, MinimumReward, u128), + Balance::from(0u128) + ); + + // deposit for AuthorMapping + assert_eq!( + get!(pallet_author_mapping, DepositAmount, u128), + Balance::from(100 * UNIT) + ); + + // proxy deposits + assert_eq!( + get!(pallet_proxy, ProxyDepositBase, u128), + Balance::from(1 * UNIT + 800 * MICROUNIT) + ); + assert_eq!( + get!(pallet_proxy, ProxyDepositFactor, u128), + Balance::from(2100 * MICROUNIT) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositBase, u128), + Balance::from(1 * UNIT + 800 * MICROUNIT) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositFactor, u128), + Balance::from(5600 * MICROUNIT) + ); + } + + #[test] + fn max_offline_rounds_lower_or_eq_than_reward_payment_delay() { + assert!( + get!(pallet_parachain_staking, MaxOfflineRounds, u32) + <= get!(pallet_parachain_staking, RewardPaymentDelay, u32) + ); + } + + #[test] + // Required migration is + // pallet_parachain_staking::migrations::IncreaseMaxTopDelegationsPerCandidate + // Purpose of this test is to remind of required migration if constant is ever changed + fn updating_maximum_delegators_per_candidate_requires_configuring_required_migration() { + assert_eq!( + get!(pallet_parachain_staking, MaxTopDelegationsPerCandidate, u32), + 300 + ); + assert_eq!( + get!( + pallet_parachain_staking, + MaxBottomDelegationsPerCandidate, + u32 + ), + 50 + ); + } + + #[test] + fn test_proxy_type_can_be_decoded_from_valid_values() { + let test_cases = vec![ + // (input, expected) + (0u8, ProxyType::Any), + (1, ProxyType::NonTransfer), + (2, ProxyType::Governance), + (3, ProxyType::Staking), + (4, ProxyType::CancelProxy), + (5, ProxyType::Balances), + (6, ProxyType::AuthorMapping), + (7, ProxyType::IdentityJudgement), + ]; + + for (input, expected) in test_cases { + let actual = ProxyType::decode(&mut input.to_le_bytes().as_slice()); + assert_eq!( + Ok(expected), + actual, + "failed decoding ProxyType for value '{}'", + input + ); + } + } + + #[test] + fn configured_base_extrinsic_weight_is_evm_compatible() { + let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000; + let base_extrinsic = ::BlockWeights::get() + .get(frame_support::dispatch::DispatchClass::Normal) + .base_extrinsic; + assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); + } + + #[test] + fn test_storage_growth_ratio_is_correct() { + let expected_storage_growth_ratio = BlockGasLimit::get() + .low_u64() + .saturating_div(BLOCK_STORAGE_LIMIT); + let actual_storage_growth_ratio = + ::GasLimitStorageGrowthRatio::get(); + assert_eq!( + expected_storage_growth_ratio, actual_storage_growth_ratio, + "Storage growth ratio is not correct" + ); + } +} diff --git a/tracing/3200/runtime/moonbase/src/migrations.rs b/tracing/3200/runtime/moonbase/src/migrations.rs new file mode 100644 index 00000000..89f5279d --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/migrations.rs @@ -0,0 +1,28 @@ +// Copyright 2024 Moonbeam Foundation Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Moonbase specific Migrations + +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{prelude::*, vec}; + +pub struct MoonbaseMigrations; + +impl GetMigrations for MoonbaseMigrations { + fn get_migrations() -> Vec> { + vec![] + } +} diff --git a/tracing/3200/runtime/moonbase/src/precompiles.rs b/tracing/3200/runtime/moonbase/src/precompiles.rs new file mode 100644 index 00000000..9d8290f8 --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/precompiles.rs @@ -0,0 +1,352 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use crate::{ + asset_config::ForeignAssetInstance, + xcm_config::{AssetType, XcmExecutorConfig}, + OpenTechCommitteeInstance, TreasuryCouncilInstance, +}; +use crate::{AccountId, AssetId, AssetManager, Balances, Erc20XcmBridge, Runtime, H160}; +use frame_support::parameter_types; +use moonbeam_runtime_common::weights as moonbase_weights; +use moonkit_xcm_primitives::{ + location_matcher::{Erc20PalletMatcher, ForeignAssetMatcher, SingleAddressMatcher}, + AccountIdAssetIdConversion, +}; +use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; +use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; +use pallet_evm_precompile_batch::BatchPrecompile; +use pallet_evm_precompile_blake2::Blake2F; +use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; +use pallet_evm_precompile_call_permit::CallPermitPrecompile; +use pallet_evm_precompile_collective::CollectivePrecompile; +use pallet_evm_precompile_conviction_voting::ConvictionVotingPrecompile; +use pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompile; +use pallet_evm_precompile_gmp::GmpPrecompile; +use pallet_evm_precompile_identity::IdentityPrecompile; +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_p256verify::P256Verify; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompile; +use pallet_evm_precompile_preimage::PreimagePrecompile; +use pallet_evm_precompile_proxy::{OnlyIsProxyAndProxy, ProxyPrecompile}; +use pallet_evm_precompile_randomness::RandomnessPrecompile; +use pallet_evm_precompile_referenda::ReferendaPrecompile; +use pallet_evm_precompile_registry::PrecompileRegistry; +use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; +use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_storage_cleaner::StorageCleanerPrecompile; +use pallet_evm_precompile_xcm::PalletXcmPrecompile; +use pallet_evm_precompile_xcm_transactor::{ + v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, +}; +use pallet_evm_precompile_xcm_utils::{AllExceptXcmExecute, XcmUtilsPrecompile}; +use pallet_evm_precompile_xtokens::XtokensPrecompile; +use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; +use pallet_precompile_benchmarks::WeightInfo; +use precompile_foreign_asset_migrator::ForeignAssetMigratorPrecompile; +use precompile_utils::precompile_set::*; +use sp_std::prelude::*; +use xcm_primitives::AsAssetType; + +parameter_types! { + pub P256VerifyWeight: frame_support::weights::Weight = + moonbase_weights::pallet_precompile_benchmarks::WeightInfo::::p256_verify(); +} + +/// ERC20 metadata for the native token. +pub struct NativeErc20Metadata; + +impl Erc20Metadata for NativeErc20Metadata { + /// Returns the name of the token. + fn name() -> &'static str { + "DEV token" + } + + /// Returns the symbol of the token. + fn symbol() -> &'static str { + "DEV" + } + + /// Returns the decimals places of the token. + fn decimals() -> u8 { + 18 + } + + /// Must return `true` only if it represents the main native currency of + /// the network. It must be the currency used in `pallet_evm`. + fn is_native_currency() -> bool { + true + } +} + +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as foreign +pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as local +pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8, 255u8, 255u8, 254u8]; + +/// Const to identify ERC20_BALANCES_PRECOMPILE address +pub const ERC20_BALANCES_PRECOMPILE: u64 = 2050; + +parameter_types! { + pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; + pub LocalAssetPrefix: &'static [u8] = LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX; +} + +type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); + +// Pallet-xcm precompile types. +// Type that converts AssetId into Location +type AssetIdToLocationManager = AsAssetType; + +// The pallet-balances address is identified by ERC20_BALANCES_PRECOMPILE const +type SingleAddressMatch = SingleAddressMatcher; + +// Type that matches an AccountId with a foreign asset address (if any) +type ForeignAssetMatch = ForeignAssetMatcher; + +// Erc20XcmBridge pallet is used to match ERC20s +type Erc20Match = Erc20PalletMatcher; + +#[precompile_utils::precompile_name_from_address] +type MoonbasePrecompilesAt = ( + // Ethereum precompiles: + // We allow DELEGATECALL to stay compliant with Ethereum behavior. + PrecompileAt, ECRecover, EthereumPrecompilesChecks>, + PrecompileAt, Sha256, EthereumPrecompilesChecks>, + PrecompileAt, Ripemd160, EthereumPrecompilesChecks>, + PrecompileAt, Identity, EthereumPrecompilesChecks>, + PrecompileAt, Modexp, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Add, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Mul, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Pairing, EthereumPrecompilesChecks>, + PrecompileAt, Blake2F, EthereumPrecompilesChecks>, + // (0x100 => 256) https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + PrecompileAt, P256Verify, EthereumPrecompilesChecks>, + // Non-Moonbeam specific nor Ethereum precompiles : + PrecompileAt, Sha3FIPS256, (CallableByContract, CallableByPrecompile)>, + RemovedPrecompileAt>, // Dispatch + PrecompileAt, ECRecoverPublicKey, (CallableByContract, CallableByPrecompile)>, + PrecompileAt, StorageCleanerPrecompile, CallableByPrecompile>, + // Moonbeam specific precompiles: + PrecompileAt< + AddressU64<2048>, + ParachainStakingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2049>, + CrowdloanRewardsPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64, + Erc20BalancesPrecompile, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, // DemocracyPrecompile + PrecompileAt< + AddressU64<2052>, + XtokensPrecompile, + ( + SubcallWithMaxNesting<1>, + CallableByContract, + CallableByPrecompile, + ), + >, + PrecompileAt< + AddressU64<2053>, + RelayEncoderPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2054>, + XcmTransactorPrecompileV1, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2055>, + AuthorMappingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2056>, + BatchPrecompile, + ( + SubcallWithMaxNesting<2>, + // Batch is the only precompile allowed to call Batch. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2057>, + RandomnessPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2058>, + CallPermitPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2059>, + ProxyPrecompile, + ( + CallableByContract>, + SubcallWithMaxNesting<0>, + // Batch is the only precompile allowed to call Proxy. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2060>, + XcmUtilsPrecompile, + CallableByContract>, + >, + PrecompileAt< + AddressU64<2061>, + XcmTransactorPrecompileV2, + (CallableByContract, CallableByPrecompile), + >, + // CouncilCollective precompile + RemovedPrecompileAt>, + // TechCommitteeCollective precompile + RemovedPrecompileAt>, + PrecompileAt< + AddressU64<2064>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2065>, + ReferendaPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2066>, + ConvictionVotingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2067>, + PreimagePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2068>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2069>, + PrecompileRegistry, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, GmpPrecompile, SubcallWithMaxNesting<0>>, + PrecompileAt< + AddressU64<2071>, + XcmTransactorPrecompileV3, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2072>, + IdentityPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2073>, + RelayDataVerifierPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2074>, + PalletXcmPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, ForeignAssetMigratorPrecompile, ()>, +); + +pub struct DisabledLocalAssets(sp_std::marker::PhantomData); + +impl sp_core::Get> for DisabledLocalAssets +where + Runtime: frame_system::Config, + Runtime::AccountId: Into, + Runtime: AccountIdAssetIdConversion, +{ + fn get() -> Vec { + vec![ + // https://moonbase.subscan.io/extrinsic/5245322-6?event=5245322-22 + 182085191673801920759598290391359780050u128, + // https://moonbase.subscan.io/extrinsic/3244752-4?event=3244752-9 + 282223684955665977914983262584256755878u128, + // https://moonbase.subscan.io/extrinsic/3158280-4?event=3158280-9 + 235962050501460763853961856666389569138u128, + // https://moonbase.subscan.io/block/3045900?tab=event&&event=3045900-4 + 45350527686064227409532032051821627910u128, + // https://moonbase.subscan.io/extrinsic/3024306-4?event=3024306-9 + 199439015574556113723291251263369885338u128, + // https://moonbase.subscan.io/extrinsic/2921640-4?event=2921640-9 + 236426850287284823323011839750645103615u128, + // https://moonbase.subscan.io/extrinsic/2748867-4?event=2748867-9 + 14626673838203901761839010613793775004u128, + // https://moonbase.subscan.io/extrinsic/2709788-4?event=2709788-9 + 95328064580428769161981851380106820590u128, + // https://moonbase.subscan.io/extrinsic/2670844-4?event=2670844-9 + 339028723712074529056817184013808486301u128, + // https://moonbase.subscan.io/extrinsic/2555083-4?event=2555083-9 + 100481493116602214283160747599845770751u128, + // https://moonbase.subscan.io/extrinsic/2473880-3?event=2473880-8 + 319515966007349957795820176952936446433u128, + // https://moonbase.subscan.io/extrinsic/2346438-3?event=2346438-6 + 337110116006454532607322340792629567158u128, + // https://moonbase.subscan.io/extrinsic/2239102-3?event=2239102-6 + 255225902946708983196362678630947296516u128, + // https://moonbase.subscan.io/extrinsic/2142964-4?event=2142964-12 + 3356866138193769031598374869367363824u128, + // https://moonbase.subscan.io/extrinsic/1967538-6?event=1967538-28 + 144992676743556815849525085098140609495u128, + ] + .iter() + .map(|id| Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, *id).into()) + .collect() + } +} + +/// The PrecompileSet installed in the Moonbase runtime. +/// We include the nine Istanbul precompiles +/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69) +/// The following distribution has been decided for the precompiles +/// 0-1023: Ethereum Mainnet Precompiles +/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific +/// 2048-4095 Moonbeam specific precompiles +pub type MoonbasePrecompiles = PrecompileSetBuilder< + R, + ( + // Skip precompiles if out of range. + PrecompilesInRangeInclusive<(AddressU64<1>, AddressU64<4095>), MoonbasePrecompilesAt>, + // Prefixed precompile sets (XC20) + PrecompileSetStartingWith< + ForeignAssetPrefix, + Erc20AssetsPrecompileSet, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompilesAt>, + ), +>; diff --git a/tracing/3200/runtime/moonbase/src/runtime_params.rs b/tracing/3200/runtime/moonbase/src/runtime_params.rs new file mode 100644 index 00000000..4916cc27 --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/runtime_params.rs @@ -0,0 +1,44 @@ +// Copyright 2024 Moonbeam Foundation. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Dynamic runtime parametes. +use crate::Runtime; +use frame_support::dynamic_params::{dynamic_pallet_params, dynamic_params}; +use sp_runtime::Perbill; + +#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::)] +pub mod dynamic_params { + use super::*; + #[dynamic_pallet_params] + #[codec(index = 0)] + pub mod runtime_config { + // for fees, 80% are burned, 20% to the treasury + #[codec(index = 0)] + pub static FeesTreasuryProportion: Perbill = Perbill::from_percent(20); + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl Default for RuntimeParameters { + fn default() -> Self { + RuntimeParameters::RuntimeConfig( + dynamic_params::runtime_config::Parameters::FeesTreasuryProportion( + dynamic_params::runtime_config::FeesTreasuryProportion, + Some(Perbill::from_percent(20)), + ), + ) + } +} diff --git a/tracing/3200/runtime/moonbase/src/xcm_config.rs b/tracing/3200/runtime/moonbase/src/xcm_config.rs new file mode 100644 index 00000000..253f898c --- /dev/null +++ b/tracing/3200/runtime/moonbase/src/xcm_config.rs @@ -0,0 +1,816 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! XCM configuration for Moonbase. +//! + +use super::{ + governance, AccountId, AssetId, AssetManager, Balance, Balances, EmergencyParaXcm, + Erc20XcmBridge, EvmForeignAssets, MaintenanceMode, MessageQueue, ParachainInfo, + ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent, + RuntimeOrigin, Treasury, XcmpQueue, +}; +use crate::OpenTechCommitteeInstance; +use moonbeam_runtime_common::weights as moonbase_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use sp_runtime::{ + traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf}, + DispatchErrorWithPostInfo, +}; + +use frame_support::{ + parameter_types, + traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin}, +}; + +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::{ConstU32, H160, H256}; +use sp_weights::Weight; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription, + NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WeightInfoBounds, WithComputedOrigin, +}; + +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; + +use xcm::latest::prelude::{ + AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, + PalletInstance, Parachain, Wild, WildFungible, +}; + +use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry}; + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use orml_xcm_support::MultiNativeAsset; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType, + IsBridgedConcreteAssetFrom, SignedToAccountId20, UtilityAvailableCalls, UtilityEncodeCall, + XcmTransact, +}; + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_core::Get; +use sp_std::{ + convert::{From, Into, TryFrom}, + prelude::*, +}; + +use orml_traits::parameter_type_with_key; + +use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot}; + +parameter_types! { + // The network Id of the relay + pub const RelayNetwork: NetworkId = NetworkId::Westend; + // The relay chain Origin type + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + // The universal location within the global consensus system + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); + + + // Self Reserve location, defines the multilocation identifiying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + // We use the RELATIVE multilocation + pub SelfReserve: Location = Location { + parents: 0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // If we receive a Location of type AccountKey20, just generate a native account + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + HashedDescription>, +); + +/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`. +pub struct LocationToH160; +impl ConvertLocation for LocationToH160 { + fn convert_location(location: &Location) -> Option { + >::convert_location(location) + .map(Into::into) + } +} + +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +// This is intended to match FOREIGN ASSETS +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + super::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId20 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + xcm_builder::IsConcrete, + // We can convert the MultiLocations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +// These correspond to +// SelfReserve asset, both pre and post 0.9.16 +// Foreign assets +// We can remove the Old reanchor once +// we import https://github.com/open-web3-stack/open-runtime-module-library/pull/708 +pub type AssetTransactors = ( + LocalAssetTransactor, + EvmForeignAssets, + ForeignFungiblesTransactor, + Erc20XcmBridge, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + // Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte- + // account local origin + SignedAccountKey20AsNative, +); + +parameter_types! { + /// Maximum number of instructions in a single XCM fragment. A sanity check against + /// weight caculations getting too crazy. + pub MaxInstructions: u32 = 100; +} + +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = WeightInfoBounds< + moonbeam_xcm_benchmarks::weights::XcmWeight, + RuntimeCall, + MaxInstructions, +>; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +// Our implementation of the Moonbeam Call +// Attachs the right origin in case the call is made to pallet-ethereum-xcm +#[cfg(not(feature = "evm-tracing"))] +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); +#[cfg(feature = "evm-tracing")] +moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!(); + +moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!(); + +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(_call: &RuntimeCall) -> bool { + // TODO review + // This needs to be addressed at EVM level + true + } +} + +parameter_types! { + /// Location of Asset Hub + pub AssetHubLocation: Location = Location::new(1, [Parachain(1001)]); + pub const RelayLocation: Location = Location::parent(); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(RelayLocation::get()), + }); + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); + pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS; +} + +type Reserves = ( + // Assets bridged from different consensus systems held in reserve on Asset Hub. + IsBridgedConcreteAssetFrom, + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + MultiNativeAsset>, +); + +pub struct XcmExecutorConfig; +impl xcm_executor::Config for XcmExecutorConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Filter to the reserve withdraw operations + // Whenever the reserve matches the relative or absolute value + // of our chain, we always return the relative reserve + type IsReserve = Reserves; + type IsTeleporter = (); // No teleport + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = XcmWeigher; + // We use two traders + // When we receive the relative representation of the self-reserve asset, + // we use UsingComponents and the local way of handling fees + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = pallet_xcm_weight_trader::Trader; + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type PalletInstancesInfo = crate::AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; + type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +// Converts a Signed Local Origin into a Location +pub type LocalOriginToLocation = SignedToAccountId20; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper< + XcmExecutorConfig, + xcm_executor::XcmExecutor, +>; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = moonbase_weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = moonbase_weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery< + cumulus_primitives_core::ParaId, + >; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +// TODO: This pallet can be removed after the lazy migration is done and +// event `Completed` is emitted. +// https://github.com/paritytech/polkadot-sdk/pull/1246 +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; +} + +parameter_types! { + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = + Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + pub const MessageQueueMaxStale: u32 = 8; + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + pub const MessageQueueHeapSize: u32 = 103 * 1024; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper< + xcm_builder::ProcessXcmMessage, + >; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + // NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins + type QueuePausedQuery = EmergencyParaXcm; + type WeightInfo = moonbase_weights::pallet_message_queue::WeightInfo; + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +pub type ResumeXcmOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +impl pallet_emergency_para_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling); + type PausedThreshold = ConstU32<300>; + type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin; + type PausedToNormalOrigin = ResumeXcmOrigin; +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(xcm::v3::Location), +} +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(xcm::v3::Location::here()) + } +} + +impl From for AssetType { + fn from(location: xcm::v3::Location) -> Self { + Self::Xcm(location) + } +} + +// This can be removed once we fully adopt xcm::v4 everywhere +impl TryFrom for AssetType { + type Error = (); + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + } + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => { + xcm_builder::WithLatestLocationConverter::convert_back(&location) + } + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We take it +impl From for AssetId { + fn from(asset: AssetType) -> AssetId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + // Our native token + SelfReserve, + // Assets representing other chains native tokens + ForeignAsset(AssetId), + // Erc20 token + Erc20 { contract_address: H160 }, +} + +impl AccountIdToCurrencyId for Runtime { + fn account_to_currency_id(account: AccountId) -> Option { + Some(match account { + // the self-reserve currency is identified by the pallet-balances address + a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve, + // the rest of the currencies, by their corresponding erc20 address + _ => match Runtime::account_to_asset_id(account) { + // A foreign asset + Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id), + // If no known prefix is identified, we consider that it's a "real" erc20 token + // (i.e. managed by a real smart contract) + None => CurrencyId::Erc20 { + contract_address: account.into(), + }, + }, + }) + } +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + CurrencyId::Erc20 { contract_address } => { + let mut location = Erc20XcmBridgePalletLocation::get(); + location + .push_interior(Junction::AccountKey20 { + key: contract_address.0, + network: None, + }) + .ok(); + Some(location) + } + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight + = Weight::from_parts(200_000_000u64, 0); + pub const MaxAssetsForTransfer: usize = 2; + // This is how we are going to detect whether the asset is a Reserve asset + // This however is the chain part only + pub SelfLocation: Location = Location::here(); + // We need this to be able to catch when someone is trying to execute a non- + // cross-chain transfer in xtokens through the absolute path way + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(ParachainInfo::parachain_id().into()) + ].into() + }; + +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + // AssetHub fee + (1, Some(Parachain(1001u32))) => Some(50_000_000u128), + _ => None, + } + }; +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdConvert = CurrencyIdToLocation<( + EvmForeignAssets, + AsAssetType, + )>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +// 1 WND/ROC should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +pub type DerivativeAddressRegistrationOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = Transactors; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type SovereignAccountDispatcherOrigin = EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdToLocation = CurrencyIdToLocation<( + EvmForeignAssets, + AsAssetType, + )>; + type XcmSender = XcmRouter; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = AbsoluteAndRelativeReserve; + type WeightInfo = moonbase_weights::pallet_xcm_transactor::WeightInfo; + type HrmpManipulatorOrigin = GeneralAdminOrRoot; + type HrmpOpenOrigin = FastGeneralAdminOrRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + // This is the relative view of erc20 assets. + // Identified by this prefix + AccountKey20(contractAddress) + // We use the RELATIVE multilocation + pub Erc20XcmBridgePalletLocation: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + + // To be able to support almost all erc20 implementations, + // we provide a sufficiently hight gas limit. + pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000; +} + +impl pallet_erc20_xcm_bridge::Config for Runtime { + type AccountIdConverter = LocationToH160; + type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation; + type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; +} + +pub struct AccountIdToH160; +impl sp_runtime::traits::Convert for AccountIdToH160 { + fn convert(account_id: AccountId) -> H160 { + account_id.into() + } +} + +pub struct EvmForeignAssetIdFilter; +impl frame_support::traits::Contains for EvmForeignAssetIdFilter { + fn contains(asset_id: &AssetId) -> bool { + use xcm_primitives::AssetTypeGetter as _; + // We should return true only if the AssetId doesn't exist in AssetManager + AssetManager::get_asset_type(*asset_id).is_none() + } +} + +pub type ForeignAssetManagerOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::FastGeneralAdmin, + >, +>; + +impl pallet_moonbeam_foreign_assets::Config for Runtime { + type AccountIdToH160 = AccountIdToH160; + type AssetIdFilter = EvmForeignAssetIdFilter; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; + type ForeignAssetCreatorOrigin = ForeignAssetManagerOrigin; + type ForeignAssetFreezerOrigin = ForeignAssetManagerOrigin; + type ForeignAssetModifierOrigin = ForeignAssetManagerOrigin; + type ForeignAssetUnfreezerOrigin = ForeignAssetManagerOrigin; + type OnForeignAssetCreated = (); + type MaxForeignAssets = ConstU32<256>; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = moonbase_weights::pallet_moonbeam_foreign_assets::WeightInfo; + type XcmLocationToH160 = LocationToH160; +} + +pub struct AssetFeesFilter; +impl frame_support::traits::Contains for AssetFeesFilter { + fn contains(location: &Location) -> bool { + location.parent_count() > 0 + && location.first_interior() != Erc20XcmBridgePalletLocation::get().first_interior() + } +} + +impl pallet_xcm_weight_trader::Config for Runtime { + type AccountIdToLocation = AccountIdToLocation; + type AddSupportedAssetOrigin = EnsureRoot; + type AssetLocationFilter = AssetFeesFilter; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type EditSupportedAssetOrigin = EnsureRoot; + type NativeLocation = SelfReserve; + type PauseSupportedAssetOrigin = EnsureRoot; + type RemoveSupportedAssetOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type ResumeSupportedAssetOrigin = EnsureRoot; + type WeightInfo = moonbase_weights::pallet_xcm_weight_trader::WeightInfo; + type WeightToFee = ::WeightToFee; + type XcmFeesAccount = XcmFeesAccount; + #[cfg(feature = "runtime-benchmarks")] + type NotFilteredLocation = RelayLocation; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use super::*; + use xcm_builder::WithLatestLocationConverter; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/tracing/3200/runtime/moonbase/tests/common/mod.rs b/tracing/3200/runtime/moonbase/tests/common/mod.rs new file mode 100644 index 00000000..19df108a --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/common/mod.rs @@ -0,0 +1,405 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![allow(dead_code)] + +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use fp_evm::GenesisAccount; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +pub use moonbase_runtime::{ + currency::UNIT, AccountId, AsyncBacking, AuthorInherent, Balance, Ethereum, EvmForeignAssets, + InflationInfo, ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, + TransactionConverter, UncheckedExtrinsic, HOURS, +}; +use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; +use polkadot_parachain::primitives::HeadData; +use sp_consensus_slots::Slot; +use sp_core::{Encode, H160}; +use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent}; + +use std::collections::BTreeMap; + +use fp_rpc::ConvertTransaction; +use pallet_transaction_payment::Multiplier; + +pub fn existential_deposit() -> u128 { + ::ExistentialDeposit::get() +} + +// A valid signed Alice transfer. +pub const VALID_ETH_TX: &str = + "02f86d8205018085174876e80085e8d4a5100082520894f24ff3a9cf04c71dbc94d0b566f7a27b9456\ + 6cac8080c001a0e1094e1a52520a75c0255db96132076dd0f1263089f838bea548cbdbfc64a4d19f031c\ + 92a8cb04e2d68d20a6158d542a07ac440cc8d07b6e36af02db046d92df"; + +// An invalid signed Alice transfer with a gas limit artifically set to 0. +pub const INVALID_ETH_TX: &str = + "f86180843b9aca00809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ca00e28ba2dd3c5a\ + 3fd467d4afd7aefb4a34b373314fff470bb9db743a84d674a0aa06e5994f2d07eafe1c37b4ce5471ca\ + ecec29011f6f5bf0b1a552c55ea348df35f"; + +pub fn rpc_run_to_block(n: u32) { + while System::block_number() < n { + Ethereum::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Ethereum::on_initialize(System::block_number()); + } +} + +/// Utility function that advances the chain to the desired block number. +/// If an author is provided, that author information is injected to all the blocks in the meantime. +pub fn run_to_block(n: u32, author: Option) { + // Finalize the first block + Ethereum::on_finalize(System::block_number()); + while System::block_number() < n { + // Set the new block number and author + match author { + Some(ref author) => { + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())], + }; + System::reset_events(); + System::initialize( + &(System::block_number() + 1), + &System::parent_hash(), + &pre_digest, + ); + } + None => { + System::set_block_number(System::block_number() + 1); + } + } + + increase_last_relay_slot_number(1); + + // Initialize the new block + AuthorInherent::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + Ethereum::on_initialize(System::block_number()); + + // Finalize the block + Ethereum::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + } +} + +pub fn last_event() -> RuntimeEvent { + System::events().pop().expect("Event expected").event +} + +// Test struct with the purpose of initializing xcm assets +#[derive(Clone)] +pub struct XcmAssetInitialization { + pub asset_id: u128, + pub xcm_location: xcm::v4::Location, + pub decimals: u8, + pub name: &'static str, + pub symbol: &'static str, + pub balances: Vec<(AccountId, Balance)>, +} + +pub struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, + // [collator, amount] + collators: Vec<(AccountId, Balance)>, + // [delegator, collator, nomination_amount] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, + // per-round inflation config + inflation: InflationInfo, + // AuthorId -> AccoutId mappings + mappings: Vec<(NimbusId, AccountId)>, + // Crowdloan fund + crowdloan_fund: Balance, + // Chain id + chain_id: u64, + // EVM genesis accounts + evm_accounts: BTreeMap, + // [assettype, metadata, Vec] + xcm_assets: Vec, + safe_xcm_version: Option, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { + balances: vec![], + delegations: vec![], + collators: vec![], + inflation: InflationInfo { + expect: Range { + min: 100_000 * UNIT, + ideal: 200_000 * UNIT, + max: 500_000 * UNIT, + }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, + mappings: vec![], + crowdloan_fund: 0, + chain_id: CHAIN_ID, + evm_accounts: BTreeMap::new(), + xcm_assets: vec![], + safe_xcm_version: None, + } + } +} + +impl ExtBuilder { + pub fn with_evm_accounts(mut self, accounts: BTreeMap) -> Self { + self.evm_accounts = accounts; + self + } + + pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + self.collators = collators; + self + } + + pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations + .into_iter() + .map(|d| (d.0, d.1, d.2, Percent::zero())) + .collect(); + self + } + + pub fn with_xcm_assets(mut self, xcm_assets: Vec) -> Self { + self.xcm_assets = xcm_assets; + self + } + + pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self { + self.crowdloan_fund = crowdloan_fund; + self + } + + pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self { + self.mappings = mappings; + self + } + + pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self { + self.safe_xcm_version = Some(safe_xcm_version); + self + } + + #[allow(dead_code)] + pub fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: Perbill::from_percent(20), + parachain_bond_reserve_percent: Percent::from_percent(30), + blocks_per_round: 2 * HOURS, + num_selected_candidates: 8, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_crowdloan_rewards::GenesisConfig:: { + funded_amount: self.crowdloan_fund, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_author_mapping::GenesisConfig:: { + mappings: self.mappings, + } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config = pallet_evm_chain_id::GenesisConfig:: { + chain_id: self.chain_id, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: self.evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_ethereum::GenesisConfig:: { + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_xcm::GenesisConfig:: { + safe_xcm_version: self.safe_xcm_version, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_transaction_payment::GenesisConfig:: { + multiplier: Multiplier::from(8u128), + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + + let xcm_assets = self.xcm_assets.clone(); + + ext.execute_with(|| { + // If any xcm assets specified, we register them here + for xcm_asset_initialization in xcm_assets { + let asset_id = xcm_asset_initialization.asset_id; + EvmForeignAssets::create_foreign_asset( + root_origin(), + asset_id, + xcm_asset_initialization.xcm_location, + xcm_asset_initialization.decimals, + xcm_asset_initialization + .symbol + .as_bytes() + .to_vec() + .try_into() + .expect("too long"), + xcm_asset_initialization + .name + .as_bytes() + .to_vec() + .try_into() + .expect("too long"), + ) + .expect("fail to create foreign asset"); + + for (account, balance) in xcm_asset_initialization.balances { + if EvmForeignAssets::mint_into(asset_id, account, balance.into()).is_err() { + panic!("fail to mint foreign asset"); + } + } + } + System::set_block_number(1); + }); + ext + } +} + +pub const CHAIN_ID: u64 = 1281; +pub const ALICE: [u8; 20] = [4u8; 20]; +pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 20] = [5u8; 20]; +pub const CHARLIE: [u8; 20] = [6u8; 20]; +pub const DAVE: [u8; 20] = [7u8; 20]; +pub const EVM_CONTRACT: [u8; 20] = [8u8; 20]; + +pub fn origin_of(account_id: AccountId) -> ::RuntimeOrigin { + ::RuntimeOrigin::signed(account_id) +} + +pub fn inherent_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::none() +} + +pub fn root_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::root() +} + +pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic { + let converter = TransactionConverter; + converter.convert_transaction(ethereum_transaction(raw_hex_tx)) +} + +pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction { + let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes."); + let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]); + assert!(transaction.is_ok()); + transaction.unwrap() +} + +/// Mock the inherent that sets validation data in ParachainSystem, which +/// contains the `relay_chain_block_number`, which is used in `author-filter` as a +/// source of randomness to filter valid authors at each block. +pub fn set_parachain_inherent_data() { + use cumulus_primitives_core::PersistedValidationData; + use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; + + let mut relay_sproof = RelayStateSproofBuilder::default(); + relay_sproof.para_id = 100u32.into(); + relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3])); + + let additional_key_values = vec![( + moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(), + sp_timestamp::Timestamp::default().encode(), + )]; + + relay_sproof.additional_key_values = additional_key_values; + + let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof(); + + let vfp = PersistedValidationData { + relay_parent_number: 1u32, + relay_parent_storage_root, + ..Default::default() + }; + let parachain_inherent_data = ParachainInherentData { + validation_data: vfp, + relay_chain_state: relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + assert_ok!(RuntimeCall::ParachainSystem( + cumulus_pallet_parachain_system::Call::::set_validation_data { + data: parachain_inherent_data + } + ) + .dispatch(inherent_origin())); +} + +pub(crate) fn increase_last_relay_slot_number(amount: u64) { + let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0); + frame_support::storage::unhashed::put( + &frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"), + &((Slot::from(last_relay_slot + amount), 0)), + ); +} diff --git a/tracing/3200/runtime/moonbase/tests/evm_tracing.rs b/tracing/3200/runtime/moonbase/tests/evm_tracing.rs new file mode 100644 index 00000000..5a5b06ec --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/evm_tracing.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase EVM tracing Integration Tests + +mod common; + +#[cfg(test)] +#[cfg(feature = "evm-tracing")] +mod tests { + use super::common::*; + + use pallet_evm::AddressMapping; + use sp_core::{H160, U256}; + + use moonbeam_core_primitives::Header; + use moonbeam_rpc_primitives_debug::runtime_decl_for_debug_runtime_api::DebugRuntimeApi; + use std::str::FromStr; + + #[test] + fn debug_runtime_api_trace_transaction() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * UNIT, + } + .into(), + ); + let transaction = ethereum_transaction(VALID_ETH_TX); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_transaction( + vec![non_eth_uxt.clone(), eth_uxt, non_eth_uxt.clone()], + &transaction, + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_block() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * UNIT, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let eth_tx = ethereum_transaction(VALID_ETH_TX); + let eth_extrinsic_hash = eth_tx.hash(); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_block( + vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], + vec![eth_extrinsic_hash, eth_extrinsic_hash], + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_call() { + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + let alith = H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"); + let alith_account_id = + ::AddressMapping::into_account_id(alith); + ExtBuilder::default() + .with_balances(vec![(alith_account_id, 100 * UNIT)]) + .build() + .execute_with(|| { + assert!(Runtime::trace_call( + &block, + alith, + H160::random(), + Vec::new(), + U256::from(99), + U256::max_value(), + Some(U256::one()), + Some(U256::one()), + None, + None, + ) + .is_ok()); + }); + } +} diff --git a/tracing/3200/runtime/moonbase/tests/integration_test.rs b/tracing/3200/runtime/moonbase/tests/integration_test.rs new file mode 100644 index 00000000..95727d79 --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/integration_test.rs @@ -0,0 +1,3141 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase Runtime Integration Tests + +mod common; +use common::*; + +use precompile_utils::{ + precompile_set::{is_precompile_or_fail, IsActivePrecompile}, + prelude::*, + testing::*, +}; + +use fp_evm::{Context, IsPrecompileResult}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchClass, + traits::{ + fungible::Inspect, Currency as CurrencyT, EnsureOrigin, PalletInfo, StorageInfo, + StorageInfoTrait, + }, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + StorageHasher, Twox128, +}; +use moonbase_runtime::{ + //asset_config::ForeignAssetInstance, + xcm_config::SelfReserve, + AccountId, + AssetId, + Balances, + CrowdloanRewards, + EvmForeignAssets, + Executive, + OpenTechCommitteeCollective, + ParachainStaking, + PolkadotXcm, + Precompiles, + Runtime, + RuntimeBlockWeights, + RuntimeCall, + RuntimeEvent, + System, + TransactionPayment, + TransactionPaymentAsGasPrice, + TreasuryCouncilCollective, + XTokens, + XcmTransactor, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + WEEKS, +}; +use polkadot_parachain::primitives::Sibling; +use precompile_utils::testing::MockHandle; +use sp_runtime::{ + traits::{Convert as XcmConvert, Dispatchable}, + BuildStorage, +}; +use std::str::from_utf8; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_executor::traits::ConvertLocation; + +use moonbase_runtime::currency::{GIGAWEI, WEI}; +use moonbeam_xcm_benchmarks::weights::XcmWeight; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use nimbus_primitives::NimbusId; +use pallet_evm::PrecompileSet; +//use pallet_evm_precompileset_assets_erc20::{SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER}; +use pallet_moonbeam_foreign_assets::AssetStatus; +use pallet_transaction_payment::Multiplier; +use pallet_xcm_transactor::{Currency, CurrencyPayment, HrmpOperation, TransactWeights}; +use parity_scale_codec::Encode; +use sha3::{Digest, Keccak256}; +use sp_core::{crypto::UncheckedFrom, ByteArray, Pair, H160, H256, U256}; +use sp_runtime::{bounded_vec, DispatchError, ModuleError}; +use std::cell::Cell; +use std::rc::Rc; +use xcm::latest::prelude::*; + +type AuthorMappingPCall = + pallet_evm_precompile_author_mapping::AuthorMappingPrecompileCall; +type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall; +type CrowdloanRewardsPCall = + pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompileCall; +type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall< + Runtime, + moonbase_runtime::xcm_config::XcmExecutorConfig, +>; +type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall; +/*type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall< + Runtime, + ForeignAssetInstance, +>;*/ +type XcmTransactorV1PCall = + pallet_evm_precompile_xcm_transactor::v1::XcmTransactorPrecompileV1Call; +type XcmTransactorV2PCall = + pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call; + +// TODO: can we construct a const U256...? +const BASE_FEE_GENISIS: u128 = 10 * GIGAWEI; + +#[test] +fn xcmp_queue_controller_origin_is_root() { + // important for the XcmExecutionManager impl of PauseExecution which uses root origin + // to suspend/resume XCM execution in xcmp_queue::on_idle + assert_ok!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + +#[test] +fn verify_pallet_prefixes() { + fn is_pallet_prefix(name: &str) { + // Compares the unhashed pallet prefix in the `StorageInstance` implementation by every + // storage item in the pallet P. This pallet prefix is used in conjunction with the + // item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName) + // https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/ + // expand/storage.rs#L389-L401 + assert_eq!( + ::PalletInfo::name::

(), + Some(name) + ); + } + // TODO: use StorageInfoTrait from https://github.com/paritytech/substrate/pull/9246 + // This is now available with polkadot-v0.9.9 dependencies + is_pallet_prefix::("System"); + is_pallet_prefix::("Utility"); + is_pallet_prefix::("ParachainSystem"); + is_pallet_prefix::("TransactionPayment"); + is_pallet_prefix::("ParachainInfo"); + is_pallet_prefix::("EthereumChainId"); + is_pallet_prefix::("EVM"); + is_pallet_prefix::("Ethereum"); + is_pallet_prefix::("ParachainStaking"); + is_pallet_prefix::("Scheduler"); + is_pallet_prefix::("Treasury"); + is_pallet_prefix::( + "OpenTechCommitteeCollective", + ); + is_pallet_prefix::("AuthorInherent"); + is_pallet_prefix::("AuthorFilter"); + is_pallet_prefix::("CrowdloanRewards"); + is_pallet_prefix::("AuthorMapping"); + is_pallet_prefix::("MaintenanceMode"); + is_pallet_prefix::("Identity"); + is_pallet_prefix::("XcmpQueue"); + is_pallet_prefix::("CumulusXcm"); + is_pallet_prefix::("DmpQueue"); + is_pallet_prefix::("PolkadotXcm"); + is_pallet_prefix::("Assets"); + is_pallet_prefix::("XTokens"); + is_pallet_prefix::("AssetManager"); + is_pallet_prefix::("Migrations"); + is_pallet_prefix::("XcmTransactor"); + is_pallet_prefix::("ProxyGenesisCompanion"); + is_pallet_prefix::("MoonbeamOrbiters"); + is_pallet_prefix::("EthereumXcm"); + is_pallet_prefix::("Randomness"); + is_pallet_prefix::("TreasuryCouncilCollective"); + is_pallet_prefix::("MoonbeamLazyMigrations"); + is_pallet_prefix::("RelayStorageRoots"); + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res.to_vec() + }; + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"TotalIssuance".to_vec(), + prefix: prefix(b"Balances", b"TotalIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"InactiveIssuance".to_vec(), + prefix: prefix(b"Balances", b"InactiveIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Account".to_vec(), + prefix: prefix(b"Balances", b"Account"), + max_values: None, + max_size: Some(100), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Locks".to_vec(), + prefix: prefix(b"Balances", b"Locks"), + max_values: None, + max_size: Some(1287), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Reserves".to_vec(), + prefix: prefix(b"Balances", b"Reserves"), + max_values: None, + max_size: Some(1037), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Holds".to_vec(), + prefix: prefix(b"Balances", b"Holds"), + max_values: None, + max_size: Some(55), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Freezes".to_vec(), + prefix: prefix(b"Balances", b"Freezes"), + max_values: None, + max_size: Some(37), + }, + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"Sudo".to_vec(), + storage_name: b"Key".to_vec(), + prefix: prefix(b"Sudo", b"Key"), + max_values: Some(1), + max_size: Some(20), + }] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Proxies".to_vec(), + prefix: prefix(b"Proxy", b"Proxies"), + max_values: None, + max_size: Some(845), + }, + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Announcements".to_vec(), + prefix: prefix(b"Proxy", b"Announcements"), + max_values: None, + max_size: Some(1837), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"MaintenanceMode".to_vec(), + storage_name: b"MaintenanceMode".to_vec(), + prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"), + max_values: Some(1), + max_size: None, + },] + ); + + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRoot".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"), + max_values: None, + max_size: Some(44), + }, + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRootKeys".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"), + max_values: Some(1), + max_size: Some(121), + }, + ] + ); +} + +#[test] +fn test_collectives_storage_item_prefixes() { + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec()); + } + + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec()); + } +} + +#[test] +fn collective_set_members_root_origin_works() { + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert_ok!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + // OpenTechCommitteeCollective + assert_ok!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + }); +} + +#[test] +fn collective_set_members_general_admin_origin_works() { + use moonbase_runtime::{ + governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility, + }; + + ExtBuilder::default().build().execute_with(|| { + let root_caller = ::RuntimeOrigin::root(); + let alice = AccountId::from(ALICE); + + // TreasuryCouncilCollective + let _ = Utility::dispatch_as( + root_caller.clone(), + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + // OpenTechCommitteeCollective + let _ = Utility::dispatch_as( + root_caller, + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + + assert_eq!( + System::events() + .into_iter() + .filter_map(|r| { + match r.event { + RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result }) + if result.is_ok() => + { + Some(true) + } + _ => None, + } + }) + .collect::>() + .len(), + 2 + ) + }); +} + +#[test] +fn collective_set_members_signed_origin_does_not_work() { + let alice = AccountId::from(ALICE); + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + // OpenTechCommitteeCollective + assert!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + }); +} + +#[test] +fn verify_pallet_indices() { + fn is_pallet_index(index: usize) { + assert_eq!( + ::PalletInfo::index::

(), + Some(index) + ); + } + is_pallet_index::(0); + is_pallet_index::(1); + is_pallet_index::(3); + is_pallet_index::(4); + is_pallet_index::(6); + is_pallet_index::(7); + is_pallet_index::(8); + is_pallet_index::(9); + is_pallet_index::(10); + is_pallet_index::(11); + is_pallet_index::(12); + is_pallet_index::(13); + //is_pallet_index::(14); Removed + is_pallet_index::(17); + is_pallet_index::(18); + is_pallet_index::(19); + is_pallet_index::(20); + is_pallet_index::(21); + is_pallet_index::(22); + is_pallet_index::(23); + is_pallet_index::(24); + is_pallet_index::(25); + is_pallet_index::(26); + is_pallet_index::(27); + is_pallet_index::(28); + is_pallet_index::(29); + is_pallet_index::(30); + is_pallet_index::(31); + is_pallet_index::(32); + is_pallet_index::(33); + is_pallet_index::(34); + is_pallet_index::(37); + is_pallet_index::(38); + is_pallet_index::(39); + is_pallet_index::(40); + is_pallet_index::(46); + is_pallet_index::(51); +} + +#[test] +fn verify_reserved_indices() { + use frame_metadata::*; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + t.execute_with(|| { + let metadata = moonbase_runtime::Runtime::metadata(); + let metadata = match metadata.1 { + RuntimeMetadata::V14(metadata) => metadata, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + // 35: BaseFee + // 36: pallet_assets:: + let reserved = vec![35, 36]; + let existing = metadata + .pallets + .iter() + .map(|p| p.index) + .collect::>(); + assert!(reserved.iter().all(|index| !existing.contains(index))); + }); +} + +#[test] +fn verify_proxy_type_indices() { + assert_eq!(moonbase_runtime::ProxyType::Any as u8, 0); + assert_eq!(moonbase_runtime::ProxyType::NonTransfer as u8, 1); + assert_eq!(moonbase_runtime::ProxyType::Governance as u8, 2); + assert_eq!(moonbase_runtime::ProxyType::Staking as u8, 3); + assert_eq!(moonbase_runtime::ProxyType::CancelProxy as u8, 4); + assert_eq!(moonbase_runtime::ProxyType::Balances as u8, 5); + assert_eq!(moonbase_runtime::ProxyType::AuthorMapping as u8, 6); + assert_eq!(moonbase_runtime::ProxyType::IdentityJudgement as u8, 7); +} + +#[test] +fn join_collator_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 2_000 * UNIT), + (AccountId::from(CHARLIE), 1_100 * UNIT), + (AccountId::from(DAVE), 1_000 * UNIT), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 1_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![ + (AccountId::from(CHARLIE), AccountId::from(ALICE), 50 * UNIT), + (AccountId::from(CHARLIE), AccountId::from(BOB), 50 * UNIT), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(ALICE)), + 1_000 * UNIT, + 2u32 + ), + pallet_parachain_staking::Error::::CandidateExists + ); + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 1_000 * UNIT, + 2u32 + ), + pallet_parachain_staking::Error::::DelegatorExists + ); + assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(DAVE)), + 1_000 * UNIT, + 2u32 + )); + assert_eq!( + last_event(), + RuntimeEvent::ParachainStaking( + pallet_parachain_staking::Event::JoinedCollatorCandidates { + account: AccountId::from(DAVE), + amount_locked: 1_000 * UNIT, + new_total_amt_locked: 3_100 * UNIT + } + ) + ); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(ALICE)); + assert_eq!(candidates.0[0].amount, 1_050 * UNIT); + assert_eq!(candidates.0[1].owner, AccountId::from(BOB)); + assert_eq!(candidates.0[1].amount, 1_050 * UNIT); + assert_eq!(candidates.0[2].owner, AccountId::from(DAVE)); + assert_eq!(candidates.0[2].amount, 1_000 * UNIT); + }); +} + +#[test] +fn transfer_through_evm_to_stake() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)]) + .build() + .execute_with(|| { + // Charlie has no balance => fails to stake + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 1_000 * UNIT, + 0u32 + ), + DispatchError::Module(ModuleError { + index: 12, + error: [8, 0, 0, 0], + message: Some("InsufficientBalance") + }) + ); + + // Alice transfer from free balance 2000 UNIT to Bob + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 2_000 * UNIT, + )); + assert_eq!(Balances::free_balance(AccountId::from(BOB)), 2_000 * UNIT); + + let gas_limit = 100000u64; + // Bob transfers 1000 UNIT to Charlie via EVM + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(CHARLIE), + input: Vec::new(), + value: (1_000 * UNIT).into(), + gas_limit, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: None, + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + assert_eq!( + Balances::free_balance(AccountId::from(CHARLIE)), + 1_000 * UNIT, + ); + + // Charlie can stake now + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 1_000 * UNIT, + 0u32, + ),); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE)); + assert_eq!(candidates.0[0].amount, 1_000 * UNIT); + }); +} + +#[test] +fn reward_block_authors() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 2_100 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + // Just before round 3 + run_to_block(2399, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1_100 * UNIT, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 500 * UNIT,); + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1213666666584000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 541333333292000000000, + ); + }); +} + +#[test] +fn reward_block_authors_with_parachain_bond_reserved() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 2_100 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + (AccountId::from(CHARLIE), UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + assert_ok!(ParachainStaking::set_parachain_bond_account( + root_origin(), + AccountId::from(CHARLIE), + ),); + + // Stop just before round 2 + run_to_block(1199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1_100 * UNIT, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 500 * UNIT,); + assert_eq!(Balances::usable_balance(AccountId::from(CHARLIE)), UNIT,); + + // Go to round 2 + run_to_block(1201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // 30% reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 47515000000000000000, + ); + + // Go to round 3 + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 1182693333281650000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 525841666640825000000, + ); + // 30% again reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 94727725000000000000, + ); + }); +} + +#[test] +fn initialize_crowdloan_addresses_with_batch_and_pay() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * UNIT); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * UNIT); + let expected = RuntimeEvent::Utility(pallet_utility::Event::BatchCompleted); + assert_eq!(last_event(), expected); + // This one should fail, as we already filled our data + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch { + calls: vec![RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![([4u8; 32].into(), Some(AccountId::from(ALICE)), 432000)] + } + )] + }) + .dispatch(root_origin()) + ); + let expected_fail = RuntimeEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 0, + error: DispatchError::Module(ModuleError { + index: 20, + error: [8, 0, 0, 0], + message: None, + }), + }); + assert_eq!(last_event(), expected_fail); + // Claim 1 block. + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(CHARLIE)))); + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(DAVE)))); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * UNIT) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + per_block + ); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + per_block + ); + // The total claimed reward should be equal to the account balance at this point. + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + (450_000 * UNIT) + per_block + ); + assert_eq!( + Balances::balance(&AccountId::from(DAVE)), + (450_000 * UNIT) + per_block + ); + assert_noop!( + CrowdloanRewards::claim(origin_of(AccountId::from(ALICE))), + pallet_crowdloan_rewards::Error::::NoAssociatedClaim + ); + }); +} + +#[test] +fn initialize_crowdloan_address_and_change_with_relay_key_sig() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + + let (pair1, _) = sp_core::sr25519::Pair::generate(); + let (pair2, _) = sp_core::sr25519::Pair::generate(); + + let public1 = pair1.public(); + let public2 = pair2.public(); + + // signature: + // WRAP_BYTES|| NetworkIdentifier|| new_account || previous_account || WRAP_BYTES + let mut message = pallet_crowdloan_rewards::WRAPPED_BYTES_PREFIX.to_vec(); + message.append(&mut b"moonbase-".to_vec()); + message.append(&mut AccountId::from(DAVE).encode()); + message.append(&mut AccountId::from(CHARLIE).encode()); + message.append(&mut pallet_crowdloan_rewards::WRAPPED_BYTES_POSTFIX.to_vec()); + + let signature1 = pair1.sign(&message); + let signature2 = pair2.sign(&message); + + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + // two relay accounts pointing at the same reward account + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public1.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public2.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 900_000 * UNIT); + + // this should fail, as we are only providing one signature + assert_noop!( + CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![(public1.into(), signature1.clone().into())] + ), + pallet_crowdloan_rewards::Error::::InsufficientNumberOfValidProofs + ); + + // this should be valid + assert_ok!(CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![ + (public1.into(), signature1.into()), + (public2.into(), signature2.into()) + ] + )); + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (900_000 * UNIT) + ); + }); +} + +#[test] +fn claim_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * UNIT); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * UNIT); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Alice uses the crowdloan precompile to claim through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENISIS.into(); + + // Construct the call data (selector, amount) + let mut call_data = Vec::::from([0u8; 4]); + call_data[0..4].copy_from_slice(&Keccak256::digest(b"claim()")[0..4]); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * UNIT) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + per_block + ); + }) +} + +#[test] +fn is_contributor_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Assert precompile reports Bob is not a contributor + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(BOB.into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(false); + + // Assert precompile reports Charlie is a nominator + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(CHARLIE.into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(true); + }) +} + +#[test] +fn reward_info_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + let expected_total: U256 = (1_500_000 * UNIT).into(); + let expected_claimed: U256 = (450_000 * UNIT).into(); + + // Assert precompile reports correct Charlie reward info. + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::reward_info { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns((expected_total, expected_claimed)); + }) +} + +#[test] +fn update_reward_address_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * UNIT) + .build() + .execute_with(|| { + // set parachain inherent data + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * UNIT + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Charlie uses the crowdloan precompile to update address through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENISIS.into(); + + // Construct the input data to check if Bob is a contributor + let mut call_data = Vec::::from([0u8; 36]); + call_data[0..4] + .copy_from_slice(&Keccak256::digest(b"update_reward_address(address)")[0..4]); + call_data[16..36].copy_from_slice(&ALICE); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + assert!(CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)).is_none()); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(ALICE)) + .unwrap() + .claimed_reward, + (450_000 * UNIT) + ); + }) +} + +#[test] +fn create_and_manipulate_foreign_asset() { + ExtBuilder::default().build().execute_with(|| { + let source_location = xcm::v4::Location::parent(); + + // Create foreign asset + assert_ok!(EvmForeignAssets::create_foreign_asset( + moonbase_runtime::RuntimeOrigin::root(), + 1, + source_location.clone(), + 12, + bounded_vec![b'M', b'T'], + bounded_vec![b'M', b'y', b'T', b'o', b'k'], + )); + assert_eq!( + EvmForeignAssets::assets_by_id(1), + Some(source_location.clone()) + ); + assert_eq!( + EvmForeignAssets::assets_by_location(&source_location), + Some((1, AssetStatus::Active)) + ); + + // Freeze foreign asset + assert_ok!(EvmForeignAssets::freeze_foreign_asset( + moonbase_runtime::RuntimeOrigin::root(), + 1, + true + )); + assert_eq!( + EvmForeignAssets::assets_by_location(&source_location), + Some((1, AssetStatus::FrozenXcmDepositAllowed)) + ); + + // Unfreeze foreign asset + assert_ok!(EvmForeignAssets::unfreeze_foreign_asset( + moonbase_runtime::RuntimeOrigin::root(), + 1, + )); + assert_eq!( + EvmForeignAssets::assets_by_location(&source_location), + Some((1, AssetStatus::Active)) + ); + }); +} + +// The precoompile asset-erc20 is deprecated and not used anymore for new evm foreign assets +// We don't have testing tools in rust test to call real evm smart contract, so we rely on ts tests. +/* +#[test] +fn xcm_asset_erc20_precompiles_supply_and_balance() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Assert the asset has been created with the correct supply + assert_eq!(Assets::total_supply(relay_asset_id), 1_000 * UNIT); + + // Access totalSupply through precompile. Important that the context is correct + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::total_supply {}, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(1000 * UNIT)); + + // Access balanceOf through precompile + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(ALICE.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(1000 * UNIT)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Transfer tokens from Alice to Bob, 400 UNIT. + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::transfer { + to: Address(BOB.into()), + value: { 400 * UNIT }.into(), + }, + ) + .expect_cost(24695) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * UNIT)), + )) + .execute_returns(true); + + // Make sure BOB has 400 UNIT + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(BOB.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(400 * UNIT)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_approve() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Aprove Bob for spending 400 UNIT from Alice + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::approve { + spender: Address(BOB.into()), + value: { 400 * UNIT }.into(), + }, + ) + .expect_cost(15604) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_APPROVAL, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * UNIT)), + )) + .execute_returns(true); + + // Transfer tokens from Alice to Charlie by using BOB as origin + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::transfer_from { + from: Address(ALICE.into()), + to: Address(CHARLIE.into()), + value: { 400 * UNIT }.into(), + }, + ) + .expect_cost(29960) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(CHARLIE), + solidity::encode_event_data(U256::from(400 * UNIT)), + )) + .execute_returns(true); + + // Make sure CHARLIE has 400 UNIT + Precompiles::new() + .prepare_test( + CHARLIE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(CHARLIE.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(400 * UNIT)); + }); +}*/ + +#[test] +fn xtokens_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = 1; + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + let inside = Rc::new(Cell::new(false)); + let inside2 = inside.clone(); + + // We use the address of the asset as an identifier of the asset we want to transfer + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address.into()), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(348298) + .expect_no_logs() + // We expect an evm subcall ERC20.burnFrom + .with_subcall_handle(move |subcall| { + let Subcall { + address, + transfer, + input, + target_gas: _, + is_static, + context, + } = subcall; + + assert_eq!(context.caller, EvmForeignAssets::account_id().into()); + assert_eq!( + address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(is_static, false); + + assert!(transfer.is_none()); + + assert_eq!( + context.address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(context.apparent_value, 0u8.into()); + + assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]); + assert_eq!(&input[4..16], &[0u8; 12]); + assert_eq!(&input[16..36], ALICE); + + inside2.set(true); + + SubcallOutput { + output: Default::default(), + cost: 149_000, + logs: vec![], + ..SubcallOutput::succeed() + } + }) + .execute_returns(()) + }) +} + +#[test] +fn xtokens_precompiles_transfer_multiasset() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000 * UNIT)], + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + let inside = Rc::new(Cell::new(false)); + let inside2 = inside.clone(); + + // This time we transfer it through TransferMultiAsset + // Instead of the address, we encode directly the multilocation referencing the asset + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer_multiasset { + // We want to transfer the relay token + asset: Location::parent(), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(348298) + .expect_no_logs() + // We expect an evm subcall ERC20.burnFrom + .with_subcall_handle(move |subcall| { + let Subcall { + address, + transfer, + input, + target_gas: _, + is_static, + context, + } = subcall; + + assert_eq!(context.caller, EvmForeignAssets::account_id().into()); + assert_eq!( + address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(is_static, false); + + assert!(transfer.is_none()); + + assert_eq!( + context.address, + [255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1].into() + ); + assert_eq!(context.apparent_value, 0u8.into()); + + assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]); + assert_eq!(&input[4..16], &[0u8; 12]); + assert_eq!(&input[16..36], ALICE); + + inside2.set(true); + + SubcallOutput { + output: Default::default(), + cost: 149_000, + logs: vec![], + ..SubcallOutput::succeed() + } + }) + .execute_returns(()); + + // Ensure that the subcall was actually called. + assert!(inside.get(), "subcall not called"); + }) +} + +#[test] +fn xtokens_precompiles_transfer_native() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Its address is + let asset_precompile_address = H160::from_low_u64_be(2050); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // We use the address of the asset as an identifier of the asset we want to transfer + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address), + amount: { 500 * UNIT }.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(16208) + .expect_no_logs() + .execute_returns(()); + }) +} + +fn run_with_system_weight(w: Weight, mut assertions: F) +where + F: FnMut() -> (), +{ + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); +} + +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonbase_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 1_000_000_001, calc_fee(1)); + assert_eq!( 10_000_001_000, calc_fee(10)); + assert_eq!( 100_001_000_000, calc_fee(100)); + assert_eq!( 1_001_000_000_000, calc_fee(1_000)); + assert_eq!( 11_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 1_100_000_000_000_000, calc_fee(100_000)); + assert_eq!( 1_001_000_000_000_000_000, calc_fee(1_000_000)); // one UNIT, ~ 1MB + assert_eq!( 1_000_010_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(1_000_000_100_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + +#[test] +fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + + let minimum_multiplier = moonbase_runtime::MinimumMultiplier::get(); + let target = moonbase_runtime::TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = moonbase_runtime::FastAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) +} + +#[test] +fn ethereum_invalid_transaction() { + ExtBuilder::default().build().execute_with(|| { + // Ensure an extrinsic not containing enough gas limit to store the transaction + // on chain is rejected. + assert_eq!( + Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)), + Err( + sp_runtime::transaction_validity::TransactionValidityError::Invalid( + sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8) + ) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_substrate() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * UNIT) + (1 * WEI)), + (AccountId::from(BOB), existential_deposit()), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * UNIT, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); +} + +#[test] +fn initial_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + + ExtBuilder::default().build().execute_with(|| { + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(8u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 10_000_000_000u128.into(), + Weight::from_parts(41_742_000u64, 0) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * UNIT) + (21_000 * BASE_FEE_GENISIS)) + (1 * WEI), + ), + (AccountId::from(BOB), existential_deposit()), + ]) + .build() + .execute_with(|| { + // EVM transfer + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,); + }); +} + +#[test] +fn refund_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * UNIT) + (21_777 * BASE_FEE_GENISIS) + existential_deposit()), + ), + (AccountId::from(BOB), existential_deposit()), + ]) + .build() + .execute_with(|| { + // EVM transfer that zeroes ALICE + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_777u64, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // ALICE is refunded + assert_eq!( + Balances::free_balance(AccountId::from(ALICE)), + 777 * BASE_FEE_GENISIS + existential_deposit(), + ); + }); +} + +#[test] +fn author_does_not_receive_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * UNIT) + (21_000 * (500 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + // Some block author as seen by pallet-evm. + let author = AccountId::from(>::find_author()); + // Currently the default impl of the evm uses `deposit_into_existing`. + // If we were to use this implementation, and for an author to receive eventual tips, + // the account needs to be somehow initialized, otherwise the deposit would fail. + Balances::make_free_balance_be(&author, 100 * UNIT); + + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(300 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // Author free balance didn't change. + assert_eq!(Balances::free_balance(author), 100 * UNIT,); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_with_priority_fee() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(BOB), + (1 * UNIT) + (21_000 * (2 * BASE_FEE_GENISIS) + existential_deposit()), + ), + (AccountId::from(ALICE), existential_deposit()), + ( + as sp_core::TypedGet>::get(), + existential_deposit(), + ), + ]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(2 * BASE_FEE_GENISIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENISIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 1 * base_fee + tip. + let fee = ((2 * BASE_FEE_GENISIS) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbase_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_without_priority_fee() { + use fp_evm::FeeCalculator; + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(BOB), + (1 * UNIT) + (21_000 * (2 * BASE_FEE_GENISIS)), + ), + (AccountId::from(ALICE), existential_deposit()), + ( + as sp_core::TypedGet>::get(), + existential_deposit(), + ), + ]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * UNIT).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 1 GWEI base fee. + let base_fee = TransactionPaymentAsGasPrice::min_gas_price().0; + assert_eq!(base_fee.as_u128(), BASE_FEE_GENISIS); // hint in case following asserts fail + let fee = (base_fee.as_u128() * 21_000u128) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbase_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn root_can_change_default_xcm_vers() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + }]) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonbase_runtime::AssetId = 1; + // Default XCM version is not set yet, so xtokens should fail because it does not + // know with which version to send + assert_noop!( + XTokens::transfer( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Unlimited + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + + // Root sets the defaultXcm + assert_ok!(PolkadotXcm::force_default_xcm_version( + root_origin(), + Some(4) + )); + + // Now transferring does not fail + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest)), + WeightLimit::Unlimited + )); + }) +} + +#[test] +fn transactor_cannot_use_more_than_max_weight() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_id: 1, + xcm_location: xcm::v4::Location::parent(), + name: "RelayToken", + symbol: "Relay", + decimals: 12, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + }]) + .build() + .execute_with(|| { + let source_id: moonbase_runtime::AssetId = 1; + assert_ok!(XcmTransactor::register( + root_origin(), + AccountId::from(ALICE), + 0, + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1, + )); + + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbase_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsCurrencyId( + moonbase_runtime::xcm_config::CurrencyId::ForeignAsset(source_id) + ), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + }) +} + +#[test] +fn root_can_use_hrmp_manage() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .build() + .execute_with(|| { + // It fails sending, because the router does not work in test mode + // But all rest checks pass + assert_noop!( + XcmTransactor::hrmp_manage( + root_origin(), + HrmpOperation::Accept { + para_id: 2000u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(10000) + }, + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: Some(Limited(20000.into())) + } + ), + pallet_xcm_transactor::Error::::ErrorValidating + ); + }) +} + +#[test] +fn transact_through_signed_precompile_works_v1() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let xcm_transactor_v1_precompile_address = H160::from_low_u64_be(2054); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + Weight::from_parts(200_000, (xcm_primitives::DEFAULT_PROOF_SIZE) + 4000), + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1, + )); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v1_precompile_address, + XcmTransactorV1PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 15000, + call: bytes.into(), + }, + ) + .expect_cost(23239) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_precompile_works_v2() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .expect_cost(23239) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_cannot_send_to_local_chain() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::here(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .execute_reverts(|output| { + from_utf8(&output) + .unwrap() + .contains("Dispatched call failed with error:") + && from_utf8(&output).unwrap().contains("ErrorValidating") + }); + }); +} + +// Test to ensure we can use either in crowdloan rewards without worrying for migrations +#[test] +fn account_id_32_encodes_like_32_byte_u8_slice() { + let account_as_account_id_32: sp_runtime::AccountId32 = [1u8; 32].into(); + let account_as_slice = [1u8; 32]; + assert_eq!(account_as_account_id_32.encode(), account_as_slice.encode()); +} + +#[test] +fn author_mapping_precompile_associate_update_and_clear() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let author_mapping_precompile_address = H160::from_low_u64_be(2055); + let first_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([1u8; 32]).into(); + let first_vrf_id: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([1u8; 32]).into(); + let second_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([2u8; 32]).into(); + let second_vrf_id: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([2u8; 32]).into(); + + // Associate it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::add_association { + nimbus_id: [1u8; 32].into(), + }, + ) + .expect_cost(14255) + .expect_no_logs() + .execute_returns(()); + + let expected_associate_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRegistered { + nimbus_id: first_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + keys: first_vrf_id.clone(), + }); + assert_eq!(last_event(), expected_associate_event); + + // Update it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::update_association { + old_nimbus_id: [1u8; 32].into(), + new_nimbus_id: [2u8; 32].into(), + }, + ) + .expect_cost(13829) + .expect_no_logs() + .execute_returns(()); + + let expected_update_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRotated { + new_nimbus_id: second_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + new_keys: second_vrf_id.clone(), + }); + assert_eq!(last_event(), expected_update_event); + + // Clear it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::clear_association { + nimbus_id: [2u8; 32].into(), + }, + ) + .expect_cost(14294) + .expect_no_logs() + .execute_returns(()); + + let expected_clear_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRemoved { + nimbus_id: second_nimbus_id, + account_id: AccountId::from(ALICE), + keys: second_vrf_id, + }); + assert_eq!(last_event(), expected_clear_event); + }); +} + +#[test] +fn author_mapping_register_and_set_keys() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let author_mapping_precompile_address = H160::from_low_u64_be(2055); + let first_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([1u8; 32]).into(); + let first_vrf_key: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([3u8; 32]).into(); + let second_nimbus_id: NimbusId = + sp_core::sr25519::Public::unchecked_from([2u8; 32]).into(); + let second_vrf_key: session_keys_primitives::VrfId = + sp_core::sr25519::Public::unchecked_from([4u8; 32]).into(); + + // Associate it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::set_keys { + keys: solidity::encode_arguments(( + H256::from([1u8; 32]), + H256::from([3u8; 32]), + )) + .into(), + }, + ) + .expect_cost(16049) + .expect_no_logs() + .execute_returns(()); + + let expected_associate_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRegistered { + nimbus_id: first_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + keys: first_vrf_key.clone(), + }); + assert_eq!(last_event(), expected_associate_event); + + // Update it + Precompiles::new() + .prepare_test( + ALICE, + author_mapping_precompile_address, + AuthorMappingPCall::set_keys { + keys: solidity::encode_arguments(( + H256::from([2u8; 32]), + H256::from([4u8; 32]), + )) + .into(), + }, + ) + .expect_cost(16049) + .expect_no_logs() + .execute_returns(()); + + let expected_update_event = + RuntimeEvent::AuthorMapping(pallet_author_mapping::Event::KeysRotated { + new_nimbus_id: second_nimbus_id.clone(), + account_id: AccountId::from(ALICE), + new_keys: second_vrf_key.clone(), + }); + assert_eq!(last_event(), expected_update_event); + }); +} + +#[test] +fn test_xcm_utils_ml_tp_account() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_address_parent: H160 = + ParentIsPreset::::convert_location(&Location::parent()) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: Location::parent(), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_parent)); + + let parachain_2000_multilocation = Location::new(1, [Parachain(2000)]); + let expected_address_parachain: H160 = + SiblingParachainConvertsVia::::convert_location( + ¶chain_2000_multilocation, + ) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: parachain_2000_multilocation, + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_parachain)); + + let alice_in_parachain_2000_multilocation = Location::new( + 1, + [ + Parachain(2000), + AccountKey20 { + network: None, + key: ALICE, + }, + ], + ); + let expected_address_alice_in_parachain_2000 = + xcm_builder::HashedDescription::< + AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&alice_in_parachain_2000_multilocation) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: alice_in_parachain_2000_multilocation, + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_alice_in_parachain_2000)); + }); +} + +#[test] +fn test_xcm_utils_weight_message() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_weight = + XcmWeight::::clear_origin().ref_time(); + + let message: Vec = xcm::VersionedXcm::<()>::V4(Xcm(vec![ClearOrigin])).encode(); + + let input = XcmUtilsPCall::weight_message { + message: message.into(), + }; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(0) + .expect_no_logs() + .execute_returns(expected_weight); + }); +} + +#[test] +fn test_xcm_utils_get_units_per_second() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let location = SelfReserve::get(); + + let input = XcmUtilsPCall::get_units_per_second { location }; + + let expected_units = + WEIGHT_REF_TIME_PER_SECOND as u128 * moonbase_runtime::currency::WEIGHT_FEE; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(expected_units); + }); +} + +#[test] +fn precompile_existence() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let precompile_addresses: std::collections::BTreeSet<_> = vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 1024, 1025, 1026, 1027, 2048, 2049, 2050, 2051, 2052, + 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, + 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, + ] + .into_iter() + .map(H160::from_low_u64_be) + .collect(); + + for i in 0..3000 { + let address = H160::from_low_u64_be(i); + + if precompile_addresses.contains(&address) { + assert!( + is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return true", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_some(), + "execute({},..) should return Some(_)", + i + ); + } else { + assert!( + !is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return false", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_none(), + "execute({},..) should return None", + i + ); + } + } + }); +} + +#[test] +fn removed_precompiles() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let removed_precompiles = [1025, 2051, 2062, 2063]; + + for i in 1..3000 { + let address = H160::from_low_u64_be(i); + + if !is_precompile_or_fail::(address, 100_000u64).expect("to be ok") { + continue; + } + + if !removed_precompiles.contains(&i) { + assert!( + match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} should be an active precompile" + ); + continue; + } + + assert!( + !match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} shouldn't be an active precompile" + ); + + precompiles + .prepare_test(Alice, address, []) + .execute_reverts(|out| out == b"Removed precompile"); + } + }) +} + +#[test] +fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() { + use frame_support::dispatch::{DispatchInfo, Pays}; + use moonbase_runtime::{currency, EXTRINSIC_BASE_WEIGHT}; + + ExtBuilder::default().build().execute_with(|| { + let size_bytes = 0; + let tip = 0; + let dispatch_info = DispatchInfo { + weight: Weight::zero(), + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; + + assert_eq!( + TransactionPayment::compute_fee(size_bytes, &dispatch_info, tip), + EXTRINSIC_BASE_WEIGHT.ref_time() as u128 * currency::WEIGHT_FEE, + ); + }); +} + +#[test] +fn deal_with_fees_handles_tip() { + use frame_support::traits::OnUnbalanced; + use moonbase_runtime::{DealWithFees, Treasury}; + + ExtBuilder::default().build().execute_with(|| { + // This test checks the functionality of the `DealWithFees` trait implementation in the runtime. + // It simulates a scenario where a fee and a tip are issued to an account and ensures that the + // treasury receives the correct amount (20% of the total), and the rest is burned (80%). + // + // The test follows these steps: + // 1. It issues a fee of 100 and a tip of 1000. + // 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100. + // 3. It checks that the treasury's balance is initially 0. + // 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip. + // 5. It checks that the treasury's balance is now 220 (20% of the fee and tip). + // 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating + // that this amount was burned. + let fee = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(100); + let tip = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(1000); + + let total_supply_before = Balances::total_issuance(); + assert_eq!(total_supply_before, 1_100); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); + + DealWithFees::on_unbalanceds(vec![fee, tip].into_iter()); + + // treasury should have received 20% + assert_eq!(Balances::free_balance(&Treasury::account_id()), 220); + + // verify 80% burned + let total_supply_after = Balances::total_issuance(); + assert_eq!(total_supply_before - total_supply_after, 880); + }); +} + +#[test] +fn evm_revert_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + // Batch a transfer followed by an invalid call to batch. + // Thus BatchAll will revert the transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(), + value: vec![U256::from(1 * UNIT), U256::zero()].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 0, "there should be no transfer event"); + }); +} + +#[test] +fn evm_success_keeps_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into())].into(), + value: vec![U256::from(1 * UNIT)].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENISIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 1, "there should be 1 transfer event"); + }); +} + +#[test] +fn validate_transaction_fails_on_filtered_call() { + use sp_runtime::transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidityError, + }; + use sp_transaction_pool::runtime_api::runtime_decl_for_tagged_transaction_queue::TaggedTransactionQueueV3; // editorconfig-checker-disable-line + + ExtBuilder::default().build().execute_with(|| { + let xt = UncheckedExtrinsic::new_unsigned( + pallet_evm::Call::::call { + source: Default::default(), + target: H160::default(), + input: Vec::new(), + value: Default::default(), + gas_limit: Default::default(), + max_fee_per_gas: Default::default(), + max_priority_fee_per_gas: Default::default(), + nonce: Default::default(), + access_list: Default::default(), + } + .into(), + ); + + assert_eq!( + Runtime::validate_transaction(TransactionSource::External, xt, Default::default(),), + Err(TransactionValidityError::Invalid(InvalidTransaction::Call)), + ); + }); +} + +#[cfg(test)] +mod fee_tests { + use super::*; + use fp_evm::FeeCalculator; + use frame_support::{ + traits::{ConstU128, OnFinalize}, + weights::{ConstantMultiplier, WeightToFee}, + }; + use moonbase_runtime::{ + currency, BlockWeights, FastAdjustingFeeUpdate, LengthToFee, MinimumMultiplier, + TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS, + }; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn test_multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() + * BlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = FastAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) + } + + #[test] + fn test_fee_calculation() { + let base_extrinsic = BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000); + let extrinsic_len = 100u32; + let extrinsic_weight = 5_000u64; + let tip = 42u128; + type WeightToFeeImpl = + ConstantMultiplier>; + type LengthToFeeImpl = LengthToFee; + + // base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip + let expected_fee = + WeightToFeeImpl::weight_to_fee(&base_extrinsic) + + multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee( + &Weight::from_parts(extrinsic_weight, 1), + )) + LengthToFeeImpl::weight_to_fee(&Weight::from_parts(extrinsic_len as u64, 1)) + + tip; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual_fee = TransactionPayment::compute_fee( + extrinsic_len, + &frame_support::dispatch::DispatchInfo { + class: DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + weight: Weight::from_parts(extrinsic_weight, 1), + }, + tip, + ); + + assert_eq!( + expected_fee, + actual_fee, + "The actual fee did not match the expected fee, diff {}", + actual_fee - expected_fee + ); + }); + } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int( + (currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128), + ) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = + (currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(998_600_980), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(999_600_080), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(1_000_600_180), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(1_002_603_380), + ); + + // 1 "real" hour (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(431_710_642), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(786_627_866), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(1_433_329_383u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(4_758_812_897u128), + ); + + // 1 "real" day (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(125_000_000), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(125_000_000), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(5_653_326_895_069u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(125_000_000_000_000u128), // upper bound enforced + ); + }); + } +} diff --git a/tracing/3200/runtime/moonbase/tests/runtime_apis.rs b/tracing/3200/runtime/moonbase/tests/runtime_apis.rs new file mode 100644 index 00000000..7cfb9dc1 --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/runtime_apis.rs @@ -0,0 +1,397 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase Runtime Api Integration Tests + +mod common; +use common::*; + +use fp_evm::GenesisAccount; +use frame_support::assert_ok; +use nimbus_primitives::NimbusId; +use pallet_evm::{Account as EVMAccount, AddressMapping, FeeCalculator}; +use sp_core::{ByteArray, H160, H256, U256}; + +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; +use moonbase_runtime::{Executive, TransactionPaymentAsGasPrice}; +use moonbeam_core_primitives::Header; +use moonbeam_rpc_primitives_txpool::runtime_decl_for_tx_pool_runtime_api::TxPoolRuntimeApi; +use nimbus_primitives::runtime_decl_for_nimbus_api::NimbusApi; +use std::{collections::BTreeMap, str::FromStr}; + +#[test] +fn ethereum_runtime_rpc_api_chain_id() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Runtime::chain_id(), CHAIN_ID); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_basic() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(ALICE), + 2_000 * UNIT + existential_deposit(), + )]) + .build() + .execute_with(|| { + assert_eq!( + Runtime::account_basic(H160::from(ALICE)), + EVMAccount { + balance: U256::from(2_000 * UNIT), + nonce: U256::zero() + } + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_gas_price() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!( + Runtime::gas_price(), + TransactionPaymentAsGasPrice::min_gas_price().0 + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_code_at() { + let address = H160::from(EVM_CONTRACT); + let code: Vec = vec![1, 2, 3, 4, 5]; + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: code.clone(), + nonce: Default::default(), + storage: Default::default(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::account_code_at(address), code); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_author() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + assert_eq!(Runtime::author(), H160::from(ALICE)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_storage_at() { + let address = H160::from(EVM_CONTRACT); + let mut key = [0u8; 32]; + key[31..32].copy_from_slice(&[6u8][..]); + let mut value = [0u8; 32]; + value[31..32].copy_from_slice(&[7u8][..]); + let item = H256::from_slice(&key[..]); + let mut storage: BTreeMap = BTreeMap::new(); + storage.insert(H256::from_slice(&key[..]), item); + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: Vec::new(), + nonce: Default::default(), + storage: storage.clone(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::storage_at(address, U256::from(6)), item); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_call() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 2_000 * UNIT), + ]) + .build() + .execute_with(|| { + let execution_result = Runtime::call( + H160::from(ALICE), // from + H160::from(BOB), // to + Vec::new(), // data + U256::from(1000u64), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_create() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * UNIT)]) + .build() + .execute_with(|| { + let execution_result = Runtime::create( + H160::from(ALICE), // from + vec![0, 1, 1, 0], // data + U256::zero(), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_transaction_statuses() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + rpc_run_to_block(2); + let statuses = + Runtime::current_transaction_statuses().expect("Transaction statuses result."); + assert_eq!(statuses.len(), 1); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_block() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + rpc_run_to_block(2); + let block = Runtime::current_block().expect("Block result."); + assert_eq!(block.header.number, U256::from(1u8)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_receipts() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * UNIT), + (AccountId::from(ALICE), 2_000 * UNIT), + (AccountId::from(BOB), 1_000 * UNIT), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * UNIT, + )]) + .build() + .execute_with(|| { + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + rpc_run_to_block(2); + let receipts = Runtime::current_receipts().expect("Receipts result."); + assert_eq!(receipts.len(), 1); + }); +} + +#[test] +fn txpool_runtime_api_extrinsic_filter() { + ExtBuilder::default().build().execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * UNIT, + } + .into(), + ); + + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let txpool = >::extrinsic_filter( + vec![eth_uxt.clone(), non_eth_uxt.clone()], + vec![unchecked_eth_tx(VALID_ETH_TX), non_eth_uxt], + ); + assert_eq!(txpool.ready.len(), 1); + assert_eq!(txpool.future.len(), 1); + }); +} + +#[test] +fn can_author_when_selected_is_empty() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000_000 * UNIT), + (AccountId::from(BOB), 10_000_000 * UNIT), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * UNIT)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }; + + // Base case: ALICE can author blocks when she is the only candidate + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Remove ALICE from candidate pool, leaving the candidate_pool empty + assert_ok!(ParachainStaking::go_offline(origin_of(AccountId::from( + ALICE + )))); + + // Need to fast forward to right before the next session, which is when selected candidates + // will be updated. We want to test the creation of the first block of the next session. + run_to_block(1799, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1799, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Check that it works as expected after session update + run_to_block(1800, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1800, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + }); +} + +// Some Priority-related test ideas +// 1. Eth balance transfer with various gas prices. Priority == gas price +// 2. Eth contract call with various gas prices. Priority == gas price +// 3. System remark with no tip -> calculate expected priority from gas weight mapping +// 4. System remark with tip. +// 5. Operational dispatch has higher priority than normal for otherwise same transactions diff --git a/tracing/3200/runtime/moonbase/tests/xcm_mock/mod.rs b/tracing/3200/runtime/moonbase/tests/xcm_mock/mod.rs new file mode 100644 index 00000000..4a9e567d --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/xcm_mock/mod.rs @@ -0,0 +1,273 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +pub mod parachain; +pub mod relay_chain; +pub mod statemint_like; +use cumulus_primitives_core::ParaId; +use pallet_xcm_transactor::relay_indices::*; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use polkadot_runtime_parachains::configuration::{ + GenesisConfig as ConfigurationGenesisConfig, HostConfiguration, +}; +use polkadot_runtime_parachains::paras::{ + GenesisConfig as ParasGenesisConfig, ParaGenesisArgs, ParaKind, +}; + +use sp_core::{H160, U256}; +use std::{collections::BTreeMap, str::FromStr}; + +pub const PARAALICE: [u8; 20] = [1u8; 20]; +pub const RELAYALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const RELAYBOB: AccountId32 = AccountId32::new([2u8; 32]); + +pub fn para_a_account() -> AccountId32 { + ParaId::from(1).into_account_truncating() +} + +pub fn para_b_account() -> AccountId32 { + ParaId::from(2).into_account_truncating() +} + +pub fn para_a_account_20() -> parachain::AccountId { + ParaId::from(1).into_account_truncating() +} + +pub fn evm_account() -> H160 { + H160::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn mock_para_genesis_info() -> ParaGenesisArgs { + ParaGenesisArgs { + genesis_head: vec![1u8].into(), + validation_code: vec![1u8].into(), + para_kind: ParaKind::Parachain, + } +} + +pub fn mock_relay_config() -> HostConfiguration { + HostConfiguration:: { + hrmp_channel_max_capacity: u32::MAX, + hrmp_channel_max_total_size: u32::MAX, + hrmp_max_parachain_inbound_channels: 10, + hrmp_max_parachain_outbound_channels: 10, + hrmp_channel_max_message_size: u32::MAX, + // Changed to avoid aritmetic errors within hrmp_close + max_downward_message_size: 100_000u32, + ..Default::default() + } +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + +decl_test_parachain! { + pub struct Statemint { + Runtime = statemint_like::Runtime, + XcmpMessageHandler = statemint_like::MsgQueue, + DmpMessageHandler = statemint_like::MsgQueue, + new_ext = statemint_ext(1000), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(vec![1, 2, 3, 1000]), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + (1000, Statemint), + ], + } +} + +pub const INITIAL_BALANCE: u128 = 10_000_000_000_000_000; + +pub const INITIAL_EVM_BALANCE: u128 = 0; +pub const INITIAL_EVM_NONCE: u32 = 1; + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(PARAALICE.into(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_xcm_transactor::GenesisConfig:: { + // match relay runtime construct_runtime order in xcm_mock::relay_chain + relay_indices: RelayChainIndices { + hrmp: 6u8, + init_open_channel: 0u8, + accept_open_channel: 1u8, + close_channel: 2u8, + cancel_open_request: 6u8, + ..Default::default() + }, + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + // EVM accounts are self-sufficient. + let mut evm_accounts = BTreeMap::new(); + evm_accounts.insert( + evm_account(), + fp_evm::GenesisAccount { + nonce: U256::from(INITIAL_EVM_NONCE), + balance: U256::from(INITIAL_EVM_BALANCE), + storage: Default::default(), + code: vec![ + 0x00, // STOP + ], + }, + ); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn statemint_ext(para_id: u32) -> sp_io::TestExternalities { + use statemint_like::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (RELAYALICE.into(), INITIAL_BALANCE), + (RELAYBOB.into(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext(paras: Vec) -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(RELAYALICE, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let para_genesis: Vec<(ParaId, ParaGenesisArgs)> = paras + .iter() + .map(|¶_id| (para_id.into(), mock_para_genesis_info())) + .collect(); + + let genesis_config = ConfigurationGenesisConfig:: { + config: mock_relay_config(), + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = ParasGenesisConfig:: { + paras: para_genesis, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} +pub type RelayChainPalletXcm = pallet_xcm::Pallet; +pub type Hrmp = polkadot_runtime_parachains::hrmp::Pallet; + +pub type StatemintBalances = pallet_balances::Pallet; +pub type StatemintChainPalletXcm = pallet_xcm::Pallet; +pub type StatemintAssets = pallet_assets::Pallet; + +pub type ParachainPalletXcm = pallet_xcm::Pallet; +pub type Assets = pallet_assets::Pallet; + +pub type Treasury = pallet_treasury::Pallet; +pub type AssetManager = pallet_asset_manager::Pallet; +pub type XTokens = orml_xtokens::Pallet; +pub type RelayBalances = pallet_balances::Pallet; +pub type ParaBalances = pallet_balances::Pallet; +pub type XcmTransactor = pallet_xcm_transactor::Pallet; +pub type XcmWeightTrader = pallet_xcm_weight_trader::Pallet; diff --git a/tracing/3200/runtime/moonbase/tests/xcm_mock/parachain.rs b/tracing/3200/runtime/moonbase/tests/xcm_mock/parachain.rs new file mode 100644 index 00000000..7dbc8584 --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/xcm_mock/parachain.rs @@ -0,0 +1,1137 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Parachain runtime mock. + +use frame_support::{ + construct_runtime, + dispatch::GetDispatchInfo, + ensure, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU32, Everything, Get, InstanceFilter, Nothing, PalletInfoAccess, + }, + weights::Weight, + PalletId, +}; + +use frame_system::{pallet_prelude::BlockNumberFor, EnsureNever, EnsureRoot}; +use pallet_xcm::migration::v1::VersionUncheckedMigrateToV1; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, Hash, IdentityLookup, MaybeEquivalence, Zero}, + Permill, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm}; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use orml_traits::parameter_type_with_key; +use pallet_ethereum::PostLogContent; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use polkadot_parachain::primitives::{Id as ParaId, Sibling}; +use xcm::latest::{ + Error as XcmError, ExecuteXcm, + Junction::{PalletInstance, Parachain}, + Location, NetworkId, Outcome, Xcm, +}; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +pub use moonbase_runtime::xcm_config::AssetType; +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper as ArgumentsBenchmarkHelper; +use scale_info::TypeInfo; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; + +pub type AccountId = moonbeam_core_primitives::AccountId; +pub type Balance = u128; +pub type AssetId = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 0; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +pub type ForeignAssetInstance = (); + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 10; // Does not really matter as this will be only called by root + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + AccountKey20Aliases, + // The rest of multilocations convert via hashing it + xcm_builder::HashedDescription< + AccountId, + xcm_builder::DescribeFamily, + >, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + SignedAccountKey20AsNative, +); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1u64, 1u64); + pub MaxInstructions: u32 = 100; +} + +// Instructing how incoming xcm assets will be handled +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + IsConcrete, + // We can convert the Locations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// These will be our transactors +// We use both transactors +pub type AssetTransactors = (LocalAssetTransactor, ForeignFungiblesTransactor); + +pub type XcmRouter = super::ParachainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); + /// Parachain token units per second of execution + pub ParaTokensPerSecond: u128 = 1000000000000; +} + +pub struct WeightToFee; +impl sp_weights::WeightToFee for WeightToFee { + type Balance = Balance; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + use sp_runtime::SaturatedConversion as _; + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(ParaTokensPerSecond::get()) + .saturating_div(frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as u128) + } +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + + // New Self Reserve location, defines the multilocation identifiying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + pub const MaxAssetsIntoHolding: u32 = 64; + + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(Location::parent()), + }); + + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); +} + +use frame_system::RawOrigin; +use sp_runtime::traits::PostDispatchInfoOf; +use sp_runtime::DispatchErrorWithPostInfo; +use xcm_executor::traits::CallDispatcher; +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); + +type Reserves = ( + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + orml_xcm_support::MultiNativeAsset< + xcm_primitives::AbsoluteAndRelativeReserve, + >, +); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = Reserves; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = pallet_xcm_weight_trader::Trader; + + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + SelfReserve, + ForeignAsset(AssetId), +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + // For now and until Xtokens is adapted to handle 0.9.16 version we use + // the old anchoring here + // This is not a problem in either cases, since the view of the destination + // chain does not change + // TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxAssetsForTransfer: usize = 2; + pub SelfLocation: Location = Location::here(); + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(MsgQueue::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + (1, Some(Parachain(1000u32))) => Some(50u128), + _ => None, + } + }; +} + +// The XCM message wrapper wrapper +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdConvert = + CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 0; + pub const SpendPeriod: u32 = 0; + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type ProposalBondMaximum = (); + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ArgumentsBenchmarkHelper; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} + +// Pallet to provide the version, used to test runtime upgrade version changes +#[frame_support::pallet] +pub mod mock_version_changer { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_version)] + pub(super) type CurrentVersion = StorageValue<_, XcmVersion, ValueQuery>; + + impl Get for Pallet { + fn get() -> XcmVersion { + Self::current_version() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + VersionChanged(XcmVersion), + } + + impl Pallet { + pub fn set_version(version: XcmVersion) { + CurrentVersion::::put(version); + Self::deposit_event(Event::VersionChanged(version)); + } + } +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl mock_version_changer::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +pub type LocalOriginToLocation = + xcm_primitives::SignedToAccountId20; + +parameter_types! { + pub MatcherLocation: Location = Location::here(); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = frame_support::traits::Nothing; + type XcmExecutor = XcmExecutor; + // Do not allow teleports + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // We use a custom one to test runtime ugprades + type AdvertisedXcmVersion = XcmVersioner; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::pallet_prelude::DispatchResult; +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset, + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset, + metadata.name, + metadata.symbol, + metadata.decimals, + false, + ) + } + + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into())?; + + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, +} + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetMetadata; + type ForeignAssetType = AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +// 1 ROC/WND should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = MockTransactors; + type DerivativeAddressRegistrationOrigin = EnsureRoot; + type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdToLocation = + CurrencyIdToLocation>; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type XcmSender = XcmRouter; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type WeightInfo = (); + type HrmpManipulatorOrigin = EnsureRoot; + type HrmpOpenOrigin = EnsureRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + pub RelayLocation: Location = Location::parent(); +} + +impl pallet_xcm_weight_trader::Config for Runtime { + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type AddSupportedAssetOrigin = EnsureRoot; + type AssetLocationFilter = Everything; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type EditSupportedAssetOrigin = EnsureRoot; + type NativeLocation = SelfReserve; + type PauseSupportedAssetOrigin = EnsureRoot; + type RemoveSupportedAssetOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type ResumeSupportedAssetOrigin = EnsureRoot; + type WeightInfo = (); + type WeightToFee = WeightToFee; + type XcmFeesAccount = XcmFeesAccount; + #[cfg(feature = "runtime-benchmarks")] + type NotFilteredLocation = RelayLocation; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 1000; +} +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +use sp_core::U256; + +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 40 KB. +const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024; + +parameter_types! { + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; + pub GasLimitStorageGrowthRatio: u64 = + BlockGasLimit::get().min(u64::MAX.into()).low_u64().saturating_div(BLOCK_STORAGE_LIMIT); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressNever; + + type AddressMapping = pallet_evm::IdentityAddressMapping; + type Currency = Balances; + type Runner = pallet_evm::runner::stack::Runner; + + type RuntimeEvent = RuntimeEvent; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = (); + type BlockGasLimit = BlockGasLimit; + type OnChargeTransaction = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +pub struct NormalFilter; +impl frame_support::traits::Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + _ => true, + } + } +} + +// We need to use the encoding from the relay mock runtime +#[derive(Encode, Decode)] +pub enum RelayCall { + #[codec(index = 5u8)] + // the index should match the position of the module in `construct_runtime!` + Utility(UtilityCall), + #[codec(index = 6u8)] + // the index should match the position of the module in `construct_runtime!` + Hrmp(HrmpCall), +} + +#[derive(Encode, Decode)] +pub enum UtilityCall { + #[codec(index = 1u8)] + AsDerivative(u16), +} + +// HRMP call encoding, needed for xcm transactor pallet +#[derive(Encode, Decode)] +pub enum HrmpCall { + #[codec(index = 0u8)] + InitOpenChannel(ParaId, u32, u32), + #[codec(index = 1u8)] + AcceptOpenChannel(ParaId), + #[codec(index = 2u8)] + CloseChannel(HrmpChannelId), + #[codec(index = 6u8)] + CancelOpenRequest(HrmpChannelId, u32), +} + +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum MockTransactors { + Relay, +} + +impl xcm_primitives::XcmTransact for MockTransactors { + fn destination(self) -> Location { + match self { + MockTransactors::Relay => Location::parent(), + } + } +} + +impl xcm_primitives::UtilityEncodeCall for MockTransactors { + fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec { + match self { + MockTransactors::Relay => match call { + xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => { + let mut call = + RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode(); + call.append(&mut b.clone()); + call + } + }, + } + } +} + +pub struct MockHrmpEncoder; +impl xcm_primitives::HrmpEncodeCall for MockHrmpEncoder { + fn hrmp_encode_call( + call: xcm_primitives::HrmpAvailableCalls, + ) -> Result, xcm::latest::Error> { + match call { + xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp( + HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()), + ) + .encode()), + xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => { + Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode()) + } + } + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} +parameter_types! { + pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo, +)] +pub enum ProxyType { + NotAllowed = 0, + Any = 1, +} + +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {} + +impl InstanceFilter for ProxyType { + fn filter(&self, _c: &RuntimeCall) -> bool { + match self { + ProxyType::NotAllowed => false, + ProxyType::Any => true, + } + } + fn is_superset(&self, _o: &Self) -> bool { + false + } +} + +impl Default for ProxyType { + fn default() -> Self { + Self::NotAllowed + } +} + +parameter_types! { + pub const ProxyCost: u64 = 1; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyCost; + type ProxyDepositFactor = ProxyCost; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ProxyCost; + type AnnouncementDepositFactor = ProxyCost; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will iMmediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlockU32; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_msg_queue, + XcmVersioner: mock_version_changer, + + PolkadotXcm: pallet_xcm, + Assets: pallet_assets, + CumulusXcm: cumulus_pallet_xcm, + XTokens: orml_xtokens, + AssetManager: pallet_asset_manager, + XcmTransactor: pallet_xcm_transactor, + XcmWeightTrader: pallet_xcm_weight_trader, + Treasury: pallet_treasury, + Proxy: pallet_proxy, + + Timestamp: pallet_timestamp, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthereumXcm: pallet_ethereum_xcm, + } +); + +pub(crate) fn para_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion}; +use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade}; +pub(crate) fn on_runtime_upgrade() { + VersionUncheckedMigrateToV1::::on_runtime_upgrade(); +} + +pub(crate) fn para_roll_to(n: BlockNumber) { + while System::block_number() < n { + PolkadotXcm::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + PolkadotXcm::on_initialize(System::block_number()); + } +} diff --git a/tracing/3200/runtime/moonbase/tests/xcm_mock/relay_chain.rs b/tracing/3200/runtime/moonbase/tests/xcm_mock/relay_chain.rs new file mode 100644 index 00000000..f391b31d --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/xcm_mock/relay_chain.rs @@ -0,0 +1,430 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, IdentityLookup}, + AccountId32, +}; + +use frame_support::weights::{Weight, WeightMeter}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_runtime_parachains::{ + configuration, dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, paras, shared, +}; +use sp_runtime::transaction_validity::TransactionPriority; +use sp_runtime::Permill; +use xcm::latest::prelude::*; +use xcm_builder::{ + Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, FixedRateOfFungible, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, IsConcrete, ProcessXcmMessage, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); + type PalletsOrigin = OriginCaller; +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub KsmLocation: Location = Here.into(); + pub const KusamaNetwork: NetworkId = NetworkId::Kusama; + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorLocation = Here; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // Not enabled in the relay per se, but we enable it to test + // the transact_through_signed extrinsic + Account32Hash, +); + +pub type LocalAssetTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1000u64, 1000u64); + pub KsmPerSecond: (AssetId, u128, u128) = (AssetId(KsmLocation::get()), 1, 1); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub MatcherLocation: Location = Location::here(); +} + +pub type XcmRouter = super::RelayChainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); + pub Statemine: Location = Parachain(1000).into(); + pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); +} + +pub type TrustedTeleporters = xcm_builder::Case; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub const FirstMessageFactorPercent: u64 = 100; +} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +/// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this +/// is more to satisfy type requirements rather than to test anything. +pub struct TestNextSessionRotation; + +impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { + fn average_session_length() -> u32 { + 10 + } + + fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } + + fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } +} + +impl paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = TestNextSessionRotation; + type QueueFootprinter = (); + type OnNewHead = (); + type AssignCoretime = (); +} + +impl dmp::Config for Runtime {} + +parameter_types! { + pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); +} + +impl hrmp::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = TestHrmpWeightInfo; + type ChannelManager = frame_system::EnsureRoot; + type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +impl origin::Config for Runtime {} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + Utility: pallet_utility, + Hrmp: hrmp, + Dmp: dmp, + Paras: paras, + Configuration: configuration, + } +); + +pub(crate) fn relay_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::{OnFinalize, OnInitialize}; +pub(crate) fn relay_roll_to(n: BlockNumber) { + while System::block_number() < n { + XcmPallet::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + XcmPallet::on_initialize(System::block_number()); + } +} + +/// A weight info that is only suitable for testing. +pub struct TestHrmpWeightInfo; + +impl hrmp::WeightInfo for TestHrmpWeightInfo { + fn hrmp_accept_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn force_clean_hrmp(_: u32, _: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_close(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_open(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_cancel_open_request(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_close_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_init_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn clean_open_channel_requests(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_open_hrmp_channel(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn establish_system_channel() -> Weight { + Weight::from_parts(1, 0) + } + + fn poke_channel_deposits() -> Weight { + Weight::from_parts(1, 0) + } + + fn establish_channel_with_system() -> Weight { + Weight::from_parts(1, 0) + } +} diff --git a/tracing/3200/runtime/moonbase/tests/xcm_mock/statemint_like.rs b/tracing/3200/runtime/moonbase/tests/xcm_mock/statemint_like.rs new file mode 100644 index 00000000..59491983 --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/xcm_mock/statemint_like.rs @@ -0,0 +1,605 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, Get, Nothing}, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, Hash, IdentityLookup}, + AccountId32, +}; + +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain::primitives::Sibling; +use sp_std::convert::TryFrom; +use xcm::latest::prelude::*; +use xcm::VersionedXcm; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + FungiblesAdapter, IsConcrete, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type AssetId = u128; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; // 1 UNIT deposit to create asset + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub Local: Location = Here.into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub KsmPerSecond: (xcm::latest::prelude::AssetId, u128, u128) = + (AssetId(KsmLocation::get()), 1, 1); +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = FungibleAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ConvertedConcreteId< + AssetId, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; +/// Means for transacting assets on this chain. +pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxInstructions: u32 = 100; +} + +pub struct ParentOrParentsExecutivePlurality; +impl Contains for ParentOrParentsExecutivePlurality { + fn contains(location: &Location) -> bool { + matches!( + location.unpack(), + (1, []) + | ( + 1, + [Plurality { + id: BodyId::Executive, + .. + }] + ) + ) + } +} + +pub struct ParentOrSiblings; +impl Contains for ParentOrSiblings { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, []) | (1, [_])) + } +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +parameter_types! { + pub MatcherLocation: Location = Location::here(); + pub const MaxAssetsIntoHolding: u32 = 64; + pub const RelayTokenLocation: Location = Location::parent(); +} + +// Copied from: +// +// https://github.com/paritytech/polkadot-sdk/blob/f4eb41773611008040c9d4d8a8e6b7323eccfca1/cumulus +// /parachains/common/src/xcm_config.rs#L118 +// +// The difference with the original "ConcreteAssetFromSystem" (which is used by AssetHub), +// is that in our tests we only need to check if the asset matches the relay one. +pub struct ConcreteAssetFromRelay(sp_std::marker::PhantomData); +impl> ContainsPair + for ConcreteAssetFromRelay +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + let is_relay = match origin.unpack() { + // The Relay Chain + (1, []) => true, + // Others + _ => false, + }; + asset.id.0 == AssetLocation::get() && is_relay + } +} + +pub type TrustedTeleporters = (ConcreteAssetFromRelay,); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = + orml_xcm_support::MultiNativeAsset; + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +pub type XcmRouter = super::ParachainXcmRouter; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Pallet to cover test cases for change https://github.com/paritytech/cumulus/pull/831 +#[frame_support::pallet] +pub mod mock_statemint_prefix { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_prefix)] + pub(super) type CurrentPrefix = StorageValue<_, Location, ValueQuery>; + + impl Get for Pallet { + fn get() -> Location { + Self::current_prefix() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Changed Prefix + PrefixChanged(Location), + } + + impl Pallet { + pub fn set_prefix(prefix: Location) { + CurrentPrefix::::put(&prefix); + Self::deposit_event(Event::PrefixChanged(prefix)); + } + } +} + +impl mock_statemint_prefix::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +type Block = frame_system::mocking::MockBlockU32; +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + PolkadotXcm: pallet_xcm, + CumulusXcm: cumulus_pallet_xcm, + MsgQueue: mock_msg_queue, + Assets: pallet_assets, + PrefixChanger: mock_statemint_prefix, + + } +); diff --git a/tracing/3200/runtime/moonbase/tests/xcm_tests.rs b/tracing/3200/runtime/moonbase/tests/xcm_tests.rs new file mode 100644 index 00000000..e9234554 --- /dev/null +++ b/tracing/3200/runtime/moonbase/tests/xcm_tests.rs @@ -0,0 +1,4853 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbase Runtime Xcm Tests + +mod xcm_mock; +use frame_support::{ + assert_ok, + traits::{ConstU32, PalletInfo, PalletInfoAccess}, + weights::constants::WEIGHT_REF_TIME_PER_SECOND, + weights::Weight, + BoundedVec, +}; +use pallet_xcm_transactor::{ + Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights, +}; +use sp_runtime::traits::MaybeEquivalence; +use sp_std::boxed::Box; +use xcm::latest::prelude::{ + AccountId32, AccountKey20, All, Asset as XcmAsset, AssetId as XcmAssetId, Assets as XcmAssets, + BuyExecution, ClearOrigin, DepositAsset, Fungible, GeneralIndex, Junction, Junctions, Limited, + Location, OriginKind, PalletInstance, Parachain, QueryResponse, Reanchorable, Response, + WeightLimit, WithdrawAsset, Xcm, +}; +use xcm::{IntoVersion, VersionedLocation, WrapVersion}; +use xcm_executor::traits::ConvertLocation; +use xcm_mock::*; +use xcm_primitives::{UtilityEncodeCall, DEFAULT_PROOF_SIZE}; +use xcm_simulator::TestExt; +mod common; +use cumulus_primitives_core::relay_chain::HrmpChannelId; + +fn add_supported_asset(asset_type: parachain::AssetType, units_per_second: u128) -> Result<(), ()> { + let parachain::AssetType::Xcm(location_v3) = asset_type; + let VersionedLocation::V4(location_v4) = VersionedLocation::V3(location_v3) + .into_version(4) + .map_err(|_| ())? + else { + return Err(()); + }; + use frame_support::weights::WeightToFee as _; + let native_amount_per_second: u128 = + ::WeightToFee::weight_to_fee( + &Weight::from_parts( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + 0, + ), + ) + .try_into() + .map_err(|_| ())?; + let precision_factor = 10u128.pow(pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS); + let relative_price: u128 = if units_per_second > 0u128 { + native_amount_per_second + .saturating_mul(precision_factor) + .saturating_div(units_per_second) + } else { + 0u128 + }; + pallet_xcm_weight_trader::SupportedAssets::::insert( + location_v4, + (true, relative_price), + ); + Ok(()) +} + +// Send a relay asset (like DOT) to a parachain A +#[test] +fn receive_relay_asset_from_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Verify that parachain received the asset + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +// Send relay asset (like DOT) back from Parachain A to relaychain +#[test] +fn send_relay_asset_to_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // Free execution + assert_ok!(add_supported_asset(source_location, 0)); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain like in previous test + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Lets gather the balance before sending back money + let mut balance_before_sending = 0; + Relay::execute_with(|| { + balance_before_sending = RelayBalances::free_balance(&RELAYALICE); + }); + + // We now send back some money to the relay + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: RELAYALICE.into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 123, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The balances in paraAlice should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // Balances in the relay should have been received + Relay::execute_with(|| { + // Free execution,x full amount received + assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending); + }); +} + +#[test] +fn send_relay_asset_to_para_b() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register asset in paraA. Free execution + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0)); + }); + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // First send relay chain asset to Parachain A like in previous test + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Now send relay asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23); + }); + + // Para B balances should have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_to_para_b() { + MockNet::reset(); + + // this represents the asset in paraA + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Send para A asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Native token is substracted in paraA + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Asset is minted in paraB + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_from_para_b_to_para_c() { + MockNet::reset(); + + // Represents para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in parachain B. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0)); + }); + + // Register para A asset in parachain C. Free execution + ParaC::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send para A asset from para B to para C + let dest = Location { + parents: 1, + interior: [ + Parachain(3), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The message passed through parachainA so we needed to pay since its the native token + ParaC::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a() { + MockNet::reset(); + + // Para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in para B + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send back para A asset to para A + let dest = Location { + parents: 1, + interior: [ + Parachain(1), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A asset has been credited + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // This time we will force the new reanchoring by manually sending the + // Message through polkadotXCM pallet + + let dest = Location { + parents: 1, + interior: [Parachain(1)].into(), + }; + + let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]); + + let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![ + WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()), + ClearOrigin, + BuyExecution { + fees: (reanchored_para_a_balances, 100).into(), + weight_limit: Limited(80.into()), + }, + DepositAsset { + assets: All.into(), + beneficiary: Location::new( + 0, + [AccountKey20 { + network: None, + key: PARAALICE, + }], + ), + }, + ])); + ParaB::execute_with(|| { + // Send a message to the sovereign account in ParaA to withdraw + // and deposit asset + assert_ok!(ParachainPalletXcm::send( + parachain::RuntimeOrigin::root(), + Box::new(dest.into()), + Box::new(message), + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn receive_relay_asset_with_trader() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 2_500_000_000_000)); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // We are sending 100 tokens from relay. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Therefore with no refund, we should receive 10 tokens less + // Native trader fails for this, and we use the asset trader + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 100).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // non-free execution, not full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 2500000000000)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // In destination chain, we only need 4 weight + // We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // We are sending 100 tokens from para A. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Since we set 10 weight in destination chain, 25 will be charged upfront + // 15 of those will be refunded, while 10 will go to treasury as the true weight used + // will be 4 + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader_and_fee() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // With these units per second, 80K weight convrets to 1 asset unit + assert_ok!(add_supported_asset(source_location, 12500000)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // we use transfer_with_fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // 100 tokens transferred plus 1 taken from fees + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 - 1 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received because the xcm instruction does not cost + // what it is specified + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101); + }); +} + +#[test] +fn error_when_not_paying_enough() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 2500000000000)); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // We are sending 100 tokens from relay. + // If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10 + // Therefore with no refund, we should receive 10 tokens less + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 5).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); +} + +#[test] +fn transact_through_derivative_multilocation() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 1)); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 1)); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000003000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 1)); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn transact_through_sovereign() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 1)); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_fee_payer_none() { + MockNet::reset(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let derivative_address = derivative_account_id(para_a_account(), 0); + + Relay::execute_with(|| { + // Transfer 100 tokens to derivative_address on the relay + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derivative_address.clone(), + 100u128 + )); + + // Transfer the XCM execution fee amount to ParaA's sovereign account + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 4000003000u128 + )); + }); + + // Check balances before the transact call + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000003000); + assert_eq!(RelayBalances::free_balance(&derivative_address), 100); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0); + }); + + // Encode the call. Balances transfer of 100 relay tokens to RELAYBOB + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: RELAYBOB, + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + // The final call will be an AsDerivative using index 0 + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + // No fee_payer here. The sovereign account will pay the fees on destination. + None, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + // Check balances after the transact call are correct + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 0); + assert_eq!(RelayBalances::free_balance(&derivative_address), 0); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 1)); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000003000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 1)); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000009000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A and set XCM version to 1 + ParaA::execute_with(|| { + parachain::XcmVersioner::set_version(1); + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + let response = Response::Version(2); + let querier: Location = [].into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + // The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force + // it directly here + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + Relay::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(RelayChainPalletXcm::force_default_xcm_version( + relay_chain::RuntimeOrigin::root(), + Some(2) + )); + + // Wrap version, which sets VersionedStorage + // This is necessary because the mock router does not use wrap_version, but + // this is not necessary in prod + assert_ok!(::wrap_version( + &Parachain(1).into(), + mock_message + )); + + // Transfer assets. Since it is an unknown destination, it will query for version + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + + // Let's advance the relay. This should trigger the subscription message + relay_chain::relay_roll_to(2); + + // queries should have been updated + assert!(RelayChainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 1, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the version change + assert!(relay_chain::relay_events().contains(&expected_supported_version)); + }); + + // ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaA::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in the relay + let expected_supported_version_2: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 2, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(relay_chain::relay_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_para_b() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + let response = Response::Version(2); + let querier: Location = [].into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + + ParaA::execute_with(|| { + // advertised version + parachain::XcmVersioner::set_version(2); + }); + + ParaB::execute_with(|| { + // Let's try with v0 + parachain::XcmVersioner::set_version(0); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + ParaA::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(ParachainPalletXcm::force_default_xcm_version( + parachain::RuntimeOrigin::root(), + Some(2) + )); + // Wrap version, which sets VersionedStorage + assert_ok!(::wrap_version( + &Location::new(1, [Parachain(2)]).into(), + mock_message + )); + + parachain::para_roll_to(2); + + // queries should have been updated + assert!(ParachainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 0, + } + .into(); + + ParaA::execute_with(|| { + // Assert that the events vector contains the version change + assert!(parachain::para_events().contains(&expected_supported_version)); + }); + + // Let's ensure talking in v0 works + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + } + .into(); + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // ParaB changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaB::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in para A + let expected_supported_version_2: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 2, + } + .into(); + + // Para A should have received the version change + ParaA::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(parachain::para_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should not have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0); + }); + + // Send native token to fresh_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + fresh_account.into(), + 100 + )); + }); + + // Re-send tokens + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn evm_account_receiving_assets_should_handle_sufficients_ref_count() { + MockNet::reset(); + + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + // Evm account is self sufficient + ParaA::execute_with(|| { + assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Evm account sufficient ref count increased by 1. + ParaA::execute_with(|| { + // TODO: since the suicided logic was introduced the data of the smart contract is not + // removed, it will have to be updated in a future release when there is the ability to + // remove contract data + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 2); + }); + + ParaA::execute_with(|| { + // Remove the account from the evm context. + parachain::EVM::remove_account(&evm_account()); + // Evm account sufficient ref count decreased by 1. + // TODO: since the suicided logic was introduced the data of the smart contract is not + // removed, it will have to be updated in a future release when there is the ability to + // remove contract data + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); +} + +#[test] +fn empty_account_should_not_be_reset() { + MockNet::reset(); + + // Test account has nonce 1 on genesis. + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + // Send native token to evm_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + evm_account_id, + 100 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([], 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Empty the assets from the account. + // As this makes the account go below the `min_balance`, the account is considered dead + // at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero. + assert_ok!(parachain::Assets::transfer( + parachain::RuntimeOrigin::signed(evm_account_id), + source_id, + PARAALICE.into(), + 123 + )); + // Verify account asset balance is Zero. + assert_eq!( + parachain::Assets::balance(source_id, &evm_account_id.into()), + 0 + ); + // Because we no longer have consumer references, we can set the balance to Zero. + // This would reset the account if our ED were to be > than Zero. + assert_ok!(ParaBalances::force_set_balance( + parachain::RuntimeOrigin::root(), + evm_account_id, + 0, + )); + // Verify account native balance is Zero. + assert_eq!(ParaBalances::free_balance(&evm_account_id), 0); + // Remove the account from the evm context. + // This decreases the sufficients reference by 1 and now is Zero. + parachain::EVM::remove_account(&evm_account()); + // Verify reference count. + let account = parachain::System::account(evm_account_id); + assert_eq!(account.sufficients, 0); + assert_eq!(account.consumers, 0); + assert_eq!(account.providers, 1); + // We expect the account to be alive in a Zero ED context. + assert_eq!(parachain::System::account_nonce(evm_account_id), 1); + }); +} + +#[test] +fn test_statemint_like() { + MockNet::reset(); + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + let statemint_asset_a_balances = Location::new( + 1, + [ + Parachain(1000), + PalletInstance(5), + xcm::latest::prelude::GeneralIndex(0u128), + ], + ); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset_a_balances) + .expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"StatemintToken".to_vec(), + symbol: b"StatemintToken".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location, 0)); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 300000000000000 + )); + + // This is needed, since the asset is created as non-sufficient + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send asset with previous prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + xcm::latest::prelude::GeneralIndex(0), + ], + 123 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +#[test] +fn send_statemint_asset_from_para_a_to_statemint_with_relay_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(relay_location, 0)); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + assert_ok!(add_supported_asset(statemint_location_asset, 0)); + }); + + let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send relay chain asset to Alice in Parachain A + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_relay) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Send some native statemint tokens to sovereign for fees. + // We can't pay fees with USDC as the asset is minted as non-sufficient. + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Send statemint USDC asset to Alice in Parachain A + let parachain_beneficiary_from_statemint: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_statemint) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + let statemint_beneficiary = Location { + parents: 1, + interior: [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + + // Alice has received 200 Relay assets + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + Statemint::execute_with(|| { + // Check that BOB's balance is empty before the transfer + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![]); + }); + + // Transfer USDC from Parachain A to Statemint using Relay asset as fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemint_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(statemint_beneficiary)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + }); + + ParaA::execute_with(|| { + // Alice has 100 USDC less + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 25 + ); + + // Alice has 100 relay asset less + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that BOB received 100 USDC on statemint + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_relay_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received the tokens back in AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 100 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_with_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_relay_id), + 100, + 10, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 90); + }); + + Statemint::execute_with(|| { + // Free execution: check that Bob received the tokens back in AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 110 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 10 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 190); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiasset() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multiasset( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new((Location::parent(), 100).into()), + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received the tokens back in AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 100 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multicurrencies() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(statemint_asset, 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs and USDC from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Now send relay tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + + // Send USDC + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemint_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received relay tokens back in AssetHub + // (100 - MinXcmFee) + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 50 + ); + + // Check that BOB received 100 USDC on AssetHub + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + let bob_previous_balance = StatemintBalances::free_balance(RELAYBOB); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + bob_previous_balance - 100 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiassets() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(statemint_asset.clone(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs and USDC from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Now send relay tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + + // Send USDC + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + let statemint_asset_to_send = XcmAsset { + id: XcmAssetId(statemint_asset), + fun: Fungible(100), + }; + + let relay_asset_to_send = XcmAsset { + id: XcmAssetId(Location::parent()), + fun: Fungible(100), + }; + + let assets_to_send: XcmAssets = + XcmAssets::from(vec![statemint_asset_to_send, relay_asset_to_send.clone()]); + + // For some reason the order of the assets is inverted when creating the array above. + // We need to use relay asset for fees, so we pick index 0. + assert_eq!(assets_to_send.get(0).unwrap(), &relay_asset_to_send); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multiassets( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(assets_to_send.into()), + 0, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received relay tokens back in AssetHub + // (100 - MinXcmFee) + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 50 + ); + + // Check that BOB received 100 USDC on AssetHub + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + let bob_previous_balance = StatemintBalances::free_balance(RELAYBOB); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + bob_previous_balance - 100 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn transact_through_signed_multilocation() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000004000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // 100 transferred + assert_eq!(RelayBalances::free_balance(¶_a_account()), 100); + + // 4000005186 refunded + assert_eq!(RelayBalances::free_balance(&derived), 4000005186); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + assert!(ParaBalances::free_balance(&derived) == 0); + + assert!(ParaBalances::free_balance(¶_a_account_20()) == 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: Some(overall_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + }); + + ParaB::execute_with(|| { + // Check the derived account was refunded + assert_eq!(ParaBalances::free_balance(&derived), 8993); + + // Check the transfer was executed + assert_eq!(ParaBalances::free_balance(¶_a_account_20()), 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact { + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer went through + assert!( + ParaBalances::free_balance(&PARAALICE.into()) + == parachain_b_alice_balances_before + 100 + ); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer wasn't executed + assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_multilocation + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + let transfer_recipient = evm_account(); + let mut transfer_recipient_balance_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into()); + + // Add proxy ALICE -> derived + let _ = parachain::Proxy::add_proxy_delegate( + &PARAALICE.into(), + derived, + parachain::ProxyType::Any, + 0, + ); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 { + gas_limit: U256::from(21000), + action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer was executed + assert!( + ParaBalances::free_balance(&transfer_recipient.into()) + == transfer_recipient_balance_before + 100 + ); + }); +} + +#[test] +fn hrmp_init_accept_through_root() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_b_account(), + 1000u128 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp init channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::InitOpen(HrmpInitParams { + para_id: 2u32.into(), + proposed_max_capacity: 1, + proposed_max_message_size: 1 + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender: 1u32.into(), + recipient: 2u32.into(), + proposed_max_capacity: 1u32, + proposed_max_message_size: 1u32, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); + ParaB::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp accept channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Accept { + para_id: 1u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { + sender: 1u32.into(), + recipient: 2u32.into(), + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +#[test] +fn hrmp_close_works() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(Hrmp::force_open_hrmp_channel( + relay_chain::RuntimeOrigin::root(), + 1u32.into(), + 2u32.into(), + 1u32, + 1u32 + )); + assert_ok!(Hrmp::force_process_hrmp_open( + relay_chain::RuntimeOrigin::root(), + 1u32 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Close(HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into() + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::ChannelClosed { + by_parachain: 1u32.into(), + channel_id: HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into(), + }, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +use parity_scale_codec::{Decode, Encode}; +use sp_io::hashing::blake2_256; + +// Helper to derive accountIds +pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 { + let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); + sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id") +} diff --git a/tracing/3200/runtime/moonbeam/Cargo.toml b/tracing/3200/runtime/moonbeam/Cargo.toml new file mode 100644 index 00000000..43f62d46 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/Cargo.toml @@ -0,0 +1,423 @@ +[package] +authors = { workspace = true } +build = "build.rs" +description = "Moonbeam Runtime" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonbeam-runtime" +version = "0.8.4" + +[dependencies] +hex-literal = { workspace = true, optional = true } +log = { workspace = true } +num_enum = { workspace = true } +rlp = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +sha3 = { workspace = true, optional = true } +smallvec = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +# Moonbeam +account = { workspace = true } +moonbeam-core-primitives = { workspace = true } +moonbeam-relay-encoder = { workspace = true } +moonbeam-runtime-common = { workspace = true } +session-keys-primitives = { workspace = true } +xcm-primitives = { workspace = true } + +# Moonbeam pallets +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-emergency-para-xcm = { workspace = true } +pallet-erc20-xcm-bridge = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-evm-chain-id = { workspace = true } +pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] } +pallet-migrations = { workspace = true } +pallet-moonbeam-foreign-assets = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-proxy-genesis-companion = { workspace = true } +pallet-randomness = { workspace = true } +pallet-xcm-transactor = { workspace = true } +pallet-xcm-weight-trader = { workspace = true } + +# Moonbeam precompiles +pallet-evm-precompile-author-mapping = { workspace = true } +pallet-evm-precompile-balances-erc20 = { workspace = true } +pallet-evm-precompile-batch = { workspace = true } +pallet-evm-precompile-call-permit = { workspace = true } +pallet-evm-precompile-collective = { workspace = true } +pallet-evm-precompile-conviction-voting = { workspace = true } +pallet-evm-precompile-crowdloan-rewards = { workspace = true } +pallet-evm-precompile-gmp = { workspace = true } +pallet-evm-precompile-identity = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } +pallet-evm-precompile-preimage = { workspace = true } +pallet-evm-precompile-proxy = { workspace = true } +pallet-evm-precompile-randomness = { workspace = true } +pallet-evm-precompile-referenda = { workspace = true } +pallet-evm-precompile-registry = { workspace = true } +pallet-evm-precompile-relay-encoder = { workspace = true } +pallet-evm-precompile-relay-verifier = { workspace = true } +pallet-evm-precompile-xcm-transactor = { workspace = true } +pallet-evm-precompile-xcm-utils = { workspace = true } +pallet-evm-precompile-xtokens = { workspace = true } +pallet-evm-precompileset-assets-erc20 = { workspace = true } +pallet-evm-precompile-p256verify = { workspace = true } + +# Moonbeam tracing +evm-tracing-events = { workspace = true, optional = true } +moonbeam-evm-tracer = { workspace = true, optional = true } +moonbeam-rpc-primitives-debug = { workspace = true } +moonbeam-rpc-primitives-txpool = { workspace = true } + +# Substrate +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-identity = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-society = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +parity-scale-codec = { workspace = true, features = [ + "derive", + "max-encoded-len", + "chain-error", +] } +scale-info = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true, features = ["improved_panic_error_reporting"] } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } +sp-genesis-builder = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde"] } +pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-precompile-blake2 = { workspace = true } +pallet-evm-precompile-bn128 = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } +pallet-evm-precompile-modexp = { workspace = true } +pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-simple = { workspace = true } +precompile-utils = { workspace = true } + +# Polkadot / XCM +orml-traits = { workspace = true } +orml-xcm-support = { workspace = true } +orml-xtokens = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { workspace = true, optional = true } +pallet-message-queue = { workspace = true } +polkadot-core-primitives = { workspace = true } +polkadot-runtime-common = { workspace = true } +polkadot-parachain = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } + +# Cumulus +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } + +# Moonkit +async-backing-primitives = { workspace = true } +moonkit-xcm-primitives = { workspace = true } +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } +pallet-relay-storage-roots = { workspace = true } + +# Benchmarking +frame-benchmarking = { workspace = true, optional = true } +frame-system-benchmarking = { workspace = true, optional = true } +frame-try-runtime = { workspace = true, optional = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true } + +[features] +default = ["std", "evm-tracing"] +std = [ + "account/std", + "async-backing-primitives/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "cumulus-primitives-storage-weight-reclaim/std", + "evm-tracing-events/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-metadata-hash-extension/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "moonbeam-core-primitives/std", + "moonbeam-evm-tracer/std", + "moonbeam-relay-encoder/std", + "moonbeam-rpc-primitives-debug/std", + "moonbeam-rpc-primitives-txpool/std", + "moonbeam-runtime-common/std", + "moonbeam-xcm-benchmarks/std", + "moonkit-xcm-primitives/std", + "nimbus-primitives/std", + "orml-xtokens/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-author-slot-filter/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-conviction-voting/std", + "pallet-crowdloan-rewards/std", + "pallet-emergency-para-xcm/std", + "pallet-erc20-xcm-bridge/std", + "pallet-evm-chain-id/std", + "pallet-ethereum-xcm/std", + "pallet-ethereum/std", + "pallet-evm-precompile-author-mapping/std", + "pallet-evm-precompile-balances-erc20/std", + "pallet-evm-precompile-batch/std", + "pallet-evm-precompile-call-permit/std", + "pallet-evm-precompile-collective/std", + "pallet-evm-precompile-conviction-voting/std", + "pallet-evm-precompile-parachain-staking/std", + "pallet-evm-precompile-preimage/std", + "pallet-evm-precompile-randomness/std", + "pallet-evm-precompile-referenda/std", + "pallet-evm-precompile-relay-encoder/std", + "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm-transactor/std", + "pallet-evm-precompile-xcm-utils/std", + "pallet-evm-precompile-xtokens/std", + "pallet-evm-precompileset-assets-erc20/std", + "pallet-evm-precompile-p256verify/std", + "pallet-evm/std", + "pallet-identity/std", + "pallet-maintenance-mode/std", + "pallet-migrations/std", + "pallet-moonbeam-foreign-assets/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-moonbeam-orbiters/std", + "pallet-multisig/std", + "pallet-parachain-staking/std", + "pallet-precompile-benchmarks/std", + "pallet-preimage/std", + "pallet-proxy-genesis-companion/std", + "pallet-proxy/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-relay-storage-roots/std", + "pallet-root-testing/std", + "pallet-scheduler/std", + "pallet-society/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-treasury/std", + "pallet-utility/std", + "pallet-whitelist/std", + "pallet-xcm-transactor/std", + "pallet-xcm/std", + "pallet-xcm-weight-trader/std", + "parachain-info/std", + "parachains-common/std", + "parity-scale-codec/std", + "precompile-utils/std", + "scale-info/std", + "session-keys-primitives/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-genesis-builder/std", + "strum/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm-primitives/std", + "xcm/std", +] +evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"] + +# Will be enabled by the `wasm-builder` when building the runtime for WASM. +runtime-wasm = [] + +# Enable the metadata hash generation in the wasm builder. +metadata-hash = ["substrate-wasm-builder/metadata-hash"] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "moonbeam-relay-encoder/runtime-benchmarks", + "moonbeam-runtime-common/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", + "pallet-moonbeam-foreign-assets/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-precompile-benchmarks/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-relay-storage-roots/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-society/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-xcm-weight-trader/runtime-benchmarks", + "session-keys-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] + +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "fp-self-contained/try-runtime", + "frame-executive/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime", + "moonbeam-runtime-common/try-runtime", + "pallet-asset-manager/try-runtime", + "pallet-async-backing/try-runtime", + "pallet-author-mapping/try-runtime", + "pallet-author-slot-filter/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-maintenance-mode/try-runtime", + "pallet-migrations/try-runtime", + "pallet-moonbeam-lazy-migrations/try-runtime", + "pallet-parachain-staking/try-runtime", + "pallet-precompile-benchmarks/try-runtime", + "pallet-preimage/try-runtime", + "pallet-referenda/try-runtime", + "pallet-relay-storage-roots/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-xcm/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-utility/try-runtime", + "pallet-transaction-payment/try-runtime", + "parachain-info/try-runtime", + "pallet-evm-chain-id/try-runtime", + "parachain-info/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum/try-runtime", + "pallet-treasury/try-runtime", + "pallet-author-inherent/try-runtime", + "pallet-crowdloan-rewards/try-runtime", + "pallet-proxy/try-runtime", + "pallet-identity/try-runtime", + "orml-xtokens/try-runtime", + "pallet-assets/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-proxy-genesis-companion/try-runtime", + "pallet-moonbeam-orbiters/try-runtime", + "pallet-ethereum-xcm/try-runtime", + "pallet-randomness/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-erc20-xcm-bridge/try-runtime", + "pallet-multisig/try-runtime", +] diff --git a/tracing/3200/runtime/moonbeam/build.rs b/tracing/3200/runtime/moonbeam/build.rs new file mode 100644 index 00000000..f1802267 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/build.rs @@ -0,0 +1,36 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +#[cfg(not(feature = "metadata-hash"))] +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} + +#[cfg(feature = "metadata-hash")] +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .enable_metadata_hash("GLMR", 18) + .build() +} diff --git a/tracing/3200/runtime/moonbeam/src/asset_config.rs b/tracing/3200/runtime/moonbeam/src/asset_config.rs new file mode 100644 index 00000000..200841c5 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/asset_config.rs @@ -0,0 +1,216 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Asset configuration for Moonbase. +//! + +use super::{ + currency, governance, xcm_config, AccountId, AssetId, AssetManager, Assets, Balance, Balances, + OpenTechCommitteeInstance, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use frame_support::{ + dispatch::GetDispatchInfo, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, EitherOfDiverse}, + weights::Weight, +}; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; + +use frame_system::{EnsureNever, EnsureRoot}; +use sp_core::H160; + +use parity_scale_codec::{Compact, Decode, Encode}; +use scale_info::TypeInfo; + +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; + +// Number of items that can be destroyed with our configured max extrinsic proof size. +// x = (a - b) / c where: +// a: maxExtrinsic proof size +// b: base proof size for destroy_accounts in pallet_assets weights +// c: proof size for each item +// 656.87 = (3_407_872 - 8232) / 5180 +const REMOVE_ITEMS_LIMIT: u32 = 656; + +// Not to disrupt the previous asset instance, we assign () to Foreign +pub type ForeignAssetInstance = (); + +// For foreign assets, these parameters dont matter much +// as this will only be called by root with the forced arguments +// No deposit is substracted with those methods +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::GLMR * currency::SUPPLY_FACTOR; + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = currency::deposit(1,68); + pub const MetadataDepositPerByte: Balance = currency::deposit(0, 1); +} + +/// We allow Root and General Admin to execute privileged asset operations. +pub type AssetsForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +// Foreign assets +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>; + type WeightInfo = moonbeam_weights::pallet_assets::WeightInfo; + type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>; + type AssetIdParameter = Compact; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::{pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + #[transactional] + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + // Lastly, the metadata + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + // For us both of them (Foreign and Local) have the same annotated weight for a given + // witness + // We need to take the dispatch info from the destroy call, which is already annotated in + // the assets pallet + + // This is the dispatch info of destroy + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} +pub type ForeignAssetModifierOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type ForeignAssetType = xcm_config::AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = ForeignAssetModifierOrigin; + type WeightInfo = moonbeam_weights::pallet_asset_manager::WeightInfo; +} + +// Instruct how to go from an H160 to an AssetID +// We just take the lowest 128 bits +impl AccountIdAssetIdConversion for Runtime { + /// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF + /// and by taking the lowest 128 bits as the assetId + fn account_to_asset_id(account: AccountId) -> Option<(Vec, AssetId)> { + let h160_account: H160 = account.into(); + let mut data = [0u8; 16]; + let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4); + if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX { + data.copy_from_slice(id_part); + let asset_id: AssetId = u128::from_be_bytes(data).into(); + Some((prefix_part.to_vec(), asset_id)) + } else { + None + } + } + + // The opposite conversion + fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(prefix); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + AccountId::from(data) + } +} diff --git a/tracing/3200/runtime/moonbeam/src/governance/councils.rs b/tracing/3200/runtime/moonbeam/src/governance/councils.rs new file mode 100644 index 00000000..c8cc1ca3 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/governance/councils.rs @@ -0,0 +1,61 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Councils for Gov1 and Gov2 + +use super::*; + +pub type TreasuryCouncilInstance = pallet_collective::Instance3; +pub type OpenTechCommitteeInstance = pallet_collective::Instance4; + +parameter_types! { + // TODO: Check value of this parameter + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for treasury council members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 3 * DAYS }>; + /// The maximum number of proposals that can be open in the treasury council at once. + type MaxProposals = ConstU32<20>; + /// The maximum number of treasury council members. + type MaxMembers = ConstU32<9>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for technical committee members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 14 * DAYS }>; + /// The maximum number of proposals that can be open in the technical committee at once. + type MaxProposals = ConstU32<100>; + /// The maximum number of technical committee members. + type MaxMembers = ConstU32<100>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonbeam_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} diff --git a/tracing/3200/runtime/moonbeam/src/governance/mod.rs b/tracing/3200/runtime/moonbeam/src/governance/mod.rs new file mode 100644 index 00000000..bfe3def3 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/governance/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Governance configurations + +pub mod councils; +pub mod referenda; + +use super::*; + +mod origins; +pub use origins::{ + custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; diff --git a/tracing/3200/runtime/moonbeam/src/governance/origins.rs b/tracing/3200/runtime/moonbeam/src/governance/origins.rs new file mode 100644 index 00000000..48154cd1 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/governance/origins.rs @@ -0,0 +1,85 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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. + +//! Custom origins for governance interventions. +#![cfg_attr(not(feature = "std"), no_std)] + +pub use custom_origins::*; + +#[frame_support::pallet] +pub mod custom_origins { + use frame_support::pallet_prelude::*; + use strum_macros::EnumString; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive( + PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug, EnumString, + )] + #[strum(serialize_all = "snake_case")] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// General admin + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Fast General Admin + FastGeneralAdmin, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + GeneralAdmin, + FastGeneralAdmin, + ); +} diff --git a/tracing/3200/runtime/moonbeam/src/governance/referenda.rs b/tracing/3200/runtime/moonbeam/src/governance/referenda.rs new file mode 100644 index 00000000..62720a0d --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/governance/referenda.rs @@ -0,0 +1,100 @@ +// Copyright 2019-2023 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Gov2 config +//! Includes runtime configs for these substrate pallets: +//! 1. pallet-conviction-voting +//! 2. pallet-whitelist +//! 3. pallet-referenda + +use super::*; +use crate::currency::{GLMR, SUPPLY_FACTOR}; +use frame_support::traits::{EitherOf, MapSuccess}; +use frame_system::EnsureRootWithSuccess; +use sp_runtime::traits::Replace; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 1 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Polls = Referenda; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + // Maximum number of concurrent votes an account may have + type MaxVotes = ConstU32<20>; + // Minimum period of vote locking + type VoteLockingPeriod = VoteLockingPeriod; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 10 * GLMR * SUPPLY_FACTOR; + pub const UndecidingTimeout: BlockNumber = 21 * DAYS; +} + +// Origin for general admin or root +pub type GeneralAdminOrRoot = EitherOf, origins::GeneralAdmin>; +// The policy allows for Root or FastGeneralAdmin. +pub type FastGeneralAdminOrRoot = EitherOf, origins::FastGeneralAdmin>; + +impl custom_origins::Config for Runtime {} + +// The purpose of this pallet is to queue calls to be dispatched as by root later => the Dispatch +// origin corresponds to the Gov2 Whitelist track. +impl pallet_whitelist::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_whitelist::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WhitelistOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + pallet_collective::EnsureProportionAtLeast< + Self::AccountId, + OpenTechCommitteeInstance, + 5, + 9, + >, + Replace>, + >, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +impl pallet_referenda::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/tracing/3200/runtime/moonbeam/src/governance/tracks.rs b/tracing/3200/runtime/moonbeam/src/governance/tracks.rs new file mode 100644 index 00000000..a69cd645 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/governance/tracks.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{GLMR, KILOGLMR, SUPPLY_FACTOR}; +use sp_std::str::FromStr; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} +const fn permill(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 1000) +} + +use pallet_referenda::Curve; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + // Name of this track. + name: "root", + // A limit for the number of referenda on this track that can be being decided at once. + // For Root origin this should generally be just one. + max_deciding: 5, + // Amount that must be placed on deposit before a decision can be made. + decision_deposit: 20 * KILOGLMR * SUPPLY_FACTOR, + // Amount of time this must be submitted for before a decision can be made. + prepare_period: 1 * DAYS, + // Amount of time that a decision may take to be approved prior to cancellation. + decision_period: 14 * DAYS, + // Amount of time that the approval criteria must hold before it can be approved. + confirm_period: 1 * DAYS, + // Minimum amount of time that an approved proposal must be in the dispatch queue. + min_enactment_period: 1 * DAYS, + // Minimum aye votes as percentage of overall conviction-weighted votes needed for + // approval as a function of time into decision period. + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + // Minimum pre-conviction aye-votes ("support") as percentage of overall population that + // is needed for approval as a function of time into decision period. + min_support: Curve::make_linear(14, 14, permill(5), percent(25)), + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 2 * KILOGLMR * SUPPLY_FACTOR, + prepare_period: 10 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)), + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 100 * GLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 1 * DAYS, + min_enactment_period: 1 * DAYS, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)), + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 20, + decision_deposit: 2 * KILOGLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 100, + decision_deposit: 4 * KILOGLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "fast_general_admin", + max_deciding: 10, + decision_deposit: 100 * GLMR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)), + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => { + if let Some((track_id, _)) = Self::tracks() + .into_iter() + .find(|(_, track)| track.name == "root") + { + Ok(*track_id) + } else { + Err(()) + } + } + _ => Err(()), + } + } else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) { + if let Some((track_id, _)) = Self::tracks().into_iter().find(|(_, track)| { + if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track.name) { + track_custom_origin == custom_origin + } else { + false + } + }) { + Ok(*track_id) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +#[test] +/// To ensure voters are always locked into their vote +fn vote_locking_always_longer_than_enactment_period() { + for (_, track) in TRACKS_DATA { + assert!( + ::VoteLockingPeriod::get() + >= track.min_enactment_period, + "Track {} has enactment period {} < vote locking period {}", + track.name, + track.min_enactment_period, + ::VoteLockingPeriod::get(), + ); + } +} + +#[test] +fn all_tracks_have_origins() { + for (_, track) in TRACKS_DATA { + // check name.into() is successful either converts into "root" or custom origin + let track_is_root = track.name == "root"; + let track_has_custom_origin = custom_origins::Origin::from_str(track.name).is_ok(); + assert!(track_is_root || track_has_custom_origin); + } +} diff --git a/tracing/3200/runtime/moonbeam/src/lib.rs b/tracing/3200/runtime/moonbeam/src/lib.rs new file mode 100644 index 00000000..d1290a63 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/lib.rs @@ -0,0 +1,1843 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! The Moonbeam Runtime. +//! +//! Primary features of this runtime include: +//! * Ethereum compatibility +//! * Moonbeam tokenomics + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512. +#![recursion_limit = "512"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use account::AccountId20; +use cumulus_pallet_parachain_system::{ + RelayChainStateProof, RelayStateProof, RelaychainDataProvider, ValidationData, +}; +use fp_rpc::TransactionStatus; + +use cumulus_primitives_core::{relay_chain, AggregateMessageOrigin}; +#[cfg(feature = "std")] +pub use fp_evm::GenesisAccount; +pub use frame_support::traits::Get; +use frame_support::{ + construct_runtime, + dispatch::{DispatchClass, GetDispatchInfo, PostDispatchInfo}, + ensure, + pallet_prelude::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Credit, HoldConsideration, Inspect}, + tokens::imbalance::ResolveTo, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, + EqualPrivilegeOnly, Imbalance, InstanceFilter, LinearStoragePrice, OnFinalize, + OnUnbalanced, + }, + weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, + }, + PalletId, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +pub use moonbeam_core_primitives::{ + AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, + Index, Signature, +}; +use moonbeam_rpc_primitives_txpool::TxPoolResponse; +use moonbeam_runtime_common::{ + timestamp::{ConsensusHookWrapperForRelayTimestamp, RelayTimestamp}, + weights as moonbeam_weights, +}; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction}; +use pallet_evm::{ + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, GasWeightMapping, IdentityAddressMapping, + OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, +}; +pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range}; +use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_treasury::TreasuryAccountId; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use smallvec::smallvec; +use sp_api::impl_runtime_apis; +use sp_consensus_slots::Slot; +use sp_core::{OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{ + BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentityLookup, + PostDispatchInfoOf, UniqueSaturatedInto, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, DispatchErrorWithPostInfo, FixedPointNumber, Perbill, Permill, + Perquintill, SaturatedConversion, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; + +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use nimbus_primitives::CanAuthor; + +mod migrations; +mod precompiles; +pub use precompiles::{ + MoonbeamPrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +pub type Precompiles = MoonbeamPrecompiles; + +pub mod asset_config; +pub mod governance; +pub mod xcm_config; +use governance::councils::*; + +/// GLMR, the native token, uses 18 decimals of precision. +pub mod currency { + use super::Balance; + + // Provide a common factor between runtimes based on a supply of 10_000_000 tokens. + pub const SUPPLY_FACTOR: Balance = 100; + + pub const WEI: Balance = 1; + pub const KILOWEI: Balance = 1_000; + pub const MEGAWEI: Balance = 1_000_000; + pub const GIGAWEI: Balance = 1_000_000_000; + pub const MICROGLMR: Balance = 1_000_000_000_000; + pub const MILLIGLMR: Balance = 1_000_000_000_000_000; + pub const GLMR: Balance = 1_000_000_000_000_000_000; + pub const KILOGLMR: Balance = 1_000_000_000_000_000_000_000; + + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; + pub const STORAGE_BYTE_FEE: Balance = 100 * MICROGLMR * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR / 4; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 100 * MILLIGLMR * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE + } +} + +/// Maximum weight per block +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX) + .saturating_mul(2) + .set_proof_size(relay_chain::MAX_POV_SIZE as u64); + +pub const MILLISECS_PER_BLOCK: u64 = 6_000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; +pub const MONTHS: BlockNumber = DAYS * 30; +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core datastructures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + pub type Block = generic::Block; + + impl_opaque_keys! { + pub struct SessionKeys { + pub nimbus: AuthorInherent, + pub vrf: session_keys_primitives::VrfSessionKey, + } + } +} + +/// This runtime version. +/// The spec_version is composed of 2x2 digits. The first 2 digits represent major changes +/// that can't be skipped, such as data migration upgrades. The last 2 digits represent minor +/// changes which can be skipped. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("moonbeam"), + impl_name: create_runtime_str!("moonbeam"), + authoring_version: 3, + spec_version: 3200, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 3, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we +// subtract roughly the cost of a balance transfer from it (about 1/3 the cost) +// and some cost to account for per-byte-fee. +// TODO: we should use benchmarking's overhead feature to measure this +pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_parts(10000 * WEIGHT_PER_GAS, 0); + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Provided BlockWeight definitions are valid, qed") + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + /// We allow for 5 MB blocks. + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); +} + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Index; + /// The index type for blocks. + type Block = Block; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// The aggregated RuntimeTask type. + type RuntimeTask = RuntimeTask; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = ConstU32<256>; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type BlockWeights = RuntimeBlockWeights; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type BlockLength = BlockLength; + /// Runtime version. + type Version = Version; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = moonbeam_weights::db::rocksdb::constants::RocksDbWeight; + type BaseCallFilter = MaintenanceMode; + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<1284>; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = moonbeam_weights::pallet_utility::WeightInfo; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3000>; + type WeightInfo = moonbeam_weights::pallet_timestamp::WeightInfo; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 0; +} + +impl pallet_balances::Config for Runtime { + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 4]; + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = moonbeam_weights::pallet_balances::WeightInfo; +} + +pub struct DealWithFees(sp_std::marker::PhantomData); +impl OnUnbalanced>> for DealWithFees +where + R: pallet_balances::Config + pallet_treasury::Config, +{ + // this seems to be called for substrate-based transactions + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>>, + ) { + if let Some(fees) = fees_then_tips.next() { + // for fees, 80% are burned, 20% to the treasury + let (_, to_treasury) = fees.ration(80, 20); + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + + // handle tip if there is one + if let Some(tip) = fees_then_tips.next() { + // for now we use the same burn/treasury strategy used for regular fees + let (_, to_treasury) = tip.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + } + } + } + + // this is called from pallet_evm for Ethereum-based transactions + // (technically, it calls on_unbalanced, which calls this when non-zero) + fn on_nonzero_unbalanced(amount: Credit>) { + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + let (_, to_treasury) = amount.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced(to_treasury); + } +} + +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1 * currency::SUPPLY_FACTOR, + negative: false, + }, + ] + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = FungibleAdapter>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = ConstantMultiplier>; + type LengthToFee = LengthToFee; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 2000ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; + +parameter_types! { + pub BlockGasLimit: U256 + = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); + /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less + /// than this will decrease the weight and more will increase. + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); + /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to + /// change the fees more rapidly. This low value causes changes to occur slowly over time. + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); + /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure + /// that combined with `AdjustmentVariable`, we can recover from the minimum. + /// See `multiplier_can_grow_from_zero` in integration_tests.rs. + /// This value is currently only used by pallet-transaction-payment as an assertion that the + /// next multiplier is always > min value. + pub MinimumMultiplier: Multiplier = Multiplier::from(1u128); + /// Maximum multiplier. We pick a value that is expensive but not impossibly so; it should act + /// as a safety net. + pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); + pub PrecompilesValue: MoonbeamPrecompiles = MoonbeamPrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 4 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + /// We should re-check `xcm_config::Erc20XcmBridgeTransferGasLimit` when changing this value + pub const GasLimitPovSizeRatio: u64 = 16; + /// The amount of gas per storage (in bytes): BLOCK_GAS_LIMIT / BLOCK_STORAGE_LIMIT + /// The current definition of BLOCK_STORAGE_LIMIT is 160 KB, resulting in a value of 366. + pub GasLimitStorageGrowthRatio: u64 = 366; +} + +pub struct TransactionPaymentAsGasPrice; +impl FeeCalculator for TransactionPaymentAsGasPrice { + fn min_gas_price() -> (U256, Weight) { + // note: transaction-payment differs from EIP-1559 in that its tip and length fees are not + // scaled by the multiplier, which means its multiplier will be overstated when + // applied to an ethereum transaction + // note: transaction-payment uses both a congestion modifier (next_fee_multiplier, which is + // updated once per block in on_finalize) and a 'WeightToFee' implementation. Our + // runtime implements this as a 'ConstantModifier', so we can get away with a simple + // multiplication here. + // It is imperative that `saturating_mul_int` be performed as late as possible in the + // expression since it involves fixed point multiplication with a division by a fixed + // divisor. This leads to truncation and subsequent precision loss if performed too early. + // This can lead to min_gas_price being same across blocks even if the multiplier changes. + // There's still some precision loss when the final `gas_price` (used_gas * min_gas_price) + // is computed in frontier, but that's currently unavoidable. + let min_gas_price = TransactionPayment::next_fee_multiplier() + .saturating_mul_int((currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128)); + ( + min_gas_price.into(), + ::DbWeight::get().reads(1), + ) + } +} + +/// Parameterized slow adjusting fee updated based on +/// https://w3f-research.readthedocs.io/en/latest/polkadot/overview/2-token-economics.html#-2.-slow-adjusting-mechanism // editorconfig-checker-disable-line +/// +/// The adjustment algorithm boils down to: +/// +/// diff = (previous_block_weight - target) / maximum_block_weight +/// next_multiplier = prev_multiplier * (1 + (v * diff) + ((v * diff)^2 / 2)) +/// assert(next_multiplier > min) +/// where: v is AdjustmentVariable +/// target is TargetBlockFullness +/// min is MinimumMultiplier +pub type SlowAdjustingFeeUpdate = TargetedFeeAdjustment< + R, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, +>; + +use frame_support::traits::FindAuthor; +//TODO It feels like this shold be able to work for any T: H160, but I tried for +// embarassingly long and couldn't figure that out. + +/// The author inherent provides a AccountId20, but pallet evm needs an H160. +/// This simple adapter makes the conversion. +pub struct FindAuthorAdapter(sp_std::marker::PhantomData); + +impl FindAuthor for FindAuthorAdapter +where + Inner: FindAuthor, +{ + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + Inner::find_author(digests).map(Into::into) + } +} + +moonbeam_runtime_common::impl_on_charge_evm_transaction!(); + +impl pallet_evm::Config for Runtime { + type FeeCalculator = TransactionPaymentAsGasPrice; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = IdentityAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = MoonbeamPrecompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EthereumChainId; + type OnChargeTransaction = OnChargeEVMTransaction>; + type BlockGasLimit = BlockGasLimit; + type FindAuthor = FindAuthorAdapter; + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = RelayTimestamp; + type WeightInfo = moonbeam_weights::pallet_evm::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = moonbeam_weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = 5 * currency::GLMR * currency::SUPPLY_FACTOR ; + pub const PreimageByteDeposit: Balance = currency::STORAGE_BYTE_FEE; + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_preimage::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const TreasuryId: PalletId = PalletId(*b"py/trsry"); + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +type TreasuryApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +type TreasuryRejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + // At least three-fifths majority of the council is required (or root) to approve a proposal + type ApproveOrigin = TreasuryApproveOrigin; + // More than half of the council is required (or root) to reject a proposal + type RejectOrigin = TreasuryRejectOrigin; + type RuntimeEvent = RuntimeEvent; + // If spending proposal rejected, transfer proposer bond to treasury + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU128<{ 1 * currency::GLMR * currency::SUPPLY_FACTOR }>; + type SpendPeriod = ConstU32<{ 6 * DAYS }>; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = moonbeam_weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type ProposalBondMaximum = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Disabled, no spending + #[cfg(feature = "runtime-benchmarks")] + type SpendOrigin = + frame_system::EnsureWithSuccess, AccountId, benches::MaxBalance>; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +parameter_types! { + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; + pub const PendingUsernameExpiration: u32 = 7 * DAYS; + pub const MaxSuffixLength: u32 = 7; + pub const MaxUsernameLength: u32 = 32; +} + +type IdentityForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type IdentityRegistrarOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_identity::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + // Add one item in storage and take 258 bytes + type BasicDeposit = ConstU128<{ currency::deposit(1, 258) }>; + // Does not add any item to the storage but takes 1 bytes + type ByteDeposit = ConstU128<{ currency::deposit(0, 1) }>; + // Add one item in storage and take 53 bytes + type SubAccountDeposit = ConstU128<{ currency::deposit(1, 53) }>; + type MaxSubAccounts = MaxSubAccounts; + type IdentityInformation = pallet_identity::legacy::IdentityInfo; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = IdentityForceOrigin; + type RegistrarOrigin = IdentityRegistrarOrigin; + type OffchainSignature = Signature; + type SigningPublicKey = ::Signer; + type UsernameAuthorityOrigin = EnsureRoot; + type PendingUsernameExpiration = PendingUsernameExpiration; + type MaxSuffixLength = MaxSuffixLength; + type MaxUsernameLength = MaxUsernameLength; + type WeightInfo = moonbeam_weights::pallet_identity::WeightInfo; +} + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook< + Runtime, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainInfo; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = EmergencyParaXcm; + type ConsensusHook = ConsensusHookWrapperForRelayTimestamp; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = moonbeam_weights::cumulus_pallet_parachain_system::WeightInfo; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will immediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +impl parachain_info::Config for Runtime {} + +pub struct OnNewRound; +impl pallet_parachain_staking::OnNewRound for OnNewRound { + fn on_new_round(round_index: pallet_parachain_staking::RoundIndex) -> Weight { + MoonbeamOrbiters::on_new_round(round_index) + } +} +pub struct PayoutCollatorOrOrbiterReward; +impl pallet_parachain_staking::PayoutCollatorReward for PayoutCollatorOrOrbiterReward { + fn payout_collator_reward( + for_round: pallet_parachain_staking::RoundIndex, + collator_id: AccountId, + amount: Balance, + ) -> Weight { + let extra_weight = + if MoonbeamOrbiters::is_collator_pool_with_active_orbiter(for_round, collator_id) { + MoonbeamOrbiters::distribute_rewards(for_round, collator_id, amount) + } else { + ParachainStaking::mint_collator_reward(for_round, collator_id, amount) + }; + + ::DbWeight::get() + .reads(1) + .saturating_add(extra_weight) + } +} + +pub struct OnInactiveCollator; +impl pallet_parachain_staking::OnInactiveCollator for OnInactiveCollator { + fn on_inactive_collator( + collator_id: AccountId, + round: pallet_parachain_staking::RoundIndex, + ) -> Result> { + let extra_weight = if !MoonbeamOrbiters::is_collator_pool_with_active_orbiter( + round, + collator_id.clone(), + ) { + ParachainStaking::go_offline_inner(collator_id)?; + ::WeightInfo::go_offline( + pallet_parachain_staking::MAX_CANDIDATES, + ) + } else { + Weight::zero() + }; + + Ok(::DbWeight::get() + .reads(1) + .saturating_add(extra_weight)) + } +} +type MonetaryGovernanceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +pub struct RelayChainSlotProvider; +impl Get for RelayChainSlotProvider { + fn get() -> Slot { + let slot_info = pallet_async_backing::pallet::Pallet::::slot_info(); + slot_info.unwrap_or_default().0 + } +} + +impl pallet_parachain_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = MonetaryGovernanceOrigin; + /// Minimum round length is 2 minutes (10 * 12 second block times) + type MinBlocksPerRound = ConstU32<10>; + /// If a collator doesn't produce any block on this number of rounds, it is notified as inactive + type MaxOfflineRounds = ConstU32<1>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<{ 4 * 7 }>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after + type MinSelectedCandidates = ConstU32<8>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = ConstU128<{ 20_000 * currency::GLMR * currency::SUPPLY_FACTOR }>; + /// Minimum stake required to be reserved to be a delegator + type MinDelegation = ConstU128<{ 500 * currency::MILLIGLMR * currency::SUPPLY_FACTOR }>; + type BlockAuthor = AuthorInherent; + type OnCollatorPayout = (); + type PayoutCollatorReward = PayoutCollatorOrOrbiterReward; + type OnInactiveCollator = OnInactiveCollator; + type OnNewRound = OnNewRound; + type SlotProvider = RelayChainSlotProvider; + type WeightInfo = moonbeam_weights::pallet_parachain_staking::WeightInfo; + type MaxCandidates = ConstU32<200>; + type SlotDuration = ConstU64<6_000>; + type BlockTime = ConstU64<6_000>; +} + +impl pallet_author_inherent::Config for Runtime { + type SlotBeacon = RelaychainDataProvider; + type AccountLookup = MoonbeamOrbiters; + type CanAuthor = AuthorFilter; + type AuthorId = AccountId; + type WeightInfo = moonbeam_weights::pallet_author_inherent::WeightInfo; +} + +impl pallet_author_slot_filter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RandomnessSource = Randomness; + type PotentialAuthors = ParachainStaking; + type WeightInfo = moonbeam_weights::pallet_author_slot_filter::WeightInfo; +} + +impl pallet_async_backing::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type GetAndVerifySlot = pallet_async_backing::RelaySlot; + type ExpectedBlockTime = ConstU64<6000>; +} + +parameter_types! { + pub const InitializationPayment: Perbill = Perbill::from_percent(30); + pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100); + pub const SignatureNetworkIdentifier: &'static [u8] = b"moonbeam-"; +} + +impl pallet_crowdloan_rewards::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Initialized = ConstBool; + type InitializationPayment = InitializationPayment; + type MaxInitContributors = ConstU32<500>; + type MinimumReward = ConstU128<0>; + type RewardCurrency = Balances; + type RelayChainAccountId = [u8; 32]; + type RewardAddressAssociateOrigin = EnsureSigned; + type RewardAddressChangeOrigin = EnsureSigned; + type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold; + type SignatureNetworkIdentifier = SignatureNetworkIdentifier; + type VestingBlockNumber = relay_chain::BlockNumber; + type VestingBlockProvider = RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_crowdloan_rewards::WeightInfo; +} + +// This is a simple session key manager. It should probably either work with, or be replaced +// entirely by pallet sessions +impl pallet_author_mapping::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DepositCurrency = Balances; + type DepositAmount = ConstU128<{ 100 * currency::GLMR * currency::SUPPLY_FACTOR }>; + type Keys = session_keys_primitives::VrfId; + type WeightInfo = moonbeam_weights::pallet_author_mapping::WeightInfo; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] +pub enum ProxyType { + /// All calls can be proxied. This is the trivial/most permissive filter. + Any = 0, + /// Only extrinsics that do not transfer funds. + NonTransfer = 1, + /// Only extrinsics related to governance (democracy and collectives). + Governance = 2, + /// Only extrinsics related to staking. + Staking = 3, + /// Allow to veto an announced proxy call. + CancelProxy = 4, + /// Allow extrinsic related to Balances. + Balances = 5, + /// Allow extrinsic related to AuthorMapping. + AuthorMapping = 6, + /// Allow extrinsic related to IdentityJudgement. + IdentityJudgement = 7, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +fn is_governance_precompile(precompile_name: &precompiles::PrecompileName) -> bool { + matches!( + precompile_name, + PrecompileName::ConvictionVotingPrecompile + | PrecompileName::PreimagePrecompile + | PrecompileName::ReferendaPrecompile + | PrecompileName::OpenTechCommitteeInstance + | PrecompileName::TreasuryCouncilInstance + ) +} + +// Be careful: Each time this filter is modified, the substrate filter must also be modified +// consistently. +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType { + fn is_evm_proxy_call_allowed( + &self, + call: &pallet_evm_precompile_proxy::EvmSubCall, + recipient_has_code: bool, + gas: u64, + ) -> precompile_utils::EvmResult { + Ok(match self { + ProxyType::Any => { + match PrecompileName::from_address(call.to.0) { + // Any precompile that can execute a subcall should be forbidden here, + // to ensure that unauthorized smart contract can't be called + // indirectly. + // To be safe, we only allow the precompiles we need. + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + // All non-whitelisted precompiles are forbidden + Some(_) => false, + // Allow evm transfer to "simple" account (no code nor precompile) + // For the moment, no smart contract other than precompiles is allowed. + // In the future, we may create a dynamic whitelist to authorize some audited + // smart contracts through governance. + None => { + // If the address is not recognized, allow only evm transfert to "simple" + // accounts (no code nor precompile). + // Note: Checking the presence of the code is not enough because some + // precompiles have no code. + !recipient_has_code + && precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + } + } + ProxyType::NonTransfer => { + call.value == U256::zero() + && match PrecompileName::from_address(call.to.0) { + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + _ => false, + } + } + ProxyType::Governance => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(ref precompile) if is_governance_precompile(precompile) + ) + } + ProxyType::Staking => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile + ) + ) + } + // The proxy precompile does not contain method cancel_proxy + ProxyType::CancelProxy => false, + ProxyType::Balances => { + // Allow only "simple" accounts as recipient (no code nor precompile). + // Note: Checking the presence of the code is not enough because some precompiles + // have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + ProxyType::AuthorMapping => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(PrecompileName::AuthorMappingPrecompile) + ) + } + // There is no identity precompile + ProxyType::IdentityJudgement => false, + }) + } +} + +// Be careful: Each time this filter is modified, the EVM filter must also be modified consistently. +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::ParachainSystem(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::ParachainStaking(..) + | RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Identity(..) + | RuntimeCall::Utility(..) + | RuntimeCall::Proxy(..) | RuntimeCall::AuthorMapping(..) + | RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::claim { .. } + ) + ) + } + ProxyType::Governance => matches!( + c, + RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Utility(..) + ), + ProxyType::Staking => matches!( + c, + RuntimeCall::ParachainStaking(..) + | RuntimeCall::Utility(..) + | RuntimeCall::AuthorMapping(..) + | RuntimeCall::MoonbeamOrbiters(..) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ), + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + } + ProxyType::AuthorMapping => matches!(c, RuntimeCall::AuthorMapping(..)), + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) + | RuntimeCall::Utility(..) + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8 + type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)). + type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = moonbeam_weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 56 bytes: + // - 20 bytes AccountId + // - 32 bytes Hasher (Blake2256) + // - 4 bytes BlockNumber (u32) + type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MigrationsList = ( + moonbeam_runtime_common::migrations::CommonMigrations, + migrations::MoonbeamMigrations, + ); + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_moonbeam_lazy_migrations::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_moonbeam_lazy_migrations::WeightInfo; +} + +/// Maintenance mode Call filter +pub struct MaintenanceFilter; +impl Contains for MaintenanceFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(_) => false, + RuntimeCall::Balances(_) => false, + RuntimeCall::CrowdloanRewards(_) => false, + RuntimeCall::Ethereum(_) => false, + RuntimeCall::EVM(_) => false, + RuntimeCall::Identity(_) => false, + RuntimeCall::XTokens(_) => false, + RuntimeCall::ParachainStaking(_) => false, + RuntimeCall::MoonbeamOrbiters(_) => false, + RuntimeCall::PolkadotXcm(_) => false, + RuntimeCall::Treasury(_) => false, + RuntimeCall::XcmTransactor(_) => false, + RuntimeCall::EthereumXcm(_) => false, + _ => true, + } + } +} + +/// Normal Call Filter +/// We dont allow to create nor mint assets, this for now is disabled +/// We only allow transfers. For now creation of assets will go through +/// asset-manager, while minting/burning only happens through xcm messages +/// This can change in the future +pub struct NormalFilter; +impl Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(method) => match method { + pallet_assets::Call::transfer { .. } => true, + pallet_assets::Call::transfer_keep_alive { .. } => true, + pallet_assets::Call::approve_transfer { .. } => true, + pallet_assets::Call::transfer_approved { .. } => true, + pallet_assets::Call::cancel_approval { .. } => true, + pallet_assets::Call::destroy_accounts { .. } => true, + pallet_assets::Call::destroy_approvals { .. } => true, + pallet_assets::Call::finish_destroy { .. } => true, + _ => false, + }, + // We just want to enable this in case of live chains, since the default version + // is populated at genesis + RuntimeCall::PolkadotXcm(method) => match method { + pallet_xcm::Call::force_default_xcm_version { .. } => true, + _ => false, + }, + // We filter anonymous proxy as they make "reserve" inconsistent + // See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line + RuntimeCall::Proxy(method) => match method { + pallet_proxy::Call::create_pure { .. } => false, + pallet_proxy::Call::kill_pure { .. } => false, + pallet_proxy::Call::proxy { real, .. } => { + !pallet_evm::AccountCodes::::contains_key(H160::from(*real)) + } + _ => true, + }, + // Filtering the EVM prevents possible re-entrancy from the precompiles which could + // lead to unexpected scenarios. + // See https://github.com/PureStake/sr-moonbeam/issues/30 + // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so + // this can be seen as an additional security + RuntimeCall::EVM(_) => false, + RuntimeCall::Treasury( + pallet_treasury::Call::spend { .. } + | pallet_treasury::Call::payout { .. } + | pallet_treasury::Call::check_status { .. } + | pallet_treasury::Call::void_spend { .. }, + ) => false, + _ => true, + } + } +} + +pub struct XcmExecutionManager; +impl moonkit_xcm_primitives::PauseXcmExecution for XcmExecutionManager { + fn suspend_xcm_execution() -> DispatchResult { + XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root()) + } + fn resume_xcm_execution() -> DispatchResult { + XcmpQueue::resume_xcm_execution(RuntimeOrigin::root()) + } +} + +impl pallet_maintenance_mode::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type NormalCallFilter = NormalFilter; + type MaintenanceCallFilter = MaintenanceFilter; + type MaintenanceOrigin = + pallet_collective::EnsureProportionAtLeast; + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_proxy_genesis_companion::Config for Runtime { + type ProxyType = ProxyType; +} + +parameter_types! { + pub OrbiterReserveIdentifier: [u8; 4] = [b'o', b'r', b'b', b'i']; +} + +type AddCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type DelCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_moonbeam_orbiters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountLookup = AuthorMapping; + type AddCollatorOrigin = AddCollatorOrigin; + type Currency = Balances; + type DelCollatorOrigin = DelCollatorOrigin; + /// Maximum number of orbiters per collator + type MaxPoolSize = ConstU32<8>; + /// Maximum number of round to keep on storage + type MaxRoundArchive = ConstU32<4>; + type OrbiterReserveIdentifier = OrbiterReserveIdentifier; + type RotatePeriod = ConstU32<1>; + /// Round index type. + type RoundIndex = pallet_parachain_staking::RoundIndex; + type WeightInfo = moonbeam_weights::pallet_moonbeam_orbiters::WeightInfo; +} + +/// Only callable after `set_validation_data` is called which forms this proof the same way +fn relay_chain_state_proof() -> RelayChainStateProof +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + let relay_storage_root = ValidationData::::get() + .expect("set in `set_validation_data`") + .relay_parent_storage_root; + let relay_chain_state = + RelayStateProof::::get().expect("set in `set_validation_data`"); + RelayChainStateProof::new(ParachainInfo::get(), relay_storage_root, relay_chain_state) + .expect("Invalid relay chain state proof, already constructed in `set_validation_data`") +} + +pub struct BabeDataGetter(sp_std::marker::PhantomData); +impl pallet_randomness::GetBabeData> for BabeDataGetter +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + // Tolerate panic here because only ever called in inherent (so can be omitted) + fn get_epoch_index() -> u64 { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + const BENCHMARKING_NEW_EPOCH: u64 = 10u64; + return BENCHMARKING_NEW_EPOCH; + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::EPOCH_INDEX) + .ok() + .flatten() + .expect("expected to be able to read epoch index from relay chain state proof") + } + fn get_epoch_randomness() -> Option { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + let benchmarking_babe_output = Hash::default(); + return Some(benchmarking_babe_output); + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::ONE_EPOCH_AGO_RANDOMNESS) + .ok() + .flatten() + } +} + +impl pallet_randomness::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddressMapping = sp_runtime::traits::ConvertInto; + type Currency = Balances; + type BabeDataGetter = BabeDataGetter; + type VrfKeyLookup = AuthorMapping; + type Deposit = ConstU128<{ 1 * currency::GLMR * currency::SUPPLY_FACTOR }>; + type MaxRandomWords = ConstU8<100>; + type MinBlockDelay = ConstU32<2>; + type MaxBlockDelay = ConstU32<2_000>; + type BlockExpirationDelay = ConstU32<10_000>; + type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = moonbeam_weights::pallet_randomness::WeightInfo; +} + +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + // One storage item; key size is 32 + 20; value is size 4+4+16+20 bytes = 44 bytes. + pub const DepositBase: Balance = currency::deposit(1, 96); + // Additional storage item size of 20 bytes. + pub const DepositFactor: Balance = currency::deposit(0, 20); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = moonbeam_weights::pallet_multisig::WeightInfo; +} + +impl pallet_relay_storage_roots::Config for Runtime { + type MaxStorageRoots = ConstU32<30>; + type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider; + type WeightInfo = moonbeam_weights::pallet_relay_storage_roots::WeightInfo; +} + +impl pallet_precompile_benchmarks::Config for Runtime { + type WeightInfo = moonbeam_weights::pallet_precompile_benchmarks::WeightInfo; +} + +construct_runtime! { + pub enum Runtime + { + // System support stuff. + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 1, + // Previously 2: pallet_randomness_collective_flip + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 5, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Config, Event} = 11, + + // Consensus support. + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 20, + AuthorInherent: pallet_author_inherent::{Pallet, Call, Storage, Inherent} = 21, + AuthorFilter: pallet_author_slot_filter::{Pallet, Call, Storage, Event, Config} = 22, + AuthorMapping: pallet_author_mapping::{Pallet, Call, Config, Storage, Event} = 23, + MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event} = 24, + AsyncBacking: pallet_async_backing::{Pallet, Storage} = 25, + + // Handy utilities. + Utility: pallet_utility::{Pallet, Call, Event} = 30, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 31, + MaintenanceMode: pallet_maintenance_mode::{Pallet, Call, Config, Storage, Event} = 32, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 33, + Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 34, + ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 35, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, + MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 37, + + // Has been permanently removed for safety reasons. + // Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event} = 40, + + // Ethereum compatibility. + EthereumChainId: pallet_evm_chain_id::{Pallet, Storage, Config} = 50, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 51, + Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Origin, Config} = 52, + + // Governance stuff. + Scheduler: pallet_scheduler::{Pallet, Storage, Event, Call} = 60, + // Democracy: 61, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 62, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 63, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 64, + Origins: governance::custom_origins::{Origin} = 65, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 66, + + // Council stuff. + // CouncilCollective: 70 + // TechCommitteeCollective: 71 + TreasuryCouncilCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 72, + OpenTechCommitteeCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 73, + + // Treasury stuff. + Treasury: pallet_treasury::{Pallet, Storage, Config, Event, Call} = 80, + + // Crowdloan stuff. + CrowdloanRewards: pallet_crowdloan_rewards::{Pallet, Call, Config, Storage, Event} = 90, + + // XCM + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Storage, Event} = 100, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 101, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 102, + PolkadotXcm: pallet_xcm::{Pallet, Storage, Call, Event, Origin, Config} = 103, + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 104, + AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event} = 105, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event} = 106, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Storage, Event} = 107, + // Previously 108: pallet_assets:: + EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin, Event} = 109, + Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 110, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 111, + EvmForeignAssets: pallet_moonbeam_foreign_assets::{Pallet, Call, Storage, Event} = 114, + XcmWeightTrader: pallet_xcm_weight_trader::{Pallet, Call, Storage, Event} = 115, + EmergencyParaXcm: pallet_emergency_para_xcm::{Pallet, Call, Storage, Event} = 116, + + // Utils + RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 112, + + // TODO should not be included in production + PrecompileBenchmarks: pallet_precompile_benchmarks::{Pallet} = 113, + + // Randomness + Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 120, + } +} + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_support::parameter_types! { + pub const MaxBalance: crate::Balance = crate::Balance::max_value(); + } + + frame_benchmarking::define_benchmarks!( + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_balances, Balances] + [pallet_evm, EVM] + [pallet_assets, Assets] + [pallet_parachain_staking, ParachainStaking] + [pallet_scheduler, Scheduler] + [pallet_treasury, Treasury] + [pallet_author_inherent, AuthorInherent] + [pallet_author_slot_filter, AuthorFilter] + [pallet_crowdloan_rewards, CrowdloanRewards] + [pallet_author_mapping, AuthorMapping] + [pallet_proxy, Proxy] + [pallet_identity, Identity] + [cumulus_pallet_parachain_system, ParachainSystem] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_message_queue, MessageQueue] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_asset_manager, AssetManager] + [pallet_xcm_transactor, XcmTransactor] + [pallet_moonbeam_orbiters, MoonbeamOrbiters] + [pallet_randomness, Randomness] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_preimage, Preimage] + [pallet_whitelist, Whitelist] + [pallet_multisig, Multisig] + [pallet_moonbeam_lazy_migrations, MoonbeamLazyMigrations] + [pallet_relay_storage_roots, RelayStorageRoots] + ); +} + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + frame_metadata_hash_extension::CheckMetadataHash, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// Executive: handles dispatch to the various pallets. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +// All of our runtimes share most of their Runtime API implementations. +// We use a macro to implement this common part and add runtime-specific additional implementations. +// This macro expands to : +// ``` +// impl_runtime_apis! { +// // All impl blocks shared between all runtimes. +// +// // Specific impls provided to the `impl_runtime_apis_plus_common!` macro. +// } +// ``` +moonbeam_runtime_common::impl_runtime_apis_plus_common! { + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + xt: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + // Filtered calls should not enter the tx pool as they'll fail if inserted. + // If this call is not allowed, we return early. + if !::BaseCallFilter::contains(&xt.0.function) { + return InvalidTransaction::Call.into(); + } + + // This runtime uses Substrate's pallet transaction payment. This + // makes the chain feel like a standard Substrate chain when submitting + // frame transactions and using Substrate ecosystem tools. It has the downside that + // transaction are not prioritized by gas_price. The following code reprioritizes + // transactions to overcome this. + // + // A more elegant, ethereum-first solution is + // a pallet that replaces pallet transaction payment, and allows users + // to directly specify a gas price rather than computing an effective one. + // #HopefullySomeday + + // First we pass the transactions to the standard FRAME executive. This calculates all the + // necessary tags, longevity and other properties that we will leave unchanged. + // This also assigns some priority that we don't care about and will overwrite next. + let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?; + + let dispatch_info = xt.get_dispatch_info(); + + // If this is a pallet ethereum transaction, then its priority is already set + // according to gas price from pallet ethereum. If it is any other kind of transaction, + // we modify its priority. + Ok(match &xt.0.function { + RuntimeCall::Ethereum(transact { .. }) => intermediate_valid, + _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid, + _ => { + let tip = match xt.0.signature { + None => 0, + Some((_, _, ref signed_extra)) => { + // Yuck, this depends on the index of charge transaction in Signed Extra + let charge_transaction = &signed_extra.7; + charge_transaction.tip() + } + }; + + // Calculate the fee that will be taken by pallet transaction payment + let fee: u64 = TransactionPayment::compute_fee( + xt.encode().len() as u32, + &dispatch_info, + tip, + ).saturated_into(); + + // Calculate how much gas this effectively uses according to the existing mapping + let effective_gas = + ::GasWeightMapping::weight_to_gas( + dispatch_info.weight + ); + + // Here we calculate an ethereum-style effective gas price using the + // current fee of the transaction. Because the weight -> gas conversion is + // lossy, we have to handle the case where a very low weight maps to zero gas. + let effective_gas_price = if effective_gas > 0 { + fee / effective_gas + } else { + // If the effective gas was zero, we just act like it was 1. + fee + }; + + // Overwrite the original prioritization with this ethereum one + intermediate_valid.priority = effective_gas_price; + intermediate_valid + } + }) + } + } + + impl async_backing_primitives::UnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: async_backing_primitives::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } +} + +struct CheckInherents; + +// Parity has decided to depreciate this trait, but does not offer a satisfactory replacement, +// see issue: https://github.com/paritytech/polkadot-sdk/issues/2841 +#[allow(deprecated)] +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + inherent_data.check_extrinsics(block) + } +} + +// Nimbus's Executive wrapper allows relay validators to verify the seal digest +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = pallet_author_inherent::BlockExecutor::, + CheckInherents = CheckInherents, +); + +moonbeam_runtime_common::impl_self_contained_call!(); + +// Shorthand for a Get field of a pallet Config. +#[macro_export] +macro_rules! get { + ($pallet:ident, $name:ident, $type:ty) => { + <<$crate::Runtime as $pallet::Config>::$name as $crate::Get<$type>>::get() + }; +} + +#[cfg(test)] +mod tests { + use super::{currency::*, *}; + + #[test] + // Helps us to identify a Pallet Call in case it exceeds the 1kb limit. + // Hint: this should be a rare case. If that happens, one or more of the dispatchable arguments + // need to be Boxed. + fn call_max_size() { + const CALL_ALIGN: u32 = 1024; + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + } + + #[test] + fn currency_constants_are_correct() { + assert_eq!(SUPPLY_FACTOR, 100); + + // txn fees + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(100 * GIGAWEI)); + assert_eq!( + get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), + 5_u8 + ); + assert_eq!(STORAGE_BYTE_FEE, Balance::from(10 * MILLIGLMR)); + + // treasury minimums + assert_eq!( + get!(pallet_treasury, ProposalBondMinimum, u128), + Balance::from(100 * GLMR) + ); + + // pallet_identity deposits + assert_eq!( + get!(pallet_identity, BasicDeposit, u128), + Balance::from(10 * GLMR + 2580 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_identity, ByteDeposit, u128), + Balance::from(10 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_identity, SubAccountDeposit, u128), + Balance::from(10 * GLMR + 530 * MILLIGLMR) + ); + + // staking minimums + assert_eq!( + get!(pallet_parachain_staking, MinCandidateStk, u128), + Balance::from(2_000_000 * GLMR) + ); + assert_eq!( + get!(pallet_parachain_staking, MinDelegation, u128), + Balance::from(50 * GLMR) + ); + + // crowdloan min reward + assert_eq!( + get!(pallet_crowdloan_rewards, MinimumReward, u128), + Balance::from(0u128) + ); + + // deposit for AuthorMapping + assert_eq!( + get!(pallet_author_mapping, DepositAmount, u128), + Balance::from(10 * KILOGLMR) + ); + + // proxy deposits + assert_eq!( + get!(pallet_proxy, ProxyDepositBase, u128), + Balance::from(10 * GLMR + 80 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_proxy, ProxyDepositFactor, u128), + Balance::from(210 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositBase, u128), + Balance::from(10 * GLMR + 80 * MILLIGLMR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositFactor, u128), + Balance::from(560 * MILLIGLMR) + ); + } + + #[test] + fn max_offline_rounds_lower_or_eq_than_reward_payment_delay() { + assert!( + get!(pallet_parachain_staking, MaxOfflineRounds, u32) + <= get!(pallet_parachain_staking, RewardPaymentDelay, u32) + ); + } + + #[test] + // Required migration is + // pallet_parachain_staking::migrations::IncreaseMaxTopDelegationsPerCandidate + // Purpose of this test is to remind of required migration if constant is ever changed + fn updating_maximum_delegators_per_candidate_requires_configuring_required_migration() { + assert_eq!( + get!(pallet_parachain_staking, MaxTopDelegationsPerCandidate, u32), + 300 + ); + assert_eq!( + get!( + pallet_parachain_staking, + MaxBottomDelegationsPerCandidate, + u32 + ), + 50 + ); + } + + #[test] + fn configured_base_extrinsic_weight_is_evm_compatible() { + let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000; + let base_extrinsic = ::BlockWeights::get() + .get(frame_support::dispatch::DispatchClass::Normal) + .base_extrinsic; + assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); + } + + #[test] + fn test_storage_growth_ratio_is_correct() { + // This is the highest amount of new storage that can be created in a block 160 KB + let block_storage_limit = 160 * 1024; + let expected_storage_growth_ratio = BlockGasLimit::get() + .low_u64() + .saturating_div(block_storage_limit); + let actual_storage_growth_ratio = + ::GasLimitStorageGrowthRatio::get(); + assert_eq!( + expected_storage_growth_ratio, actual_storage_growth_ratio, + "Storage growth ratio is not correct" + ); + } +} diff --git a/tracing/3200/runtime/moonbeam/src/migrations.rs b/tracing/3200/runtime/moonbeam/src/migrations.rs new file mode 100644 index 00000000..ec5eff74 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/migrations.rs @@ -0,0 +1,27 @@ +// Copyright 2024 Moonbeam Foundation Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Moonbeam specific Migrations +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{prelude::*, vec}; + +pub struct MoonbeamMigrations; + +impl GetMigrations for MoonbeamMigrations { + fn get_migrations() -> Vec> { + vec![] + } +} diff --git a/tracing/3200/runtime/moonbeam/src/precompiles.rs b/tracing/3200/runtime/moonbeam/src/precompiles.rs new file mode 100644 index 00000000..685f292c --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/precompiles.rs @@ -0,0 +1,296 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use crate::{ + asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, OpenTechCommitteeInstance, + Runtime, TreasuryCouncilInstance, +}; +use crate::{AssetId, H160}; +use frame_support::parameter_types; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; +use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; +use pallet_evm_precompile_batch::BatchPrecompile; +use pallet_evm_precompile_blake2::Blake2F; +use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; +use pallet_evm_precompile_call_permit::CallPermitPrecompile; +use pallet_evm_precompile_collective::CollectivePrecompile; +use pallet_evm_precompile_conviction_voting::ConvictionVotingPrecompile; +use pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompile; +use pallet_evm_precompile_gmp::GmpPrecompile; +use pallet_evm_precompile_identity::IdentityPrecompile; +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_p256verify::P256Verify; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompile; +use pallet_evm_precompile_preimage::PreimagePrecompile; +use pallet_evm_precompile_proxy::{OnlyIsProxyAndProxy, ProxyPrecompile}; +use pallet_evm_precompile_randomness::RandomnessPrecompile; +use pallet_evm_precompile_referenda::ReferendaPrecompile; +use pallet_evm_precompile_registry::PrecompileRegistry; +use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; +use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_xcm_transactor::{ + v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, +}; +use pallet_evm_precompile_xcm_utils::XcmUtilsPrecompile; +use pallet_evm_precompile_xtokens::XtokensPrecompile; +use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; +use pallet_precompile_benchmarks::WeightInfo; +use precompile_utils::precompile_set::*; +use sp_std::prelude::*; + +parameter_types! { + pub P256VerifyWeight: frame_support::weights::Weight = + moonbeam_weights::pallet_precompile_benchmarks::WeightInfo::::p256_verify(); +} + +pub struct NativeErc20Metadata; + +/// ERC20 metadata for the native token. +impl Erc20Metadata for NativeErc20Metadata { + /// Returns the name of the token. + fn name() -> &'static str { + "GLMR token" + } + + /// Returns the symbol of the token. + fn symbol() -> &'static str { + "GLMR" + } + + /// Returns the decimals places of the token. + fn decimals() -> u8 { + 18 + } + + /// Must return `true` only if it represents the main native currency of + /// the network. It must be the currency used in `pallet_evm`. + fn is_native_currency() -> bool { + true + } +} + +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as foreign +pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as local +pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8, 255u8, 255u8, 254u8]; + +parameter_types! { + pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; + pub LocalAssetPrefix: &'static [u8] = LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX; +} + +type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); + +#[precompile_utils::precompile_name_from_address] +type MoonbeamPrecompilesAt = ( + // Ethereum precompiles: + // We allow DELEGATECALL to stay compliant with Ethereum behavior. + PrecompileAt, ECRecover, EthereumPrecompilesChecks>, + PrecompileAt, Sha256, EthereumPrecompilesChecks>, + PrecompileAt, Ripemd160, EthereumPrecompilesChecks>, + PrecompileAt, Identity, EthereumPrecompilesChecks>, + PrecompileAt, Modexp, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Add, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Mul, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Pairing, EthereumPrecompilesChecks>, + PrecompileAt, Blake2F, EthereumPrecompilesChecks>, + // (0x100 => 256) https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + PrecompileAt, P256Verify, EthereumPrecompilesChecks>, + // Non-Moonbeam specific nor Ethereum precompiles : + PrecompileAt, Sha3FIPS256, (CallableByContract, CallableByPrecompile)>, + RemovedPrecompileAt>, // Dispatch + PrecompileAt, ECRecoverPublicKey, (CallableByContract, CallableByPrecompile)>, + // Moonbeam specific precompiles: + PrecompileAt< + AddressU64<2048>, + ParachainStakingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2049>, + CrowdloanRewardsPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2050>, + Erc20BalancesPrecompile, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, // Democracy + PrecompileAt< + AddressU64<2052>, + XtokensPrecompile, + ( + SubcallWithMaxNesting<1>, + CallableByContract, + CallableByPrecompile, + ), + >, + PrecompileAt< + AddressU64<2053>, + RelayEncoderPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2054>, + XcmTransactorPrecompileV1, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2055>, + AuthorMappingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2056>, + BatchPrecompile, + ( + SubcallWithMaxNesting<2>, + // Batch is the only precompile allowed to call Batch. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2057>, + RandomnessPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2058>, + CallPermitPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2059>, + ProxyPrecompile, + ( + CallableByContract>, + SubcallWithMaxNesting<0>, + // Batch is the only precompile allowed to call Proxy. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2060>, + XcmUtilsPrecompile, + CallableByContract< + pallet_evm_precompile_xcm_utils::AllExceptXcmExecute, + >, + >, + PrecompileAt< + AddressU64<2061>, + XcmTransactorPrecompileV2, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, //CouncilInstance + RemovedPrecompileAt>, // TechCommitteeInstance + PrecompileAt< + AddressU64<2064>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2065>, + ReferendaPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2066>, + ConvictionVotingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2067>, + PreimagePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2068>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2069>, + PrecompileRegistry, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, GmpPrecompile, SubcallWithMaxNesting<0>>, + PrecompileAt< + AddressU64<2071>, + XcmTransactorPrecompileV3, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2072>, + IdentityPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2073>, + RelayDataVerifierPrecompile, + (CallableByContract, CallableByPrecompile), + >, +); + +pub struct DisabledLocalAssets(sp_std::marker::PhantomData); + +impl sp_core::Get> for DisabledLocalAssets +where + Runtime: frame_system::Config, + Runtime::AccountId: Into, + Runtime: AccountIdAssetIdConversion, +{ + fn get() -> Vec { + vec![ + 337110116006454532607322340792629567158u128, + 278750993613512357835566279094880339619, + 228256396637196286254896220398224702687, + 270195117769614861929703564202131636628, + ] + .iter() + .map(|id| Runtime::asset_id_to_account(LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, *id).into()) + .collect() + } +} + +/// The PrecompileSet installed in the Moonbeam runtime. +/// We include the nine Istanbul precompiles +/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69) +/// as well as a special precompile for dispatching Substrate extrinsics +/// The following distribution has been decided for the precompiles +/// 0-1023: Ethereum Mainnet Precompiles +/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific +/// 2048-4095 Moonbeam specific precompiles +pub type MoonbeamPrecompiles = PrecompileSetBuilder< + R, + ( + // Skip precompiles if out of range. + PrecompilesInRangeInclusive<(AddressU64<1>, AddressU64<4095>), MoonbeamPrecompilesAt>, + // Prefixed precompile sets (XC20) + PrecompileSetStartingWith< + ForeignAssetPrefix, + Erc20AssetsPrecompileSet, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompilesAt>, + ), +>; diff --git a/tracing/3200/runtime/moonbeam/src/xcm_config.rs b/tracing/3200/runtime/moonbeam/src/xcm_config.rs new file mode 100644 index 00000000..7ffab1d7 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/src/xcm_config.rs @@ -0,0 +1,802 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! XCM configuration for Moonbase. +//! + +use super::{ + governance, AccountId, AssetId, AssetManager, Balance, Balances, EmergencyParaXcm, + Erc20XcmBridge, MaintenanceMode, MessageQueue, OpenTechCommitteeInstance, ParachainInfo, + ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent, + RuntimeOrigin, Treasury, XcmpQueue, +}; + +use frame_support::{ + parameter_types, + traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin}, +}; +use moonbeam_runtime_common::weights as moonbeam_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use sp_runtime::{ + traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf}, + DispatchErrorWithPostInfo, +}; +use sp_weights::Weight; + +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::{ConstU32, H160, H256}; + +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription, + NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WeightInfoBounds, WithComputedOrigin, +}; + +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use xcm::latest::prelude::{ + AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, + PalletInstance, Parachain, Wild, WildFungible, +}; + +use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry}; + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use orml_xcm_support::MultiNativeAsset; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType, + IsBridgedConcreteAssetFrom, SignedToAccountId20, UtilityAvailableCalls, UtilityEncodeCall, + XcmTransact, +}; + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_core::Get; +use sp_std::{ + convert::{From, Into, TryFrom}, + prelude::*, +}; + +use orml_traits::parameter_type_with_key; + +use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot}; + +parameter_types! { + // The network Id of the relay + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + // The relay chain Origin type + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); + // Self Reserve location, defines the multilocation identifiying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + // We use the RELATIVE multilocation + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // If we receive a Location of type AccountKey20, just generate a native account + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + HashedDescription>, +); + +/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`. +pub struct LocationToH160; +impl ConvertLocation for LocationToH160 { + fn convert_location(location: &Location) -> Option { + >::convert_location(location) + .map(Into::into) + } +} + +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + super::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId20 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + xcm_builder::IsConcrete, + // We can convert the MultiLocations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +pub type AssetTransactors = ( + LocalAssetTransactor, + ForeignFungiblesTransactor, + Erc20XcmBridge, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + // Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte- + // account local origin + SignedAccountKey20AsNative, +); + +parameter_types! { + /// Maximum number of instructions in a single XCM fragment. A sanity check against + /// weight caculations getting too crazy. + pub MaxInstructions: u32 = 100; +} + +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = WeightInfoBounds< + moonbeam_xcm_benchmarks::weights::XcmWeight, + RuntimeCall, + MaxInstructions, +>; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(_call: &RuntimeCall) -> bool { + // TODO review + // This needs to be addressed at EVM level + true + } +} + +parameter_types! { + /// Location of Asset Hub + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub const RelayLocation: Location = Location::parent(); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(RelayLocation::get()), + }); + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); + pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS; +} + +type Reserves = ( + // Assets bridged from different consensus systems held in reserve on Asset Hub. + IsBridgedConcreteAssetFrom, + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + MultiNativeAsset>, +); + +// Our implementation of the Moonbeam Call +// Attachs the right origin in case the call is made to pallet-ethereum-xcm +#[cfg(not(feature = "evm-tracing"))] +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); +#[cfg(feature = "evm-tracing")] +moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!(); + +moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!(); + +pub struct XcmExecutorConfig; +impl xcm_executor::Config for XcmExecutorConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Filter to the reserve withdraw operations + // Whenever the reserve matches the relative or absolute value + // of our chain, we always return the relative reserve + type IsReserve = Reserves; + type IsTeleporter = (); // No teleport + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = XcmWeigher; + // We use two traders + // When we receive the relative representation of the self-reserve asset, + // we use UsingComponents and the local way of handling fees + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = pallet_xcm_weight_trader::Trader; + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type PalletInstancesInfo = crate::AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; + type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper< + XcmExecutorConfig, + xcm_executor::XcmExecutor, +>; + +// Converts a Signed Local Origin into a Location +pub type LocalOriginToLocation = SignedToAccountId20; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = moonbeam_weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = moonbeam_weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery< + cumulus_primitives_core::ParaId, + >; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +// TODO: This pallet can be removed after the lazy migration is done and +// event `Completed` is emitted. +// https://github.com/paritytech/polkadot-sdk/pull/1246 +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; +} + +parameter_types! { + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = + Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + pub const MessageQueueMaxStale: u32 = 8; + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + pub const MessageQueueHeapSize: u32 = 103 * 1024; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper< + xcm_builder::ProcessXcmMessage, + >; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + // NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins + type QueuePausedQuery = EmergencyParaXcm; + type WeightInfo = moonbeam_weights::pallet_message_queue::WeightInfo; + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +pub type ResumeXcmOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +impl pallet_emergency_para_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling); + type PausedThreshold = ConstU32<300>; + type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin; + type PausedToNormalOrigin = ResumeXcmOrigin; +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(xcm::v3::Location), +} +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(xcm::v3::Location::here()) + } +} + +impl From for AssetType { + fn from(location: xcm::v3::Location) -> Self { + Self::Xcm(location) + } +} + +// This can be removed once we fully adopt xcm::v4 everywhere +impl TryFrom for AssetType { + type Error = (); + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + } + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => { + xcm_builder::WithLatestLocationConverter::convert_back(&location) + } + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We simply hash the AssetType and take the lowest 128 bits +impl From for AssetId { + fn from(asset: AssetType) -> AssetId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + // Our native token + SelfReserve, + // Assets representing other chains native tokens + ForeignAsset(AssetId), + // Erc20 token + Erc20 { contract_address: H160 }, +} + +impl AccountIdToCurrencyId for Runtime { + fn account_to_currency_id(account: AccountId) -> Option { + Some(match account { + // the self-reserve currency is identified by the pallet-balances address + a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve, + // the rest of the currencies, by their corresponding erc20 address + _ => match Runtime::account_to_asset_id(account) { + // We distinguish by prefix, and depending on it we create either + // Foreign or Local + Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id), + // If no known prefix is identified, we consider that it's a "real" erc20 token + // (i.e. managed by a real smart contract) + None => CurrencyId::Erc20 { + contract_address: account.into(), + }, + }, + }) + } +} +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: sp_runtime::traits::MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + CurrencyId::Erc20 { contract_address } => { + let mut location = Erc20XcmBridgePalletLocation::get(); + location + .push_interior(Junction::AccountKey20 { + key: contract_address.0, + network: None, + }) + .ok(); + Some(location) + } + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0); + pub const MaxAssetsForTransfer: usize = 2; + + // This is how we are going to detect whether the asset is a Reserve asset + // This however is the chain part only + pub SelfLocation: Location = Location::here(); + // We need this to be able to catch when someone is trying to execute a non- + // cross-chain transfer in xtokens through the absolute path way + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(ParachainInfo::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + // Polkadot AssetHub fee + (1, Some(Parachain(1000u32))) => Some(50_000_000u128), + _ => None, + } + }; +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdConvert = CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +// 1 DOT should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +pub type DerivativeAddressRegistrationOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = Transactors; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type SovereignAccountDispatcherOrigin = EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdToLocation = CurrencyIdToLocation>; + type XcmSender = XcmRouter; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = AbsoluteAndRelativeReserve; + type WeightInfo = moonbeam_weights::pallet_xcm_transactor::WeightInfo; + type HrmpManipulatorOrigin = GeneralAdminOrRoot; + type HrmpOpenOrigin = FastGeneralAdminOrRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + // This is the relative view of erc20 assets. + // Identified by this prefix + AccountKey20(contractAddress) + // We use the RELATIVE multilocation + pub Erc20XcmBridgePalletLocation: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + + // To be able to support almost all erc20 implementations, + // we provide a sufficiently hight gas limit. + pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000; +} + +impl pallet_erc20_xcm_bridge::Config for Runtime { + type AccountIdConverter = LocationToH160; + type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation; + type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; +} + +pub struct AccountIdToH160; +impl sp_runtime::traits::Convert for AccountIdToH160 { + fn convert(account_id: AccountId) -> H160 { + account_id.into() + } +} + +impl pallet_moonbeam_foreign_assets::Config for Runtime { + type AccountIdToH160 = AccountIdToH160; + type AssetIdFilter = Nothing; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; + type ForeignAssetCreatorOrigin = frame_system::EnsureNever; + type ForeignAssetFreezerOrigin = frame_system::EnsureNever; + type ForeignAssetModifierOrigin = frame_system::EnsureNever; + type ForeignAssetUnfreezerOrigin = frame_system::EnsureNever; + type OnForeignAssetCreated = (); + type MaxForeignAssets = ConstU32<256>; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = moonbeam_weights::pallet_moonbeam_foreign_assets::WeightInfo; + type XcmLocationToH160 = LocationToH160; +} + +pub struct AssetFeesFilter; +impl frame_support::traits::Contains for AssetFeesFilter { + fn contains(location: &Location) -> bool { + location.parent_count() > 0 + && location.first_interior() != Erc20XcmBridgePalletLocation::get().first_interior() + } +} + +pub type AddSupportedAssetOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +pub type EditSupportedAssetOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::FastGeneralAdmin, + >, +>; + +pub type RemoveSupportedAssetOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_xcm_weight_trader::Config for Runtime { + type AccountIdToLocation = AccountIdToLocation; + type AddSupportedAssetOrigin = AddSupportedAssetOrigin; + type AssetLocationFilter = AssetFeesFilter; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type EditSupportedAssetOrigin = EditSupportedAssetOrigin; + type NativeLocation = SelfReserve; + type PauseSupportedAssetOrigin = EditSupportedAssetOrigin; + type RemoveSupportedAssetOrigin = RemoveSupportedAssetOrigin; + type RuntimeEvent = RuntimeEvent; + type ResumeSupportedAssetOrigin = RemoveSupportedAssetOrigin; + type WeightInfo = moonbeam_weights::pallet_xcm_weight_trader::WeightInfo; + type WeightToFee = ::WeightToFee; + type XcmFeesAccount = XcmFeesAccount; + #[cfg(feature = "runtime-benchmarks")] + type NotFilteredLocation = RelayLocation; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use super::*; + use xcm_builder::WithLatestLocationConverter; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/tracing/3200/runtime/moonbeam/tests/common/mod.rs b/tracing/3200/runtime/moonbeam/tests/common/mod.rs new file mode 100644 index 00000000..3d92f80a --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/common/mod.rs @@ -0,0 +1,394 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![allow(dead_code)] + +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use fp_evm::GenesisAccount; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +pub use moonbeam_runtime::{ + asset_config::AssetRegistrarMetadata, currency::GLMR, xcm_config::AssetType, AccountId, + AssetId, AssetManager, AsyncBacking, AuthorInherent, Balance, Ethereum, InflationInfo, + ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, TransactionConverter, + UncheckedExtrinsic, HOURS, +}; +use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; +use polkadot_parachain::primitives::HeadData; +use sp_consensus_slots::Slot; +use sp_core::{Encode, H160}; +use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent}; + +use std::collections::BTreeMap; + +use fp_rpc::ConvertTransaction; + +// A valid signed Alice transfer. +pub const VALID_ETH_TX: &str = + "02f869820501808085e8d4a51000825208943cd0a705a2dc65e5b1e1205896baa2be8a07c6e00180c\ + 001a061087911e877a5802142a89a40d231d50913db399eb50839bb2d04e612b22ec8a01aa313efdf2\ + 793bea76da6813bda611444af16a6207a8cfef2d9c8aa8f8012f7"; + +// An invalid signed Alice transfer with a gas limit artifically set to 0. +pub const INVALID_ETH_TX: &str = + "f8628085174876e800809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ba011110796057\ + 0e2d49fcc2afbc582e1abd3eeb027242b92abcebcec7cdefab63ea001732f6fac84acdd5b096554230\ + 75003e7f07430652c3d6722e18f50b3d34e29"; + +pub fn rpc_run_to_block(n: u32) { + while System::block_number() < n { + Ethereum::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Ethereum::on_initialize(System::block_number()); + } +} + +/// Utility function that advances the chain to the desired block number. +/// If an author is provided, that author information is injected to all the blocks in the meantime. +pub fn run_to_block(n: u32, author: Option) { + // Finalize the first block + Ethereum::on_finalize(System::block_number()); + while System::block_number() < n { + // Set the new block number and author + match author { + Some(ref author) => { + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())], + }; + System::reset_events(); + System::initialize( + &(System::block_number() + 1), + &System::parent_hash(), + &pre_digest, + ); + } + None => { + System::set_block_number(System::block_number() + 1); + } + } + + increase_last_relay_slot_number(1); + + // Initialize the new block + AuthorInherent::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + Ethereum::on_initialize(System::block_number()); + + // Finalize the block + Ethereum::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + } +} + +pub fn last_event() -> RuntimeEvent { + System::events().pop().expect("Event expected").event +} + +// Helper function to give a simple evm context suitable for tests. +// We can remove this once https://github.com/rust-blockchain/evm/pull/35 +// is in our dependency graph. +pub fn evm_test_context() -> fp_evm::Context { + fp_evm::Context { + address: Default::default(), + caller: Default::default(), + apparent_value: From::from(0), + } +} + +// Test struct with the purpose of initializing xcm assets +#[derive(Clone)] +pub struct XcmAssetInitialization { + pub asset_type: AssetType, + pub metadata: AssetRegistrarMetadata, + pub balances: Vec<(AccountId, Balance)>, + pub is_sufficient: bool, +} + +pub struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, + // [collator, amount] + collators: Vec<(AccountId, Balance)>, + // [delegator, collator, nomination_amount] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, + // per-round inflation config + inflation: InflationInfo, + // AuthorId -> AccountId mappings + mappings: Vec<(NimbusId, AccountId)>, + // Crowdloan fund + crowdloan_fund: Balance, + // Chain id + chain_id: u64, + // EVM genesis accounts + evm_accounts: BTreeMap, + // [assettype, metadata, Vec, is_sufficient] + xcm_assets: Vec, + safe_xcm_version: Option, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { + balances: vec![], + delegations: vec![], + collators: vec![], + inflation: InflationInfo { + expect: Range { + min: 100_000 * GLMR, + ideal: 200_000 * GLMR, + max: 500_000 * GLMR, + }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, + mappings: vec![], + crowdloan_fund: 0, + chain_id: CHAIN_ID, + evm_accounts: BTreeMap::new(), + xcm_assets: vec![], + safe_xcm_version: None, + } + } +} + +impl ExtBuilder { + pub fn with_evm_accounts(mut self, accounts: BTreeMap) -> Self { + self.evm_accounts = accounts; + self + } + + pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + self.collators = collators; + self + } + + pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations + .into_iter() + .map(|d| (d.0, d.1, d.2, Percent::zero())) + .collect(); + self + } + + pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self { + self.crowdloan_fund = crowdloan_fund; + self + } + + pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self { + self.mappings = mappings; + self + } + + pub fn with_xcm_assets(mut self, xcm_assets: Vec) -> Self { + self.xcm_assets = xcm_assets; + self + } + + pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self { + self.safe_xcm_version = Some(safe_xcm_version); + self + } + + #[allow(dead_code)] + pub fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: Perbill::from_percent(20), + parachain_bond_reserve_percent: Percent::from_percent(30), + blocks_per_round: 6 * HOURS, + num_selected_candidates: 8, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_crowdloan_rewards::GenesisConfig:: { + funded_amount: self.crowdloan_fund, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_author_mapping::GenesisConfig:: { + mappings: self.mappings, + } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config = pallet_evm_chain_id::GenesisConfig:: { + chain_id: self.chain_id, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: self.evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_ethereum::GenesisConfig:: { + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_xcm::GenesisConfig:: { + safe_xcm_version: self.safe_xcm_version, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + let xcm_assets = self.xcm_assets.clone(); + ext.execute_with(|| { + // If any xcm assets specified, we register them here + for xcm_asset_initialization in xcm_assets { + let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into(); + AssetManager::register_foreign_asset( + root_origin(), + xcm_asset_initialization.asset_type, + xcm_asset_initialization.metadata, + 1, + xcm_asset_initialization.is_sufficient, + ) + .unwrap(); + for (account, balance) in xcm_asset_initialization.balances { + moonbeam_runtime::Assets::mint( + origin_of(AssetManager::account_id()), + asset_id.into(), + account, + balance, + ) + .unwrap(); + } + } + System::set_block_number(1); + }); + ext + } +} + +pub const CHAIN_ID: u64 = 1281; +pub const ALICE: [u8; 20] = [4u8; 20]; +pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 20] = [5u8; 20]; +pub const CHARLIE: [u8; 20] = [6u8; 20]; +pub const DAVE: [u8; 20] = [7u8; 20]; +pub const EVM_CONTRACT: [u8; 20] = [8u8; 20]; + +pub fn origin_of(account_id: AccountId) -> ::RuntimeOrigin { + ::RuntimeOrigin::signed(account_id) +} + +pub fn inherent_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::none() +} + +pub fn root_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::root() +} + +/// Mock the inherent that sets validation data in ParachainSystem, which +/// contains the `relay_chain_block_number`, which is used in `author-filter` as a +/// source of randomness to filter valid authors at each block. +pub fn set_parachain_inherent_data() { + use cumulus_primitives_core::PersistedValidationData; + use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; + + let mut relay_sproof = RelayStateSproofBuilder::default(); + relay_sproof.para_id = 100u32.into(); + relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3])); + + let additional_key_values = vec![( + moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(), + sp_timestamp::Timestamp::default().encode(), + )]; + + relay_sproof.additional_key_values = additional_key_values; + + let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof(); + + let vfp = PersistedValidationData { + relay_parent_number: 1u32, + relay_parent_storage_root, + ..Default::default() + }; + let parachain_inherent_data = ParachainInherentData { + validation_data: vfp, + relay_chain_state: relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + assert_ok!(RuntimeCall::ParachainSystem( + cumulus_pallet_parachain_system::Call::::set_validation_data { + data: parachain_inherent_data + } + ) + .dispatch(inherent_origin())); +} + +pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic { + let converter = TransactionConverter; + converter.convert_transaction(ethereum_transaction(raw_hex_tx)) +} + +pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction { + let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes."); + let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]); + assert!(transaction.is_ok()); + transaction.unwrap() +} + +pub(crate) fn increase_last_relay_slot_number(amount: u64) { + let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0); + frame_support::storage::unhashed::put( + &frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"), + &((Slot::from(last_relay_slot + amount), 0)), + ); +} diff --git a/tracing/3200/runtime/moonbeam/tests/evm_tracing.rs b/tracing/3200/runtime/moonbeam/tests/evm_tracing.rs new file mode 100644 index 00000000..c47675d1 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/evm_tracing.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam EVM tracing Integration Tests + +mod common; + +#[cfg(test)] +#[cfg(feature = "evm-tracing")] +mod tests { + use super::common::*; + + use pallet_evm::AddressMapping; + use sp_core::{H160, U256}; + + use moonbeam_core_primitives::Header; + use moonbeam_rpc_primitives_debug::runtime_decl_for_debug_runtime_api::DebugRuntimeApi; + use std::str::FromStr; + + #[test] + fn debug_runtime_api_trace_transaction() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * GLMR), + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * GLMR, + } + .into(), + ); + let transaction = ethereum_transaction(VALID_ETH_TX); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_transaction( + vec![non_eth_uxt.clone(), eth_uxt, non_eth_uxt.clone()], + &transaction, + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_block() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * GLMR), + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * GLMR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let eth_tx = ethereum_transaction(VALID_ETH_TX); + let eth_extrinsic_hash = eth_tx.hash(); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_block( + vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], + vec![eth_extrinsic_hash, eth_extrinsic_hash], + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_call() { + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + let alith = H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"); + let alith_account_id = + ::AddressMapping::into_account_id(alith); + ExtBuilder::default() + .with_balances(vec![(alith_account_id, 100 * GLMR)]) + .build() + .execute_with(|| { + assert!(Runtime::trace_call( + &block, + alith, + H160::random(), + Vec::new(), + U256::from(99), + U256::max_value(), + Some(U256::one()), + Some(U256::one()), + None, + None, + ) + .is_ok()); + }); + } +} diff --git a/tracing/3200/runtime/moonbeam/tests/integration_test.rs b/tracing/3200/runtime/moonbeam/tests/integration_test.rs new file mode 100644 index 00000000..78a80b04 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/integration_test.rs @@ -0,0 +1,2899 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam Runtime Integration Tests + +#![cfg(test)] + +mod common; +use common::*; + +use fp_evm::{Context, IsPrecompileResult}; +use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchClass, + traits::{ + fungible::Inspect, Currency as CurrencyT, EnsureOrigin, PalletInfo, StorageInfo, + StorageInfoTrait, + }, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + StorageHasher, Twox128, +}; +use moonbeam_runtime::currency::{GIGAWEI, WEI}; +use moonbeam_runtime::{ + asset_config::ForeignAssetInstance, + currency::GLMR, + xcm_config::{CurrencyId, SelfReserve}, + AccountId, Balances, CrowdloanRewards, Executive, OpenTechCommitteeCollective, + ParachainStaking, PolkadotXcm, Precompiles, Runtime, RuntimeBlockWeights, RuntimeCall, + RuntimeEvent, System, TransactionPayment, TransactionPaymentAsGasPrice, + TreasuryCouncilCollective, XTokens, XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + WEEKS, +}; +use moonbeam_xcm_benchmarks::weights::XcmWeight; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use nimbus_primitives::NimbusId; +use pallet_evm::PrecompileSet; +use pallet_evm_precompileset_assets_erc20::{SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER}; +use pallet_transaction_payment::Multiplier; +use pallet_xcm_transactor::{Currency, CurrencyPayment, TransactWeights}; +use parity_scale_codec::Encode; +use polkadot_parachain::primitives::Sibling; +use precompile_utils::{ + precompile_set::{is_precompile_or_fail, IsActivePrecompile}, + prelude::*, + testing::*, +}; +use sha3::{Digest, Keccak256}; +use sp_core::{ByteArray, Pair, H160, U256}; +use sp_runtime::{ + traits::{Convert, Dispatchable}, + BuildStorage, DispatchError, ModuleError, +}; +use std::str::from_utf8; +use xcm::latest::prelude::*; +use xcm::{VersionedAsset, VersionedAssets, VersionedLocation}; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_executor::traits::ConvertLocation; + +type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall; +type CrowdloanRewardsPCall = + pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompileCall; +type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall< + Runtime, + moonbeam_runtime::xcm_config::XcmExecutorConfig, +>; +type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall; +type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall< + Runtime, + ForeignAssetInstance, +>; +type XcmTransactorV2PCall = + pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call; + +const BASE_FEE_GENESIS: u128 = 10000 * GIGAWEI; + +#[test] +fn xcmp_queue_controller_origin_is_root() { + // important for the XcmExecutionManager impl of PauseExecution which uses root origin + // to suspend/resume XCM execution in xcmp_queue::on_idle + assert_ok!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + +#[test] +fn verify_pallet_prefixes() { + fn is_pallet_prefix(name: &str) { + // Compares the unhashed pallet prefix in the `StorageInstance` implementation by every + // storage item in the pallet P. This pallet prefix is used in conjunction with the + // item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName) + // https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/ + // expand/storage.rs#L389-L401 + assert_eq!( + ::PalletInfo::name::

(), + Some(name) + ); + } + // TODO: use StorageInfoTrait once https://github.com/paritytech/substrate/pull/9246 + // is pulled in substrate deps. + is_pallet_prefix::("System"); + is_pallet_prefix::("Utility"); + is_pallet_prefix::("ParachainSystem"); + is_pallet_prefix::("TransactionPayment"); + is_pallet_prefix::("ParachainInfo"); + is_pallet_prefix::("EthereumChainId"); + is_pallet_prefix::("EVM"); + is_pallet_prefix::("Ethereum"); + is_pallet_prefix::("ParachainStaking"); + is_pallet_prefix::("Scheduler"); + is_pallet_prefix::( + "OpenTechCommitteeCollective", + ); + is_pallet_prefix::("Treasury"); + is_pallet_prefix::("AuthorInherent"); + is_pallet_prefix::("AuthorFilter"); + is_pallet_prefix::("CrowdloanRewards"); + is_pallet_prefix::("AuthorMapping"); + is_pallet_prefix::("MaintenanceMode"); + is_pallet_prefix::("Identity"); + is_pallet_prefix::("XcmpQueue"); + is_pallet_prefix::("CumulusXcm"); + is_pallet_prefix::("DmpQueue"); + is_pallet_prefix::("PolkadotXcm"); + is_pallet_prefix::("Assets"); + is_pallet_prefix::("XTokens"); + is_pallet_prefix::("AssetManager"); + is_pallet_prefix::("Migrations"); + is_pallet_prefix::("XcmTransactor"); + is_pallet_prefix::("ProxyGenesisCompanion"); + is_pallet_prefix::("MoonbeamOrbiters"); + is_pallet_prefix::("TreasuryCouncilCollective"); + is_pallet_prefix::("MoonbeamLazyMigrations"); + is_pallet_prefix::("RelayStorageRoots"); + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res.to_vec() + }; + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"Now".to_vec(), + prefix: prefix(b"Timestamp", b"Now"), + max_values: Some(1), + max_size: Some(8), + }, + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"DidUpdate".to_vec(), + prefix: prefix(b"Timestamp", b"DidUpdate"), + max_values: Some(1), + max_size: Some(1), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"TotalIssuance".to_vec(), + prefix: prefix(b"Balances", b"TotalIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"InactiveIssuance".to_vec(), + prefix: prefix(b"Balances", b"InactiveIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Account".to_vec(), + prefix: prefix(b"Balances", b"Account"), + max_values: None, + max_size: Some(100), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Locks".to_vec(), + prefix: prefix(b"Balances", b"Locks"), + max_values: None, + max_size: Some(1287), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Reserves".to_vec(), + prefix: prefix(b"Balances", b"Reserves"), + max_values: None, + max_size: Some(1037), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Holds".to_vec(), + prefix: prefix(b"Balances", b"Holds"), + max_values: None, + max_size: Some(55), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Freezes".to_vec(), + prefix: prefix(b"Balances", b"Freezes"), + max_values: None, + max_size: Some(37), + }, + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Proxies".to_vec(), + prefix: prefix(b"Proxy", b"Proxies"), + max_values: None, + max_size: Some(845), + }, + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Announcements".to_vec(), + prefix: prefix(b"Proxy", b"Announcements"), + max_values: None, + max_size: Some(1837), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"MaintenanceMode".to_vec(), + storage_name: b"MaintenanceMode".to_vec(), + prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"), + max_values: Some(1), + max_size: None, + },] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRoot".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"), + max_values: None, + max_size: Some(44), + }, + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRootKeys".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"), + max_values: Some(1), + max_size: Some(121), + }, + ] + ); +} + +#[test] +fn test_collectives_storage_item_prefixes() { + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec()); + } + + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec()); + } +} + +#[test] +fn collective_set_members_root_origin_works() { + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert_ok!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + // OpenTechCommitteeCollective + assert_ok!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + }); +} + +#[test] +fn collective_set_members_general_admin_origin_works() { + use moonbeam_runtime::{ + governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility, + }; + + ExtBuilder::default().build().execute_with(|| { + let root_caller = ::RuntimeOrigin::root(); + let alice = AccountId::from(ALICE); + + // TreasuryCouncilCollective + let _ = Utility::dispatch_as( + root_caller.clone(), + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + // OpenTechCommitteeCollective + let _ = Utility::dispatch_as( + root_caller, + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + + assert_eq!( + System::events() + .into_iter() + .filter_map(|r| { + match r.event { + RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result }) + if result.is_ok() => + { + Some(true) + } + _ => None, + } + }) + .collect::>() + .len(), + 2 + ) + }); +} + +#[test] +fn collective_set_members_signed_origin_does_not_work() { + let alice = AccountId::from(ALICE); + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + // OpenTechCommitteeCollective + assert!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + }); +} + +#[test] +fn verify_pallet_indices() { + fn is_pallet_index(index: usize) { + assert_eq!( + ::PalletInfo::index::

(), + Some(index) + ); + } + + // System support + is_pallet_index::(0); + is_pallet_index::(1); + is_pallet_index::(3); + is_pallet_index::(4); + // Monetary + is_pallet_index::(10); + is_pallet_index::(11); + // Consensus support + is_pallet_index::(20); + is_pallet_index::(21); + is_pallet_index::(22); + is_pallet_index::(23); + is_pallet_index::(24); + // Handy utilities + is_pallet_index::(30); + is_pallet_index::(31); + is_pallet_index::(32); + is_pallet_index::(33); + is_pallet_index::(34); + is_pallet_index::(35); + is_pallet_index::(37); + // Ethereum compatibility + is_pallet_index::(50); + is_pallet_index::(51); + is_pallet_index::(52); + // Governance + is_pallet_index::(60); + // is_pallet_index::(61); Removed + // Council + // is_pallet_index::(70); Removed + // is_pallet_index::(71); Removed + is_pallet_index::(72); + is_pallet_index::(73); + // Treasury + is_pallet_index::(80); + // Crowdloan + is_pallet_index::(90); + // XCM Stuff + is_pallet_index::(100); + is_pallet_index::(101); + is_pallet_index::(102); + is_pallet_index::(103); + is_pallet_index::(104); + is_pallet_index::(105); + is_pallet_index::(106); + is_pallet_index::(107); +} + +#[test] +fn verify_reserved_indices() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + t.execute_with(|| { + use frame_metadata::*; + let metadata = moonbeam_runtime::Runtime::metadata(); + let metadata = match metadata.1 { + RuntimeMetadata::V14(metadata) => metadata, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + // 40: Sudo + // 53: BaseFee + // 108: pallet_assets:: + let reserved = vec![40, 53, 108]; + let existing = metadata + .pallets + .iter() + .map(|p| p.index) + .collect::>(); + assert!(reserved.iter().all(|index| !existing.contains(index))); + }); +} + +#[test] +fn verify_proxy_type_indices() { + assert_eq!(moonbeam_runtime::ProxyType::Any as u8, 0); + assert_eq!(moonbeam_runtime::ProxyType::NonTransfer as u8, 1); + assert_eq!(moonbeam_runtime::ProxyType::Governance as u8, 2); + assert_eq!(moonbeam_runtime::ProxyType::Staking as u8, 3); + assert_eq!(moonbeam_runtime::ProxyType::CancelProxy as u8, 4); + assert_eq!(moonbeam_runtime::ProxyType::Balances as u8, 5); + assert_eq!(moonbeam_runtime::ProxyType::AuthorMapping as u8, 6); + assert_eq!(moonbeam_runtime::ProxyType::IdentityJudgement as u8, 7); +} + +#[test] +fn join_collator_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 10_000_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + (AccountId::from(CHARLIE), 10_000_000 * GLMR), + (AccountId::from(DAVE), 10_000_000 * GLMR), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 2_000_000 * GLMR), + (AccountId::from(BOB), 2_000_000 * GLMR), + ]) + .with_delegations(vec![ + ( + AccountId::from(CHARLIE), + AccountId::from(ALICE), + 5_000 * GLMR, + ), + (AccountId::from(CHARLIE), AccountId::from(BOB), 5_000 * GLMR), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(ALICE)), + 2_000_000 * GLMR, + 2u32 + ), + pallet_parachain_staking::Error::::CandidateExists + ); + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + 2u32 + ), + pallet_parachain_staking::Error::::DelegatorExists + ); + assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(DAVE)), + 2_000_000 * GLMR, + 2u32 + )); + assert_eq!( + last_event(), + RuntimeEvent::ParachainStaking( + pallet_parachain_staking::Event::JoinedCollatorCandidates { + account: AccountId::from(DAVE), + amount_locked: 2_000_000 * GLMR, + new_total_amt_locked: 6_010_000 * GLMR + } + ) + ); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(ALICE)); + assert_eq!(candidates.0[0].amount, 2_005_000 * GLMR); + assert_eq!(candidates.0[1].owner, AccountId::from(BOB)); + assert_eq!(candidates.0[1].amount, 2_005_000 * GLMR); + assert_eq!(candidates.0[2].owner, AccountId::from(DAVE)); + assert_eq!(candidates.0[2].amount, 2_000_000 * GLMR); + }); +} + +#[test] +fn transfer_through_evm_to_stake() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 10_000_000 * GLMR)]) + .build() + .execute_with(|| { + // Charlie has no balance => fails to stake + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + 2u32 + ), + DispatchError::Module(ModuleError { + index: 20, + error: [8, 0, 0, 0], + message: Some("InsufficientBalance") + }) + ); + // Alice transfer from free balance 3_000_000 GLMR to Bob + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 3_000_000 * GLMR, + )); + assert_eq!( + Balances::free_balance(AccountId::from(BOB)), + 3_000_000 * GLMR + ); + + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + // Bob transfers 2_000_000 GLMR to Charlie via EVM + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(CHARLIE), + input: vec![], + value: (2_000_000 * GLMR).into(), + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + assert_eq!( + Balances::free_balance(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + ); + + // Charlie can stake now + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 2_000_000 * GLMR, + 2u32 + ),); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE)); + assert_eq!(candidates.0[0].amount, 2_000_000 * GLMR); + }); +} + +#[test] +fn reward_block_authors() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 10k extra tokens for her mapping deposit + (AccountId::from(ALICE), 10_010_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * GLMR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + // Just before round 3 + run_to_block(7199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8_010_000 * GLMR, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9_950_000 * GLMR, + ); + run_to_block(7201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8990978048702400000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9969521950497200000000000, + ); + }); +} + +#[test] +fn reward_block_authors_with_parachain_bond_reserved() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 10k extra tokens for her mapping deposit + (AccountId::from(ALICE), 10_010_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + (AccountId::from(CHARLIE), 10_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * GLMR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + assert_ok!(ParachainStaking::set_parachain_bond_account( + root_origin(), + AccountId::from(CHARLIE), + ),); + + // Stop just before round 3 + run_to_block(7199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + // no collators rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8_010_000 * GLMR, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9_950_000 * GLMR, + ); + // 30% reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 310300000000000000000000, + ); + + // Go to round 3 + run_to_block(7201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // collators rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 8698492682878000000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9962207316621500000000000, + ); + // 30% reserved for parachain bond again + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 615104500000000000000000, + ); + }); +} + +#[test] +fn initialize_crowdloan_addresses_with_batch_and_pay() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(300_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 150_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 150_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + 45_000_000 * GLMR + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 45_000_000 * GLMR); + let expected = RuntimeEvent::Utility(pallet_utility::Event::BatchCompleted); + assert_eq!(last_event(), expected); + // This one should fail, as we already filled our data + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch { + calls: vec![RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(ALICE)), + 43_200_000 + )] + } + )] + }) + .dispatch(root_origin()) + ); + let expected_fail = RuntimeEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 0, + error: DispatchError::Module(ModuleError { + index: 90, + error: [8, 0, 0, 0], + message: None, + }), + }); + assert_eq!(last_event(), expected_fail); + // Claim 1 block. + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(CHARLIE)))); + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(DAVE)))); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (105_000_000 * GLMR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (45_000_000 * GLMR) + per_block + ); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (45_000_000 * GLMR) + per_block + ); + // The total claimed reward should be equal to the account balance at this point. + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + (45_000_000 * GLMR) + per_block + ); + assert_eq!( + Balances::balance(&AccountId::from(DAVE)), + (45_000_000 * GLMR) + per_block + ); + assert_noop!( + CrowdloanRewards::claim(origin_of(AccountId::from(ALICE))), + pallet_crowdloan_rewards::Error::::NoAssociatedClaim + ); + }); +} + +#[test] +fn initialize_crowdloan_address_and_change_with_relay_key_sig() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + + let (pair1, _) = sp_core::sr25519::Pair::generate(); + let (pair2, _) = sp_core::sr25519::Pair::generate(); + + let public1 = pair1.public(); + let public2 = pair2.public(); + + // signature is new_account || previous_account + let mut message = pallet_crowdloan_rewards::WRAPPED_BYTES_PREFIX.to_vec(); + message.append(&mut b"moonbeam-".to_vec()); + message.append(&mut AccountId::from(DAVE).encode()); + message.append(&mut AccountId::from(CHARLIE).encode()); + message.append(&mut pallet_crowdloan_rewards::WRAPPED_BYTES_POSTFIX.to_vec()); + let signature1 = pair1.sign(&message); + let signature2 = pair2.sign(&message); + + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + // two relay accounts pointing at the same reward account + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public1.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public2.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 900_000 * GLMR); + + // this should fail, as we are only providing one signature + assert_noop!( + CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![(public1.into(), signature1.clone().into())] + ), + pallet_crowdloan_rewards::Error::::InsufficientNumberOfValidProofs + ); + + // this should be valid + assert_ok!(CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![ + (public1.into(), signature1.into()), + (public2.into(), signature2.into()) + ] + )); + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (900_000 * GLMR) + ); + }); +} + +#[test] +fn claim_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + assert!(CrowdloanRewards::initialized()); + + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * GLMR); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * GLMR); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Alice uses the crowdloan precompile to claim through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the call data (selector, amount) + let mut call_data = Vec::::from([0u8; 4]); + call_data[0..4].copy_from_slice(&Keccak256::digest(b"claim()")[0..4]); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * GLMR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * GLMR) + per_block + ); + }) +} + +#[test] +fn is_contributor_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Assert precompile reports Bob is not a contributor + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(BOB).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(false); + + // Assert precompile reports Charlie is a nominator + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(true); + }) +} + +#[test] +fn reward_info_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + let expected_total: U256 = (1_500_000 * GLMR).into(); + let expected_claimed: U256 = (450_000 * GLMR).into(); + + // Assert precompile reports correct Charlie reward info. + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::reward_info { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns((expected_total, expected_claimed)); + }) +} + +#[test] +fn update_reward_address_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * GLMR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * GLMR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Charlie uses the crowdloan precompile to update address through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the input data to check if Bob is a contributor + let mut call_data = Vec::::from([0u8; 36]); + call_data[0..4] + .copy_from_slice(&Keccak256::digest(b"update_reward_address(address)")[0..4]); + call_data[16..36].copy_from_slice(&ALICE); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + assert!(CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)).is_none()); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(ALICE)) + .unwrap() + .claimed_reward, + (450_000 * GLMR) + ); + }) +} + +fn run_with_system_weight(w: Weight, mut assertions: F) +where + F: FnMut() -> (), +{ + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); +} + +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonbeam_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 100_000_000_100, calc_fee(1)); + assert_eq!( 1_000_000_100_000, calc_fee(10)); + assert_eq!( 10_000_100_000_000, calc_fee(100)); + assert_eq!( 100_100_000_000_000, calc_fee(1_000)); + assert_eq!( 1_100_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 110_000_000_000_000_000, calc_fee(100_000)); + assert_eq!( 100_100_000_000_000_000_000, calc_fee(1_000_000)); // 100 GLMR, ~ 1MB + assert_eq!( 100_001_000_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(100_000_010_000_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + +#[test] +fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + + let minimum_multiplier = moonbeam_runtime::MinimumMultiplier::get(); + let target = moonbeam_runtime::TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = moonbeam_runtime::SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) +} + +#[test] +fn ethereum_invalid_transaction() { + ExtBuilder::default().build().execute_with(|| { + // Ensure an extrinsic not containing enough gas limit to store the transaction + // on chain is rejected. + assert_eq!( + Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)), + Err( + sp_runtime::transaction_validity::TransactionValidityError::Invalid( + sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8) + ) + ) + ); + }); +} + +#[test] +fn initial_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + + ExtBuilder::default().build().execute_with(|| { + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(1u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 125_000_000_000u128.into(), + Weight::from_parts(41_742_000u64, 0) + ) + ); + }); +} + +#[test] +fn min_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + use frame_support::traits::Hooks; + + ExtBuilder::default().build().execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::put(Multiplier::from(0)); + TransactionPayment::on_finalize(System::block_number()); // should trigger min to kick in + + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(1u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 125_000_000_000u128.into(), + Weight::from_parts(41_742_000u64, 0) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_substrate() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * GLMR) + (1 * WEI)), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * GLMR, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); +} + +#[test] +fn transfer_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * GLMR) + (21_000 * BASE_FEE_GENESIS)) + (1 * WEI), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: Some(BASE_FEE_GENESIS.into()), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,); + }); +} + +#[test] +fn refund_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * GLMR) + (21_777 * BASE_FEE_GENESIS)), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer that zeroes ALICE + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_777u64, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: Some(BASE_FEE_GENESIS.into()), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // ALICE is refunded + assert_eq!( + Balances::free_balance(AccountId::from(ALICE)), + 777 * BASE_FEE_GENESIS, + ); + }); +} + +#[test] +fn author_does_not_receive_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * GLMR) + (21_000 * (500 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + // Some block author as seen by pallet-evm. + let author = AccountId::from(>::find_author()); + // Currently the default impl of the evm uses `deposit_into_existing`. + // If we were to use this implementation, and for an author to receive eventual tips, + // the account needs to be somehow initialized, otherwise the deposit would fail. + Balances::make_free_balance_be(&author, 100 * GLMR); + + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(300 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // Author free balance didn't change. + assert_eq!(Balances::free_balance(author), 100 * GLMR,); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_with_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * GLMR) + (21_000 * (200 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(200 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(100 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 100 GWEI base fee + 100 GWEI tip. + let fee = ((200 * GIGAWEI) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbeam_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_without_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * GLMR) + (21_000 * BASE_FEE_GENESIS), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * GLMR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: Some(BASE_FEE_GENESIS.into()), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + // Fee is 100 GWEI base fee. + let fee = (BASE_FEE_GENESIS * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonbeam_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn root_can_change_default_xcm_vers() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + // Default XCM version is not set yet, so xtokens should fail because it does not + // know with which version to send + assert_noop!( + XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + + // Root sets the defaultXcm + assert_ok!(PolkadotXcm::force_default_xcm_version( + root_origin(), + Some(2) + )); + + // Now transferring does not fail + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest)), + WeightLimit::Limited(4000000000.into()) + )); + }) +} + +#[test] +fn asset_can_be_registered() { + ExtBuilder::default().build().execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + let asset_metadata = AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }; + assert_ok!(AssetManager::register_foreign_asset( + moonbeam_runtime::RuntimeOrigin::root(), + source_location, + asset_metadata, + 1u128, + true + )); + assert!(AssetManager::asset_id_type(source_id).is_some()); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_supply_and_balance() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * GLMR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Assert the asset has been created with the correct supply + assert_eq!( + moonbeam_runtime::Assets::total_supply(relay_asset_id), + 1_000 * GLMR + ); + + // Access totalSupply through precompile. Important that the context is correct + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::total_supply {}, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(1000 * GLMR)); + + // Access balanceOf through precompile + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(ALICE.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(1000 * GLMR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * GLMR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Transfer tokens from Aice to Bob, 400 GLMR. + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::transfer { + to: Address(BOB.into()), + value: { 400 * GLMR }.into(), + }, + ) + .expect_cost(24673) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * GLMR)), + )) + .execute_returns(true); + + // Make sure BOB has 400 GLMR + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(BOB.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(400 * GLMR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_approve() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * GLMR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Aprove Bob for spending 400 GLMR from Alice + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::approve { + spender: Address(BOB.into()), + value: { 400 * GLMR }.into(), + }, + ) + .expect_cost(15571) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_APPROVAL, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * GLMR)), + )) + .execute_returns(true); + + // Transfer tokens from Alice to Charlie by using BOB as origin + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::transfer_from { + from: Address(ALICE.into()), + to: Address(CHARLIE.into()), + value: { 400 * GLMR }.into(), + }, + ) + .expect_cost(29961) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(CHARLIE), + solidity::encode_event_data(U256::from(400 * GLMR)), + )) + .execute_returns(true); + + // Make sure CHARLIE has 400 GLMR + Precompiles::new() + .prepare_test( + CHARLIE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(CHARLIE.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(400 * GLMR)); + }); +} + +#[test] +fn xtokens_precompile_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonbeam_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // We use the address of the asset as an identifier of the asset we want to transfer + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address.into()), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(196698) + .expect_no_logs() + .execute_returns(()) + }) +} + +#[test] +fn xtokens_precompile_transfer_multiasset() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // This time we transfer it through TransferMultiAsset + // Instead of the address, we encode directly the multilocation referencing the asset + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer_multiasset { + // We want to transfer the relay token + asset: Location::parent(), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(196698) + .expect_no_logs() + .execute_returns(()); + }) +} + +#[test] +fn make_sure_glmr_can_be_transferred_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + assert_ok!(XTokens::transfer_multiasset( + origin_of(AccountId::from(ALICE)), + Box::new(VersionedAsset::V4(Asset { + id: AssetId(moonbeam_runtime::xcm_config::SelfReserve::get()), + fun: Fungible(1000) + })), + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(40000.into()) + )); + }); +} + +#[test] +fn make_sure_glmr_can_be_transferred() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(40000.into()) + )); + }); +} + +#[test] +fn make_sure_polkadot_xcm_cannot_be_called() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let assets: Assets = [Asset { + id: AssetId(moonbeam_runtime::xcm_config::SelfLocation::get()), + fun: Fungible(1000), + }] + .to_vec() + .into(); + assert_noop!( + RuntimeCall::PolkadotXcm(pallet_xcm::Call::::reserve_transfer_assets { + dest: Box::new(VersionedLocation::V4(dest.clone())), + beneficiary: Box::new(VersionedLocation::V4(dest)), + assets: Box::new(VersionedAssets::V4(assets)), + fee_asset_item: 0, + }) + .dispatch(::RuntimeOrigin::signed( + AccountId::from(ALICE) + )), + frame_system::Error::::CallFiltered + ); + }); +} + +#[test] +fn transact_through_signed_precompile_works_v2() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .expect_cost(23239) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_cannot_send_to_local_chain() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::here(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .execute_reverts(|output| { + from_utf8(&output) + .unwrap() + .contains("Dispatched call failed with error:") + && from_utf8(&output).unwrap().contains("ErrorValidating") + }); + }); +} + +#[test] +fn transactor_cannot_use_more_than_max_weight() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + assert_ok!(XcmTransactor::register( + root_origin(), + AccountId::from(ALICE), + 0, + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000.into(), + None + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1, + )); + + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbeam_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + vec![], + // 2000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonbeam_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsCurrencyId(CurrencyId::ForeignAsset(source_id)), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + }) +} + +#[test] +fn call_xtokens_with_fee() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 1_000 * GLMR), + ]) + .with_safe_xcm_version(2) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonbeam_runtime::AssetId = source_location.clone().into(); + + let before_balance = + moonbeam_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + + // We are able to transfer with fee + assert_ok!(XTokens::transfer_with_fee( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + 100, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + )); + + let after_balance = + moonbeam_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + // At least these much (plus fees) should have been charged + assert_eq!(before_balance - 100_000_000_000_000 - 100, after_balance); + }); +} + +#[test] +fn test_xcm_utils_ml_tp_account() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_address_parent: H160 = + ParentIsPreset::::convert_location(&Location::parent()) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: Location::parent(), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_parent)); + + let parachain_2000_location = Location::new(1, [Parachain(2000)]); + let expected_address_parachain: H160 = + SiblingParachainConvertsVia::::convert_location( + ¶chain_2000_location, + ) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: parachain_2000_location, + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_parachain)); + + let alice_in_parachain_2000_location = Location::new( + 1, + [ + Parachain(2000), + AccountKey20 { + network: None, + key: ALICE, + }, + ], + ); + let expected_address_alice_in_parachain_2000 = + xcm_builder::HashedDescription::< + AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&alice_in_parachain_2000_location) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: alice_in_parachain_2000_location, + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_alice_in_parachain_2000)); + }); +} + +#[test] +fn test_xcm_utils_weight_message() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_weight = + XcmWeight::::clear_origin().ref_time(); + + let message: Vec = xcm::VersionedXcm::<()>::V4(Xcm(vec![ClearOrigin])).encode(); + + let input = XcmUtilsPCall::weight_message { + message: message.into(), + }; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(0) + .expect_no_logs() + .execute_returns(expected_weight); + }); +} + +#[test] +fn test_xcm_utils_get_units_per_second() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let location = SelfReserve::get(); + + let input = XcmUtilsPCall::get_units_per_second { location }; + + let expected_units = + WEIGHT_REF_TIME_PER_SECOND as u128 * moonbeam_runtime::currency::WEIGHT_FEE; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(expected_units); + }); +} + +#[test] +fn precompile_existence() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let precompile_addresses: std::collections::BTreeSet<_> = vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 1024, 1025, 1026, 2048, 2049, 2050, 2051, 2052, 2053, + 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, + 2068, 2069, 2070, 2071, 2072, 2073, + ] + .into_iter() + .map(H160::from_low_u64_be) + .collect(); + + for i in 0..3000 { + let address = H160::from_low_u64_be(i); + + if precompile_addresses.contains(&address) { + assert!( + is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return true", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_some(), + "execute({},..) should return Some(_)", + i + ); + } else { + assert!( + !is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return false", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_none(), + "execute({},..) should return None", + i + ); + } + } + }); +} + +#[test] +fn removed_precompiles() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let removed_precompiles = [1025, 2051, 2062, 2063]; + + for i in 1..3000 { + let address = H160::from_low_u64_be(i); + + if !is_precompile_or_fail::(address, 100_000u64).expect("to be ok") { + continue; + } + + if !removed_precompiles.contains(&i) { + assert!( + match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} should be an active precompile" + ); + continue; + } + + assert!( + !match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} shouldn't be an active precompile" + ); + + precompiles + .prepare_test(Alice, address, []) + .execute_reverts(|out| out == b"Removed precompile"); + } + }) +} + +#[test] +fn deal_with_fees_handles_tip() { + use frame_support::traits::OnUnbalanced; + use moonbeam_runtime::{DealWithFees, Treasury}; + + ExtBuilder::default().build().execute_with(|| { + // This test checks the functionality of the `DealWithFees` trait implementation in the runtime. + // It simulates a scenario where a fee and a tip are issued to an account and ensures that the + // treasury receives the correct amount (20% of the total), and the rest is burned (80%). + // + // The test follows these steps: + // 1. It issues a fee of 100 and a tip of 1000. + // 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100. + // 3. It checks that the treasury's balance is initially 0. + // 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip. + // 5. It checks that the treasury's balance is now 220 (20% of the fee and tip). + // 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating + // that this amount was burned. + let fee = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(100); + let tip = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(1000); + + let total_supply_before = Balances::total_issuance(); + assert_eq!(total_supply_before, 1_100); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); + + DealWithFees::on_unbalanceds(vec![fee, tip].into_iter()); + + // treasury should have received 20% + assert_eq!(Balances::free_balance(&Treasury::account_id()), 220); + + // verify 80% burned + let total_supply_after = Balances::total_issuance(); + assert_eq!(total_supply_before - total_supply_after, 880); + }); +} + +#[test] +fn evm_revert_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + // Batch a transfer followed by an invalid call to batch. + // Thus BatchAll will revert the transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + + input: BatchPCall::batch_all { + to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(), + value: vec![U256::from(1 * GLMR), U256::zero()].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 0, "there should be no transfer event"); + }); +} + +#[test] +fn evm_success_keeps_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into())].into(), + value: vec![U256::from(1 * GLMR)].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: BASE_FEE_GENESIS.into(), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 1, "there should be 1 transfer event"); + }); +} + +#[cfg(test)] +mod fee_tests { + use super::*; + use fp_evm::FeeCalculator; + use frame_support::{ + traits::{ConstU128, OnFinalize}, + weights::{ConstantMultiplier, WeightToFee}, + }; + use moonbeam_runtime::{ + currency, LengthToFee, MinimumMultiplier, RuntimeBlockWeights, SlowAdjustingFeeUpdate, + TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS, + }; + use sp_core::Get; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn test_multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) + } + + #[test] + fn test_fee_calculation() { + let base_extrinsic = RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000); + let extrinsic_len = 100u32; + let extrinsic_weight = 5_000u64; + let tip = 42u128; + type WeightToFeeImpl = ConstantMultiplier>; + type LengthToFeeImpl = LengthToFee; + + // base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip + let expected_fee = + WeightToFeeImpl::weight_to_fee(&base_extrinsic) + + multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee( + &Weight::from_parts(extrinsic_weight, 1), + )) + LengthToFeeImpl::weight_to_fee(&Weight::from_parts(extrinsic_len as u64, 1)) + + tip; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual_fee = TransactionPayment::compute_fee( + extrinsic_len, + &frame_support::dispatch::DispatchInfo { + class: DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + weight: Weight::from_parts(extrinsic_weight, 1), + }, + tip, + ); + + assert_eq!( + expected_fee, + actual_fee, + "The actual fee did not match the expected fee, diff {}", + actual_fee - expected_fee + ); + }); + } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int( + (currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128), + ) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = + (currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(125_075_022_500u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(125_325_422_500u128), + ); + + // 1 "real" hour (at 12-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(179_166_172_951u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(594_851_612_166u128), + ); + + // 1 "real" day (at 12-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(125_000_000_000u128), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(706_665_861_883_635u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(12_500_000_000_000_000u128), // upper bound enforced + ); + }); + } +} diff --git a/tracing/3200/runtime/moonbeam/tests/runtime_apis.rs b/tracing/3200/runtime/moonbeam/tests/runtime_apis.rs new file mode 100644 index 00000000..b7df77d0 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/runtime_apis.rs @@ -0,0 +1,395 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam Runtime Api Integration Tests + +mod common; +use common::*; + +use fp_evm::GenesisAccount; +use frame_support::assert_ok; +use nimbus_primitives::NimbusId; +use pallet_evm::{Account as EVMAccount, AddressMapping, FeeCalculator}; +use sp_core::{ByteArray, H160, H256, U256}; + +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; +use moonbeam_core_primitives::Header; +use moonbeam_rpc_primitives_txpool::runtime_decl_for_tx_pool_runtime_api::TxPoolRuntimeApi; +use moonbeam_runtime::{Executive, TransactionPaymentAsGasPrice}; +use nimbus_primitives::runtime_decl_for_nimbus_api::NimbusApi; +use std::{collections::BTreeMap, str::FromStr}; + +#[test] +fn ethereum_runtime_rpc_api_chain_id() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Runtime::chain_id(), CHAIN_ID); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_basic() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * GLMR)]) + .build() + .execute_with(|| { + assert_eq!( + Runtime::account_basic(H160::from(ALICE)), + EVMAccount { + balance: U256::from(2_000 * GLMR), + nonce: U256::zero() + } + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_gas_price() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!( + Runtime::gas_price(), + TransactionPaymentAsGasPrice::min_gas_price().0 + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_code_at() { + let address = H160::from(EVM_CONTRACT); + let code: Vec = vec![1, 2, 3, 4, 5]; + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: code.clone(), + nonce: Default::default(), + storage: Default::default(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::account_code_at(address), code); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_author() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + assert_eq!(Runtime::author(), H160::from(ALICE)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_storage_at() { + let address = H160::from(EVM_CONTRACT); + let mut key = [0u8; 32]; + key[31..32].copy_from_slice(&[6u8][..]); + let mut value = [0u8; 32]; + value[31..32].copy_from_slice(&[7u8][..]); + let item = H256::from_slice(&key[..]); + let mut storage: BTreeMap = BTreeMap::new(); + storage.insert(H256::from_slice(&key[..]), item); + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: Vec::new(), + nonce: Default::default(), + storage: storage.clone(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::storage_at(address, U256::from(6)), item); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_call() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * GLMR), + (AccountId::from(BOB), 2_000 * GLMR), + ]) + .build() + .execute_with(|| { + let execution_result = Runtime::call( + H160::from(ALICE), // from + H160::from(BOB), // to + Vec::new(), // data + U256::from(1000u64), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_create() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * GLMR)]) + .build() + .execute_with(|| { + let execution_result = Runtime::create( + H160::from(ALICE), // from + vec![0, 1, 1, 0], // data + U256::zero(), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_transaction_statuses() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 200_000 * GLMR), + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + + rpc_run_to_block(2); + let statuses = + Runtime::current_transaction_statuses().expect("Transaction statuses result."); + assert_eq!(statuses.len(), 1); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_block() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + rpc_run_to_block(2); + let block = Runtime::current_block().expect("Block result."); + assert_eq!(block.header.number, U256::from(1u8)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_receipts() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 100_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 200_000 * GLMR), + (AccountId::from(ALICE), 200_000 * GLMR), + (AccountId::from(BOB), 100_000 * GLMR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 50_000 * GLMR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + + let _result = Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)); + + rpc_run_to_block(2); + let receipts = Runtime::current_receipts().expect("Receipts result."); + assert_eq!(receipts.len(), 1); + }); +} + +#[test] +fn txpool_runtime_api_extrinsic_filter() { + ExtBuilder::default().build().execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * GLMR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let txpool = >::extrinsic_filter( + vec![eth_uxt.clone(), non_eth_uxt.clone()], + vec![unchecked_eth_tx(VALID_ETH_TX), non_eth_uxt], + ); + assert_eq!(txpool.ready.len(), 1); + assert_eq!(txpool.future.len(), 1); + }); +} + +#[test] +fn can_author_when_selected_is_empty() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000_000 * GLMR), + (AccountId::from(BOB), 10_000_000 * GLMR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * GLMR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }; + + // Base case: ALICE can author blocks when she is the only candidate + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Remove ALICE from candidate pool, leaving the candidate_pool empty + assert_ok!(ParachainStaking::go_offline(origin_of(AccountId::from( + ALICE + )))); + + // Need to fast forward to right before the next session, which is when selected candidates + // will be updated. We want to test the creation of the first block of the next session. + run_to_block(1799, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1799, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Check that it works as expected after session update + run_to_block(1800, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1800, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + }); +} diff --git a/tracing/3200/runtime/moonbeam/tests/xcm_mock/mod.rs b/tracing/3200/runtime/moonbeam/tests/xcm_mock/mod.rs new file mode 100644 index 00000000..23119603 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/xcm_mock/mod.rs @@ -0,0 +1,272 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +pub mod parachain; +pub mod relay_chain; +pub mod statemint_like; + +use cumulus_primitives_core::ParaId; +use pallet_xcm_transactor::relay_indices::*; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use polkadot_runtime_parachains::configuration::{ + GenesisConfig as ConfigurationGenesisConfig, HostConfiguration, +}; +use polkadot_runtime_parachains::paras::{ + GenesisConfig as ParasGenesisConfig, ParaGenesisArgs, ParaKind, +}; +use sp_core::{H160, U256}; +use std::{collections::BTreeMap, str::FromStr}; + +pub const PARAALICE: [u8; 20] = [1u8; 20]; +pub const RELAYALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const RELAYBOB: AccountId32 = AccountId32::new([2u8; 32]); + +pub fn para_a_account() -> AccountId32 { + ParaId::from(1).into_account_truncating() +} + +pub fn para_b_account() -> AccountId32 { + ParaId::from(2).into_account_truncating() +} + +pub fn para_a_account_20() -> parachain::AccountId { + ParaId::from(1).into_account_truncating() +} + +pub fn evm_account() -> H160 { + H160::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn mock_para_genesis_info() -> ParaGenesisArgs { + ParaGenesisArgs { + genesis_head: vec![1u8].into(), + validation_code: vec![1u8].into(), + para_kind: ParaKind::Parachain, + } +} + +pub fn mock_relay_config() -> HostConfiguration { + HostConfiguration:: { + hrmp_channel_max_capacity: u32::MAX, + hrmp_channel_max_total_size: u32::MAX, + hrmp_max_parachain_inbound_channels: 10, + hrmp_max_parachain_outbound_channels: 10, + hrmp_channel_max_message_size: u32::MAX, + // Changed to avoid aritmetic errors within hrmp_close + max_downward_message_size: 100_000u32, + ..Default::default() + } +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + +decl_test_parachain! { + pub struct Statemint { + Runtime = statemint_like::Runtime, + XcmpMessageHandler = statemint_like::MsgQueue, + DmpMessageHandler = statemint_like::MsgQueue, + new_ext = statemint_ext(1000), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(vec![1, 2, 3, 1000]), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + (1000, Statemint), + ], + } +} + +pub const INITIAL_BALANCE: u128 = 10_000_000_000_000_000; + +pub const INITIAL_EVM_BALANCE: u128 = 0; +pub const INITIAL_EVM_NONCE: u32 = 1; + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(PARAALICE.into(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_xcm_transactor::GenesisConfig:: { + // match relay runtime construct_runtime order in xcm_mock::relay_chain + relay_indices: RelayChainIndices { + hrmp: 6u8, + init_open_channel: 0u8, + accept_open_channel: 1u8, + close_channel: 2u8, + cancel_open_request: 6u8, + ..Default::default() + }, + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + // EVM accounts are self-sufficient. + let mut evm_accounts = BTreeMap::new(); + evm_accounts.insert( + evm_account(), + fp_evm::GenesisAccount { + nonce: U256::from(INITIAL_EVM_NONCE), + balance: U256::from(INITIAL_EVM_BALANCE), + storage: Default::default(), + code: vec![ + 0x00, // STOP + ], + }, + ); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn statemint_ext(para_id: u32) -> sp_io::TestExternalities { + use statemint_like::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (RELAYALICE.into(), INITIAL_BALANCE), + (RELAYBOB.into(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext(paras: Vec) -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(RELAYALICE, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let para_genesis: Vec<(ParaId, ParaGenesisArgs)> = paras + .iter() + .map(|¶_id| (para_id.into(), mock_para_genesis_info())) + .collect(); + + let genesis_config = ConfigurationGenesisConfig:: { + config: mock_relay_config(), + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = ParasGenesisConfig:: { + paras: para_genesis, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} + +pub type RelayChainPalletXcm = pallet_xcm::Pallet; +pub type Hrmp = polkadot_runtime_parachains::hrmp::Pallet; + +pub type StatemintBalances = pallet_balances::Pallet; +pub type StatemintChainPalletXcm = pallet_xcm::Pallet; +pub type StatemintAssets = pallet_assets::Pallet; + +pub type Assets = pallet_assets::Pallet; +pub type Treasury = pallet_treasury::Pallet; +pub type AssetManager = pallet_asset_manager::Pallet; +pub type XTokens = orml_xtokens::Pallet; +pub type RelayBalances = pallet_balances::Pallet; +pub type ParaBalances = pallet_balances::Pallet; +pub type XcmTransactor = pallet_xcm_transactor::Pallet; +pub type XcmWeightTrader = pallet_xcm_weight_trader::Pallet; diff --git a/tracing/3200/runtime/moonbeam/tests/xcm_mock/parachain.rs b/tracing/3200/runtime/moonbeam/tests/xcm_mock/parachain.rs new file mode 100644 index 00000000..3f41bcad --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/xcm_mock/parachain.rs @@ -0,0 +1,1125 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Parachain runtime mock. + +use frame_support::{ + construct_runtime, + dispatch::GetDispatchInfo, + ensure, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU32, Everything, Get, InstanceFilter, Nothing, PalletInfoAccess, + }, + weights::Weight, + PalletId, +}; +pub use moonbeam_runtime::xcm_config::AssetType; + +use frame_system::{pallet_prelude::BlockNumberFor, EnsureNever, EnsureRoot}; +use pallet_xcm::migration::v1::VersionUncheckedMigrateToV1; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, Hash, IdentityLookup, MaybeEquivalence, Zero}, + Permill, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm}; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use orml_traits::parameter_type_with_key; +use pallet_ethereum::PostLogContent; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use polkadot_parachain::primitives::{Id as ParaId, Sibling}; +use xcm::latest::{ + Error as XcmError, ExecuteXcm, + Junction::{PalletInstance, Parachain}, + Location, NetworkId, Outcome, Xcm, +}; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper as ArgumentsBenchmarkHelper; +use scale_info::TypeInfo; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; + +pub type AccountId = moonbeam_core_primitives::AccountId; +pub type Balance = u128; +pub type AssetId = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 0; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +pub type ForeignAssetInstance = (); + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 1; // Does not really matter as this will be only called by root + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + xcm_builder::HashedDescription< + AccountId, + xcm_builder::DescribeFamily, + >, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + SignedAccountKey20AsNative, +); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1u64, 1u64); + pub MaxInstructions: u32 = 100; +} + +// Instructing how incoming xcm assets will be handled +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + IsConcrete, + // We can convert the Locations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +pub type AssetTransactors = (LocalAssetTransactor, ForeignFungiblesTransactor); +pub type XcmRouter = super::ParachainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); + /// Parachain token units per second of execution + pub ParaTokensPerSecond: u128 = WEIGHT_REF_TIME_PER_SECOND as u128; +} + +pub struct WeightToFee; +impl sp_weights::WeightToFee for WeightToFee { + type Balance = Balance; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + use sp_runtime::SaturatedConversion as _; + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(ParaTokensPerSecond::get()) + .saturating_div(frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as u128) + } +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + pub const MaxAssetsIntoHolding: u32 = 64; + + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(Location::parent()), + }); + + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); +} + +use frame_system::RawOrigin; +use sp_runtime::traits::PostDispatchInfoOf; +use sp_runtime::DispatchErrorWithPostInfo; +use xcm_executor::traits::CallDispatcher; +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); + +type Reserves = ( + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + orml_xcm_support::MultiNativeAsset< + xcm_primitives::AbsoluteAndRelativeReserve, + >, +); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = Reserves; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = pallet_xcm_weight_trader::Trader; + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + SelfReserve, + ForeignAsset(AssetId), +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxAssetsForTransfer: usize = 2; + pub SelfLocation: Location = Location::here(); + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(MsgQueue::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + (1, Some(Parachain(1000u32))) => Some(50u128), + _ => None, + } + }; +} + +// The XCM message wrapper wrapper +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdConvert = + CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 0; + pub const SpendPeriod: u32 = 0; + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type ProposalBondMaximum = (); + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ArgumentsBenchmarkHelper; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} + +// Pallet to provide the version, used to test runtime upgrade version changes +#[frame_support::pallet] +pub mod mock_version_changer { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_version)] + pub(super) type CurrentVersion = StorageValue<_, XcmVersion, ValueQuery>; + + impl Get for Pallet { + fn get() -> XcmVersion { + Self::current_version() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + VersionChanged(XcmVersion), + } + + impl Pallet { + pub fn set_version(version: XcmVersion) { + CurrentVersion::::put(version); + Self::deposit_event(Event::VersionChanged(version)); + } + } +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl mock_version_changer::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +pub type LocalOriginToLocation = + xcm_primitives::SignedToAccountId20; + +parameter_types! { + pub MatcherLocation: Location = Location::here(); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = frame_support::traits::Nothing; + type XcmExecutor = XcmExecutor; + // Do not allow teleports + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // We use a custom one to test runtime ugprades + type AdvertisedXcmVersion = XcmVersioner; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::pallet_prelude::DispatchResult; +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset, + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset, + metadata.name, + metadata.symbol, + metadata.decimals, + false, + ) + } + + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into())?; + + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, +} + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetMetadata; + type ForeignAssetType = AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +// 1 DOT should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = MockTransactors; + type DerivativeAddressRegistrationOrigin = EnsureRoot; + type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdToLocation = + CurrencyIdToLocation>; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type XcmSender = XcmRouter; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type WeightInfo = (); + type HrmpManipulatorOrigin = EnsureRoot; + type HrmpOpenOrigin = EnsureRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + pub RelayLocation: Location = Location::parent(); +} + +impl pallet_xcm_weight_trader::Config for Runtime { + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type AddSupportedAssetOrigin = EnsureRoot; + type AssetLocationFilter = Everything; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type EditSupportedAssetOrigin = EnsureRoot; + type NativeLocation = SelfReserve; + type PauseSupportedAssetOrigin = EnsureRoot; + type RemoveSupportedAssetOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type ResumeSupportedAssetOrigin = EnsureRoot; + type WeightInfo = (); + type WeightToFee = WeightToFee; + type XcmFeesAccount = XcmFeesAccount; + #[cfg(feature = "runtime-benchmarks")] + type NotFilteredLocation = RelayLocation; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 1000; +} +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +use sp_core::U256; + +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 160 KB. +const BLOCK_STORAGE_LIMIT: u64 = 160 * 1024; + +parameter_types! { + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; + pub GasLimitStorageGrowthRatio: u64 = + BlockGasLimit::get().min(u64::MAX.into()).low_u64().saturating_div(BLOCK_STORAGE_LIMIT); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressNever; + + type AddressMapping = pallet_evm::IdentityAddressMapping; + type Currency = Balances; + type Runner = pallet_evm::runner::stack::Runner; + + type RuntimeEvent = RuntimeEvent; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = (); + type BlockGasLimit = BlockGasLimit; + type OnChargeTransaction = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +pub struct NormalFilter; +impl frame_support::traits::Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + _ => true, + } + } +} + +// We need to use the encoding from the relay mock runtime +#[derive(Encode, Decode)] +pub enum RelayCall { + #[codec(index = 5u8)] + // the index should match the position of the module in `construct_runtime!` + Utility(UtilityCall), + #[codec(index = 6u8)] + // the index should match the position of the module in `construct_runtime!` + Hrmp(HrmpCall), +} + +#[derive(Encode, Decode)] +pub enum UtilityCall { + #[codec(index = 1u8)] + AsDerivative(u16), +} + +// HRMP call encoding, needed for xcm transactor pallet +#[derive(Encode, Decode)] +pub enum HrmpCall { + #[codec(index = 0u8)] + InitOpenChannel(ParaId, u32, u32), + #[codec(index = 1u8)] + AcceptOpenChannel(ParaId), + #[codec(index = 2u8)] + CloseChannel(HrmpChannelId), + #[codec(index = 6u8)] + CancelOpenRequest(HrmpChannelId, u32), +} + +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum MockTransactors { + Relay, +} + +impl xcm_primitives::XcmTransact for MockTransactors { + fn destination(self) -> Location { + match self { + MockTransactors::Relay => Location::parent(), + } + } +} + +impl xcm_primitives::UtilityEncodeCall for MockTransactors { + fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec { + match self { + MockTransactors::Relay => match call { + xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => { + let mut call = + RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode(); + call.append(&mut b.clone()); + call + } + }, + } + } +} + +pub struct MockHrmpEncoder; +impl xcm_primitives::HrmpEncodeCall for MockHrmpEncoder { + fn hrmp_encode_call( + call: xcm_primitives::HrmpAvailableCalls, + ) -> Result, xcm::latest::Error> { + match call { + xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp( + HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()), + ) + .encode()), + xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => { + Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode()) + } + } + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} +parameter_types! { + pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo, +)] +pub enum ProxyType { + NotAllowed = 0, + Any = 1, +} + +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {} + +impl InstanceFilter for ProxyType { + fn filter(&self, _c: &RuntimeCall) -> bool { + match self { + ProxyType::NotAllowed => false, + ProxyType::Any => true, + } + } + fn is_superset(&self, _o: &Self) -> bool { + false + } +} + +impl Default for ProxyType { + fn default() -> Self { + Self::NotAllowed + } +} + +parameter_types! { + pub const ProxyCost: u64 = 1; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyCost; + type ProxyDepositFactor = ProxyCost; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ProxyCost; + type AnnouncementDepositFactor = ProxyCost; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will iMmediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlockU32; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_msg_queue, + XcmVersioner: mock_version_changer, + + PolkadotXcm: pallet_xcm, + Assets: pallet_assets, + CumulusXcm: cumulus_pallet_xcm, + XTokens: orml_xtokens, + AssetManager: pallet_asset_manager, + XcmTransactor: pallet_xcm_transactor, + XcmWeightTrader: pallet_xcm_weight_trader, + Treasury: pallet_treasury, + Proxy: pallet_proxy, + + Timestamp: pallet_timestamp, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthereumXcm: pallet_ethereum_xcm, + } +); + +pub(crate) fn para_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion}; +use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade}; +use sp_weights::constants::WEIGHT_REF_TIME_PER_SECOND; + +pub(crate) fn on_runtime_upgrade() { + VersionUncheckedMigrateToV1::::on_runtime_upgrade(); +} + +pub(crate) fn para_roll_to(n: BlockNumber) { + while System::block_number() < n { + PolkadotXcm::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + PolkadotXcm::on_initialize(System::block_number()); + } +} diff --git a/tracing/3200/runtime/moonbeam/tests/xcm_mock/relay_chain.rs b/tracing/3200/runtime/moonbeam/tests/xcm_mock/relay_chain.rs new file mode 100644 index 00000000..f391b31d --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/xcm_mock/relay_chain.rs @@ -0,0 +1,430 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, IdentityLookup}, + AccountId32, +}; + +use frame_support::weights::{Weight, WeightMeter}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_runtime_parachains::{ + configuration, dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, paras, shared, +}; +use sp_runtime::transaction_validity::TransactionPriority; +use sp_runtime::Permill; +use xcm::latest::prelude::*; +use xcm_builder::{ + Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, FixedRateOfFungible, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, IsConcrete, ProcessXcmMessage, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); + type PalletsOrigin = OriginCaller; +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub KsmLocation: Location = Here.into(); + pub const KusamaNetwork: NetworkId = NetworkId::Kusama; + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorLocation = Here; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // Not enabled in the relay per se, but we enable it to test + // the transact_through_signed extrinsic + Account32Hash, +); + +pub type LocalAssetTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1000u64, 1000u64); + pub KsmPerSecond: (AssetId, u128, u128) = (AssetId(KsmLocation::get()), 1, 1); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub MatcherLocation: Location = Location::here(); +} + +pub type XcmRouter = super::RelayChainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); + pub Statemine: Location = Parachain(1000).into(); + pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); +} + +pub type TrustedTeleporters = xcm_builder::Case; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub const FirstMessageFactorPercent: u64 = 100; +} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +/// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this +/// is more to satisfy type requirements rather than to test anything. +pub struct TestNextSessionRotation; + +impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { + fn average_session_length() -> u32 { + 10 + } + + fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } + + fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } +} + +impl paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = TestNextSessionRotation; + type QueueFootprinter = (); + type OnNewHead = (); + type AssignCoretime = (); +} + +impl dmp::Config for Runtime {} + +parameter_types! { + pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); +} + +impl hrmp::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = TestHrmpWeightInfo; + type ChannelManager = frame_system::EnsureRoot; + type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +impl origin::Config for Runtime {} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + Utility: pallet_utility, + Hrmp: hrmp, + Dmp: dmp, + Paras: paras, + Configuration: configuration, + } +); + +pub(crate) fn relay_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::{OnFinalize, OnInitialize}; +pub(crate) fn relay_roll_to(n: BlockNumber) { + while System::block_number() < n { + XcmPallet::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + XcmPallet::on_initialize(System::block_number()); + } +} + +/// A weight info that is only suitable for testing. +pub struct TestHrmpWeightInfo; + +impl hrmp::WeightInfo for TestHrmpWeightInfo { + fn hrmp_accept_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn force_clean_hrmp(_: u32, _: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_close(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_open(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_cancel_open_request(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_close_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_init_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn clean_open_channel_requests(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_open_hrmp_channel(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn establish_system_channel() -> Weight { + Weight::from_parts(1, 0) + } + + fn poke_channel_deposits() -> Weight { + Weight::from_parts(1, 0) + } + + fn establish_channel_with_system() -> Weight { + Weight::from_parts(1, 0) + } +} diff --git a/tracing/3200/runtime/moonbeam/tests/xcm_mock/statemint_like.rs b/tracing/3200/runtime/moonbeam/tests/xcm_mock/statemint_like.rs new file mode 100644 index 00000000..3b37a8e6 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/xcm_mock/statemint_like.rs @@ -0,0 +1,607 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, Get, Nothing}, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSigned}; + +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, Hash, IdentityLookup}, + AccountId32, +}; + +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; + +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain::primitives::Sibling; +use sp_std::convert::TryFrom; +use xcm::latest::prelude::*; +use xcm::VersionedXcm; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + FungiblesAdapter, IsConcrete, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type AssetId = u128; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; // 1 UNIT deposit to create asset + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub Local: Location = Here.into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub KsmPerSecond: (xcm::latest::prelude::AssetId, u128, u128) = + (AssetId(KsmLocation::get()), 1, 1); +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = FungibleAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ConvertedConcreteId< + AssetId, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; +/// Means for transacting assets on this chain. +pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxInstructions: u32 = 100; +} + +pub struct ParentOrParentsExecutivePlurality; +impl Contains for ParentOrParentsExecutivePlurality { + fn contains(location: &Location) -> bool { + matches!( + location.unpack(), + (1, []) + | ( + 1, + [Plurality { + id: BodyId::Executive, + .. + }] + ) + ) + } +} + +pub struct ParentOrSiblings; +impl Contains for ParentOrSiblings { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, []) | (1, [_])) + } +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +parameter_types! { + pub MatcherLocation: Location = Location::here(); + pub const MaxAssetsIntoHolding: u32 = 64; + pub const RelayTokenLocation: Location = Location::parent(); +} + +// Copied from: +// +// https://github.com/paritytech/polkadot-sdk/blob/f4eb41773611008040c9d4d8a8e6b7323eccfca1/cumulus +// /parachains/common/src/xcm_config.rs#L118 +// +// The difference with the original "ConcreteAssetFromSystem" (which is used by AssetHub), +// is that in our tests we only need to check if the asset matches the relay one. +pub struct ConcreteAssetFromRelay(sp_std::marker::PhantomData); +impl> ContainsPair + for ConcreteAssetFromRelay +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + let is_relay = match origin.unpack() { + // The Relay Chain + (1, []) => true, + // Others + _ => false, + }; + asset.id.0 == AssetLocation::get() && is_relay + } +} + +pub type TrustedTeleporters = (ConcreteAssetFromRelay,); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = + orml_xcm_support::MultiNativeAsset; + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +pub type XcmRouter = super::ParachainXcmRouter; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Pallet to cover test cases for change https://github.com/paritytech/cumulus/pull/831 +#[frame_support::pallet] +pub mod mock_statemint_prefix { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_prefix)] + pub(super) type CurrentPrefix = StorageValue<_, Location, ValueQuery>; + + impl Get for Pallet { + fn get() -> Location { + Self::current_prefix() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Changed Prefix + PrefixChanged(Location), + } + + impl Pallet { + pub fn set_prefix(prefix: Location) { + CurrentPrefix::::put(&prefix); + Self::deposit_event(Event::PrefixChanged(prefix)); + } + } +} + +impl mock_statemint_prefix::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +type Block = frame_system::mocking::MockBlockU32; +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + PolkadotXcm: pallet_xcm, + CumulusXcm: cumulus_pallet_xcm, + MsgQueue: mock_msg_queue, + Assets: pallet_assets, + PrefixChanger: mock_statemint_prefix, + + } +); diff --git a/tracing/3200/runtime/moonbeam/tests/xcm_tests.rs b/tracing/3200/runtime/moonbeam/tests/xcm_tests.rs new file mode 100644 index 00000000..1fdaa220 --- /dev/null +++ b/tracing/3200/runtime/moonbeam/tests/xcm_tests.rs @@ -0,0 +1,4584 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonbeam Runtime Xcm Tests + +mod xcm_mock; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use frame_support::{ + assert_ok, + traits::{PalletInfo, PalletInfoAccess}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + BoundedVec, +}; +use pallet_xcm_transactor::{ + Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights, +}; +use sp_core::ConstU32; +use sp_runtime::traits::MaybeEquivalence; +use xcm::latest::prelude::{ + AccountId32, AccountKey20, Asset as XcmAsset, AssetId as XcmAssetId, Assets as XcmAssets, + Fungible, GeneralIndex, Junction, Junctions, Limited, Location, OriginKind, PalletInstance, + Parachain, QueryResponse, Reanchorable, Response, WeightLimit, Xcm, +}; +use xcm::{IntoVersion, VersionedLocation, WrapVersion}; +use xcm_executor::traits::ConvertLocation; +use xcm_mock::parachain; +use xcm_mock::relay_chain; +use xcm_mock::*; +use xcm_primitives::{UtilityEncodeCall, DEFAULT_PROOF_SIZE}; +use xcm_simulator::TestExt; + +fn add_supported_asset(asset_type: parachain::AssetType, units_per_second: u128) -> Result<(), ()> { + let parachain::AssetType::Xcm(location_v3) = asset_type; + let VersionedLocation::V4(location_v4) = VersionedLocation::V3(location_v3) + .into_version(4) + .map_err(|_| ())? + else { + return Err(()); + }; + use frame_support::weights::WeightToFee as _; + let native_amount_per_second: u128 = + ::WeightToFee::weight_to_fee( + &Weight::from_parts( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + 0, + ), + ) + .try_into() + .map_err(|_| ())?; + let precision_factor = 10u128.pow(pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS); + let relative_price: u128 = if units_per_second > 0u128 { + native_amount_per_second + .saturating_mul(precision_factor) + .saturating_div(units_per_second) + } else { + 0u128 + }; + pallet_xcm_weight_trader::SupportedAssets::::insert( + location_v4, + (true, relative_price), + ); + Ok(()) +} + +// Send a relay asset (like DOT) to a parachain A +#[test] +fn receive_relay_asset_from_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Verify that parachain received the asset + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +// Send relay asset (like DOT) back from Parachain A to relaychain +#[test] +fn send_relay_asset_to_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // Free execution + assert_ok!(add_supported_asset(source_location, 0u128)); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain like in previous test + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Lets gather the balance before sending back money + let mut balance_before_sending = 0; + Relay::execute_with(|| { + balance_before_sending = RelayBalances::free_balance(&RELAYALICE); + }); + + // We now send back some money to the relay + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: RELAYALICE.into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 123, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The balances in paraAlice should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // Balances in the relay should have been received + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending); + }); +} + +#[test] +fn send_relay_asset_to_para_b() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register asset in paraA. Free execution + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Now send relay asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23); + }); + + // Para B balances should have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_to_para_b() { + MockNet::reset(); + + // This represents the asset in paraA + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send para A asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // Native token is substracted in paraA + ParaA::execute_with(|| { + // Free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Asset is minted in paraB + ParaB::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_from_para_b_to_para_c() { + MockNet::reset(); + + // Represents para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in parachain B. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Register para A asset in parachain C. Free execution + ParaC::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send para A asset from para B to para C + let dest = Location { + parents: 1, + interior: [ + Parachain(3), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The message passed through parachainA so we needed to pay since its the native token + ParaC::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a() { + MockNet::reset(); + + // para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in para B + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send back para A asset to para A + let dest = Location { + parents: 1, + interior: [ + Parachain(1), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn receive_relay_asset_with_trader() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset( + source_location.clone(), + 2500000000000u128 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // We are sending 100 tokens from relay. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Therefore with no refund, we should receive 10 tokens less + // Native trader fails for this, and we use the asset trader + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 100).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // non-free execution, not full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset( + source_location.clone(), + 2500000000000u128 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // In destination chain, we only need 4 weight + // We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // We are sending 100 tokens from para A. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Since we set 10 weight in destination chain, 25 will be charged upfront + // 15 of those will be refunded, while 10 will go to treasury as the true weight used + // will be 4 + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader_and_fee() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // With these units per second, 80K weight convrets to 1 asset unit + assert_ok!(add_supported_asset(source_location.clone(), 12500000u128)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // we use transfer_with_fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // 100 tokens transferred plus 1 taken from fees + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 - 1 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received because trully the xcm instruction does not cost + // what it is specified + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101); + }); +} + +#[test] +fn error_when_not_paying_enough() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset( + source_location.clone(), + 2500000000000u128 + )); + }); + + // We are sending 100 tokens from relay. + // If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10 + // Therefore with no refund, we should receive 10 tokens less + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 5).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); +} + +#[test] +fn transact_through_derivative_multilocation() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 400000000 + 3000 we should have taken out 4000003000 tokens from the caller + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000003000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn transact_through_sovereign() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_fee_payer_none() { + MockNet::reset(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let derivative_address = derivative_account_id(para_a_account(), 0); + + Relay::execute_with(|| { + // Transfer 100 tokens to derivative_address on the relay + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derivative_address.clone(), + 100u128 + )); + + // Transfer the XCM execution fee amount to ParaA's sovereign account + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 4000003000u128 + )); + }); + + // Check balances before the transact call + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000003000); + assert_eq!(RelayBalances::free_balance(&derivative_address), 100); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0); + }); + + // Encode the call. Balances transfer of 100 relay tokens to RELAYBOB + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: RELAYBOB, + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + // The final call will be an AsDerivative using index 0 + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + // No fee_payer here. The sovereign account will pay the fees on destination. + None, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + // Check balances after the transact call are correct + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 0); + assert_eq!(RelayBalances::free_balance(&derivative_address), 0); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000003000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000009000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A and set XCM version to 1 + ParaA::execute_with(|| { + parachain::XcmVersioner::set_version(1); + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + let response = Response::Version(2); + let querier: Location = ([]/* Here */).into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + // The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force + // it directly here + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + Relay::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(RelayChainPalletXcm::force_default_xcm_version( + relay_chain::RuntimeOrigin::root(), + Some(2) + )); + + // Wrap version, which sets VersionedStorage + // This is necessary because the mock router does not use wrap_version, but + // this is not necessary in prod + assert_ok!(::wrap_version( + &Parachain(1).into(), + mock_message + )); + + // Transfer assets. Since it is an unknown destination, it will query for version + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + + // Let's advance the relay. This should trigger the subscription message + relay_chain::relay_roll_to(2); + + // queries should have been updated + assert!(RelayChainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 1, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the version change + assert!(relay_chain::relay_events().contains(&expected_supported_version)); + }); + + // ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaA::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in the relay + let expected_supported_version_2: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 2, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(relay_chain::relay_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should not have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0); + }); + + // Send native token to fresh_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + fresh_account.into(), + 100 + )); + }); + + // Re-send tokens + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn evm_account_receiving_assets_should_handle_sufficients_ref_count() { + MockNet::reset(); + + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + // Evm account is self sufficient + ParaA::execute_with(|| { + assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Evm account sufficient ref count increased by 1. + ParaA::execute_with(|| { + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 2); + }); + + ParaA::execute_with(|| { + // Remove the account from the evm context. + parachain::EVM::remove_account(&evm_account()); + // Evm account sufficient ref count decreased by 1. + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); +} + +#[test] +fn empty_account_should_not_be_reset() { + MockNet::reset(); + + // Test account has nonce 1 on genesis. + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send native token to evm_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + evm_account_id, + 100 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Empty the assets from the account. + // As this makes the account go below the `min_balance`, the account is considered dead + // at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero. + assert_ok!(parachain::Assets::transfer( + parachain::RuntimeOrigin::signed(evm_account_id), + source_id, + PARAALICE.into(), + 123 + )); + // Verify account asset balance is Zero. + assert_eq!( + parachain::Assets::balance(source_id, &evm_account_id.into()), + 0 + ); + // Because we no longer have consumer references, we can set the balance to Zero. + // This would reset the account if our ED were to be > than Zero. + assert_ok!(ParaBalances::force_set_balance( + parachain::RuntimeOrigin::root(), + evm_account_id, + 0, + )); + // Verify account native balance is Zero. + assert_eq!(ParaBalances::free_balance(&evm_account_id), 0); + // Remove the account from the evm context. + // This decreases the sufficients reference by 1 and now is Zero. + parachain::EVM::remove_account(&evm_account()); + // Verify reference count. + let account = parachain::System::account(evm_account_id); + assert_eq!(account.sufficients, 0); + assert_eq!(account.consumers, 0); + assert_eq!(account.providers, 1); + // We expect the account to be alive in a Zero ED context. + assert_eq!(parachain::System::account_nonce(evm_account_id), 1); + }); +} + +#[test] +fn test_statemint_like() { + MockNet::reset(); + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + let statemint_asset_a_balances = Location::new( + 1, + [ + Parachain(1000), + PalletInstance(5), + xcm::latest::prelude::GeneralIndex(0u128), + ], + ); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset_a_balances) + .expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"StatemintToken".to_vec(), + symbol: b"StatemintToken".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 300000000000000 + )); + + // This is needed, since the asset is created as non-sufficient + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + xcm::latest::prelude::GeneralIndex(0), + ], + 123 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +#[test] + +fn send_statemint_asset_from_para_a_to_statemint_with_relay_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(relay_location, 0u128)); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + assert_ok!(add_supported_asset(statemint_location_asset, 0u128)); + }); + + let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send relay chain asset to Alice in Parachain A + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_relay) + .clone() + .into() + ), + Box::new(([] /* Here */, 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + Statemint::execute_with(|| { + // Set new prefix + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Send some native statemint tokens to sovereign for fees. + // We can't pay fees with USDC as the asset is minted as non-sufficient. + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Send statemint USDC asset to Alice in Parachain A + let parachain_beneficiary_from_statemint: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_statemint) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + let statemint_beneficiary = Location { + parents: 1, + interior: [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + + // Alice has received 200 Relay assets + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + Statemint::execute_with(|| { + // Check that BOB's balance is empty before the transfer + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![]); + }); + + // Transfer USDC from Parachain A to Statemint using Relay asset as fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemint_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(statemint_beneficiary)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + }); + + ParaA::execute_with(|| { + // Alice has 100 USDC less + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 25 + ); + + // Alice has 100 relay asset less + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + println!("STATEMINT EVENTS: {:?}", parachain::para_events()); + // Check that BOB received 100 USDC on statemint + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_relay_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received the tokens back in AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 100 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_with_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_relay_id), + 100, + 10, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 90); + }); + + Statemint::execute_with(|| { + // Free execution: check that Bob received the tokens back in AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 110 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 10 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 190); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiasset() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multiasset( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new((Location::parent(), 100).into()), + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received the tokens back in AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 100 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!(StatemintBalances::free_balance(RELAYBOB), INITIAL_BALANCE); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multicurrencies() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(statemint_asset.clone(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs and USDC from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Now send relay tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + + // Send USDC + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemint_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received relay tokens back in AssetHub + // (100 - MinXcmFee) + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 50 + ); + + // Check that BOB received 100 USDC on AssetHub + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + let bob_previous_balance = StatemintBalances::free_balance(RELAYBOB); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + bob_previous_balance - 100 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemint_via_xtokens_transfer_multiassets() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemint asset + let statemint_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemint_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemint_asset).expect("convert to v3"), + ); + let source_statemint_asset_id: parachain::AssetId = statemint_location_asset.clone().into(); + + let asset_metadata_statemint_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemint_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemint_location_asset.clone(), + asset_metadata_statemint_asset, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(statemint_asset.clone(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemint_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemint_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs and USDC from AssetHub to ParaA (Moonbeam) + Statemint::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemintBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemintBalances::transfer_allow_death( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + statemint_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemintAssets::create( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemintAssets::mint( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Now send relay tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + + // Send USDC + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemint_asset_id, &PARAALICE.into()), + 125 + ); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + let statemint_asset_to_send = XcmAsset { + id: XcmAssetId(statemint_asset), + fun: Fungible(100), + }; + + let relay_asset_to_send = XcmAsset { + id: XcmAssetId(Location::parent()), + fun: Fungible(100), + }; + + let assets_to_send: XcmAssets = + XcmAssets::from(vec![statemint_asset_to_send, relay_asset_to_send.clone()]); + + // For some reason the order of the assets is inverted when creating the array above. + // We need to use relay asset for fees, so we pick index 0. + assert_eq!(assets_to_send.get(0).unwrap(), &relay_asset_to_send); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multiassets( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(assets_to_send.into()), + 0, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemint::execute_with(|| { + // Check that Bob received relay tokens back in AssetHub + // (100 - MinXcmFee) + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 50 + ); + + // Check that BOB received 100 USDC on AssetHub + assert_eq!(StatemintAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemint::execute_with(|| { + let bob_previous_balance = StatemintBalances::free_balance(RELAYBOB); + + // Now send those tokens to ParaA + assert_ok!(StatemintChainPalletXcm::limited_reserve_transfer_assets( + statemint_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemintBalances::free_balance(RELAYBOB), + bob_previous_balance - 100 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn transact_through_signed_multilocation() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000004000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // 100 transferred + assert_eq!(RelayBalances::free_balance(¶_a_account()), 100); + + // 4000005186 refunded + assert_eq!(RelayBalances::free_balance(&derived), 4000005186); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + assert!(ParaBalances::free_balance(&derived) == 0); + + assert!(ParaBalances::free_balance(¶_a_account_20()) == 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: Some(overall_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + }); + + ParaB::execute_with(|| { + // Check the derived account was refunded + assert_eq!(ParaBalances::free_balance(&derived), 8993); + + // Check the transfer was executed + assert_eq!(ParaBalances::free_balance(¶_a_account_20()), 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact { + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer went through + assert!( + ParaBalances::free_balance(&PARAALICE.into()) + == parachain_b_alice_balances_before + 100 + ); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer wasn't executed + assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let transfer_recipient = evm_account(); + let mut transfer_recipient_balance_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into()); + + // Add proxy ALICE -> derived + let _ = parachain::Proxy::add_proxy_delegate( + &PARAALICE.into(), + derived, + parachain::ProxyType::Any, + 0, + ); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 { + gas_limit: U256::from(21000), + action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer was executed + assert!( + ParaBalances::free_balance(&transfer_recipient.into()) + == transfer_recipient_balance_before + 100 + ); + }); +} + +#[test] +fn hrmp_init_accept_through_root() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_b_account(), + 1000u128 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp init channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::InitOpen(HrmpInitParams { + para_id: 2u32.into(), + proposed_max_capacity: 1, + proposed_max_message_size: 1 + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender: 1u32.into(), + recipient: 2u32.into(), + proposed_max_capacity: 1u32, + proposed_max_message_size: 1u32, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); + ParaB::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp accept channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Accept { + para_id: 1u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { + sender: 1u32.into(), + recipient: 2u32.into(), + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +#[test] +fn hrmp_close_works() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(Hrmp::force_open_hrmp_channel( + relay_chain::RuntimeOrigin::root(), + 1u32.into(), + 2u32.into(), + 1u32, + 1u32 + )); + assert_ok!(Hrmp::force_process_hrmp_open( + relay_chain::RuntimeOrigin::root(), + 1u32 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp close + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Close(HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into() + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::ChannelClosed { + by_parachain: 1u32.into(), + channel_id: HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into(), + }, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +use parity_scale_codec::{Decode, Encode}; +use sp_io::hashing::blake2_256; + +// Helper to derive accountIds +pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 { + let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); + sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id") +} diff --git a/tracing/3200/runtime/moonriver/Cargo.toml b/tracing/3200/runtime/moonriver/Cargo.toml new file mode 100644 index 00000000..34643241 --- /dev/null +++ b/tracing/3200/runtime/moonriver/Cargo.toml @@ -0,0 +1,428 @@ +[package] +authors = { workspace = true } +build = "build.rs" +description = "Moonriver Runtime" +edition = "2021" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +name = "moonriver-runtime" +version = "0.8.4" + +[dependencies] +hex-literal = { workspace = true, optional = true } +log = { workspace = true } +num_enum = { workspace = true } +rlp = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"] } +sha3 = { workspace = true, optional = true } +smallvec = { workspace = true } +strum = { workspace = true } +strum_macros = { workspace = true } + +# Moonbeam +account = { workspace = true } +moonbeam-core-primitives = { workspace = true } +moonbeam-relay-encoder = { workspace = true } +moonbeam-runtime-common = { workspace = true } +session-keys-primitives = { workspace = true } +xcm-primitives = { workspace = true } + +# Moonbeam pallets +moonbeam-xcm-benchmarks = { workspace = true } +pallet-asset-manager = { workspace = true } +pallet-author-mapping = { workspace = true } +pallet-crowdloan-rewards = { workspace = true } +pallet-emergency-para-xcm = { workspace = true } +pallet-erc20-xcm-bridge = { workspace = true } +pallet-ethereum-xcm = { workspace = true } +pallet-evm-chain-id = { workspace = true } +pallet-maintenance-mode = { workspace = true, features = ["xcm-support"] } +pallet-migrations = { workspace = true } +pallet-moonbeam-foreign-assets = { workspace = true } +pallet-moonbeam-lazy-migrations = { workspace = true } +pallet-moonbeam-orbiters = { workspace = true } +pallet-parachain-staking = { workspace = true } +pallet-precompile-benchmarks = { workspace = true } +pallet-proxy-genesis-companion = { workspace = true } +pallet-randomness = { workspace = true } +pallet-xcm-transactor = { workspace = true } +pallet-xcm-weight-trader = { workspace = true } + +# Moonbeam precompiles +pallet-evm-precompile-author-mapping = { workspace = true } +pallet-evm-precompile-balances-erc20 = { workspace = true } +pallet-evm-precompile-batch = { workspace = true } +pallet-evm-precompile-call-permit = { workspace = true } +pallet-evm-precompile-collective = { workspace = true } +pallet-evm-precompile-conviction-voting = { workspace = true } +pallet-evm-precompile-crowdloan-rewards = { workspace = true } +pallet-evm-precompile-gmp = { workspace = true } +pallet-evm-precompile-identity = { workspace = true } +pallet-evm-precompile-parachain-staking = { workspace = true } +pallet-evm-precompile-preimage = { workspace = true } +pallet-evm-precompile-proxy = { workspace = true } +pallet-evm-precompile-randomness = { workspace = true } +pallet-evm-precompile-referenda = { workspace = true } +pallet-evm-precompile-registry = { workspace = true } +pallet-evm-precompile-relay-encoder = { workspace = true } +pallet-evm-precompile-relay-verifier = { workspace = true } +pallet-evm-precompile-xcm-transactor = { workspace = true } +pallet-evm-precompile-xcm-utils = { workspace = true } +pallet-evm-precompile-xtokens = { workspace = true } +pallet-evm-precompileset-assets-erc20 = { workspace = true } +pallet-evm-precompile-p256verify = { workspace = true } + +# Moonbeam tracing +evm-tracing-events = { workspace = true, optional = true } +moonbeam-evm-tracer = { workspace = true, optional = true } +moonbeam-rpc-primitives-debug = { workspace = true } +moonbeam-rpc-primitives-txpool = { workspace = true } + +# Substrate +frame-executive = { workspace = true } +frame-metadata-hash-extension = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-system-rpc-runtime-api = { workspace = true } +pallet-assets = { workspace = true } +pallet-balances = { workspace = true, features = ["insecure_zero_ed"] } +pallet-collective = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-identity = { workspace = true } +pallet-multisig = { workspace = true } +pallet-preimage = { workspace = true } +pallet-proxy = { workspace = true } +pallet-referenda = { workspace = true } +pallet-root-testing = { workspace = true } +pallet-scheduler = { workspace = true } +pallet-society = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } +pallet-treasury = { workspace = true } +pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } +parity-scale-codec = { workspace = true, features = [ + "derive", + "max-encoded-len", + "chain-error", +] } +scale-info = { workspace = true, features = ["derive"] } +sp-api = { workspace = true } +sp-block-builder = { workspace = true } +sp-consensus-slots = { workspace = true } +sp-core = { workspace = true } +sp-debug-derive = { workspace = true } +sp-inherents = { workspace = true } +sp-io = { workspace = true, features = ["improved_panic_error_reporting"] } +sp-offchain = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } +sp-transaction-pool = { workspace = true } +sp-version = { workspace = true } +sp-weights = { workspace = true } +sp-genesis-builder = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +fp-rpc = { workspace = true } +fp-self-contained = { workspace = true, features = ["serde"] } +pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] } +pallet-evm-precompile-blake2 = { workspace = true } +pallet-evm-precompile-bn128 = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } +pallet-evm-precompile-modexp = { workspace = true } +pallet-evm-precompile-sha3fips = { workspace = true } +pallet-evm-precompile-simple = { workspace = true } +precompile-utils = { workspace = true } + +# Polkadot / XCM +orml-traits = { workspace = true } +orml-xcm-support = { workspace = true } +orml-xtokens = { workspace = true } +pallet-xcm = { workspace = true } +pallet-xcm-benchmarks = { workspace = true, optional = true } +polkadot-core-primitives = { workspace = true } +polkadot-parachain = { workspace = true } +polkadot-runtime-common = { workspace = true } +xcm = { workspace = true } +xcm-builder = { workspace = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } +pallet-message-queue = { workspace = true } + +# Cumulus +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-primitives-storage-weight-reclaim = { workspace = true } +parachain-info = { workspace = true } +parachains-common = { workspace = true } + +# Moonkit +async-backing-primitives = { workspace = true } +moonkit-xcm-primitives = { workspace = true } +nimbus-primitives = { workspace = true } +pallet-async-backing = { workspace = true } +pallet-author-inherent = { workspace = true } +pallet-author-slot-filter = { workspace = true } +pallet-relay-storage-roots = { workspace = true } + +# Benchmarking +frame-benchmarking = { workspace = true, optional = true } +frame-system-benchmarking = { workspace = true, optional = true } +frame-try-runtime = { workspace = true, optional = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true } + +[features] +default = ["std", "evm-tracing"] +std = [ + "account/std", + "async-backing-primitives/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "cumulus-primitives-storage-weight-reclaim/std", + "evm-tracing-events/std", + "fp-evm/std", + "fp-rpc/std", + "fp-self-contained/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-metadata-hash-extension/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "moonbeam-core-primitives/std", + "moonbeam-evm-tracer/std", + "moonbeam-relay-encoder/std", + "moonbeam-rpc-primitives-debug/std", + "moonbeam-rpc-primitives-txpool/std", + "moonbeam-runtime-common/std", + "moonbeam-xcm-benchmarks/std", + "moonkit-xcm-primitives/std", + "nimbus-primitives/std", + "orml-xtokens/std", + "pallet-asset-manager/std", + "pallet-assets/std", + "pallet-async-backing/std", + "pallet-author-inherent/std", + "pallet-author-mapping/std", + "pallet-author-slot-filter/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-conviction-voting/std", + "pallet-crowdloan-rewards/std", + "pallet-emergency-para-xcm/std", + "pallet-erc20-xcm-bridge/std", + "pallet-evm-chain-id/std", + "pallet-ethereum-xcm/std", + "pallet-ethereum/std", + "pallet-evm-precompile-author-mapping/std", + "pallet-evm-precompile-balances-erc20/std", + "pallet-evm-precompile-batch/std", + "pallet-evm-precompile-call-permit/std", + "pallet-evm-precompile-collective/std", + "pallet-evm-precompile-conviction-voting/std", + "pallet-evm-precompile-parachain-staking/std", + "pallet-evm-precompile-preimage/std", + "pallet-evm-precompile-randomness/std", + "pallet-evm-precompile-referenda/std", + "pallet-evm-precompile-relay-encoder/std", + "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm-transactor/std", + "pallet-evm-precompile-xcm-utils/std", + "pallet-evm-precompile-xtokens/std", + "pallet-evm-precompile-p256verify/std", + "pallet-evm/std", + "pallet-identity/std", + "pallet-maintenance-mode/std", + "pallet-migrations/std", + "pallet-moonbeam-foreign-assets/std", + "pallet-moonbeam-lazy-migrations/std", + "pallet-moonbeam-orbiters/std", + "pallet-multisig/std", + "pallet-parachain-staking/std", + "pallet-precompile-benchmarks/std", + "pallet-preimage/std", + "pallet-proxy-genesis-companion/std", + "pallet-proxy/std", + "pallet-randomness/std", + "pallet-referenda/std", + "pallet-relay-storage-roots/std", + "pallet-root-testing/std", + "pallet-scheduler/std", + "pallet-society/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-treasury/std", + "pallet-utility/std", + "pallet-whitelist/std", + "pallet-xcm-transactor/std", + "pallet-xcm/std", + "pallet-xcm-weight-trader/std", + "parachain-info/std", + "parachains-common/std", + "parity-scale-codec/std", + "precompile-utils/std", + "scale-info/std", + "session-keys-primitives/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-slots/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "sp-genesis-builder/std", + "strum/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", + "xcm-primitives/std", + "xcm/std", +] + +# Must be enabled for tracing runtimes only +evm-tracing = ["evm-tracing-events", "moonbeam-evm-tracer", "rlp", "sha3"] + +# Allow to print logs details (no wasm:stripped) +force-debug = ["sp-debug-derive/force-debug"] + +# Will be enabled by the `wasm-builder` when building the runtime for WASM. +runtime-wasm = [] + +# Enable the metadata hash generation in the wasm builder. +metadata-hash = ["substrate-wasm-builder/metadata-hash"] + +# A feature that should be enabled when the runtime should be build for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller like logging for example. +on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "moonbeam-relay-encoder/runtime-benchmarks", + "moonbeam-runtime-common/runtime-benchmarks", + "moonbeam-xcm-benchmarks/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "pallet-asset-manager/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-author-inherent/runtime-benchmarks", + "pallet-author-mapping/runtime-benchmarks", + "pallet-author-slot-filter/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", + "pallet-crowdloan-rewards/runtime-benchmarks", + "pallet-ethereum-xcm/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", + "pallet-identity/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", + "pallet-moonbeam-foreign-assets/runtime-benchmarks", + "pallet-moonbeam-lazy-migrations/runtime-benchmarks", + "pallet-moonbeam-orbiters/runtime-benchmarks", + "pallet-multisig/runtime-benchmarks", + "pallet-parachain-staking/runtime-benchmarks", + "pallet-precompile-benchmarks/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", + "pallet-randomness/runtime-benchmarks", + "pallet-referenda/runtime-benchmarks", + "pallet-relay-storage-roots/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", + "pallet-society/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-xcm-weight-trader/runtime-benchmarks", + "session-keys-primitives/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] +try-runtime = [ + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-dmp-queue/try-runtime", + "fp-self-contained/try-runtime", + "frame-executive/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime", + "moonbeam-runtime-common/try-runtime", + "pallet-asset-manager/try-runtime", + "pallet-author-mapping/try-runtime", + "pallet-author-slot-filter/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-conviction-voting/try-runtime", + "pallet-maintenance-mode/try-runtime", + "pallet-migrations/try-runtime", + "pallet-moonbeam-lazy-migrations/try-runtime", + "pallet-parachain-staking/try-runtime", + "pallet-precompile-benchmarks/try-runtime", + "pallet-preimage/try-runtime", + "pallet-referenda/try-runtime", + "pallet-relay-storage-roots/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-scheduler/try-runtime", + "pallet-society/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-xcm/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-utility/try-runtime", + "pallet-transaction-payment/try-runtime", + "parachain-info/try-runtime", + "pallet-evm-chain-id/try-runtime", + "parachain-info/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum/try-runtime", + "pallet-treasury/try-runtime", + "pallet-author-inherent/try-runtime", + "pallet-crowdloan-rewards/try-runtime", + "pallet-proxy/try-runtime", + "pallet-identity/try-runtime", + "orml-xtokens/try-runtime", + "pallet-assets/try-runtime", + "pallet-async-backing/try-runtime", + "pallet-xcm-transactor/try-runtime", + "pallet-proxy-genesis-companion/try-runtime", + "pallet-moonbeam-orbiters/try-runtime", + "pallet-ethereum-xcm/try-runtime", + "pallet-randomness/try-runtime", + "pallet-whitelist/try-runtime", + "pallet-erc20-xcm-bridge/try-runtime", + "pallet-multisig/try-runtime", +] diff --git a/tracing/3200/runtime/moonriver/build.rs b/tracing/3200/runtime/moonriver/build.rs new file mode 100644 index 00000000..772c2d1e --- /dev/null +++ b/tracing/3200/runtime/moonriver/build.rs @@ -0,0 +1,36 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use substrate_wasm_builder::WasmBuilder; + +#[cfg(not(feature = "metadata-hash"))] +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} + +#[cfg(feature = "metadata-hash")] +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .enable_metadata_hash("MOVR", 18) + .build() +} diff --git a/tracing/3200/runtime/moonriver/src/asset_config.rs b/tracing/3200/runtime/moonriver/src/asset_config.rs new file mode 100644 index 00000000..957fb04a --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/asset_config.rs @@ -0,0 +1,217 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Asset configuration for Moonbase. +//! + +use super::{ + currency, governance, xcm_config, AccountId, AssetId, AssetManager, Assets, Balance, Balances, + OpenTechCommitteeInstance, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +use moonbeam_runtime_common::weights as moonriver_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; + +use frame_support::{ + dispatch::GetDispatchInfo, + parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, EitherOfDiverse}, + weights::Weight, +}; +use frame_system::{EnsureNever, EnsureRoot}; +use sp_core::H160; + +use parity_scale_codec::{Compact, Decode, Encode}; +use scale_info::TypeInfo; + +use sp_std::{ + convert::{From, Into}, + prelude::*, +}; + +// Number of items that can be destroyed with our configured max extrinsic proof size. +// x = (a - b) / c where: +// a: maxExtrinsic proof size +// b: base proof size for destroy_accounts in pallet_assets weights +// c: proof size for each item +// 656.87 = (3_407_872 - 8232) / 5180 +const REMOVE_ITEMS_LIMIT: u32 = 656; + +// Not to disrupt the previous asset instance, we assign () to Foreign +pub type ForeignAssetInstance = (); + +// For foreign assets, these parameters dont matter much +// as this will only be called by root with the forced arguments +// No deposit is substracted with those methods +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::MOVR * currency::SUPPLY_FACTOR; + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = currency::deposit(1,68); + pub const MetadataDepositPerByte: Balance = currency::deposit(0, 1); +} + +/// We allow Root and General Admin to execute privileged asset operations. +pub type AssetsForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +// Foreign assets +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = ConstU128<{ currency::deposit(1, 18) }>; + type WeightInfo = moonriver_weights::pallet_assets::WeightInfo; + type RemoveItemsLimit = ConstU32<{ REMOVE_ITEMS_LIMIT }>; + type AssetIdParameter = Compact; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::{pallet_prelude::DispatchResult, transactional}; + +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + #[transactional] + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetRegistrarMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset.into(), + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + // Lastly, the metadata + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset.into(), + metadata.name, + metadata.symbol, + metadata.decimals, + metadata.is_frozen, + ) + } + + #[transactional] + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + // For us both of them (Foreign and Local) have the same annotated weight for a given + // witness + // We need to take the dispatch info from the destroy call, which is already annotated in + // the assets pallet + + // This is the dispatch info of destroy + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetRegistrarMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub is_frozen: bool, +} + +pub type ForeignAssetModifierOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetRegistrarMetadata; + type ForeignAssetType = xcm_config::AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = ForeignAssetModifierOrigin; + type WeightInfo = moonriver_weights::pallet_asset_manager::WeightInfo; +} + +// Instruct how to go from an H160 to an AssetID +// We just take the lowest 128 bits +impl AccountIdAssetIdConversion for Runtime { + /// The way to convert an account to assetId is by ensuring that the prefix is 0XFFFFFFFF + /// and by taking the lowest 128 bits as the assetId + fn account_to_asset_id(account: AccountId) -> Option<(Vec, AssetId)> { + let h160_account: H160 = account.into(); + let mut data = [0u8; 16]; + let (prefix_part, id_part) = h160_account.as_fixed_bytes().split_at(4); + if prefix_part == FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX { + data.copy_from_slice(id_part); + let asset_id: AssetId = u128::from_be_bytes(data).into(); + Some((prefix_part.to_vec(), asset_id)) + } else { + None + } + } + + // The opposite conversion + fn asset_id_to_account(prefix: &[u8], asset_id: AssetId) -> AccountId { + let mut data = [0u8; 20]; + data[0..4].copy_from_slice(prefix); + data[4..20].copy_from_slice(&asset_id.to_be_bytes()); + AccountId::from(data) + } +} diff --git a/tracing/3200/runtime/moonriver/src/governance/councils.rs b/tracing/3200/runtime/moonriver/src/governance/councils.rs new file mode 100644 index 00000000..b09c47a4 --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/governance/councils.rs @@ -0,0 +1,61 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Councils for Gov1 and Gov2 + +use super::*; + +pub type TreasuryCouncilInstance = pallet_collective::Instance3; +pub type OpenTechCommitteeInstance = pallet_collective::Instance4; + +parameter_types! { + // TODO: Check value of this parameter + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for treasury council members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 3 * DAYS }>; + /// The maximum number of proposals that can be open in the treasury council at once. + type MaxProposals = ConstU32<20>; + /// The maximum number of treasury council members. + type MaxMembers = ConstU32<9>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonriver_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; + /// The maximum amount of time (in blocks) for technical committee members to vote on motions. + /// Motions may end in fewer blocks if enough votes are cast to determine the result. + type MotionDuration = ConstU32<{ 14 * DAYS }>; + /// The maximum number of proposals that can be open in the technical committee at once. + type MaxProposals = ConstU32<100>; + /// The maximum number of technical committee members. + type MaxMembers = ConstU32<100>; + type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; + type WeightInfo = moonriver_weights::pallet_collective::WeightInfo; + type SetMembersOrigin = referenda::GeneralAdminOrRoot; + type MaxProposalWeight = MaxProposalWeight; +} diff --git a/tracing/3200/runtime/moonriver/src/governance/mod.rs b/tracing/3200/runtime/moonriver/src/governance/mod.rs new file mode 100644 index 00000000..36a2c6be --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/governance/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Governance configurations + +pub mod councils; +pub mod referenda; + +use super::*; + +mod origins; +pub use origins::{ + custom_origins, GeneralAdmin, ReferendumCanceller, ReferendumKiller, WhitelistedCaller, +}; +mod tracks; +pub use tracks::TracksInfo; diff --git a/tracing/3200/runtime/moonriver/src/governance/origins.rs b/tracing/3200/runtime/moonriver/src/governance/origins.rs new file mode 100644 index 00000000..ef4675d6 --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/governance/origins.rs @@ -0,0 +1,84 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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. + +//! Custom origins for governance interventions. +#![cfg_attr(not(feature = "std"), no_std)] +pub use custom_origins::*; + +#[frame_support::pallet] +pub mod custom_origins { + use frame_support::pallet_prelude::*; + use strum_macros::EnumString; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive( + PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug, EnumString, + )] + #[strum(serialize_all = "snake_case")] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// General admin + GeneralAdmin, + /// Origin able to cancel referenda. + ReferendumCanceller, + /// Origin able to kill referenda. + ReferendumKiller, + /// Fast General Admin + FastGeneralAdmin, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!( + ReferendumCanceller, + ReferendumKiller, + WhitelistedCaller, + GeneralAdmin, + FastGeneralAdmin, + ); +} diff --git a/tracing/3200/runtime/moonriver/src/governance/referenda.rs b/tracing/3200/runtime/moonriver/src/governance/referenda.rs new file mode 100644 index 00000000..d3c06af7 --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/governance/referenda.rs @@ -0,0 +1,100 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Gov2 config +//! Includes runtime configs for these substrate pallets: +//! 1. pallet-conviction-voting +//! 2. pallet-whitelist +//! 3. pallet-referenda + +use super::*; +use crate::currency::*; +use frame_support::traits::{EitherOf, MapSuccess}; +use frame_system::EnsureRootWithSuccess; +use sp_runtime::traits::Replace; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = 1 * DAYS; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = moonriver_weights::pallet_conviction_voting::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Polls = Referenda; + type MaxTurnout = frame_support::traits::TotalIssuanceOf; + // Maximum number of concurrent votes an account may have + type MaxVotes = ConstU32<20>; + // Minimum period of vote locking + type VoteLockingPeriod = VoteLockingPeriod; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 10 * MOVR * SUPPLY_FACTOR; + pub const UndecidingTimeout: BlockNumber = 21 * DAYS; +} + +// Origin for general admin or root +pub type GeneralAdminOrRoot = EitherOf, origins::GeneralAdmin>; +// The policy allows for Root or FastGeneralAdmin. +pub type FastGeneralAdminOrRoot = EitherOf, origins::FastGeneralAdmin>; + +impl custom_origins::Config for Runtime {} + +// The purpose of this pallet is to queue calls to be dispatched as by root later => the Dispatch +// origin corresponds to the Gov2 Whitelist track. +impl pallet_whitelist::Config for Runtime { + type WeightInfo = moonriver_weights::pallet_whitelist::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WhitelistOrigin = EitherOf< + EnsureRootWithSuccess>, + MapSuccess< + pallet_collective::EnsureProportionAtLeast< + Self::AccountId, + OpenTechCommitteeInstance, + 5, + 9, + >, + Replace>, + >, + >; + type DispatchWhitelistedOrigin = EitherOf, WhitelistedCaller>; + type Preimages = Preimage; +} + +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +impl pallet_referenda::Config for Runtime { + type WeightInfo = moonriver_weights::pallet_referenda::WeightInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EitherOf, ReferendumCanceller>; + type KillOrigin = EitherOf, ReferendumKiller>; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/tracing/3200/runtime/moonriver/src/governance/tracks.rs b/tracing/3200/runtime/moonriver/src/governance/tracks.rs new file mode 100644 index 00000000..8dddbeca --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/governance/tracks.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// 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 . + +//! Track configurations for governance. + +use super::*; +use crate::currency::{KILOMOVR, MOVR, SUPPLY_FACTOR}; +use sp_std::str::FromStr; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} +const fn permill(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 1000) +} + +use pallet_referenda::Curve; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + // Name of this track. + name: "root", + // A limit for the number of referenda on this track that can be being decided at once. + // For Root origin this should generally be just one. + max_deciding: 5, + // Amount that must be placed on deposit before a decision can be made. + decision_deposit: 100 * KILOMOVR * SUPPLY_FACTOR, + // Amount of time this must be submitted for before a decision can be made. + prepare_period: 1 * DAYS, + // Amount of time that a decision may take to be approved prior to cancellation. + decision_period: 14 * DAYS, + // Amount of time that the approval criteria must hold before it can be approved. + confirm_period: 1 * DAYS, + // Minimum amount of time that an approved proposal must be in the dispatch queue. + min_enactment_period: 1 * DAYS, + // Minimum aye votes as percentage of overall conviction-weighted votes needed for + // approval as a function of time into decision period. + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + // Minimum pre-conviction aye-votes ("support") as percentage of overall population that + // is needed for approval as a function of time into decision period. + min_support: Curve::make_linear(14, 14, permill(5), percent(25)), + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 100, + decision_deposit: 10 * KILOMOVR * SUPPLY_FACTOR, + prepare_period: 10 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 10 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14 * 24, percent(1), percent(0), percent(2)), + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "general_admin", + max_deciding: 10, + decision_deposit: 500 * MOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 1 * DAYS, + min_enactment_period: 1 * DAYS, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(7, 14, percent(10), percent(0), percent(50)), + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "referendum_canceller", + max_deciding: 20, + decision_deposit: 10 * KILOMOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "referendum_killer", + max_deciding: 100, + decision_deposit: 20 * KILOMOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(1, 14, percent(96), percent(50), percent(100)), + min_support: Curve::make_reciprocal(1, 14, percent(1), percent(0), percent(10)), + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "fast_general_admin", + max_deciding: 10, + decision_deposit: 500 * MOVR * SUPPLY_FACTOR, + prepare_period: 1 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 3 * HOURS, + min_enactment_period: 10 * MINUTES, + min_approval: Curve::make_reciprocal(4, 14, percent(80), percent(50), percent(100)), + min_support: Curve::make_reciprocal(5, 14, percent(1), percent(0), percent(50)), + }, + ), +]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => { + if let Some((track_id, _)) = Self::tracks() + .into_iter() + .find(|(_, track)| track.name == "root") + { + Ok(*track_id) + } else { + Err(()) + } + } + _ => Err(()), + } + } else if let Ok(custom_origin) = custom_origins::Origin::try_from(id.clone()) { + if let Some((track_id, _)) = Self::tracks().into_iter().find(|(_, track)| { + if let Ok(track_custom_origin) = custom_origins::Origin::from_str(track.name) { + track_custom_origin == custom_origin + } else { + false + } + }) { + Ok(*track_id) + } else { + Err(()) + } + } else { + Err(()) + } + } +} + +#[test] +/// To ensure voters are always locked into their vote +fn vote_locking_always_longer_than_enactment_period() { + for (_, track) in TRACKS_DATA { + assert!( + ::VoteLockingPeriod::get() + >= track.min_enactment_period, + "Track {} has enactment period {} < vote locking period {}", + track.name, + track.min_enactment_period, + ::VoteLockingPeriod::get(), + ); + } +} + +#[test] +fn all_tracks_have_origins() { + for (_, track) in TRACKS_DATA { + // check name.into() is successful either converts into "root" or custom origin + let track_is_root = track.name == "root"; + let track_has_custom_origin = custom_origins::Origin::from_str(track.name).is_ok(); + assert!(track_is_root || track_has_custom_origin); + } +} diff --git a/tracing/3200/runtime/moonriver/src/lib.rs b/tracing/3200/runtime/moonriver/src/lib.rs new file mode 100644 index 00000000..4c75b411 --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/lib.rs @@ -0,0 +1,1844 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! The Moonriver Runtime. +//! +//! Primary features of this runtime include: +//! * Ethereum compatibility +//! * Moonriver tokenomics + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512. +#![recursion_limit = "512"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +use account::AccountId20; +use cumulus_pallet_parachain_system::{ + RelayChainStateProof, RelayStateProof, RelaychainDataProvider, ValidationData, +}; +use fp_rpc::TransactionStatus; + +// Re-export required by get! macro. +use cumulus_primitives_core::{relay_chain, AggregateMessageOrigin}; +#[cfg(feature = "std")] +pub use fp_evm::GenesisAccount; +pub use frame_support::traits::Get; +use frame_support::{ + construct_runtime, + dispatch::{DispatchClass, GetDispatchInfo, PostDispatchInfo}, + ensure, + pallet_prelude::DispatchResult, + parameter_types, + traits::{ + fungible::{Balanced, Credit, HoldConsideration, Inspect}, + tokens::imbalance::ResolveTo, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, + EqualPrivilegeOnly, Imbalance, InstanceFilter, LinearStoragePrice, OnFinalize, + OnUnbalanced, + }, + weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, + }, + PalletId, +}; +use frame_system::{EnsureRoot, EnsureSigned}; +pub use moonbeam_core_primitives::{ + AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, + Index, Signature, +}; +use moonbeam_rpc_primitives_txpool::TxPoolResponse; +use moonbeam_runtime_common::{ + timestamp::{ConsensusHookWrapperForRelayTimestamp, RelayTimestamp}, + weights as moonriver_weights, +}; +use pallet_ethereum::Call::transact; +use pallet_ethereum::{PostLogContent, Transaction as EthereumTransaction}; +use pallet_evm::{ + Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot, + FeeCalculator, GasWeightMapping, IdentityAddressMapping, + OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner, +}; +pub use pallet_parachain_staking::{weights::WeightInfo, InflationInfo, Range}; +use pallet_transaction_payment::{FungibleAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_treasury::TreasuryAccountId; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_api::impl_runtime_apis; +use sp_consensus_slots::Slot; +use sp_core::{OpaqueMetadata, H160, H256, U256}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + serde::{Deserialize, Serialize}, + traits::{ + BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentityLookup, + PostDispatchInfoOf, UniqueSaturatedInto, Zero, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + }, + ApplyExtrinsicResult, DispatchErrorWithPostInfo, FixedPointNumber, Perbill, Permill, + Perquintill, SaturatedConversion, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; +use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; + +use smallvec::smallvec; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use nimbus_primitives::CanAuthor; + +pub use precompiles::{ + MoonriverPrecompiles, PrecompileName, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, +}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +pub type Precompiles = MoonriverPrecompiles; + +pub mod asset_config; +pub mod governance; +pub mod xcm_config; + +mod migrations; +mod precompiles; + +pub use governance::councils::*; + +/// MOVR, the native token, uses 18 decimals of precision. +pub mod currency { + use super::Balance; + + // Provide a common factor between runtimes based on a supply of 10_000_000 tokens. + pub const SUPPLY_FACTOR: Balance = 1; + + pub const WEI: Balance = 1; + pub const KILOWEI: Balance = 1_000; + pub const MEGAWEI: Balance = 1_000_000; + pub const GIGAWEI: Balance = 1_000_000_000; + pub const MICROMOVR: Balance = 1_000_000_000_000; + pub const MILLIMOVR: Balance = 1_000_000_000_000_000; + pub const MOVR: Balance = 1_000_000_000_000_000_000; + pub const KILOMOVR: Balance = 1_000_000_000_000_000_000_000; + + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; + pub const STORAGE_BYTE_FEE: Balance = 100 * MICROMOVR * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR / 4; + + pub const fn deposit(items: u32, bytes: u32) -> Balance { + items as Balance * 1 * MOVR * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE + } +} + +/// Maximum weight per block +pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX) + .saturating_mul(2) + .set_proof_size(relay_chain::MAX_POV_SIZE as u64); + +pub const MILLISECS_PER_BLOCK: u64 = 6_000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const WEEKS: BlockNumber = DAYS * 7; +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core datastructures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + pub type Block = generic::Block; + + impl_opaque_keys! { + pub struct SessionKeys { + pub nimbus: AuthorInherent, + pub vrf: session_keys_primitives::VrfSessionKey, + } + } +} + +/// This runtime version. +/// The spec_version is composed of 2x2 digits. The first 2 digits represent major changes +/// that can't be skipped, such as data migration upgrades. The last 2 digits represent minor +/// changes which can be skipped. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("moonriver"), + impl_name: create_runtime_str!("moonriver"), + authoring_version: 3, + spec_version: 3200, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 3, + state_version: 0, +}; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we +// subtract roughly the cost of a balance transfer from it (about 1/3 the cost) +// and some cost to account for per-byte-fee. +// TODO: we should use benchmarking's overhead feature to measure this +pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_parts(10000 * WEIGHT_PER_GAS, 0); + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> frame_system::limits::BlockWeights { + frame_system::limits::BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Provided BlockWeight definitions are valid, qed") + } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + /// We allow for 5 MB blocks. + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); +} + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Index; + /// The index type for blocks. + type Block = Block; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The output of the `Hashing` function. + type Hash = H256; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// The aggregated RuntimeTask type. + type RuntimeTask = RuntimeTask; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = ConstU32<256>; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type BlockWeights = RuntimeBlockWeights; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type BlockLength = BlockLength; + /// Runtime version. + type Version = Version; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = moonriver_weights::db::rocksdb::constants::RocksDbWeight; + type BaseCallFilter = MaintenanceMode; + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<1285>; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = moonriver_weights::pallet_utility::WeightInfo; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3000>; + type WeightInfo = moonriver_weights::pallet_timestamp::WeightInfo; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 0; +} + +impl pallet_balances::Config for Runtime { + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 4]; + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type WeightInfo = moonriver_weights::pallet_balances::WeightInfo; +} + +pub struct DealWithFees(sp_std::marker::PhantomData); +impl OnUnbalanced>> for DealWithFees +where + R: pallet_balances::Config + pallet_treasury::Config, +{ + // this seems to be called for substrate-based transactions + fn on_unbalanceds( + mut fees_then_tips: impl Iterator>>, + ) { + if let Some(fees) = fees_then_tips.next() { + // for fees, 80% are burned, 20% to the treasury + let (_, to_treasury) = fees.ration(80, 20); + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + + // handle tip if there is one + if let Some(tip) = fees_then_tips.next() { + // for now we use the same burn/treasury strategy used for regular fees + let (_, to_treasury) = tip.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced( + to_treasury, + ); + } + } + } + + // this is called from pallet_evm for Ethereum-based transactions + // (technically, it calls on_unbalanced, which calls this when non-zero) + fn on_nonzero_unbalanced(amount: Credit>) { + // Balances pallet automatically burns dropped Credits by decreasing + // total_supply accordingly + let (_, to_treasury) = amount.ration(80, 20); + ResolveTo::, pallet_balances::Pallet>::on_unbalanced(to_treasury); + } +} + +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1 * currency::SUPPLY_FACTOR, + negative: false, + }, + ] + } +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = FungibleAdapter>; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = ConstantMultiplier>; + type LengthToFee = LengthToFee; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; +} + +impl pallet_evm_chain_id::Config for Runtime {} + +/// Current approximation of the gas/s consumption considering +/// EVM execution over compiled WASM (on 4.4Ghz CPU). +/// Given the 2000ms Weight, from which 75% only are used for transactions, +/// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. +pub const GAS_PER_SECOND: u64 = 40_000_000; + +/// Approximate ratio of the amount of Weight per Gas. +/// u64 works for approximations because Weight is a very small unit compared to gas. +pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; + +parameter_types! { + pub BlockGasLimit: U256 + = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); + /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less + /// than this will decrease the weight and more will increase. + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); + /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to + /// change the fees more rapidly. This low value causes changes to occur slowly over time. + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); + /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure + /// that combined with `AdjustmentVariable`, we can recover from the minimum. + /// See `multiplier_can_grow_from_zero` in integration_tests.rs. + /// This value is currently only used by pallet-transaction-payment as an assertion that the + /// next multiplier is always > min value. + pub MinimumMultiplier: Multiplier = Multiplier::from(1u128); + /// Maximum multiplier. We pick a value that is expensive but not impossibly so; it should act + /// as a safety net. + pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128); + pub PrecompilesValue: MoonriverPrecompiles = MoonriverPrecompiles::<_>::new(); + pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0); + /// The amount of gas per pov. A ratio of 16 if we convert ref_time to gas and we compare + /// it with the pov_size for a block. E.g. + /// ceil( + /// (max_extrinsic.ref_time() / max_extrinsic.proof_size()) / WEIGHT_PER_GAS + /// ) + /// We should re-check `xcm_config::Erc20XcmBridgeTransferGasLimit` when changing this value + pub const GasLimitPovSizeRatio: u64 = 16; + /// The amount of gas per storage (in bytes): BLOCK_GAS_LIMIT / BLOCK_STORAGE_LIMIT + /// The current definition of BLOCK_STORAGE_LIMIT is 160 KB, resulting in a value of 366. + pub GasLimitStorageGrowthRatio: u64 = 366; +} + +pub struct TransactionPaymentAsGasPrice; +impl FeeCalculator for TransactionPaymentAsGasPrice { + fn min_gas_price() -> (U256, Weight) { + // note: transaction-payment differs from EIP-1559 in that its tip and length fees are not + // scaled by the multiplier, which means its multiplier will be overstated when + // applied to an ethereum transaction + // note: transaction-payment uses both a congestion modifier (next_fee_multiplier, which is + // updated once per block in on_finalize) and a 'WeightToFee' implementation. Our + // runtime implements this as a 'ConstantModifier', so we can get away with a simple + // multiplication here. + // It is imperative that `saturating_mul_int` be performed as late as possible in the + // expression since it involves fixed point multiplication with a division by a fixed + // divisor. This leads to truncation and subsequent precision loss if performed too early. + // This can lead to min_gas_price being same across blocks even if the multiplier changes. + // There's still some precision loss when the final `gas_price` (used_gas * min_gas_price) + // is computed in frontier, but that's currently unavoidable. + let min_gas_price = TransactionPayment::next_fee_multiplier() + .saturating_mul_int((currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128)); + ( + min_gas_price.into(), + ::DbWeight::get().reads(1), + ) + } +} + +/// Parameterized slow adjusting fee updated based on +/// https://w3f-research.readthedocs.io/en/latest/polkadot/overview/2-token-economics.html#-2.-slow-adjusting-mechanism // editorconfig-checker-disable-line +/// +/// The adjustment algorithm boils down to: +/// +/// diff = (previous_block_weight - target) / maximum_block_weight +/// next_multiplier = prev_multiplier * (1 + (v * diff) + ((v * diff)^2 / 2)) +/// assert(next_multiplier > min) +/// where: v is AdjustmentVariable +/// target is TargetBlockFullness +/// min is MinimumMultiplier +pub type SlowAdjustingFeeUpdate = TargetedFeeAdjustment< + R, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, +>; + +use frame_support::traits::FindAuthor; +//TODO It feels like this shold be able to work for any T: H160, but I tried for +// embarassingly long and couldn't figure that out. + +/// The author inherent provides a AccountId20, but pallet evm needs an H160. +/// This simple adapter makes the conversion. +pub struct FindAuthorAdapter(sp_std::marker::PhantomData); + +impl FindAuthor for FindAuthorAdapter +where + Inner: FindAuthor, +{ + fn find_author<'a, I>(digests: I) -> Option + where + I: 'a + IntoIterator, + { + Inner::find_author(digests).map(Into::into) + } +} + +moonbeam_runtime_common::impl_on_charge_evm_transaction!(); + +impl pallet_evm::Config for Runtime { + type FeeCalculator = TransactionPaymentAsGasPrice; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = IdentityAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = MoonriverPrecompiles; + type PrecompilesValue = PrecompilesValue; + type ChainId = EthereumChainId; + type OnChargeTransaction = OnChargeEVMTransaction>; + type BlockGasLimit = BlockGasLimit; + type FindAuthor = FindAuthorAdapter; + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = RelayTimestamp; + type WeightInfo = moonriver_weights::pallet_evm::WeightInfo; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<50>; + type WeightInfo = moonriver_weights::pallet_scheduler::WeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageBaseDeposit: Balance = 5 * currency::MOVR * currency::SUPPLY_FACTOR ; + pub const PreimageByteDeposit: Balance = currency::STORAGE_BYTE_FEE; + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = moonriver_weights::pallet_preimage::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const TreasuryId: PalletId = PalletId(*b"py/trsry"); + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +type TreasuryApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +type TreasuryRejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + // At least three-fifths majority of the council is required (or root) to approve a proposal + type ApproveOrigin = TreasuryApproveOrigin; + // More than half of the council is required (or root) to reject a proposal + type RejectOrigin = TreasuryRejectOrigin; + type RuntimeEvent = RuntimeEvent; + // If spending proposal rejected, transfer proposer bond to treasury + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ConstU128<{ 1 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type SpendPeriod = ConstU32<{ 6 * DAYS }>; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = ConstU32<100>; + type WeightInfo = moonriver_weights::pallet_treasury::WeightInfo; + type SpendFunds = (); + type ProposalBondMaximum = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Disabled, no spending + #[cfg(feature = "runtime-benchmarks")] + type SpendOrigin = + frame_system::EnsureWithSuccess, AccountId, benches::MaxBalance>; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +parameter_types! { + pub const MaxSubAccounts: u32 = 100; + pub const MaxAdditionalFields: u32 = 100; + pub const MaxRegistrars: u32 = 20; + pub const PendingUsernameExpiration: u32 = 7 * DAYS; + pub const MaxSuffixLength: u32 = 7; + pub const MaxUsernameLength: u32 = 32; +} + +type IdentityForceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type IdentityRegistrarOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_identity::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + // Add one item in storage and take 258 bytes + type BasicDeposit = ConstU128<{ currency::deposit(1, 258) }>; + // Does not add any item to the storage but takes 1 bytes + type ByteDeposit = ConstU128<{ currency::deposit(0, 1) }>; + // Add one item in storage and take 53 bytes + type SubAccountDeposit = ConstU128<{ currency::deposit(1, 53) }>; + type MaxSubAccounts = MaxSubAccounts; + type IdentityInformation = pallet_identity::legacy::IdentityInfo; + type MaxRegistrars = MaxRegistrars; + type Slashed = Treasury; + type ForceOrigin = IdentityForceOrigin; + type RegistrarOrigin = IdentityRegistrarOrigin; + type OffchainSignature = Signature; + type SigningPublicKey = ::Signer; + type UsernameAuthorityOrigin = EnsureRoot; + type PendingUsernameExpiration = PendingUsernameExpiration; + type MaxSuffixLength = MaxSuffixLength; + type MaxUsernameLength = MaxUsernameLength; + type WeightInfo = moonriver_weights::pallet_identity::WeightInfo; +} + +pub struct TransactionConverter; + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ) + } +} + +impl fp_rpc::ConvertTransaction for TransactionConverter { + fn convert_transaction( + &self, + transaction: pallet_ethereum::Transaction, + ) -> opaque::UncheckedExtrinsic { + let extrinsic = UncheckedExtrinsic::new_unsigned( + pallet_ethereum::Call::::transact { transaction }.into(), + ); + let encoded = extrinsic.encode(); + opaque::UncheckedExtrinsic::decode(&mut &encoded[..]) + .expect("Encoded extrinsic is always valid") + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will immediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; + +type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook< + Runtime, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = ParachainInfo; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = EmergencyParaXcm; + type ConsensusHook = ConsensusHookWrapperForRelayTimestamp; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = moonriver_weights::cumulus_pallet_parachain_system::WeightInfo; +} + +impl parachain_info::Config for Runtime {} + +pub struct OnNewRound; +impl pallet_parachain_staking::OnNewRound for OnNewRound { + fn on_new_round(round_index: pallet_parachain_staking::RoundIndex) -> Weight { + MoonbeamOrbiters::on_new_round(round_index) + } +} +pub struct PayoutCollatorOrOrbiterReward; +impl pallet_parachain_staking::PayoutCollatorReward for PayoutCollatorOrOrbiterReward { + fn payout_collator_reward( + for_round: pallet_parachain_staking::RoundIndex, + collator_id: AccountId, + amount: Balance, + ) -> Weight { + let extra_weight = + if MoonbeamOrbiters::is_collator_pool_with_active_orbiter(for_round, collator_id) { + MoonbeamOrbiters::distribute_rewards(for_round, collator_id, amount) + } else { + ParachainStaking::mint_collator_reward(for_round, collator_id, amount) + }; + + ::DbWeight::get() + .reads(1) + .saturating_add(extra_weight) + } +} + +pub struct OnInactiveCollator; +impl pallet_parachain_staking::OnInactiveCollator for OnInactiveCollator { + fn on_inactive_collator( + collator_id: AccountId, + round: pallet_parachain_staking::RoundIndex, + ) -> Result> { + let extra_weight = if !MoonbeamOrbiters::is_collator_pool_with_active_orbiter( + round, + collator_id.clone(), + ) { + ParachainStaking::go_offline_inner(collator_id)?; + ::WeightInfo::go_offline( + pallet_parachain_staking::MAX_CANDIDATES, + ) + } else { + Weight::zero() + }; + + Ok(::DbWeight::get() + .reads(1) + .saturating_add(extra_weight)) + } +} + +type MonetaryGovernanceOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +pub struct RelayChainSlotProvider; +impl Get for RelayChainSlotProvider { + fn get() -> Slot { + let slot_info = pallet_async_backing::pallet::Pallet::::slot_info(); + slot_info.unwrap_or_default().0 + } +} + +impl pallet_parachain_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = MonetaryGovernanceOrigin; + /// Minimum round length is 2 minutes (10 * 12 second block times) + type MinBlocksPerRound = ConstU32<10>; + /// If a collator doesn't produce any block on this number of rounds, it is notified as inactive + type MaxOfflineRounds = ConstU32<2>; + /// Rounds before the collator leaving the candidates request can be executed + type LeaveCandidatesDelay = ConstU32<24>; + /// Rounds before the candidate bond increase/decrease can be executed + type CandidateBondLessDelay = ConstU32<24>; + /// Rounds before the delegator exit can be executed + type LeaveDelegatorsDelay = ConstU32<24>; + /// Rounds before the delegator revocation can be executed + type RevokeDelegationDelay = ConstU32<24>; + /// Rounds before the delegator bond increase/decrease can be executed + type DelegationBondLessDelay = ConstU32<24>; + /// Rounds before the reward is paid + type RewardPaymentDelay = ConstU32<2>; + /// Minimum collators selected per round, default at genesis and minimum forever after + type MinSelectedCandidates = ConstU32<8>; + /// Maximum top delegations per candidate + type MaxTopDelegationsPerCandidate = ConstU32<300>; + /// Maximum bottom delegations per candidate + type MaxBottomDelegationsPerCandidate = ConstU32<50>; + /// Maximum delegations per delegator + type MaxDelegationsPerDelegator = ConstU32<100>; + /// Minimum stake required to be reserved to be a candidate + type MinCandidateStk = ConstU128<{ 500 * currency::MOVR * currency::SUPPLY_FACTOR }>; + /// Minimum stake required to be reserved to be a delegator + type MinDelegation = ConstU128<{ 5 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type BlockAuthor = AuthorInherent; + type OnCollatorPayout = (); + type PayoutCollatorReward = PayoutCollatorOrOrbiterReward; + type OnInactiveCollator = OnInactiveCollator; + type OnNewRound = OnNewRound; + type SlotProvider = RelayChainSlotProvider; + type WeightInfo = moonriver_weights::pallet_parachain_staking::WeightInfo; + type MaxCandidates = ConstU32<200>; + type SlotDuration = ConstU64<6_000>; + type BlockTime = ConstU64<6_000>; +} + +impl pallet_author_inherent::Config for Runtime { + type SlotBeacon = RelaychainDataProvider; + type AccountLookup = MoonbeamOrbiters; + type CanAuthor = AuthorFilter; + type AuthorId = AccountId; + type WeightInfo = moonriver_weights::pallet_author_inherent::WeightInfo; +} + +impl pallet_author_slot_filter::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RandomnessSource = Randomness; + type PotentialAuthors = ParachainStaking; + type WeightInfo = moonriver_weights::pallet_author_slot_filter::WeightInfo; +} + +impl pallet_async_backing::Config for Runtime { + type AllowMultipleBlocksPerSlot = ConstBool; + type GetAndVerifySlot = pallet_async_backing::RelaySlot; + type ExpectedBlockTime = ConstU64<6000>; +} + +parameter_types! { + pub const InitializationPayment: Perbill = Perbill::from_percent(30); + pub const RelaySignaturesThreshold: Perbill = Perbill::from_percent(100); + pub const SignatureNetworkIdentifier: &'static [u8] = b"moonriver-"; + +} + +impl pallet_crowdloan_rewards::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Initialized = ConstBool; + type InitializationPayment = InitializationPayment; + type MaxInitContributors = ConstU32<500>; + type MinimumReward = ConstU128<0>; + type RewardCurrency = Balances; + type RelayChainAccountId = [u8; 32]; + type RewardAddressAssociateOrigin = EnsureSigned; + type RewardAddressChangeOrigin = EnsureSigned; + type RewardAddressRelayVoteThreshold = RelaySignaturesThreshold; + type SignatureNetworkIdentifier = SignatureNetworkIdentifier; + type VestingBlockNumber = relay_chain::BlockNumber; + type VestingBlockProvider = RelaychainDataProvider; + type WeightInfo = moonriver_weights::pallet_crowdloan_rewards::WeightInfo; +} + +// This is a simple session key manager. It should probably either work with, or be replaced +// entirely by pallet sessions +impl pallet_author_mapping::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DepositCurrency = Balances; + type DepositAmount = ConstU128<{ 100 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type Keys = session_keys_primitives::VrfId; + type WeightInfo = moonriver_weights::pallet_author_mapping::WeightInfo; +} + +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + Debug, + MaxEncodedLen, + TypeInfo, + Serialize, + Deserialize, +)] +pub enum ProxyType { + /// All calls can be proxied. This is the trivial/most permissive filter. + Any = 0, + /// Only extrinsics that do not transfer funds. + NonTransfer = 1, + /// Only extrinsics related to governance (democracy and collectives). + Governance = 2, + /// Only extrinsics related to staking. + Staking = 3, + /// Allow to veto an announced proxy call. + CancelProxy = 4, + /// Allow extrinsic related to Balances. + Balances = 5, + /// Allow extrinsic related to AuthorMapping. + AuthorMapping = 6, + /// Allow extrinsic related to IdentityJudgement. + IdentityJudgement = 7, +} + +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +fn is_governance_precompile(precompile_name: &precompiles::PrecompileName) -> bool { + matches!( + precompile_name, + PrecompileName::TreasuryCouncilInstance + | PrecompileName::PreimagePrecompile + | PrecompileName::ReferendaPrecompile + | PrecompileName::ConvictionVotingPrecompile + | PrecompileName::OpenTechCommitteeInstance + ) +} + +// Be careful: Each time this filter is modified, the substrate filter must also be modified +// consistently. +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType { + fn is_evm_proxy_call_allowed( + &self, + call: &pallet_evm_precompile_proxy::EvmSubCall, + recipient_has_code: bool, + gas: u64, + ) -> precompile_utils::EvmResult { + Ok(match self { + ProxyType::Any => { + match PrecompileName::from_address(call.to.0) { + // Any precompile that can execute a subcall should be forbidden here, + // to ensure that unauthorized smart contract can't be called + // indirectly. + // To be safe, we only allow the precompiles we need. + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + // All non-whitelisted precompiles are forbidden + Some(_) => false, + // Allow evm transfer to "simple" account (no code nor precompile) + // For the moment, no smart contract other than precompiles is allowed. + // In the future, we may create a dynamic whitelist to authorize some audited + // smart contracts through governance. + None => { + // If the address is not recognized, allow only evm transfert to "simple" + // accounts (no code nor precompile). + // Note: Checking the presence of the code is not enough because some + // precompiles have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + } + } + ProxyType::NonTransfer => { + call.value == U256::zero() + && match PrecompileName::from_address(call.to.0) { + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile, + ) => true, + Some(ref precompile) if is_governance_precompile(precompile) => true, + _ => false, + } + } + ProxyType::Governance => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(ref precompile) if is_governance_precompile(precompile) + ) + } + ProxyType::Staking => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some( + PrecompileName::AuthorMappingPrecompile + | PrecompileName::ParachainStakingPrecompile + ) + ) + } + // The proxy precompile does not contain method cancel_proxy + ProxyType::CancelProxy => false, + ProxyType::Balances => { + // Allow only "simple" accounts as recipient (no code nor precompile). + // Note: Checking the presence of the code is not enough because some precompiles + // have no code. + !recipient_has_code + && !precompile_utils::precompile_set::is_precompile_or_fail::( + call.to.0, gas, + )? + } + ProxyType::AuthorMapping => { + call.value == U256::zero() + && matches!( + PrecompileName::from_address(call.to.0), + Some(PrecompileName::AuthorMappingPrecompile) + ) + } + // There is no identity precompile + ProxyType::IdentityJudgement => false, + }) + } +} + +// Be careful: Each time this filter is modified, the EVM filter must also be modified consistently. +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => { + matches!( + c, + RuntimeCall::System(..) + | RuntimeCall::ParachainSystem(..) + | RuntimeCall::Timestamp(..) + | RuntimeCall::ParachainStaking(..) + | RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Identity(..) + | RuntimeCall::Utility(..) + | RuntimeCall::Proxy(..) | RuntimeCall::AuthorMapping(..) + | RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::claim { .. } + ) + ) + } + ProxyType::Governance => matches!( + c, + RuntimeCall::Referenda(..) + | RuntimeCall::Preimage(..) + | RuntimeCall::ConvictionVoting(..) + | RuntimeCall::TreasuryCouncilCollective(..) + | RuntimeCall::OpenTechCommitteeCollective(..) + | RuntimeCall::Utility(..) + ), + ProxyType::Staking => matches!( + c, + RuntimeCall::ParachainStaking(..) + | RuntimeCall::Utility(..) + | RuntimeCall::AuthorMapping(..) + | RuntimeCall::MoonbeamOrbiters(..) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) + ), + ProxyType::Balances => { + matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + } + ProxyType::AuthorMapping => matches!(c, RuntimeCall::AuthorMapping(..)), + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) + | RuntimeCall::Utility(..) + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + _ => false, + } + } +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + // One storage item; key size 32, value size 8 + type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)). + type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>; + type MaxProxies = ConstU32<32>; + type WeightInfo = moonriver_weights::pallet_proxy::WeightInfo; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>; + // Additional storage item size of 56 bytes: + // - 20 bytes AccountId + // - 32 bytes Hasher (Blake2256) + // - 4 bytes BlockNumber (u32) + type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MigrationsList = ( + moonbeam_runtime_common::migrations::CommonMigrations, + migrations::MoonriverMigrations, + ); + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_moonbeam_lazy_migrations::Config for Runtime { + type WeightInfo = moonriver_weights::pallet_moonbeam_lazy_migrations::WeightInfo; +} + +/// Maintenance mode Call filter +pub struct MaintenanceFilter; +impl Contains for MaintenanceFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(_) => false, + RuntimeCall::Balances(_) => false, + RuntimeCall::CrowdloanRewards(_) => false, + RuntimeCall::Ethereum(_) => false, + RuntimeCall::EVM(_) => false, + RuntimeCall::Identity(_) => false, + RuntimeCall::XTokens(_) => false, + RuntimeCall::ParachainStaking(_) => false, + RuntimeCall::MoonbeamOrbiters(_) => false, + RuntimeCall::PolkadotXcm(_) => false, + RuntimeCall::Treasury(_) => false, + RuntimeCall::XcmTransactor(_) => false, + RuntimeCall::EthereumXcm(_) => false, + _ => true, + } + } +} + +/// Normal Call Filter +/// We dont allow to create nor mint assets, this for now is disabled +/// We only allow transfers. For now creation of assets will go through +/// asset-manager, while minting/burning only happens through xcm messages +/// This can change in the future +pub struct NormalFilter; +impl Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + RuntimeCall::Assets(method) => match method { + pallet_assets::Call::transfer { .. } => true, + pallet_assets::Call::transfer_keep_alive { .. } => true, + pallet_assets::Call::approve_transfer { .. } => true, + pallet_assets::Call::transfer_approved { .. } => true, + pallet_assets::Call::cancel_approval { .. } => true, + pallet_assets::Call::destroy_accounts { .. } => true, + pallet_assets::Call::destroy_approvals { .. } => true, + pallet_assets::Call::finish_destroy { .. } => true, + _ => false, + }, + // We just want to enable this in case of live chains, since the default version + // is populated at genesis + RuntimeCall::PolkadotXcm(method) => match method { + pallet_xcm::Call::force_default_xcm_version { .. } => true, + _ => false, + }, + // We filter anonymous proxy as they make "reserve" inconsistent + // See: https://github.com/paritytech/substrate/blob/37cca710eed3dadd4ed5364c7686608f5175cce1/frame/proxy/src/lib.rs#L270 // editorconfig-checker-disable-line + RuntimeCall::Proxy(method) => match method { + pallet_proxy::Call::create_pure { .. } => false, + pallet_proxy::Call::kill_pure { .. } => false, + pallet_proxy::Call::proxy { real, .. } => { + !pallet_evm::AccountCodes::::contains_key(H160::from(*real)) + } + _ => true, + }, + // Filtering the EVM prevents possible re-entrancy from the precompiles which could + // lead to unexpected scenarios. + // See https://github.com/PureStake/sr-moonbeam/issues/30 + // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so + // this can be seen as an additional security + RuntimeCall::EVM(_) => false, + RuntimeCall::Treasury( + pallet_treasury::Call::spend { .. } + | pallet_treasury::Call::payout { .. } + | pallet_treasury::Call::check_status { .. } + | pallet_treasury::Call::void_spend { .. }, + ) => false, + _ => true, + } + } +} + +pub struct XcmExecutionManager; +impl moonkit_xcm_primitives::PauseXcmExecution for XcmExecutionManager { + fn suspend_xcm_execution() -> DispatchResult { + XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root()) + } + fn resume_xcm_execution() -> DispatchResult { + XcmpQueue::resume_xcm_execution(RuntimeOrigin::root()) + } +} + +impl pallet_maintenance_mode::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type NormalCallFilter = NormalFilter; + type MaintenanceCallFilter = MaintenanceFilter; + type MaintenanceOrigin = + pallet_collective::EnsureProportionAtLeast; + type XcmExecutionManager = XcmExecutionManager; +} + +impl pallet_proxy_genesis_companion::Config for Runtime { + type ProxyType = ProxyType; +} + +parameter_types! { + pub OrbiterReserveIdentifier: [u8; 4] = [b'o', b'r', b'b', b'i']; +} + +type AddCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; +type DelCollatorOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_moonbeam_orbiters::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountLookup = AuthorMapping; + type AddCollatorOrigin = AddCollatorOrigin; + type Currency = Balances; + type DelCollatorOrigin = DelCollatorOrigin; + /// Maximum number of orbiters per collator + type MaxPoolSize = ConstU32<8>; + /// Maximum number of round to keep on storage + type MaxRoundArchive = ConstU32<4>; + type OrbiterReserveIdentifier = OrbiterReserveIdentifier; + type RotatePeriod = ConstU32<3>; + /// Round index type. + type RoundIndex = pallet_parachain_staking::RoundIndex; + type WeightInfo = moonriver_weights::pallet_moonbeam_orbiters::WeightInfo; +} + +/// Only callable after `set_validation_data` is called which forms this proof the same way +fn relay_chain_state_proof() -> RelayChainStateProof +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + let relay_storage_root = ValidationData::::get() + .expect("set in `set_validation_data`") + .relay_parent_storage_root; + let relay_chain_state = + RelayStateProof::::get().expect("set in `set_validation_data`"); + RelayChainStateProof::new(ParachainInfo::get(), relay_storage_root, relay_chain_state) + .expect("Invalid relay chain state proof, already constructed in `set_validation_data`") +} + +pub struct BabeDataGetter(sp_std::marker::PhantomData); +impl pallet_randomness::GetBabeData> for BabeDataGetter +where + Runtime: cumulus_pallet_parachain_system::Config, +{ + // Tolerate panic here because only ever called in inherent (so can be omitted) + fn get_epoch_index() -> u64 { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + const BENCHMARKING_NEW_EPOCH: u64 = 10u64; + return BENCHMARKING_NEW_EPOCH; + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::EPOCH_INDEX) + .ok() + .flatten() + .expect("expected to be able to read epoch index from relay chain state proof") + } + fn get_epoch_randomness() -> Option { + if cfg!(feature = "runtime-benchmarks") { + // storage reads as per actual reads + let _relay_storage_root = ValidationData::::get(); + let _relay_chain_state = RelayStateProof::::get(); + let benchmarking_babe_output = Hash::default(); + return Some(benchmarking_babe_output); + } + relay_chain_state_proof::() + .read_optional_entry(relay_chain::well_known_keys::ONE_EPOCH_AGO_RANDOMNESS) + .ok() + .flatten() + } +} + +impl pallet_randomness::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddressMapping = sp_runtime::traits::ConvertInto; + type Currency = Balances; + type BabeDataGetter = BabeDataGetter; + type VrfKeyLookup = AuthorMapping; + type Deposit = ConstU128<{ 1 * currency::MOVR * currency::SUPPLY_FACTOR }>; + type MaxRandomWords = ConstU8<100>; + type MinBlockDelay = ConstU32<2>; + type MaxBlockDelay = ConstU32<2_000>; + type BlockExpirationDelay = ConstU32<10_000>; + type EpochExpirationDelay = ConstU64<10_000>; + type WeightInfo = moonriver_weights::pallet_randomness::WeightInfo; +} + +impl pallet_root_testing::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +parameter_types! { + // One storage item; key size is 32 + 20; value is size 4+4+16+20 bytes = 44 bytes. + pub const DepositBase: Balance = currency::deposit(1, 96); + // Additional storage item size of 20 bytes. + pub const DepositFactor: Balance = currency::deposit(0, 20); + pub const MaxSignatories: u32 = 100; +} + +impl pallet_multisig::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = moonriver_weights::pallet_multisig::WeightInfo; +} + +impl pallet_relay_storage_roots::Config for Runtime { + type MaxStorageRoots = ConstU32<30>; + type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider; + type WeightInfo = moonriver_weights::pallet_relay_storage_roots::WeightInfo; +} + +impl pallet_precompile_benchmarks::Config for Runtime { + type WeightInfo = moonriver_weights::pallet_precompile_benchmarks::WeightInfo; +} + +construct_runtime! { + pub enum Runtime + { + // System support stuff. + System: frame_system::{Pallet, Call, Storage, Config, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 1, + // Previously 2: pallet_randomness_collective_flip + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + RootTesting: pallet_root_testing::{Pallet, Call, Storage, Event} = 5, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Config, Event} = 11, + + // Consensus support. + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 20, + AuthorInherent: pallet_author_inherent::{Pallet, Call, Storage, Inherent} = 21, + AuthorFilter: pallet_author_slot_filter::{Pallet, Call, Storage, Event, Config} = 22, + AuthorMapping: pallet_author_mapping::{Pallet, Call, Config, Storage, Event} = 23, + MoonbeamOrbiters: pallet_moonbeam_orbiters::{Pallet, Call, Storage, Event} = 24, + AsyncBacking: pallet_async_backing::{Pallet, Storage} = 25, + + // Handy utilities. + Utility: pallet_utility::{Pallet, Call, Event} = 30, + Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 31, + MaintenanceMode: pallet_maintenance_mode::{Pallet, Call, Config, Storage, Event} = 32, + Identity: pallet_identity::{Pallet, Call, Storage, Event} = 33, + Migrations: pallet_migrations::{Pallet, Storage, Config, Event} = 34, + ProxyGenesisCompanion: pallet_proxy_genesis_companion::{Pallet, Config} = 35, + Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 36, + MoonbeamLazyMigrations: pallet_moonbeam_lazy_migrations::{Pallet, Call, Storage} = 37, + + // Sudo was previously index 40 + + // Ethereum compatibility + EthereumChainId: pallet_evm_chain_id::{Pallet, Storage, Config} = 50, + EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 51, + Ethereum: pallet_ethereum::{Pallet, Call, Storage, Event, Origin, Config} = 52, + + // Governance stuff. + Scheduler: pallet_scheduler::{Pallet, Storage, Event, Call} = 60, + // Democracy: 61, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 62, + ConvictionVoting: pallet_conviction_voting::{Pallet, Call, Storage, Event} = 63, + Referenda: pallet_referenda::{Pallet, Call, Storage, Event} = 64, + Origins: governance::custom_origins::{Origin} = 65, + Whitelist: pallet_whitelist::{Pallet, Call, Storage, Event} = 66, + + // Council stuff. + // CouncilCollective: 70 + // TechCommitteeCollective: 71, + TreasuryCouncilCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 72, + OpenTechCommitteeCollective: + pallet_collective::::{Pallet, Call, Storage, Event, Origin, Config} = 73, + + // Treasury stuff. + Treasury: pallet_treasury::{Pallet, Storage, Config, Event, Call} = 80, + + // Crowdloan stuff. + CrowdloanRewards: pallet_crowdloan_rewards::{Pallet, Call, Config, Storage, Event} = 90, + + // XCM Stuff + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Storage, Event} = 100, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 101, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 102, + PolkadotXcm: pallet_xcm::{Pallet, Storage, Call, Event, Origin, Config} = 103, + Assets: pallet_assets::{Pallet, Call, Storage, Event} = 104, + AssetManager: pallet_asset_manager::{Pallet, Call, Storage, Event} = 105, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event} = 106, + XcmTransactor: pallet_xcm_transactor::{Pallet, Call, Storage, Event} = 107, + // Previously 108: pallet_assets:: + EthereumXcm: pallet_ethereum_xcm::{Pallet, Call, Storage, Origin, Event} = 109, + Erc20XcmBridge: pallet_erc20_xcm_bridge::{Pallet} = 110, + MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 111, + EvmForeignAssets: pallet_moonbeam_foreign_assets::{Pallet, Call, Storage, Event} = 114, + XcmWeightTrader: pallet_xcm_weight_trader::{Pallet, Call, Storage, Event} = 115, + EmergencyParaXcm: pallet_emergency_para_xcm::{Pallet, Call, Storage, Event} = 116, + + // Utils + RelayStorageRoots: pallet_relay_storage_roots::{Pallet, Storage} = 112, + PrecompileBenchmarks: pallet_precompile_benchmarks::{Pallet} = 113, + + // Randomness + Randomness: pallet_randomness::{Pallet, Call, Storage, Event, Inherent} = 120, + } +} + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +mod benches { + frame_support::parameter_types! { + pub const MaxBalance: crate::Balance = crate::Balance::max_value(); + } + + frame_benchmarking::define_benchmarks!( + [pallet_utility, Utility] + [pallet_timestamp, Timestamp] + [pallet_balances, Balances] + [pallet_evm, EVM] + [pallet_assets, Assets] + [pallet_parachain_staking, ParachainStaking] + [pallet_scheduler, Scheduler] + [pallet_treasury, Treasury] + [pallet_author_inherent, AuthorInherent] + [pallet_author_slot_filter, AuthorFilter] + [pallet_crowdloan_rewards, CrowdloanRewards] + [pallet_author_mapping, AuthorMapping] + [pallet_proxy, Proxy] + [pallet_identity, Identity] + [cumulus_pallet_parachain_system, ParachainSystem] + [cumulus_pallet_xcmp_queue, XcmpQueue] + [pallet_message_queue, MessageQueue] + [pallet_xcm, PalletXcmExtrinsicsBenchmark::] + [pallet_asset_manager, AssetManager] + [pallet_xcm_transactor, XcmTransactor] + [pallet_moonbeam_orbiters, MoonbeamOrbiters] + [pallet_randomness, Randomness] + [pallet_conviction_voting, ConvictionVoting] + [pallet_referenda, Referenda] + [pallet_preimage, Preimage] + [pallet_whitelist, Whitelist] + [pallet_multisig, Multisig] + [pallet_moonbeam_lazy_migrations, MoonbeamLazyMigrations] + [pallet_relay_storage_roots, RelayStorageRoots] + ); +} + +/// Block type as expected by this runtime. +pub type Block = generic::Block; +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + frame_metadata_hash_extension::CheckMetadataHash, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + fp_self_contained::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = + fp_self_contained::CheckedExtrinsic; +/// Executive: handles dispatch to the various pallets. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +// All of our runtimes share most of their Runtime API implementations. +// We use a macro to implement this common part and add runtime-specific additional implementations. +// This macro expands to : +// ``` +// impl_runtime_apis! { +// // All impl blocks shared between all runtimes. +// +// // Specific impls provided to the `impl_runtime_apis_plus_common!` macro. +// } +// ``` +moonbeam_runtime_common::impl_runtime_apis_plus_common! { + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + xt: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + // Filtered calls should not enter the tx pool as they'll fail if inserted. + // If this call is not allowed, we return early. + if !::BaseCallFilter::contains(&xt.0.function) { + return InvalidTransaction::Call.into(); + } + + // This runtime uses Substrate's pallet transaction payment. This + // makes the chain feel like a standard Substrate chain when submitting + // frame transactions and using Substrate ecosystem tools. It has the downside that + // transaction are not prioritized by gas_price. The following code reprioritizes + // transactions to overcome this. + // + // A more elegant, ethereum-first solution is + // a pallet that replaces pallet transaction payment, and allows users + // to directly specify a gas price rather than computing an effective one. + // #HopefullySomeday + + // First we pass the transactions to the standard FRAME executive. This calculates all the + // necessary tags, longevity and other properties that we will leave unchanged. + // This also assigns some priority that we don't care about and will overwrite next. + let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?; + + let dispatch_info = xt.get_dispatch_info(); + + // If this is a pallet ethereum transaction, then its priority is already set + // according to gas price from pallet ethereum. If it is any other kind of transaction, + // we modify its priority. + Ok(match &xt.0.function { + RuntimeCall::Ethereum(transact { .. }) => intermediate_valid, + _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid, + _ => { + let tip = match xt.0.signature { + None => 0, + Some((_, _, ref signed_extra)) => { + // Yuck, this depends on the index of charge transaction in Signed Extra + let charge_transaction = &signed_extra.7; + charge_transaction.tip() + } + }; + + // Calculate the fee that will be taken by pallet transaction payment + let fee: u64 = TransactionPayment::compute_fee( + xt.encode().len() as u32, + &dispatch_info, + tip, + ).saturated_into(); + + // Calculate how much gas this effectively uses according to the existing mapping + let effective_gas = + ::GasWeightMapping::weight_to_gas( + dispatch_info.weight + ); + + // Here we calculate an ethereum-style effective gas price using the + // current fee of the transaction. Because the weight -> gas conversion is + // lossy, we have to handle the case where a very low weight maps to zero gas. + let effective_gas_price = if effective_gas > 0 { + fee / effective_gas + } else { + // If the effective gas was zero, we just act like it was 1. + fee + }; + + // Overwrite the original prioritization with this ethereum one + intermediate_valid.priority = effective_gas_price; + intermediate_valid + } + }) + } + } + + impl async_backing_primitives::UnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: async_backing_primitives::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } +} + +struct CheckInherents; + +// Parity has decided to depreciate this trait, but does not offer a satisfactory replacement, +// see issue: https://github.com/paritytech/polkadot-sdk/issues/2841 +#[allow(deprecated)] +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + inherent_data.check_extrinsics(block) + } +} + +// Nimbus's Executive wrapper allows relay validators to verify the seal digest +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = pallet_author_inherent::BlockExecutor::, + CheckInherents = CheckInherents, +); + +moonbeam_runtime_common::impl_self_contained_call!(); + +// Shorthand for a Get field of a pallet Config. +#[macro_export] +macro_rules! get { + ($pallet:ident, $name:ident, $type:ty) => { + <<$crate::Runtime as $pallet::Config>::$name as $crate::Get<$type>>::get() + }; +} + +#[cfg(test)] +mod tests { + use super::{currency::*, *}; + + #[test] + // Helps us to identify a Pallet Call in case it exceeds the 1kb limit. + // Hint: this should be a rare case. If that happens, one or more of the dispatchable arguments + // need to be Boxed. + fn call_max_size() { + const CALL_ALIGN: u32 = 1024; + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() <= CALL_ALIGN as usize + ); + assert!(std::mem::size_of::>() <= CALL_ALIGN as usize); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + assert!( + std::mem::size_of::>() + <= CALL_ALIGN as usize + ); + } + + #[test] + fn currency_constants_are_correct() { + assert_eq!(SUPPLY_FACTOR, 1); + + // txn fees + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(1 * GIGAWEI)); + assert_eq!( + get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), + 5_u8 + ); + assert_eq!(STORAGE_BYTE_FEE, Balance::from(100 * MICROMOVR)); + + // treasury minimums + assert_eq!( + get!(pallet_treasury, ProposalBondMinimum, u128), + Balance::from(1 * MOVR) + ); + + // pallet_identity deposits + assert_eq!( + get!(pallet_identity, BasicDeposit, u128), + Balance::from(1 * MOVR + 25800 * MICROMOVR) + ); + assert_eq!( + get!(pallet_identity, ByteDeposit, u128), + Balance::from(100 * MICROMOVR) + ); + assert_eq!( + get!(pallet_identity, SubAccountDeposit, u128), + Balance::from(1 * MOVR + 5300 * MICROMOVR) + ); + + // staking minimums + assert_eq!( + get!(pallet_parachain_staking, MinCandidateStk, u128), + Balance::from(500 * MOVR) + ); + assert_eq!( + get!(pallet_parachain_staking, MinDelegation, u128), + Balance::from(5 * MOVR) + ); + + // crowdloan min reward + assert_eq!( + get!(pallet_crowdloan_rewards, MinimumReward, u128), + Balance::from(0u128) + ); + + // deposit for AuthorMapping + assert_eq!( + get!(pallet_author_mapping, DepositAmount, u128), + Balance::from(100 * MOVR) + ); + + // proxy deposits + assert_eq!( + get!(pallet_proxy, ProxyDepositBase, u128), + Balance::from(1 * MOVR + 800 * MICROMOVR) + ); + assert_eq!( + get!(pallet_proxy, ProxyDepositFactor, u128), + Balance::from(2100 * MICROMOVR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositBase, u128), + Balance::from(1 * MOVR + 800 * MICROMOVR) + ); + assert_eq!( + get!(pallet_proxy, AnnouncementDepositFactor, u128), + Balance::from(5600 * MICROMOVR) + ); + } + + #[test] + fn max_offline_rounds_lower_or_eq_than_reward_payment_delay() { + assert!( + get!(pallet_parachain_staking, MaxOfflineRounds, u32) + <= get!(pallet_parachain_staking, RewardPaymentDelay, u32) + ); + } + + #[test] + // Required migration is + // pallet_parachain_staking::migrations::IncreaseMaxTopDelegationsPerCandidate + // Purpose of this test is to remind of required migration if constant is ever changed + fn updating_maximum_delegators_per_candidate_requires_configuring_required_migration() { + assert_eq!( + get!(pallet_parachain_staking, MaxTopDelegationsPerCandidate, u32), + 300 + ); + assert_eq!( + get!( + pallet_parachain_staking, + MaxBottomDelegationsPerCandidate, + u32 + ), + 50 + ); + } + + #[test] + fn configured_base_extrinsic_weight_is_evm_compatible() { + let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000; + let base_extrinsic = ::BlockWeights::get() + .get(frame_support::dispatch::DispatchClass::Normal) + .base_extrinsic; + assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); + } + + #[test] + fn test_storage_growth_ratio_is_correct() { + // This is the highest amount of new storage that can be created in a block 40 KB + let block_storage_limit = 160 * 1024; + let expected_storage_growth_ratio = BlockGasLimit::get() + .low_u64() + .saturating_div(block_storage_limit); + let actual_storage_growth_ratio = + ::GasLimitStorageGrowthRatio::get(); + assert_eq!( + expected_storage_growth_ratio, actual_storage_growth_ratio, + "Storage growth ratio is not correct" + ); + } +} diff --git a/tracing/3200/runtime/moonriver/src/migrations.rs b/tracing/3200/runtime/moonriver/src/migrations.rs new file mode 100644 index 00000000..bea77819 --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/migrations.rs @@ -0,0 +1,31 @@ +// Copyright 2024 Moonbeam Foundation Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! # Moonriver specific Migrations + +use pallet_migrations::{GetMigrations, Migration}; +use sp_std::{prelude::*, vec}; + +pub struct MoonriverMigrations; + +impl GetMigrations for MoonriverMigrations { + fn get_migrations() -> Vec> { + vec![ + // Runtime 3000 + // Box::new(PalletStakingMultiplyRoundLenBy2) + ] + } +} diff --git a/tracing/3200/runtime/moonriver/src/precompiles.rs b/tracing/3200/runtime/moonriver/src/precompiles.rs new file mode 100644 index 00000000..a7106e4a --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/precompiles.rs @@ -0,0 +1,269 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use crate::{ + asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, OpenTechCommitteeInstance, + Runtime, TreasuryCouncilInstance, +}; +use frame_support::parameter_types; +use moonbeam_runtime_common::weights as moonriver_weights; +use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; +use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; +use pallet_evm_precompile_batch::BatchPrecompile; +use pallet_evm_precompile_blake2::Blake2F; +use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; +use pallet_evm_precompile_call_permit::CallPermitPrecompile; +use pallet_evm_precompile_collective::CollectivePrecompile; +use pallet_evm_precompile_conviction_voting::ConvictionVotingPrecompile; +use pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompile; +use pallet_evm_precompile_gmp::GmpPrecompile; +use pallet_evm_precompile_identity::IdentityPrecompile; +use pallet_evm_precompile_modexp::Modexp; +use pallet_evm_precompile_p256verify::P256Verify; +use pallet_evm_precompile_parachain_staking::ParachainStakingPrecompile; +use pallet_evm_precompile_preimage::PreimagePrecompile; +use pallet_evm_precompile_proxy::{OnlyIsProxyAndProxy, ProxyPrecompile}; +use pallet_evm_precompile_randomness::RandomnessPrecompile; +use pallet_evm_precompile_referenda::ReferendaPrecompile; +use pallet_evm_precompile_registry::PrecompileRegistry; +use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; +use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; +use pallet_evm_precompile_sha3fips::Sha3FIPS256; +use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_xcm_transactor::{ + v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, +}; +use pallet_evm_precompile_xcm_utils::XcmUtilsPrecompile; +use pallet_evm_precompile_xtokens::XtokensPrecompile; +use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; +use pallet_precompile_benchmarks::WeightInfo; +use precompile_utils::precompile_set::*; + +parameter_types! { + pub P256VerifyWeight: frame_support::weights::Weight = + moonriver_weights::pallet_precompile_benchmarks::WeightInfo::::p256_verify(); +} + +pub struct NativeErc20Metadata; + +/// ERC20 metadata for the native token. +impl Erc20Metadata for NativeErc20Metadata { + /// Returns the name of the token. + fn name() -> &'static str { + "MOVR token" + } + + /// Returns the symbol of the token. + fn symbol() -> &'static str { + "MOVR" + } + + /// Returns the decimals places of the token. + fn decimals() -> u8 { + 18 + } + + /// Must return `true` only if it represents the main native currency of + /// the network. It must be the currency used in `pallet_evm`. + fn is_native_currency() -> bool { + true + } +} + +/// The asset precompile address prefix. Addresses that match against this prefix will be routed +/// to Erc20AssetsPrecompileSet being marked as foreign +pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; + +parameter_types! { + pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; +} + +type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); + +#[precompile_utils::precompile_name_from_address] +type MoonriverPrecompilesAt = ( + // Ethereum precompiles: + // We allow DELEGATECALL to stay compliant with Ethereum behavior. + PrecompileAt, ECRecover, EthereumPrecompilesChecks>, + PrecompileAt, Sha256, EthereumPrecompilesChecks>, + PrecompileAt, Ripemd160, EthereumPrecompilesChecks>, + PrecompileAt, Identity, EthereumPrecompilesChecks>, + PrecompileAt, Modexp, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Add, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Mul, EthereumPrecompilesChecks>, + PrecompileAt, Bn128Pairing, EthereumPrecompilesChecks>, + PrecompileAt, Blake2F, EthereumPrecompilesChecks>, + // (0x100 => 256) https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + PrecompileAt, P256Verify, EthereumPrecompilesChecks>, + // Non-Moonbeam specific nor Ethereum precompiles : + PrecompileAt, Sha3FIPS256, (CallableByContract, CallableByPrecompile)>, + RemovedPrecompileAt>, // Dispatch + PrecompileAt, ECRecoverPublicKey, (CallableByContract, CallableByPrecompile)>, + // Moonbeam specific precompiles: + PrecompileAt< + AddressU64<2048>, + ParachainStakingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2049>, + CrowdloanRewardsPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2050>, + Erc20BalancesPrecompile, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, // DemocracyPrecompile + PrecompileAt< + AddressU64<2052>, + XtokensPrecompile, + ( + SubcallWithMaxNesting<1>, + CallableByContract, + CallableByPrecompile, + ), + >, + PrecompileAt< + AddressU64<2053>, + RelayEncoderPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2054>, + XcmTransactorPrecompileV1, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2055>, + AuthorMappingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2056>, + BatchPrecompile, + ( + SubcallWithMaxNesting<2>, + // Batch is the only precompile allowed to call Batch. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2057>, + RandomnessPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2058>, + CallPermitPrecompile, + (SubcallWithMaxNesting<0>, CallableByContract), + >, + PrecompileAt< + AddressU64<2059>, + ProxyPrecompile, + ( + CallableByContract>, + SubcallWithMaxNesting<0>, + // Batch is the only precompile allowed to call Proxy. + CallableByPrecompile>>, + ), + >, + PrecompileAt< + AddressU64<2060>, + XcmUtilsPrecompile, + CallableByContract< + pallet_evm_precompile_xcm_utils::AllExceptXcmExecute, + >, + >, + PrecompileAt< + AddressU64<2061>, + XcmTransactorPrecompileV2, + (CallableByContract, CallableByPrecompile), + >, + RemovedPrecompileAt>, //CouncilInstance + RemovedPrecompileAt>, // TechCommitteeInstance + PrecompileAt< + AddressU64<2064>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2065>, + ReferendaPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2066>, + ConvictionVotingPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2067>, + PreimagePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2068>, + CollectivePrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2069>, + PrecompileRegistry, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt, GmpPrecompile, SubcallWithMaxNesting<0>>, + PrecompileAt< + AddressU64<2071>, + XcmTransactorPrecompileV3, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2072>, + IdentityPrecompile, + (CallableByContract, CallableByPrecompile), + >, + PrecompileAt< + AddressU64<2073>, + RelayDataVerifierPrecompile, + (CallableByContract, CallableByPrecompile), + >, +); + +/// The PrecompileSet installed in the Moonriver runtime. +/// We include the nine Istanbul precompiles +/// (https://github.com/ethereum/go-ethereum/blob/3c46f557/core/vm/contracts.go#L69) +/// The following distribution has been decided for the precompiles +/// 0-1023: Ethereum Mainnet Precompiles +/// 1024-2047 Precompiles that are not in Ethereum Mainnet but are neither Moonbeam specific +/// 2048-4095 Moonbeam specific precompiles +pub type MoonriverPrecompiles = PrecompileSetBuilder< + R, + ( + // Skip precompiles if out of range. + PrecompilesInRangeInclusive<(AddressU64<1>, AddressU64<4095>), MoonriverPrecompilesAt>, + // Prefixed precompile sets (XC20) + PrecompileSetStartingWith< + ForeignAssetPrefix, + Erc20AssetsPrecompileSet, + CallableByContract, + >, + // Moonriver never had any local assets (No blacklist needed + // https://moonriver.subscan.io/event?module=localassets&event_id=created + // https://moonriver.subscan.io/event?module=localassets&event_id=forcecreated + ), +>; diff --git a/tracing/3200/runtime/moonriver/src/xcm_config.rs b/tracing/3200/runtime/moonriver/src/xcm_config.rs new file mode 100644 index 00000000..cf55c3db --- /dev/null +++ b/tracing/3200/runtime/moonriver/src/xcm_config.rs @@ -0,0 +1,815 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! XCM configuration for Moonbase. +//! + +use super::{ + governance, AccountId, AssetId, AssetManager, Balance, Balances, EmergencyParaXcm, + Erc20XcmBridge, MaintenanceMode, MessageQueue, OpenTechCommitteeInstance, ParachainInfo, + ParachainSystem, Perbill, PolkadotXcm, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent, + RuntimeOrigin, Treasury, XcmpQueue, +}; + +use frame_support::{ + parameter_types, + traits::{EitherOfDiverse, Everything, Nothing, PalletInfoAccess, TransformOrigin}, +}; +use moonbeam_runtime_common::weights as moonriver_weights; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use sp_runtime::{ + traits::{Hash as THash, MaybeEquivalence, PostDispatchInfoOf}, + DispatchErrorWithPostInfo, +}; +use sp_weights::Weight; + +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::{ConstU32, H160, H256}; + +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, HashedDescription, + NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WeightInfoBounds, WithComputedOrigin, +}; + +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use xcm::latest::prelude::{ + AllOf, Asset, AssetFilter, GlobalConsensus, InteriorLocation, Junction, Location, NetworkId, + PalletInstance, Parachain, Wild, WildFungible, +}; + +use xcm_executor::traits::{CallDispatcher, ConvertLocation, JustTry}; + +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use orml_xcm_support::MultiNativeAsset; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToCurrencyId, AccountIdToLocation, AsAssetType, + IsBridgedConcreteAssetFrom, SignedToAccountId20, UtilityAvailableCalls, UtilityEncodeCall, + XcmTransact, +}; + +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_core::Get; +use sp_std::{ + convert::{From, Into, TryFrom}, + prelude::*, +}; + +use orml_traits::parameter_type_with_key; + +use crate::governance::referenda::{FastGeneralAdminOrRoot, GeneralAdminOrRoot}; + +parameter_types! { + // The network Id of the relay + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + // The relay chain Origin type + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + // The universal location within the global consensus system + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); + + // Self Reserve location, defines the multilocation identifying the self-reserve currency + // This is used to match it also against our Balances pallet when we receive such + // a Location: (Self Balances pallet index) + // We use the RELATIVE multilocation + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // If we receive a Location of type AccountKey20, just generate a native account + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + HashedDescription>, +); + +/// Wrapper type around `LocationToAccountId` to convert an `AccountId` to type `H160`. +pub struct LocationToH160; +impl ConvertLocation for LocationToH160 { + fn convert_location(location: &Location) -> Option { + >::convert_location(location) + .map(Into::into) + } +} + +// The non-reserve fungible transactor type +// It will use pallet-assets, and the Id will be matched against AsAssetType +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + super::Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId20 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +/// The transactor for our own chain currency. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + xcm_builder::IsConcrete, + // We can convert the MultiLocations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use all transactors +// These correspond to +// SelfReserve asset, both pre and post 0.9.16 +// Foreign assets +// Local assets, both pre and post 0.9.16 +// We can remove the Old reanchor once +// we import https://github.com/open-web3-stack/open-runtime-module-library/pull/708 +pub type AssetTransactors = ( + LocalAssetTransactor, + ForeignFungiblesTransactor, + Erc20XcmBridge, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + // Xcm Origins defined by a Multilocation of type AccountKey20 can be converted to a 20 byte- + // account local origin + SignedAccountKey20AsNative, +); + +parameter_types! { + /// Maximum number of instructions in a single XCM fragment. A sanity check against + /// weight caculations getting too crazy. + pub MaxInstructions: u32 = 100; +} + +/// Xcm Weigher shared between multiple Xcm-related configs. +pub type XcmWeigher = WeightInfoBounds< + moonbeam_xcm_benchmarks::weights::XcmWeight, + RuntimeCall, + MaxInstructions, +>; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); +} + +pub struct SafeCallFilter; +impl frame_support::traits::Contains for SafeCallFilter { + fn contains(_call: &RuntimeCall) -> bool { + // TODO review + // This needs to be addressed at EVM level + true + } +} + +parameter_types! { + /// Location of Asset Hub + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub const RelayLocation: Location = Location::parent(); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(RelayLocation::get()), + }); + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); + pub const MaxAssetsIntoHolding: u32 = xcm_primitives::MAX_ASSETS; +} + +type Reserves = ( + // Assets bridged from different consensus systems held in reserve on Asset Hub. + IsBridgedConcreteAssetFrom, + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + MultiNativeAsset>, +); + +// Our implementation of the Moonbeam Call +// Attachs the right origin in case the call is made to pallet-ethereum-xcm +#[cfg(not(feature = "evm-tracing"))] +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); +#[cfg(feature = "evm-tracing")] +moonbeam_runtime_common::impl_moonbeam_xcm_call_tracing!(); + +moonbeam_runtime_common::impl_evm_runner_precompile_or_eth_xcm!(); + +pub struct XcmExecutorConfig; +impl xcm_executor::Config for XcmExecutorConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + // Filter to the reserve withdraw operations + // Whenever the reserve matches the relative or absolute value + // of our chain, we always return the relative reserve + type IsReserve = Reserves; + type IsTeleporter = (); // No teleport + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = XcmWeigher; + // We use two traders + // When we receive the relative representation of the self-reserve asset, + // we use UsingComponents and the local way of handling fees + // When we receive a non-reserve asset, we use AssetManager to fetch how many + // units per second we should charge + type Trader = pallet_xcm_weight_trader::Trader; + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = pallet_erc20_xcm_bridge::AssetTrapWrapper; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type PalletInstancesInfo = crate::AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = SafeCallFilter; + type Aliasers = Nothing; + type TransactionalProcessor = xcm_builder::FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +type XcmExecutor = pallet_erc20_xcm_bridge::XcmExecutorWrapper< + XcmExecutorConfig, + xcm_executor::XcmExecutor, +>; + +// Converts a Signed Local Origin into a Location +pub type LocalOriginToLocation = SignedToAccountId20; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = LocationToAccountId; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = moonriver_weights::pallet_xcm::WeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = PolkadotXcm; + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = moonriver_weights::cumulus_pallet_xcmp_queue::WeightInfo; + type PriceForSiblingDelivery = polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery< + cumulus_primitives_core::ParaId, + >; +} + +parameter_types! { + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +// TODO: This pallet can be removed after the lazy migration is done and +// event `Completed` is emitted. +// https://github.com/paritytech/polkadot-sdk/pull/1246 +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type DmpSink = frame_support::traits::EnqueueWithOrigin; + type WeightInfo = cumulus_pallet_dmp_queue::weights::SubstrateWeight; +} + +parameter_types! { + /// The amount of weight (if any) which should be provided to the message queue for + /// servicing enqueued items. + /// + /// This may be legitimately `None` in the case that you will call + /// `ServiceQueues::service_queues` manually. + pub MessageQueueServiceWeight: Weight = + Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block; + /// The maximum number of stale pages (i.e. of overweight messages) allowed before culling + /// can happen. Once there are more stale pages than this, then historical pages may be + /// dropped, even if they contain unprocessed overweight messages. + pub const MessageQueueMaxStale: u32 = 8; + /// The size of the page; this implies the maximum message size which can be sent. + /// + /// A good value depends on the expected message sizes, their weights, the weight that is + /// available for processing them and the maximal needed message size. The maximal message + /// size is slightly lower than this as defined by [`MaxMessageLenOf`]. + pub const MessageQueueHeapSize: u32 = 103 * 1024; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = pallet_ethereum_xcm::MessageProcessorWrapper< + xcm_builder::ProcessXcmMessage, + >; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + // NarrowOriginToSibling calls XcmpQueue's is_paused if Origin is sibling. Allows all other origins + type QueuePausedQuery = EmergencyParaXcm; + type WeightInfo = moonriver_weights::pallet_message_queue::WeightInfo; + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +pub type FastAuthorizeUpgradeOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +pub type ResumeXcmOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, +>; + +impl pallet_emergency_para_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling); + type PausedThreshold = ConstU32<300>; + type FastAuthorizeUpgradeOrigin = FastAuthorizeUpgradeOrigin; + type PausedToNormalOrigin = ResumeXcmOrigin; +} + +// Our AssetType. For now we only handle Xcm Assets +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum AssetType { + Xcm(xcm::v3::Location), +} +impl Default for AssetType { + fn default() -> Self { + Self::Xcm(xcm::v3::Location::here()) + } +} + +impl From for AssetType { + fn from(location: xcm::v3::Location) -> Self { + Self::Xcm(location) + } +} + +// This can be removed once we fully adopt xcm::v4 everywhere +impl TryFrom for AssetType { + type Error = (); + fn try_from(location: Location) -> Result { + Ok(Self::Xcm(location.try_into()?)) + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => Some(location), + } + } +} + +impl Into> for AssetType { + fn into(self) -> Option { + match self { + Self::Xcm(location) => { + xcm_builder::WithLatestLocationConverter::convert_back(&location) + } + } + } +} + +// Implementation on how to retrieve the AssetId from an AssetType +// We simply hash the AssetType and take the lowest 128 bits +impl From for AssetId { + fn from(asset: AssetType) -> AssetId { + match asset { + AssetType::Xcm(id) => { + let mut result: [u8; 16] = [0u8; 16]; + let hash: H256 = id.using_encoded(::Hashing::hash); + result.copy_from_slice(&hash.as_fixed_bytes()[0..16]); + u128::from_le_bytes(result) + } + } + } +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + // Our native token + SelfReserve, + // Assets representing other chains native tokens + ForeignAsset(AssetId), + // Erc20 token + Erc20 { contract_address: H160 }, +} + +impl AccountIdToCurrencyId for Runtime { + fn account_to_currency_id(account: AccountId) -> Option { + Some(match account { + // the self-reserve currency is identified by the pallet-balances address + a if a == H160::from_low_u64_be(2050).into() => CurrencyId::SelfReserve, + // the rest of the currencies, by their corresponding erc20 address + _ => match Runtime::account_to_asset_id(account) { + // A foreign asset + Some((_prefix, asset_id)) => CurrencyId::ForeignAsset(asset_id), + // If no known prefix is identified, we consider that it's a "real" erc20 token + // (i.e. managed by a real smart contract) + None => CurrencyId::Erc20 { + contract_address: account.into(), + }, + }, + }) + } +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + // For now and until Xtokens is adapted to handle 0.9.16 version we use + // the old anchoring here + // This is not a problem in either cases, since the view of the destination + // chain does not change + // TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it + CurrencyId::SelfReserve => { + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + CurrencyId::Erc20 { contract_address } => { + let mut location = Erc20XcmBridgePalletLocation::get(); + location + .push_interior(Junction::AccountKey20 { + key: contract_address.0, + network: None, + }) + .ok(); + Some(location) + } + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(200_000_000u64, 0); + pub const MaxAssetsForTransfer: usize = 2; + + // This is how we are going to detect whether the asset is a Reserve asset + // This however is the chain part only + pub SelfLocation: Location = Location::here(); + // We need this to be able to catch when someone is trying to execute a non- + // cross-chain transfer in xtokens through the absolute path way + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(ParachainInfo::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + // Kusama AssetHub fee + (1, Some(Parachain(1000u32))) => Some(50_000_000u128), + _ => None, + } + }; +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdConvert = CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +// 1 KSM should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +pub type DerivativeAddressRegistrationOrigin = + EitherOfDiverse, governance::custom_origins::GeneralAdmin>; + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = Transactors; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type SovereignAccountDispatcherOrigin = EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = AccountIdToLocation; + type CurrencyIdToLocation = CurrencyIdToLocation>; + type XcmSender = XcmRouter; + type SelfLocation = SelfLocation; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = AbsoluteAndRelativeReserve; + type WeightInfo = moonriver_weights::pallet_xcm_transactor::WeightInfo; + type HrmpManipulatorOrigin = GeneralAdminOrRoot; + type HrmpOpenOrigin = FastGeneralAdminOrRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + // This is the relative view of erc20 assets. + // Identified by this prefix + AccountKey20(contractAddress) + // We use the RELATIVE multilocation + pub Erc20XcmBridgePalletLocation: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + + // To be able to support almost all erc20 implementations, + // we provide a sufficiently hight gas limit. + pub Erc20XcmBridgeTransferGasLimit: u64 = 800_000; +} + +impl pallet_erc20_xcm_bridge::Config for Runtime { + type AccountIdConverter = LocationToH160; + type Erc20MultilocationPrefix = Erc20XcmBridgePalletLocation; + type Erc20TransferGasLimit = Erc20XcmBridgeTransferGasLimit; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; +} + +pub struct AccountIdToH160; +impl sp_runtime::traits::Convert for AccountIdToH160 { + fn convert(account_id: AccountId) -> H160 { + account_id.into() + } +} + +impl pallet_moonbeam_foreign_assets::Config for Runtime { + type AccountIdToH160 = AccountIdToH160; + type AssetIdFilter = Nothing; + type EvmRunner = EvmRunnerPrecompileOrEthXcm; + type ForeignAssetCreatorOrigin = frame_system::EnsureNever; + type ForeignAssetFreezerOrigin = frame_system::EnsureNever; + type ForeignAssetModifierOrigin = frame_system::EnsureNever; + type ForeignAssetUnfreezerOrigin = frame_system::EnsureNever; + type OnForeignAssetCreated = (); + type MaxForeignAssets = ConstU32<256>; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = moonriver_weights::pallet_moonbeam_foreign_assets::WeightInfo; + type XcmLocationToH160 = LocationToH160; +} + +pub struct AssetFeesFilter; +impl frame_support::traits::Contains for AssetFeesFilter { + fn contains(location: &Location) -> bool { + location.parent_count() > 0 + && location.first_interior() != Erc20XcmBridgePalletLocation::get().first_interior() + } +} + +pub type AddSupportedAssetOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::GeneralAdmin, + >, +>; + +pub type EditSupportedAssetOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse< + pallet_collective::EnsureProportionMoreThan, + governance::custom_origins::FastGeneralAdmin, + >, +>; + +pub type RemoveSupportedAssetOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +impl pallet_xcm_weight_trader::Config for Runtime { + type AccountIdToLocation = AccountIdToLocation; + type AddSupportedAssetOrigin = AddSupportedAssetOrigin; + type AssetLocationFilter = AssetFeesFilter; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type EditSupportedAssetOrigin = EditSupportedAssetOrigin; + type NativeLocation = SelfReserve; + type PauseSupportedAssetOrigin = EditSupportedAssetOrigin; + type RemoveSupportedAssetOrigin = RemoveSupportedAssetOrigin; + type RuntimeEvent = RuntimeEvent; + type ResumeSupportedAssetOrigin = RemoveSupportedAssetOrigin; + type WeightInfo = moonriver_weights::pallet_xcm_weight_trader::WeightInfo; + type WeightToFee = ::WeightToFee; + type XcmFeesAccount = XcmFeesAccount; + #[cfg(feature = "runtime-benchmarks")] + type NotFilteredLocation = RelayLocation; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use super::*; + use xcm_builder::WithLatestLocationConverter; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/tracing/3200/runtime/moonriver/tests/common/mod.rs b/tracing/3200/runtime/moonriver/tests/common/mod.rs new file mode 100644 index 00000000..99000bb5 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/common/mod.rs @@ -0,0 +1,401 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![allow(dead_code)] + +use cumulus_primitives_parachain_inherent::ParachainInherentData; +use fp_evm::GenesisAccount; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +pub use moonriver_runtime::{ + asset_config::AssetRegistrarMetadata, currency::MOVR, xcm_config::AssetType, AccountId, + AssetId, AssetManager, AsyncBacking, AuthorInherent, Balance, Ethereum, InflationInfo, + ParachainStaking, Range, Runtime, RuntimeCall, RuntimeEvent, System, TransactionConverter, + UncheckedExtrinsic, HOURS, +}; +use nimbus_primitives::{NimbusId, NIMBUS_ENGINE_ID}; +use polkadot_parachain::primitives::HeadData; +use sp_consensus_slots::Slot; +use sp_core::{Encode, H160}; +use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill, Percent}; + +use std::collections::BTreeMap; + +use fp_rpc::ConvertTransaction; +use pallet_transaction_payment::Multiplier; + +// A valid signed Alice transfer. +pub const VALID_ETH_TX: &str = + "02f86d8205018085174876e80085e8d4a5100082520894f24ff3a9cf04c71dbc94d0b566f7a27b9456\ + 6cac8080c001a0e1094e1a52520a75c0255db96132076dd0f1263089f838bea548cbdbfc64a4d19f031c\ + 92a8cb04e2d68d20a6158d542a07ac440cc8d07b6e36af02db046d92df"; + +// An invalid signed Alice transfer with a gas limit artifically set to 0. +pub const INVALID_ETH_TX: &str = + "f86180843b9aca00809412cb274aad8251c875c0bf6872b67d9983e53fdd01801ca00e28ba2dd3c5a\ + 3fd467d4afd7aefb4a34b373314fff470bb9db743a84d674a0aa06e5994f2d07eafe1c37b4ce5471ca\ + ecec29011f6f5bf0b1a552c55ea348df35f"; + +pub fn rpc_run_to_block(n: u32) { + while System::block_number() < n { + Ethereum::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Ethereum::on_initialize(System::block_number()); + } +} + +/// Utility function that advances the chain to the desired block number. +/// If an author is provided, that author information is injected to all the blocks in the meantime. +pub fn run_to_block(n: u32, author: Option) { + // Finalize the first block + Ethereum::on_finalize(System::block_number()); + while System::block_number() < n { + // Set the new block number and author + match author { + Some(ref author) => { + let pre_digest = Digest { + logs: vec![DigestItem::PreRuntime(NIMBUS_ENGINE_ID, author.encode())], + }; + System::reset_events(); + System::initialize( + &(System::block_number() + 1), + &System::parent_hash(), + &pre_digest, + ); + } + None => { + System::set_block_number(System::block_number() + 1); + } + } + + increase_last_relay_slot_number(1); + + // Initialize the new block + AuthorInherent::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + Ethereum::on_initialize(System::block_number()); + + // Finalize the block + Ethereum::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + } +} + +pub fn last_event() -> RuntimeEvent { + System::events().pop().expect("Event expected").event +} + +// Helper function to give a simple evm context suitable for tests. +// We can remove this once https://github.com/rust-blockchain/evm/pull/35 +// is in our dependency graph. +pub fn evm_test_context() -> fp_evm::Context { + fp_evm::Context { + address: Default::default(), + caller: Default::default(), + apparent_value: From::from(0), + } +} + +// Test struct with the purpose of initializing xcm assets +#[derive(Clone)] +pub struct XcmAssetInitialization { + pub asset_type: AssetType, + pub metadata: AssetRegistrarMetadata, + pub balances: Vec<(AccountId, Balance)>, + pub is_sufficient: bool, +} + +pub struct ExtBuilder { + // endowed accounts with balances + balances: Vec<(AccountId, Balance)>, + // [collator, amount] + collators: Vec<(AccountId, Balance)>, + // [delegator, collator, nomination_amount] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, + // per-round inflation config + inflation: InflationInfo, + // AuthorId -> AccoutId mappings + mappings: Vec<(NimbusId, AccountId)>, + // Crowdloan fund + crowdloan_fund: Balance, + // Chain id + chain_id: u64, + // EVM genesis accounts + evm_accounts: BTreeMap, + // [assettype, metadata, Vec, is_sufficient] + xcm_assets: Vec, + safe_xcm_version: Option, +} + +impl Default for ExtBuilder { + fn default() -> ExtBuilder { + ExtBuilder { + balances: vec![], + delegations: vec![], + collators: vec![], + inflation: InflationInfo { + expect: Range { + min: 100_000 * MOVR, + ideal: 200_000 * MOVR, + max: 500_000 * MOVR, + }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, + mappings: vec![], + crowdloan_fund: 0, + chain_id: CHAIN_ID, + evm_accounts: BTreeMap::new(), + xcm_assets: vec![], + safe_xcm_version: None, + } + } +} + +impl ExtBuilder { + pub fn with_evm_accounts(mut self, accounts: BTreeMap) -> Self { + self.evm_accounts = accounts; + self + } + + pub fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + self.collators = collators; + self + } + + pub fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations + .into_iter() + .map(|d| (d.0, d.1, d.2, Percent::zero())) + .collect(); + self + } + + pub fn with_crowdloan_fund(mut self, crowdloan_fund: Balance) -> Self { + self.crowdloan_fund = crowdloan_fund; + self + } + + pub fn with_mappings(mut self, mappings: Vec<(NimbusId, AccountId)>) -> Self { + self.mappings = mappings; + self + } + + #[allow(dead_code)] + pub fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; + self + } + + pub fn with_xcm_assets(mut self, xcm_assets: Vec) -> Self { + self.xcm_assets = xcm_assets; + self + } + + pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self { + self.safe_xcm_version = Some(safe_xcm_version); + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: Perbill::from_percent(20), + parachain_bond_reserve_percent: Percent::from_percent(30), + blocks_per_round: 2 * HOURS, + num_selected_candidates: 8, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_crowdloan_rewards::GenesisConfig:: { + funded_amount: self.crowdloan_fund, + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_author_mapping::GenesisConfig:: { + mappings: self.mappings, + } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config = pallet_evm_chain_id::GenesisConfig:: { + chain_id: self.chain_id, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: self.evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_ethereum::GenesisConfig:: { + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_xcm::GenesisConfig:: { + safe_xcm_version: self.safe_xcm_version, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = pallet_transaction_payment::GenesisConfig:: { + multiplier: Multiplier::from(10u128), + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + let xcm_assets = self.xcm_assets.clone(); + ext.execute_with(|| { + // If any xcm assets specified, we register them here + for xcm_asset_initialization in xcm_assets { + let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into(); + AssetManager::register_foreign_asset( + root_origin(), + xcm_asset_initialization.asset_type, + xcm_asset_initialization.metadata, + 1, + xcm_asset_initialization.is_sufficient, + ) + .unwrap(); + for (account, balance) in xcm_asset_initialization.balances { + moonriver_runtime::Assets::mint( + origin_of(AssetManager::account_id()), + asset_id.into(), + account, + balance, + ) + .unwrap(); + } + } + System::set_block_number(1); + }); + ext + } +} + +pub const CHAIN_ID: u64 = 1281; +pub const ALICE: [u8; 20] = [4u8; 20]; +pub const ALICE_NIMBUS: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 20] = [5u8; 20]; +pub const CHARLIE: [u8; 20] = [6u8; 20]; +pub const DAVE: [u8; 20] = [7u8; 20]; +pub const EVM_CONTRACT: [u8; 20] = [8u8; 20]; + +pub fn origin_of(account_id: AccountId) -> ::RuntimeOrigin { + ::RuntimeOrigin::signed(account_id) +} + +pub fn inherent_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::none() +} + +pub fn root_origin() -> ::RuntimeOrigin { + ::RuntimeOrigin::root() +} + +/// Mock the inherent that sets validation data in ParachainSystem, which +/// contains the `relay_chain_block_number`, which is used in `author-filter` as a +/// source of randomness to filter valid authors at each block. +pub fn set_parachain_inherent_data() { + use cumulus_primitives_core::PersistedValidationData; + use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; + + let mut relay_sproof = RelayStateSproofBuilder::default(); + relay_sproof.para_id = 100u32.into(); + relay_sproof.included_para_head = Some(HeadData(vec![1, 2, 3])); + + let additional_key_values = vec![( + moonbeam_core_primitives::well_known_relay_keys::TIMESTAMP_NOW.to_vec(), + sp_timestamp::Timestamp::default().encode(), + )]; + + relay_sproof.additional_key_values = additional_key_values; + + let (relay_parent_storage_root, relay_chain_state) = relay_sproof.into_state_root_and_proof(); + + let vfp = PersistedValidationData { + relay_parent_number: 1u32, + relay_parent_storage_root, + ..Default::default() + }; + let parachain_inherent_data = ParachainInherentData { + validation_data: vfp, + relay_chain_state: relay_chain_state, + downward_messages: Default::default(), + horizontal_messages: Default::default(), + }; + assert_ok!(RuntimeCall::ParachainSystem( + cumulus_pallet_parachain_system::Call::::set_validation_data { + data: parachain_inherent_data + } + ) + .dispatch(inherent_origin())); +} + +pub fn unchecked_eth_tx(raw_hex_tx: &str) -> UncheckedExtrinsic { + let converter = TransactionConverter; + converter.convert_transaction(ethereum_transaction(raw_hex_tx)) +} + +pub fn ethereum_transaction(raw_hex_tx: &str) -> pallet_ethereum::Transaction { + let bytes = hex::decode(raw_hex_tx).expect("Transaction bytes."); + let transaction = ethereum::EnvelopedDecodable::decode(&bytes[..]); + assert!(transaction.is_ok()); + transaction.unwrap() +} + +pub(crate) fn increase_last_relay_slot_number(amount: u64) { + let last_relay_slot = u64::from(AsyncBacking::slot_info().unwrap_or_default().0); + frame_support::storage::unhashed::put( + &frame_support::storage::storage_prefix(b"AsyncBacking", b"SlotInfo"), + &((Slot::from(last_relay_slot + amount), 0)), + ); +} diff --git a/tracing/3200/runtime/moonriver/tests/evm_tracing.rs b/tracing/3200/runtime/moonriver/tests/evm_tracing.rs new file mode 100644 index 00000000..79fb9265 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/evm_tracing.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver EVM tracing Integration Tests + +mod common; + +#[cfg(test)] +#[cfg(feature = "evm-tracing")] +mod tests { + use super::common::*; + + use pallet_evm::AddressMapping; + use sp_core::{H160, U256}; + + use moonbeam_core_primitives::Header; + use moonbeam_rpc_primitives_debug::runtime_decl_for_debug_runtime_api::DebugRuntimeApi; + use std::str::FromStr; + + #[test] + fn debug_runtime_api_trace_transaction() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * MOVR, + } + .into(), + ); + let transaction = ethereum_transaction(VALID_ETH_TX); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_transaction( + vec![non_eth_uxt.clone(), eth_uxt, non_eth_uxt.clone()], + &transaction, + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_block() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * MOVR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let eth_tx = ethereum_transaction(VALID_ETH_TX); + let eth_extrinsic_hash = eth_tx.hash(); + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + assert!(Runtime::trace_block( + vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], + vec![eth_extrinsic_hash, eth_extrinsic_hash], + &block + ) + .is_ok()); + }); + } + + #[test] + fn debug_runtime_api_trace_call() { + let block = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1, + parent_hash: Default::default(), + state_root: Default::default(), + }; + let alith = H160::from_str("6be02d1d3665660d22ff9624b7be0551ee1ac91b") + .expect("internal H160 is valid; qed"); + let alith_account_id = + ::AddressMapping::into_account_id(alith); + ExtBuilder::default() + .with_balances(vec![(alith_account_id, 100 * MOVR)]) + .build() + .execute_with(|| { + assert!(Runtime::trace_call( + &block, + alith, + H160::random(), + Vec::new(), + U256::from(99), + U256::max_value(), + Some(U256::one()), + Some(U256::one()), + None, + None, + ) + .is_ok()); + }); + } +} diff --git a/tracing/3200/runtime/moonriver/tests/integration_test.rs b/tracing/3200/runtime/moonriver/tests/integration_test.rs new file mode 100644 index 00000000..b5c64647 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/integration_test.rs @@ -0,0 +1,2808 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver Runtime Integration Tests + +#![cfg(test)] + +mod common; +use common::*; + +use fp_evm::{Context, IsPrecompileResult}; +use frame_support::traits::fungible::Inspect; +use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchClass, + traits::{Currency as CurrencyT, EnsureOrigin, PalletInfo, StorageInfo, StorageInfoTrait}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + StorageHasher, Twox128, +}; +use moonbeam_xcm_benchmarks::weights::XcmWeight; +use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use moonriver_runtime::currency::{GIGAWEI, WEI}; +use moonriver_runtime::{ + asset_config::ForeignAssetInstance, + xcm_config::{CurrencyId, SelfReserve}, + AssetId, Balances, CrowdloanRewards, Executive, OpenTechCommitteeCollective, PolkadotXcm, + Precompiles, RuntimeBlockWeights, TransactionPayment, TransactionPaymentAsGasPrice, + TreasuryCouncilCollective, XTokens, XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + WEEKS, +}; +use nimbus_primitives::NimbusId; +use pallet_evm::PrecompileSet; +use pallet_evm_precompileset_assets_erc20::{SELECTOR_LOG_APPROVAL, SELECTOR_LOG_TRANSFER}; +use pallet_transaction_payment::Multiplier; +use pallet_xcm_transactor::{Currency, CurrencyPayment, TransactWeights}; +use parity_scale_codec::Encode; +use polkadot_parachain::primitives::Sibling; +use precompile_utils::{ + precompile_set::{is_precompile_or_fail, IsActivePrecompile}, + prelude::*, + testing::*, +}; +use sha3::{Digest, Keccak256}; +use sp_core::{ByteArray, Pair, H160, U256}; +use sp_runtime::{ + traits::{Convert, Dispatchable}, + BuildStorage, DispatchError, ModuleError, +}; +use std::str::from_utf8; +use xcm::latest::prelude::*; +use xcm::{VersionedAssets, VersionedLocation}; +use xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_executor::traits::ConvertLocation; + +type BatchPCall = pallet_evm_precompile_batch::BatchPrecompileCall; +type CrowdloanRewardsPCall = + pallet_evm_precompile_crowdloan_rewards::CrowdloanRewardsPrecompileCall; +type XcmUtilsPCall = pallet_evm_precompile_xcm_utils::XcmUtilsPrecompileCall< + Runtime, + moonriver_runtime::xcm_config::XcmExecutorConfig, +>; +type XtokensPCall = pallet_evm_precompile_xtokens::XtokensPrecompileCall; +type ForeignAssetsPCall = pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSetCall< + Runtime, + ForeignAssetInstance, +>; +type XcmTransactorV2PCall = + pallet_evm_precompile_xcm_transactor::v2::XcmTransactorPrecompileV2Call; + +const BASE_FEE_GENESIS: u128 = 100 * GIGAWEI; + +#[test] +fn xcmp_queue_controller_origin_is_root() { + // important for the XcmExecutionManager impl of PauseExecution which uses root origin + // to suspend/resume XCM execution in xcmp_queue::on_idle + assert_ok!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + +#[test] +fn verify_pallet_prefixes() { + fn is_pallet_prefix(name: &str) { + // Compares the unhashed pallet prefix in the `StorageInstance` implementation by every + // storage item in the pallet P. This pallet prefix is used in conjunction with the + // item name to get the unique storage key: hash(PalletPrefix) + hash(StorageName) + // https://github.com/paritytech/substrate/blob/master/frame/support/procedural/src/pallet/ + // expand/storage.rs#L389-L401 + assert_eq!( + ::PalletInfo::name::

(), + Some(name) + ); + } + // TODO: use StorageInfoTrait from https://github.com/paritytech/substrate/pull/9246 + // This is now available with polkadot-v0.9.9 dependencies + is_pallet_prefix::("System"); + is_pallet_prefix::("Utility"); + is_pallet_prefix::("ParachainSystem"); + is_pallet_prefix::("TransactionPayment"); + is_pallet_prefix::("ParachainInfo"); + is_pallet_prefix::("EthereumChainId"); + is_pallet_prefix::("EVM"); + is_pallet_prefix::("Ethereum"); + is_pallet_prefix::("ParachainStaking"); + is_pallet_prefix::("MaintenanceMode"); + is_pallet_prefix::("Scheduler"); + is_pallet_prefix::( + "OpenTechCommitteeCollective", + ); + is_pallet_prefix::("Treasury"); + is_pallet_prefix::("AuthorInherent"); + is_pallet_prefix::("AuthorFilter"); + is_pallet_prefix::("CrowdloanRewards"); + is_pallet_prefix::("AuthorMapping"); + is_pallet_prefix::("Identity"); + is_pallet_prefix::("XcmpQueue"); + is_pallet_prefix::("CumulusXcm"); + is_pallet_prefix::("DmpQueue"); + is_pallet_prefix::("PolkadotXcm"); + is_pallet_prefix::("Assets"); + is_pallet_prefix::("XTokens"); + is_pallet_prefix::("AssetManager"); + is_pallet_prefix::("Migrations"); + is_pallet_prefix::("XcmTransactor"); + is_pallet_prefix::("ProxyGenesisCompanion"); + is_pallet_prefix::("MoonbeamOrbiters"); + is_pallet_prefix::("TreasuryCouncilCollective"); + is_pallet_prefix::("MoonbeamLazyMigrations"); + is_pallet_prefix::("RelayStorageRoots"); + + let prefix = |pallet_name, storage_name| { + let mut res = [0u8; 32]; + res[0..16].copy_from_slice(&Twox128::hash(pallet_name)); + res[16..32].copy_from_slice(&Twox128::hash(storage_name)); + res.to_vec() + }; + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"Now".to_vec(), + prefix: prefix(b"Timestamp", b"Now"), + max_values: Some(1), + max_size: Some(8), + }, + StorageInfo { + pallet_name: b"Timestamp".to_vec(), + storage_name: b"DidUpdate".to_vec(), + prefix: prefix(b"Timestamp", b"DidUpdate"), + max_values: Some(1), + max_size: Some(1), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"TotalIssuance".to_vec(), + prefix: prefix(b"Balances", b"TotalIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"InactiveIssuance".to_vec(), + prefix: prefix(b"Balances", b"InactiveIssuance"), + max_values: Some(1), + max_size: Some(16), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Account".to_vec(), + prefix: prefix(b"Balances", b"Account"), + max_values: None, + max_size: Some(100), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Locks".to_vec(), + prefix: prefix(b"Balances", b"Locks"), + max_values: None, + max_size: Some(1287), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Reserves".to_vec(), + prefix: prefix(b"Balances", b"Reserves"), + max_values: None, + max_size: Some(1037), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Holds".to_vec(), + prefix: prefix(b"Balances", b"Holds"), + max_values: None, + max_size: Some(55), + }, + StorageInfo { + pallet_name: b"Balances".to_vec(), + storage_name: b"Freezes".to_vec(), + prefix: prefix(b"Balances", b"Freezes"), + max_values: None, + max_size: Some(37), + }, + ] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Proxies".to_vec(), + prefix: prefix(b"Proxy", b"Proxies"), + max_values: None, + max_size: Some(845), + }, + StorageInfo { + pallet_name: b"Proxy".to_vec(), + storage_name: b"Announcements".to_vec(), + prefix: prefix(b"Proxy", b"Announcements"), + max_values: None, + max_size: Some(1837), + } + ] + ); + assert_eq!( + ::storage_info(), + vec![StorageInfo { + pallet_name: b"MaintenanceMode".to_vec(), + storage_name: b"MaintenanceMode".to_vec(), + prefix: prefix(b"MaintenanceMode", b"MaintenanceMode"), + max_values: Some(1), + max_size: None, + },] + ); + assert_eq!( + ::storage_info(), + vec![ + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRoot".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRoot"), + max_values: None, + max_size: Some(44), + }, + StorageInfo { + pallet_name: b"RelayStorageRoots".to_vec(), + storage_name: b"RelayStorageRootKeys".to_vec(), + prefix: prefix(b"RelayStorageRoots", b"RelayStorageRootKeys"), + max_values: Some(1), + max_size: Some(121), + }, + ] + ); +} + +#[test] +fn test_collectives_storage_item_prefixes() { + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"TreasuryCouncilCollective".to_vec()); + } + + for StorageInfo { pallet_name, .. } in + ::storage_info() + { + assert_eq!(pallet_name, b"OpenTechCommitteeCollective".to_vec()); + } +} + +#[test] +fn collective_set_members_root_origin_works() { + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert_ok!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + // OpenTechCommitteeCollective + assert_ok!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::root(), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + )); + }); +} + +#[test] +fn collective_set_members_general_admin_origin_works() { + use moonriver_runtime::{ + governance::custom_origins::Origin as CustomOrigin, OriginCaller, Utility, + }; + + ExtBuilder::default().build().execute_with(|| { + let root_caller = ::RuntimeOrigin::root(); + let alice = AccountId::from(ALICE); + + // TreasuryCouncilCollective + let _ = Utility::dispatch_as( + root_caller.clone(), + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + // OpenTechCommitteeCollective + let _ = Utility::dispatch_as( + root_caller, + Box::new(OriginCaller::Origins(CustomOrigin::GeneralAdmin)), + Box::new( + pallet_collective::Call::::set_members { + new_members: vec![alice, AccountId::from(BOB)], + prime: Some(alice), + old_count: 2, + } + .into(), + ), + ); + + assert_eq!( + System::events() + .into_iter() + .filter_map(|r| { + match r.event { + RuntimeEvent::Utility(pallet_utility::Event::DispatchedAs { result }) + if result.is_ok() => + { + Some(true) + } + _ => None, + } + }) + .collect::>() + .len(), + 2 + ) + }); +} + +#[test] +fn collective_set_members_signed_origin_does_not_work() { + let alice = AccountId::from(ALICE); + ExtBuilder::default().build().execute_with(|| { + // TreasuryCouncilCollective + assert!(TreasuryCouncilCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + // OpenTechCommitteeCollective + assert!(OpenTechCommitteeCollective::set_members( + ::RuntimeOrigin::signed(alice), + vec![AccountId::from(ALICE), AccountId::from(BOB)], + Some(AccountId::from(ALICE)), + 2 + ) + .is_err()); + }); +} + +#[test] +fn verify_pallet_indices() { + fn is_pallet_index(index: usize) { + assert_eq!( + ::PalletInfo::index::

(), + Some(index) + ); + } + // System support + is_pallet_index::(0); + is_pallet_index::(1); + is_pallet_index::(3); + is_pallet_index::(4); + // Monetary + is_pallet_index::(10); + is_pallet_index::(11); + // Consensus support + is_pallet_index::(20); + is_pallet_index::(21); + is_pallet_index::(22); + is_pallet_index::(23); + is_pallet_index::(24); + // Handy utilities + is_pallet_index::(30); + is_pallet_index::(31); + is_pallet_index::(32); + is_pallet_index::(33); + is_pallet_index::(34); + is_pallet_index::(35); + is_pallet_index::(37); + // Ethereum compatibility + is_pallet_index::(50); + is_pallet_index::(51); + is_pallet_index::(52); + // Governance + is_pallet_index::(60); + // is_pallet_index::(61); Removed + // Council + // is_pallet_index::(70); Removed + // is_pallet_index::(71); Removed + is_pallet_index::(72); + is_pallet_index::(73); + // Treasury + is_pallet_index::(80); + // Crowdloan + is_pallet_index::(90); + // XCM Stuff + is_pallet_index::(100); + is_pallet_index::(101); + is_pallet_index::(102); + is_pallet_index::(103); + is_pallet_index::(104); + is_pallet_index::(105); + is_pallet_index::(106); + is_pallet_index::(107); +} + +#[test] +fn verify_reserved_indices() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + t.execute_with(|| { + use frame_metadata::*; + let metadata = moonriver_runtime::Runtime::metadata(); + let metadata = match metadata.1 { + RuntimeMetadata::V14(metadata) => metadata, + _ => panic!("metadata has been bumped, test needs to be updated"), + }; + // 40: Sudo + // 53: BaseFee + // 108: pallet_assets:: + let reserved = vec![40, 53, 108]; + let existing = metadata + .pallets + .iter() + .map(|p| p.index) + .collect::>(); + assert!(reserved.iter().all(|index| !existing.contains(index))); + }); +} + +#[test] +fn verify_proxy_type_indices() { + assert_eq!(moonriver_runtime::ProxyType::Any as u8, 0); + assert_eq!(moonriver_runtime::ProxyType::NonTransfer as u8, 1); + assert_eq!(moonriver_runtime::ProxyType::Governance as u8, 2); + assert_eq!(moonriver_runtime::ProxyType::Staking as u8, 3); + assert_eq!(moonriver_runtime::ProxyType::CancelProxy as u8, 4); + assert_eq!(moonriver_runtime::ProxyType::Balances as u8, 5); + assert_eq!(moonriver_runtime::ProxyType::AuthorMapping as u8, 6); + assert_eq!(moonriver_runtime::ProxyType::IdentityJudgement as u8, 7); +} + +#[test] +fn join_collator_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000 * MOVR), + (AccountId::from(BOB), 20_000 * MOVR), + (AccountId::from(CHARLIE), 10_100 * MOVR), + (AccountId::from(DAVE), 10_000 * MOVR), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 10_000 * MOVR), + (AccountId::from(BOB), 10_000 * MOVR), + ]) + .with_delegations(vec![ + (AccountId::from(CHARLIE), AccountId::from(ALICE), 50 * MOVR), + (AccountId::from(CHARLIE), AccountId::from(BOB), 50 * MOVR), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(ALICE)), + 10_000 * MOVR, + 2u32 + ), + pallet_parachain_staking::Error::::CandidateExists + ); + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 10_000 * MOVR, + 2u32 + ), + pallet_parachain_staking::Error::::DelegatorExists + ); + assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(DAVE)), + 10_000 * MOVR, + 2u32 + )); + assert_eq!( + last_event(), + RuntimeEvent::ParachainStaking( + pallet_parachain_staking::Event::JoinedCollatorCandidates { + account: AccountId::from(DAVE), + amount_locked: 10_000 * MOVR, + new_total_amt_locked: 30_100 * MOVR + } + ) + ); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(ALICE)); + assert_eq!(candidates.0[0].amount, 10_050 * MOVR); + assert_eq!(candidates.0[1].owner, AccountId::from(BOB)); + assert_eq!(candidates.0[1].amount, 10_050 * MOVR); + assert_eq!(candidates.0[2].owner, AccountId::from(DAVE)); + assert_eq!(candidates.0[2].amount, 10_000 * MOVR); + }); +} + +#[test] +fn transfer_through_evm_to_stake() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 20_000 * MOVR)]) + .build() + .execute_with(|| { + // Charlie has no balance => fails to stake + assert_noop!( + ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 10_000 * MOVR, + 2u32 + ), + DispatchError::Module(ModuleError { + index: 20, + error: [8, 0, 0, 0], + message: Some("InsufficientBalance") + }) + ); + // Alice transfer from free balance 20000 MOVR to Bob + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 20_000 * MOVR, + )); + assert_eq!(Balances::free_balance(AccountId::from(BOB)), 20_000 * MOVR); + + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + // Bob transfers 10000 MOVR to Charlie via EVM + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(CHARLIE), + input: vec![], + value: (10_000 * MOVR).into(), + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + assert_eq!( + Balances::free_balance(AccountId::from(CHARLIE)), + 10_000 * MOVR, + ); + + // Charlie can stake now + assert_ok!(ParachainStaking::join_candidates( + origin_of(AccountId::from(CHARLIE)), + 10_000 * MOVR, + 2u32, + ),); + let candidates = ParachainStaking::candidate_pool(); + assert_eq!(candidates.0[0].owner, AccountId::from(CHARLIE)); + assert_eq!(candidates.0[0].amount, 10_000 * MOVR); + }); +} + +#[test] +fn reward_block_authors() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 20_100 * MOVR), + (AccountId::from(BOB), 10_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 10_000 * MOVR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + + // Just before round 3 + run_to_block(2399, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // no rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 10_100 * MOVR, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 9500 * MOVR,); + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 11547666666208000000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9557333332588000000000, + ); + }); +} + +#[test] +fn reward_block_authors_with_parachain_bond_reserved() { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 100 extra tokens for her mapping deposit + (AccountId::from(ALICE), 20_100 * MOVR), + (AccountId::from(BOB), 10_000 * MOVR), + (AccountId::from(CHARLIE), MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 10_000 * MOVR)]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + increase_last_relay_slot_number(1); + assert_ok!(ParachainStaking::set_parachain_bond_account( + root_origin(), + AccountId::from(CHARLIE), + ),); + + // Stop just before round 2 + run_to_block(1199, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // no collator rewards doled out yet + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 10_100 * MOVR, + ); + assert_eq!(Balances::usable_balance(AccountId::from(BOB)), 9500 * MOVR,); + + // Go to round 2 + run_to_block(1201, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // 30% reserved for parachain bond + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 452515000000000000000, + ); + + // Go to round 3 + run_to_block(2401, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + // rewards minted and distributed + assert_eq!( + Balances::usable_balance(AccountId::from(ALICE)), + 11117700475903800000000, + ); + assert_eq!( + Balances::usable_balance(AccountId::from(BOB)), + 9535834523343675000000, + ); + // 30% reserved for parachain bond again + assert_eq!( + Balances::usable_balance(AccountId::from(CHARLIE)), + 910802725000000000000, + ); + }); +} + +#[test] +fn initialize_crowdloan_addresses_with_batch_and_pay() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 48 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * MOVR); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * MOVR); + let expected = RuntimeEvent::Utility(pallet_utility::Event::BatchCompleted); + assert_eq!(last_event(), expected); + // This one should fail, as we already filled our data + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch { + calls: vec![RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![([4u8; 32].into(), Some(AccountId::from(ALICE)), 432000)] + } + )] + }) + .dispatch(root_origin()) + ); + let expected_fail = RuntimeEvent::Utility(pallet_utility::Event::BatchInterrupted { + index: 0, + error: DispatchError::Module(ModuleError { + index: 90, + error: [8, 0, 0, 0], + message: None, + }), + }); + assert_eq!(last_event(), expected_fail); + // Claim 1 block. + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(CHARLIE)))); + assert_ok!(CrowdloanRewards::claim(origin_of(AccountId::from(DAVE)))); + + let vesting_period = 48 * WEEKS as u128; + let per_block = (1_050_000 * MOVR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + per_block + ); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + per_block + ); + // The total claimed reward should be equal to the account balance at this point. + assert_eq!( + Balances::balance(&AccountId::from(CHARLIE)), + (450_000 * MOVR) + per_block + ); + assert_eq!( + Balances::balance(&AccountId::from(DAVE)), + (450_000 * MOVR) + per_block + ); + assert_noop!( + CrowdloanRewards::claim(origin_of(AccountId::from(ALICE))), + pallet_crowdloan_rewards::Error::::NoAssociatedClaim + ); + }); +} + +#[test] +fn initialize_crowdloan_address_and_change_with_relay_key_sig() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + + let (pair1, _) = sp_core::sr25519::Pair::generate(); + let (pair2, _) = sp_core::sr25519::Pair::generate(); + + let public1 = pair1.public(); + let public2 = pair2.public(); + + // signature: + // WRAP_BYTES|| NetworkIdentifier|| new_account || previous_account || WRAP_BYTES + let mut message = pallet_crowdloan_rewards::WRAPPED_BYTES_PREFIX.to_vec(); + message.append(&mut b"moonriver-".to_vec()); + message.append(&mut AccountId::from(DAVE).encode()); + message.append(&mut AccountId::from(CHARLIE).encode()); + message.append(&mut pallet_crowdloan_rewards::WRAPPED_BYTES_POSTFIX.to_vec()); + let signature1 = pair1.sign(&message); + let signature2 = pair2.sign(&message); + + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + // two relay accounts pointing at the same reward account + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public1.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + public2.into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 900_000 * MOVR); + + // this should fail, as we are only providing one signature + assert_noop!( + CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![(public1.into(), signature1.clone().into())] + ), + pallet_crowdloan_rewards::Error::::InsufficientNumberOfValidProofs + ); + + // this should be valid + assert_ok!(CrowdloanRewards::change_association_with_relay_keys( + origin_of(AccountId::from(CHARLIE)), + AccountId::from(DAVE), + AccountId::from(CHARLIE), + vec![ + (public1.into(), signature1.into()), + (public2.into(), signature2.into()) + ] + )); + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(DAVE)) + .unwrap() + .claimed_reward, + (900_000 * MOVR) + ); + }); +} + +#[test] +fn claim_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + assert!(CrowdloanRewards::initialized()); + + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(CHARLIE)), 450_000 * MOVR); + // 30 percent initial payout + assert_eq!(Balances::balance(&AccountId::from(DAVE)), 450_000 * MOVR); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Alice uses the crowdloan precompile to claim through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the call data (selector, amount) + let mut call_data = Vec::::from([0u8; 4]); + call_data[0..4].copy_from_slice(&Keccak256::digest(b"claim()")[0..4]); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let vesting_period = 4 * WEEKS as u128; + let per_block = (1_050_000 * MOVR) / vesting_period; + + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + per_block + ); + }) +} + +#[test] +fn is_contributor_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Assert precompile reports Bob is not a contributor + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(BOB).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(false); + + // Assert precompile reports Charlie is a nominator + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::is_contributor { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(true); + }) +} + +#[test] +fn reward_info_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + let expected_total: U256 = (1_500_000 * MOVR).into(); + let expected_claimed: U256 = (450_000 * MOVR).into(); + + // Assert precompile reports correct Charlie reward info. + Precompiles::new() + .prepare_test( + ALICE, + crowdloan_precompile_address, + CrowdloanRewardsPCall::reward_info { + contributor: Address(AccountId::from(CHARLIE).into()), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns((expected_total, expected_claimed)); + }) +} + +#[test] +fn update_reward_address_via_precompile() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_crowdloan_fund(3_000_000 * MOVR) + .build() + .execute_with(|| { + // set parachain inherent data + set_parachain_inherent_data(); + let init_block = CrowdloanRewards::init_vesting_block(); + // This matches the previous vesting + let end_block = init_block + 4 * WEEKS; + // Batch calls always succeed. We just need to check the inner event + assert_ok!( + RuntimeCall::Utility(pallet_utility::Call::::batch_all { + calls: vec![ + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [4u8; 32].into(), + Some(AccountId::from(CHARLIE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::initialize_reward_vec { + rewards: vec![( + [5u8; 32].into(), + Some(AccountId::from(DAVE)), + 1_500_000 * MOVR + )] + } + ), + RuntimeCall::CrowdloanRewards( + pallet_crowdloan_rewards::Call::::complete_initialization { + lease_ending_block: end_block + } + ) + ] + }) + .dispatch(root_origin()) + ); + + let crowdloan_precompile_address = H160::from_low_u64_be(2049); + + // Charlie uses the crowdloan precompile to update address through the EVM + let gas_limit = 100000u64; + let gas_price: U256 = BASE_FEE_GENESIS.into(); + + // Construct the input data to check if Bob is a contributor + let mut call_data = Vec::::from([0u8; 36]); + call_data[0..4] + .copy_from_slice(&Keccak256::digest(b"update_reward_address(address)")[0..4]); + call_data[16..36].copy_from_slice(&ALICE); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(CHARLIE), + target: crowdloan_precompile_address, + input: call_data, + value: U256::zero(), // No value sent in EVM + gas_limit, + max_fee_per_gas: gas_price, + max_priority_fee_per_gas: None, + nonce: None, // Use the next nonce + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + assert!(CrowdloanRewards::accounts_payable(&AccountId::from(CHARLIE)).is_none()); + assert_eq!( + CrowdloanRewards::accounts_payable(&AccountId::from(ALICE)) + .unwrap() + .claimed_reward, + (450_000 * MOVR) + ); + }) +} + +fn run_with_system_weight(w: Weight, mut assertions: F) +where + F: FnMut() -> (), +{ + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); +} + +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonriver_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 1_000_000_001, calc_fee(1)); + assert_eq!( 10_000_001_000, calc_fee(10)); + assert_eq!( 100_001_000_000, calc_fee(100)); + assert_eq!( 1_001_000_000_000, calc_fee(1_000)); + assert_eq!( 11_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 1_100_000_000_000_000, calc_fee(100_000)); + assert_eq!( 1_001_000_000_000_000_000, calc_fee(1_000_000)); // one MOVR, ~ 1MB + assert_eq!( 1_000_010_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(1_000_000_100_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + +#[test] +fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + + let minimum_multiplier = moonriver_runtime::MinimumMultiplier::get(); + let target = moonriver_runtime::TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = + moonriver_runtime::SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) +} + +#[test] +fn ethereum_invalid_transaction() { + ExtBuilder::default().build().execute_with(|| { + // Ensure an extrinsic not containing enough gas limit to store the transaction + // on chain is rejected. + assert_eq!( + Executive::apply_extrinsic(unchecked_eth_tx(INVALID_ETH_TX)), + Err( + sp_runtime::transaction_validity::TransactionValidityError::Invalid( + sp_runtime::transaction_validity::InvalidTransaction::Custom(0u8) + ) + ) + ); + }); +} + +#[test] +fn initial_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + + ExtBuilder::default().build().execute_with(|| { + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(10u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 12_500_000_000u128.into(), + Weight::from_parts(41_742_000u64, 0) + ) + ); + }); +} + +#[test] +fn min_gas_fee_is_correct() { + use fp_evm::FeeCalculator; + use frame_support::traits::Hooks; + + ExtBuilder::default().build().execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::put(Multiplier::from(0)); + TransactionPayment::on_finalize(System::block_number()); // should trigger min to kick in + + let multiplier = TransactionPayment::next_fee_multiplier(); + assert_eq!(multiplier, Multiplier::from(1u128)); + + assert_eq!( + TransactionPaymentAsGasPrice::min_gas_price(), + ( + 1_250_000_000u128.into(), + Weight::from_parts(41_742_000u64, 0) + ) + ); + }); +} + +#[test] +fn transfer_ed_0_substrate() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * MOVR) + (1 * WEI)), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer_allow_death( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * MOVR, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); +} + +#[test] +fn transfer_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * MOVR) + (21_000 * BASE_FEE_GENESIS)) + (1 * WEI), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI,); + }); +} + +#[test] +fn refund_ed_0_evm() { + ExtBuilder::default() + .with_balances(vec![ + ( + AccountId::from(ALICE), + ((1 * MOVR) + (21_777 * BASE_FEE_GENESIS)), + ), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // EVM transfer that zeroes ALICE + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(ALICE), + target: H160::from(BOB), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_777u64, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // ALICE is refunded + assert_eq!( + Balances::free_balance(AccountId::from(ALICE)), + 777 * BASE_FEE_GENESIS, + ); + }); +} + +#[test] +fn author_does_not_receive_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * MOVR) + (21_000 * (500 * GIGAWEI)), + )]) + .build() + .execute_with(|| { + // Some block author as seen by pallet-evm. + let author = AccountId::from(>::find_author()); + // Currently the default impl of the evm uses `deposit_into_existing`. + // If we were to use this implementation, and for an author to receive eventual tips, + // the account needs to be somehow initialized, otherwise the deposit would fail. + Balances::make_free_balance_be(&author, 100 * MOVR); + + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(300 * GIGAWEI), + max_priority_fee_per_gas: Some(U256::from(200 * GIGAWEI)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + // Author free balance didn't change. + assert_eq!(Balances::free_balance(author), 100 * MOVR,); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_with_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * MOVR) + (21_000 * (2 * BASE_FEE_GENESIS)), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(2u128 * BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(2u128 * BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + let fee = ((2 * BASE_FEE_GENESIS) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonriver_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn total_issuance_after_evm_transaction_without_priority_fee() { + ExtBuilder::default() + .with_balances(vec![( + AccountId::from(BOB), + (1 * MOVR) + (21_000 * (2 * BASE_FEE_GENESIS)), + )]) + .build() + .execute_with(|| { + let issuance_before = ::Currency::total_issuance(); + // EVM transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::::call { + source: H160::from(BOB), + target: H160::from(ALICE), + input: Vec::new(), + value: (1 * MOVR).into(), + gas_limit: 21_000u64, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: Some(U256::from(BASE_FEE_GENESIS)), + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let issuance_after = ::Currency::total_issuance(); + let fee = ((1 * BASE_FEE_GENESIS) * 21_000) as f64; + // 80% was burned. + let expected_burn = (fee * 0.8) as u128; + assert_eq!(issuance_after, issuance_before - expected_burn,); + // 20% was sent to treasury. + let expected_treasury = (fee * 0.2) as u128; + assert_eq!(moonriver_runtime::Treasury::pot(), expected_treasury); + }); +} + +#[test] +fn root_can_change_default_xcm_vers() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + // Default XCM version is not set yet, so xtokens should fail because it does not + // know with which version to send + assert_noop!( + XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + ), + orml_xtokens::Error::::XcmExecutionFailed + ); + + // Root sets the defaultXcm + assert_ok!(PolkadotXcm::force_default_xcm_version( + root_origin(), + Some(2) + )); + + // Now transferring does not fail + assert_ok!(XTokens::transfer( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + Box::new(xcm::VersionedLocation::V4(dest)), + WeightLimit::Limited(4000000000.into()) + )); + }) +} + +#[test] +fn asset_can_be_registered() { + ExtBuilder::default().build().execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + let asset_metadata = AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }; + assert_ok!(AssetManager::register_foreign_asset( + moonriver_runtime::RuntimeOrigin::root(), + source_location, + asset_metadata, + 1u128, + true + )); + assert!(AssetManager::asset_id_type(source_id).is_some()); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_supply_and_balance() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * MOVR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Assert the asset has been created with the correct supply + assert_eq!( + moonriver_runtime::Assets::total_supply(relay_asset_id), + 1_000 * MOVR + ); + + // Access totalSupply through precompile. Important that the context is correct + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::total_supply {}, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(1000 * MOVR)); + + // Access balanceOf through precompile + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(ALICE.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(1000 * MOVR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * MOVR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Transfer tokens from Aice to Bob, 400 MOVR. + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::transfer { + to: Address(BOB.into()), + value: { 400 * MOVR }.into(), + }, + ) + .expect_cost(24673) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * MOVR)), + )) + .execute_returns(true); + + // Make sure BOB has 400 MOVR + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(BOB.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(400 * MOVR)); + }); +} + +#[test] +fn xcm_asset_erc20_precompiles_approve() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000 * MOVR)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .build() + .execute_with(|| { + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: AssetId = AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Aprove Bob for spending 400 MOVR from Alice + Precompiles::new() + .prepare_test( + ALICE, + asset_precompile_address, + ForeignAssetsPCall::approve { + spender: Address(BOB.into()), + value: { 400 * MOVR }.into(), + }, + ) + .expect_cost(15571) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_APPROVAL, + H160::from(ALICE), + H160::from(BOB), + solidity::encode_event_data(U256::from(400 * MOVR)), + )) + .execute_returns(true); + + // Transfer tokens from Alice to Charlie by using BOB as origin + Precompiles::new() + .prepare_test( + BOB, + asset_precompile_address, + ForeignAssetsPCall::transfer_from { + from: Address(ALICE.into()), + to: Address(CHARLIE.into()), + value: { 400 * MOVR }.into(), + }, + ) + .expect_cost(29961) + .expect_log(log3( + asset_precompile_address, + SELECTOR_LOG_TRANSFER, + H160::from(ALICE), + H160::from(CHARLIE), + solidity::encode_event_data(U256::from(400 * MOVR)), + )) + .execute_returns(true); + + // Make sure CHARLIE has 400 MOVR + Precompiles::new() + .prepare_test( + CHARLIE, + asset_precompile_address, + ForeignAssetsPCall::balance_of { + who: Address(CHARLIE.into()), + }, + ) + .expect_cost(3338) + .expect_no_logs() + .execute_returns(U256::from(400 * MOVR)); + }); +} + +#[test] +fn xtokens_precompiles_transfer() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // We have the assetId that corresponds to the relay chain registered + let relay_asset_id: moonriver_runtime::AssetId = + AssetType::Xcm(xcm::v3::Location::parent()).into(); + + // Its address is + let asset_precompile_address = Runtime::asset_id_to_account( + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, + relay_asset_id, + ); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // We use the address of the asset as an identifier of the asset we want to transferS + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer { + currency_address: Address(asset_precompile_address.into()), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(196698) + .expect_no_logs() + .execute_returns(()) + }) +} + +#[test] +fn xtokens_precompiles_transfer_multiasset() { + ExtBuilder::default() + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + let xtokens_precompile_address = H160::from_low_u64_be(2052); + + // Alice has 1000 tokens. She should be able to send through precompile + let destination = Location::new( + 1, + [Junction::AccountId32 { + network: None, + id: [1u8; 32], + }], + ); + + // This time we transfer it through TransferMultiAsset + // Instead of the address, we encode directly the multilocation referencing the asset + Precompiles::new() + .prepare_test( + ALICE, + xtokens_precompile_address, + XtokensPCall::transfer_multiasset { + // We want to transfer the relay token + asset: Location::parent(), + amount: 500_000_000_000_000u128.into(), + destination, + weight: 4_000_000, + }, + ) + .expect_cost(196698) + .expect_no_logs() + .execute_returns(()); + }) +} + +#[test] +fn make_sure_polkadot_xcm_cannot_be_called() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let assets: Assets = [Asset { + id: AssetId(moonriver_runtime::xcm_config::SelfLocation::get()), + fun: Fungible(1000), + }] + .to_vec() + .into(); + assert_noop!( + RuntimeCall::PolkadotXcm(pallet_xcm::Call::::reserve_transfer_assets { + dest: Box::new(VersionedLocation::V4(dest.clone())), + beneficiary: Box::new(VersionedLocation::V4(dest)), + assets: Box::new(VersionedAssets::V4(assets)), + fee_asset_item: 0, + }) + .dispatch(::RuntimeOrigin::signed( + AccountId::from(ALICE) + )), + frame_system::Error::::CallFiltered + ); + }); +} + +#[test] +fn transactor_cannot_use_more_than_max_weight() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + assert_ok!(XcmTransactor::register( + root_origin(), + AccountId::from(ALICE), + 0, + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000.into(), + None + )); + + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + root_origin(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + 1 + )); + + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonriver_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + vec![], + // 2000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + assert_noop!( + XcmTransactor::transact_through_derivative( + origin_of(AccountId::from(ALICE)), + moonriver_runtime::xcm_config::Transactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsCurrencyId(CurrencyId::ForeignAsset(source_id)), + fee_amount: None + }, + vec![], + // 20000 is the max + TransactWeights { + transact_required_weight_at_most: 17001.into(), + overall_weight: None + }, + false + ), + pallet_xcm_transactor::Error::::MaxWeightTransactReached + ); + }) +} + +#[test] +fn transact_through_signed_precompile_works_v2() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::parent(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .expect_cost(23239) + .expect_no_logs() + .execute_returns(()); + }); +} + +#[test] +fn transact_through_signed_cannot_send_to_local_chain() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .build() + .execute_with(|| { + // Destination + let dest = Location::here(); + + let fee_payer_asset = Location::parent(); + + let bytes = vec![1u8, 2u8, 3u8]; + + let total_weight = 1_000_000_000u64; + + let xcm_transactor_v2_precompile_address = H160::from_low_u64_be(2061); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_transactor_v2_precompile_address, + XcmTransactorV2PCall::transact_through_signed_multilocation { + dest, + fee_asset: fee_payer_asset, + weight: 4_000_000, + call: bytes.into(), + fee_amount: u128::from(total_weight).into(), + overall_weight: total_weight, + }, + ) + .execute_reverts(|output| { + from_utf8(&output) + .unwrap() + .contains("Dispatched call failed with error:") + && from_utf8(&output).unwrap().contains("ErrorValidating") + }); + }); +} + +#[test] +fn call_xtokens_with_fee() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_safe_xcm_version(2) + .with_xcm_assets(vec![XcmAssetInitialization { + asset_type: AssetType::Xcm(xcm::v3::Location::parent()), + metadata: AssetRegistrarMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + is_frozen: false, + }, + balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)], + is_sufficient: true, + }]) + .build() + .execute_with(|| { + let source_location = AssetType::Xcm(xcm::v3::Location::parent()); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: [1u8; 32], + }] + .into(), + }; + let source_id: moonriver_runtime::AssetId = source_location.clone().into(); + + let before_balance = + moonriver_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + + // We are able to transfer with fee + assert_ok!(XTokens::transfer_with_fee( + origin_of(AccountId::from(ALICE)), + CurrencyId::ForeignAsset(source_id), + 100_000_000_000_000, + 100, + Box::new(xcm::VersionedLocation::V4(dest.clone())), + WeightLimit::Limited(4000000000.into()) + ),); + + let after_balance = + moonriver_runtime::Assets::balance(source_id, &AccountId::from(ALICE)); + // At least these much (plus fees) should have been charged + assert_eq!(before_balance - 100_000_000_000_000 - 100, after_balance); + }); +} + +#[test] +fn test_xcm_utils_ml_tp_account() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_address_parent: H160 = + ParentIsPreset::::convert_location(&Location::parent()) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: Location::parent(), + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_parent)); + + let parachain_2000_multilocation = Location::new(1, [Parachain(2000)]); + let expected_address_parachain: H160 = + SiblingParachainConvertsVia::::convert_location( + ¶chain_2000_multilocation, + ) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: parachain_2000_multilocation, + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_parachain)); + + let alice_in_parachain_2000_location = Location::new( + 1, + [ + Parachain(2000), + AccountKey20 { + network: None, + key: ALICE, + }, + ], + ); + let expected_address_alice_in_parachain_2000 = + xcm_builder::HashedDescription::< + AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&alice_in_parachain_2000_location) + .unwrap() + .into(); + + Precompiles::new() + .prepare_test( + ALICE, + xcm_utils_precompile_address, + XcmUtilsPCall::multilocation_to_address { + location: alice_in_parachain_2000_location, + }, + ) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(Address(expected_address_alice_in_parachain_2000)); + }); +} + +#[test] +fn test_xcm_utils_weight_message() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let expected_weight = + XcmWeight::::clear_origin().ref_time(); + + let message: Vec = xcm::VersionedXcm::<()>::V4(Xcm(vec![ClearOrigin])).encode(); + + let input = XcmUtilsPCall::weight_message { + message: message.into(), + }; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(0) + .expect_no_logs() + .execute_returns(expected_weight); + }); +} + +#[test] +fn test_xcm_utils_get_units_per_second() { + ExtBuilder::default().build().execute_with(|| { + let xcm_utils_precompile_address = H160::from_low_u64_be(2060); + let location = SelfReserve::get(); + + let input = XcmUtilsPCall::get_units_per_second { location }; + + let expected_units = + WEIGHT_REF_TIME_PER_SECOND as u128 * moonriver_runtime::currency::WEIGHT_FEE; + + Precompiles::new() + .prepare_test(ALICE, xcm_utils_precompile_address, input) + .expect_cost(1669) + .expect_no_logs() + .execute_returns(expected_units); + }); +} + +#[test] +fn precompile_existence() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let precompile_addresses: std::collections::BTreeSet<_> = vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 1024, 1025, 1026, 2048, 2049, 2050, 2051, 2052, 2053, + 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, + 2068, 2069, 2070, 2071, 2072, 2073, + ] + .into_iter() + .map(H160::from_low_u64_be) + .collect(); + + for i in 0..3000 { + let address = H160::from_low_u64_be(i); + + if precompile_addresses.contains(&address) { + assert!( + is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return true", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_some(), + "execute({},..) should return Some(_)", + i + ); + } else { + assert!( + !is_precompile_or_fail::(address, 100_000u64).expect("to be ok"), + "is_precompile({}) should return false", + i + ); + + assert!( + precompiles + .execute(&mut MockHandle::new( + address, + Context { + address, + caller: H160::zero(), + apparent_value: U256::zero() + } + ),) + .is_none(), + "execute({},..) should return None", + i + ); + } + } + }); +} + +#[test] +fn removed_precompiles() { + ExtBuilder::default().build().execute_with(|| { + let precompiles = Precompiles::new(); + let removed_precompiles = [1025, 2051, 2062, 2063]; + + for i in 1..3000 { + let address = H160::from_low_u64_be(i); + + if !is_precompile_or_fail::(address, 100_000u64).expect("to be ok") { + continue; + } + + if !removed_precompiles.contains(&i) { + assert!( + match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} should be an active precompile" + ); + continue; + } + + assert!( + !match precompiles.is_active_precompile(address, 100_000u64) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + }, + "{i} shouldn't be an active precompile" + ); + + precompiles + .prepare_test(Alice, address, []) + .execute_reverts(|out| out == b"Removed precompile"); + } + }) +} + +#[test] +fn deal_with_fees_handles_tip() { + use frame_support::traits::OnUnbalanced; + use moonriver_runtime::{DealWithFees, Treasury}; + + ExtBuilder::default().build().execute_with(|| { + // This test checks the functionality of the `DealWithFees` trait implementation in the runtime. + // It simulates a scenario where a fee and a tip are issued to an account and ensures that the + // treasury receives the correct amount (20% of the total), and the rest is burned (80%). + // + // The test follows these steps: + // 1. It issues a fee of 100 and a tip of 1000. + // 2. It checks the total supply before the fee and tip are dealt with, which should be 1_100. + // 3. It checks that the treasury's balance is initially 0. + // 4. It calls `DealWithFees::on_unbalanceds` with the fee and tip. + // 5. It checks that the treasury's balance is now 220 (20% of the fee and tip). + // 6. It checks that the total supply has decreased by 880 (80% of the fee and tip), indicating + // that this amount was burned. + let fee = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(100); + let tip = as frame_support::traits::fungible::Balanced< + AccountId, + >>::issue(1000); + + let total_supply_before = Balances::total_issuance(); + assert_eq!(total_supply_before, 1_100); + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); + + DealWithFees::on_unbalanceds(vec![fee, tip].into_iter()); + + // treasury should have received 20% + assert_eq!(Balances::free_balance(&Treasury::account_id()), 220); + + // verify 80% burned + let total_supply_after = Balances::total_issuance(); + assert_eq!(total_supply_before - total_supply_after, 880); + }); +} + +#[test] +fn evm_revert_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + // Batch a transfer followed by an invalid call to batch. + // Thus BatchAll will revert the transfer. + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into()), Address(batch_precompile_address)].into(), + value: vec![U256::from(1 * MOVR), U256::zero()].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 0, "there should be no transfer event"); + }); +} + +#[test] +fn evm_success_keeps_substrate_events() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .build() + .execute_with(|| { + let batch_precompile_address = H160::from_low_u64_be(2056); + + assert_ok!(RuntimeCall::EVM(pallet_evm::Call::call { + source: ALICE.into(), + target: batch_precompile_address, + input: BatchPCall::batch_all { + to: vec![Address(BOB.into())].into(), + value: vec![U256::from(1 * MOVR)].into(), + call_data: vec![].into(), + gas_limit: vec![].into() + } + .into(), + value: U256::zero(), // No value sent in EVM + gas_limit: 500_000, + max_fee_per_gas: U256::from(BASE_FEE_GENESIS), + max_priority_fee_per_gas: None, + nonce: Some(U256::from(0)), + access_list: Vec::new(), + }) + .dispatch(::RuntimeOrigin::root())); + + let transfer_count = System::events() + .iter() + .filter(|r| match r.event { + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => true, + _ => false, + }) + .count(); + + assert_eq!(transfer_count, 1, "there should be 1 transfer event"); + }); +} + +#[cfg(test)] +mod fee_tests { + use super::*; + use fp_evm::FeeCalculator; + use frame_support::{ + traits::{ConstU128, OnFinalize}, + weights::{ConstantMultiplier, WeightToFee}, + }; + use moonriver_runtime::{ + currency, LengthToFee, MinimumMultiplier, RuntimeBlockWeights, SlowAdjustingFeeUpdate, + TargetBlockFullness, TransactionPaymentAsGasPrice, NORMAL_WEIGHT, WEIGHT_PER_GAS, + }; + use sp_core::Get; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn test_multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() + * RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_total + .unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!( + next > minimum_multiplier, + "{:?} !>= {:?}", + next, + minimum_multiplier + ); + }) + } + + #[test] + fn test_fee_calculation() { + let base_extrinsic = RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let multiplier = sp_runtime::FixedU128::from_float(0.999000000000000000); + let extrinsic_len = 100u32; + let extrinsic_weight = Weight::from_parts(5_000u64, 1); + let tip = 42u128; + type WeightToFeeImpl = ConstantMultiplier>; + type LengthToFeeImpl = LengthToFee; + + // base_fee + (multiplier * extrinsic_weight_fee) + extrinsic_length_fee + tip + let expected_fee = WeightToFeeImpl::weight_to_fee(&base_extrinsic) + + multiplier.saturating_mul_int(WeightToFeeImpl::weight_to_fee(&extrinsic_weight)) + + LengthToFeeImpl::weight_to_fee(&(Weight::from_parts(extrinsic_len as u64, 1))) + + tip; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual_fee = TransactionPayment::compute_fee( + extrinsic_len, + &frame_support::dispatch::DispatchInfo { + class: DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + weight: extrinsic_weight, + }, + tip, + ); + + assert_eq!( + expected_fee, + actual_fee, + "The actual fee did not match the expected fee, diff {}", + actual_fee - expected_fee + ); + }); + } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int( + (currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128), + ) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = + (currency::WEIGHT_FEE * 4).saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(1_250_750_225u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(1_253_254_225u128), + ); + + // 1 "real" hour (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(1_791_661_729u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(5_948_516_121u128), + ); + + // 1 "real" day (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(1_250_000_000u128), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(7_066_658_618_836u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(125_000_000_000_000u128), // upper bound enforced + ); + }); + } +} diff --git a/tracing/3200/runtime/moonriver/tests/runtime_apis.rs b/tracing/3200/runtime/moonriver/tests/runtime_apis.rs new file mode 100644 index 00000000..06a77942 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/runtime_apis.rs @@ -0,0 +1,398 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver Runtime Api Integration Tests + +mod common; +use common::*; + +use fp_evm::{FeeCalculator, GenesisAccount}; +use frame_support::assert_ok; +use nimbus_primitives::NimbusId; +use pallet_evm::{Account as EVMAccount, AddressMapping}; +use sp_core::{ByteArray, H160, H256, U256}; + +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; +use moonbeam_core_primitives::Header; +use moonbeam_rpc_primitives_txpool::runtime_decl_for_tx_pool_runtime_api::TxPoolRuntimeApi; +use moonriver_runtime::{Executive, TransactionPaymentAsGasPrice}; +use nimbus_primitives::runtime_decl_for_nimbus_api::NimbusApi; +use std::{collections::BTreeMap, str::FromStr}; + +#[test] +fn ethereum_runtime_rpc_api_chain_id() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Runtime::chain_id(), CHAIN_ID); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_basic() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * MOVR)]) + .build() + .execute_with(|| { + assert_eq!( + Runtime::account_basic(H160::from(ALICE)), + EVMAccount { + balance: U256::from(2_000 * MOVR), + nonce: U256::zero() + } + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_gas_price() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!( + Runtime::gas_price(), + TransactionPaymentAsGasPrice::min_gas_price().0 + ); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_account_code_at() { + let address = H160::from(EVM_CONTRACT); + let code: Vec = vec![1, 2, 3, 4, 5]; + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: code.clone(), + nonce: Default::default(), + storage: Default::default(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::account_code_at(address), code); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_author() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + assert_eq!(Runtime::author(), H160::from(ALICE)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_storage_at() { + let address = H160::from(EVM_CONTRACT); + let mut key = [0u8; 32]; + key[31..32].copy_from_slice(&[6u8][..]); + let mut value = [0u8; 32]; + value[31..32].copy_from_slice(&[7u8][..]); + let item = H256::from_slice(&key[..]); + let mut storage: BTreeMap = BTreeMap::new(); + storage.insert(H256::from_slice(&key[..]), item); + ExtBuilder::default() + .with_evm_accounts({ + let mut map = BTreeMap::new(); + map.insert( + address, + GenesisAccount { + balance: U256::zero(), + code: Vec::new(), + nonce: Default::default(), + storage: storage.clone(), + }, + ); + map + }) + .build() + .execute_with(|| { + assert_eq!(Runtime::storage_at(address, U256::from(6)), item); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_call() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 2_000 * MOVR), + ]) + .build() + .execute_with(|| { + let execution_result = Runtime::call( + H160::from(ALICE), // from + H160::from(BOB), // to + Vec::new(), // data + U256::from(1000u64), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_create() { + ExtBuilder::default() + .with_balances(vec![(AccountId::from(ALICE), 2_000 * MOVR)]) + .build() + .execute_with(|| { + let execution_result = Runtime::create( + H160::from(ALICE), // from + vec![0, 1, 1, 0], // data + U256::zero(), // value + U256::from(100000u64), // gas_limit + None, // max_fee_per_gas + None, // max_priority_fee_per_gas + None, // nonce + false, // estimate + None, // access_list + ); + assert!(execution_result.is_ok()); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_transaction_statuses() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + // set_author(NimbusId::from_slice(&ALICE_NIMBUS)); + let result = + Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)).expect("Apply result."); + assert_eq!(result, Ok(())); + rpc_run_to_block(2); + let statuses = + Runtime::current_transaction_statuses().expect("Transaction statuses result."); + assert_eq!(statuses.len(), 1); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_block() { + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + // set_author(NimbusId::from_slice(&ALICE_NIMBUS)); + rpc_run_to_block(2); + let block = Runtime::current_block().expect("Block result."); + assert_eq!(block.header.number, U256::from(1u8)); + }); +} + +#[test] +fn ethereum_runtime_rpc_api_current_receipts() { + let alith = ::AddressMapping::into_account_id( + H160::from_str("f24ff3a9cf04c71dbc94d0b566f7a27b94566cac") + .expect("internal H160 is valid; qed"), + ); + ExtBuilder::default() + .with_collators(vec![(AccountId::from(ALICE), 1_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .with_balances(vec![ + (alith, 2_000 * MOVR), + (AccountId::from(ALICE), 2_000 * MOVR), + (AccountId::from(BOB), 1_000 * MOVR), + ]) + .with_delegations(vec![( + AccountId::from(BOB), + AccountId::from(ALICE), + 500 * MOVR, + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + // set_author(NimbusId::from_slice(&ALICE_NIMBUS)); + let result = + Executive::apply_extrinsic(unchecked_eth_tx(VALID_ETH_TX)).expect("Apply result."); + assert_eq!(result, Ok(())); + rpc_run_to_block(2); + let receipts = Runtime::current_receipts().expect("Receipts result."); + assert_eq!(receipts.len(), 1); + }); +} + +#[test] +fn txpool_runtime_api_extrinsic_filter() { + ExtBuilder::default().build().execute_with(|| { + let non_eth_uxt = UncheckedExtrinsic::new_unsigned( + pallet_balances::Call::::transfer_allow_death { + dest: AccountId::from(BOB), + value: 1 * MOVR, + } + .into(), + ); + let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); + let txpool = >::extrinsic_filter( + vec![eth_uxt.clone(), non_eth_uxt.clone()], + vec![unchecked_eth_tx(VALID_ETH_TX), non_eth_uxt], + ); + assert_eq!(txpool.ready.len(), 1); + assert_eq!(txpool.future.len(), 1); + }); +} + +#[test] +fn can_author_when_selected_is_empty() { + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), 20_000_000 * MOVR), + (AccountId::from(BOB), 10_000_000 * MOVR), + ]) + .with_collators(vec![(AccountId::from(ALICE), 2_000_000 * MOVR)]) + .with_mappings(vec![( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + AccountId::from(ALICE), + )]) + .build() + .execute_with(|| { + set_parachain_inherent_data(); + run_to_block(2, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: Default::default(), + parent_hash: Default::default(), + state_root: Default::default(), + }; + + // Base case: ALICE can author blocks when she is the only candidate + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Remove ALICE from candidate pool, leaving the candidate_pool empty + assert_ok!(ParachainStaking::go_offline(origin_of(AccountId::from( + ALICE + )))); + + // Need to fast forward to right before the next session, which is when selected candidates + // will be updated. We want to test the creation of the first block of the next session. + run_to_block(1799, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1799, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + + // Check that it works as expected after session update + run_to_block(1800, Some(NimbusId::from_slice(&ALICE_NIMBUS).unwrap())); + + assert_eq!(ParachainStaking::candidate_pool().0.len(), 0); + + let slot_number = 0; + let parent = Header { + digest: Default::default(), + extrinsics_root: Default::default(), + number: 1800, + parent_hash: Default::default(), + state_root: Default::default(), + }; + + let can_author_block = Runtime::can_author( + NimbusId::from_slice(&ALICE_NIMBUS).unwrap(), + slot_number, + &parent, + ); + + assert!(can_author_block); + }); +} diff --git a/tracing/3200/runtime/moonriver/tests/xcm_mock/mod.rs b/tracing/3200/runtime/moonriver/tests/xcm_mock/mod.rs new file mode 100644 index 00000000..cb1cacc4 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/xcm_mock/mod.rs @@ -0,0 +1,274 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +pub mod parachain; +pub mod relay_chain; +pub mod statemine_like; + +use cumulus_primitives_core::ParaId; +use pallet_xcm_transactor::relay_indices::*; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use polkadot_runtime_parachains::configuration::{ + GenesisConfig as ConfigurationGenesisConfig, HostConfiguration, +}; +use polkadot_runtime_parachains::paras::{ + GenesisConfig as ParasGenesisConfig, ParaGenesisArgs, ParaKind, +}; +use sp_core::{H160, U256}; +use std::{collections::BTreeMap, str::FromStr}; + +pub const PARAALICE: [u8; 20] = [1u8; 20]; +pub const RELAYALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const RELAYBOB: AccountId32 = AccountId32::new([2u8; 32]); + +pub fn para_a_account() -> AccountId32 { + ParaId::from(1).into_account_truncating() +} + +pub fn para_b_account() -> AccountId32 { + ParaId::from(2).into_account_truncating() +} + +pub fn para_a_account_20() -> parachain::AccountId { + ParaId::from(1).into_account_truncating() +} + +pub fn evm_account() -> H160 { + H160::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn mock_para_genesis_info() -> ParaGenesisArgs { + ParaGenesisArgs { + genesis_head: vec![1u8].into(), + validation_code: vec![1u8].into(), + para_kind: ParaKind::Parachain, + } +} + +pub fn mock_relay_config() -> HostConfiguration { + HostConfiguration:: { + hrmp_channel_max_capacity: u32::MAX, + hrmp_channel_max_total_size: u32::MAX, + hrmp_max_parachain_inbound_channels: 10, + hrmp_max_parachain_outbound_channels: 10, + hrmp_channel_max_message_size: u32::MAX, + // Changed to avoid aritmetic errors within hrmp_close + max_downward_message_size: 100_000u32, + ..Default::default() + } +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + +decl_test_parachain! { + pub struct Statemine { + Runtime = statemine_like::Runtime, + XcmpMessageHandler = statemine_like::MsgQueue, + DmpMessageHandler = statemine_like::MsgQueue, + new_ext = statemine_ext(1000), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(vec![1, 2, 3, 1000]), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + (1000, Statemine), + ], + } +} + +pub const INITIAL_BALANCE: u128 = 10_000_000_000_000_000; + +pub const INITIAL_EVM_BALANCE: u128 = 0; +pub const INITIAL_EVM_NONCE: u32 = 1; + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use parachain::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(PARAALICE.into(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_xcm_transactor::GenesisConfig:: { + // match relay runtime construct_runtime order in xcm_mock::relay_chain + relay_indices: RelayChainIndices { + hrmp: 6u8, + init_open_channel: 0u8, + accept_open_channel: 1u8, + close_channel: 2u8, + cancel_open_request: 6u8, + ..Default::default() + }, + ..Default::default() + } + .assimilate_storage(&mut t) + .unwrap(); + + // EVM accounts are self-sufficient. + let mut evm_accounts = BTreeMap::new(); + evm_accounts.insert( + evm_account(), + fp_evm::GenesisAccount { + nonce: U256::from(INITIAL_EVM_NONCE), + balance: U256::from(INITIAL_EVM_BALANCE), + storage: Default::default(), + code: vec![ + 0x00, // STOP + ], + }, + ); + + let genesis_config = pallet_evm::GenesisConfig:: { + accounts: evm_accounts, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn statemine_ext(para_id: u32) -> sp_io::TestExternalities { + use statemine_like::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (RELAYALICE.into(), INITIAL_BALANCE), + (RELAYBOB.into(), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext(paras: Vec) -> sp_io::TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(RELAYALICE, INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let para_genesis: Vec<(ParaId, ParaGenesisArgs)> = paras + .iter() + .map(|¶_id| (para_id.into(), mock_para_genesis_info())) + .collect(); + + let genesis_config = ConfigurationGenesisConfig:: { + config: mock_relay_config(), + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let genesis_config = ParasGenesisConfig:: { + paras: para_genesis, + ..Default::default() + }; + genesis_config.assimilate_storage(&mut t).unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} + +pub type RelayChainPalletXcm = pallet_xcm::Pallet; +pub type Hrmp = polkadot_runtime_parachains::hrmp::Pallet; + +pub type StatemineBalances = pallet_balances::Pallet; +pub type StatemineChainPalletXcm = pallet_xcm::Pallet; +pub type StatemineAssets = pallet_assets::Pallet; + +pub type ParachainPalletXcm = pallet_xcm::Pallet; +pub type Assets = pallet_assets::Pallet; + +pub type Treasury = pallet_treasury::Pallet; +pub type AssetManager = pallet_asset_manager::Pallet; +pub type XTokens = orml_xtokens::Pallet; +pub type RelayBalances = pallet_balances::Pallet; +pub type ParaBalances = pallet_balances::Pallet; +pub type XcmTransactor = pallet_xcm_transactor::Pallet; +pub type XcmWeightTrader = pallet_xcm_weight_trader::Pallet; diff --git a/tracing/3200/runtime/moonriver/tests/xcm_mock/parachain.rs b/tracing/3200/runtime/moonriver/tests/xcm_mock/parachain.rs new file mode 100644 index 00000000..e71bc1e2 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/xcm_mock/parachain.rs @@ -0,0 +1,1129 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Parachain runtime mock. + +use frame_support::{ + construct_runtime, + dispatch::GetDispatchInfo, + ensure, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU32, Everything, Get, InstanceFilter, Nothing, PalletInfoAccess, + }, + weights::Weight, + PalletId, +}; +use frame_system::{pallet_prelude::BlockNumberFor, EnsureNever, EnsureRoot}; +use pallet_xcm::migration::v1::VersionUncheckedMigrateToV1; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, Hash, IdentityLookup, MaybeEquivalence, Zero}, + Permill, +}; +use sp_std::{convert::TryFrom, prelude::*}; +use xcm::{latest::prelude::*, Version as XcmVersion, VersionedXcm}; + +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use orml_traits::parameter_type_with_key; +use pallet_ethereum::PostLogContent; +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; +use polkadot_parachain::primitives::{Id as ParaId, Sibling}; +use xcm::latest::{ + Error as XcmError, ExecuteXcm, + Junction::{PalletInstance, Parachain}, + Location, NetworkId, Outcome, Xcm, +}; +use xcm_builder::{ + AccountKey20Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, Case, ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountKey20AsNative, SovereignSignedViaLocation, + TakeWeightCredit, WithComputedOrigin, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; + +#[cfg(feature = "runtime-benchmarks")] +use moonbeam_runtime_common::benchmarking::BenchmarkHelper as ArgumentsBenchmarkHelper; +pub use moonriver_runtime::xcm_config::AssetType; +use scale_info::TypeInfo; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; + +pub type AccountId = moonbeam_core_primitives::AccountId; +pub type Balance = u128; +pub type AssetId = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 0; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +pub type ForeignAssetInstance = (); + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 1; // Does not really matter as this will be only called by root + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + AccountKey20Aliases, + // Generate remote accounts according to polkadot standards + xcm_builder::HashedDescription< + AccountId, + xcm_builder::DescribeFamily, + >, +); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, + SignedAccountKey20AsNative, +); + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1u64, 1u64); + pub MaxInstructions: u32 = 100; +} + +// Instructing how incoming xcm assets will be handled +pub type ForeignFungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ( + ConvertedConcreteId< + AssetId, + Balance, + xcm_primitives::AsAssetType, + JustTry, + >, + ), + // Do a simple punn to convert an AccountId32 Location into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleports. + NoChecking, + // We dont track any teleports + (), +>; + +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching any of the locations in + // SelfReserveRepresentations + IsConcrete, + // We can convert the Locations with our converter above: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We dont allow teleport + (), +>; + +// We use both transactors +pub type AssetTransactors = (LocalAssetTransactor, ForeignFungiblesTransactor); + +pub type XcmRouter = super::ParachainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + /// Xcm fees will go to the treasury account + pub XcmFeesAccount: AccountId = Treasury::account_id(); + /// Parachain token units per second of execution + pub ParaTokensPerSecond: u128 = 1000000000000; +} + +pub struct WeightToFee; +impl sp_weights::WeightToFee for WeightToFee { + type Balance = Balance; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + use sp_runtime::SaturatedConversion as _; + Self::Balance::saturated_from(weight.ref_time()) + .saturating_mul(ParaTokensPerSecond::get()) + .saturating_div(frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as u128) + } +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub SelfReserve: Location = Location { + parents:0, + interior: [ + PalletInstance(::index() as u8) + ].into() + }; + pub const MaxAssetsIntoHolding: u32 = 64; + + pub AssetHubLocation: Location = Location::new(1, [Parachain(1000)]); + pub RelayLocationFilter: AssetFilter = Wild(AllOf { + fun: WildFungible, + id: xcm::prelude::AssetId(Location::parent()), + }); + + pub RelayChainNativeAssetFromAssetHub: (AssetFilter, Location) = ( + RelayLocationFilter::get(), + AssetHubLocation::get() + ); +} + +use frame_system::RawOrigin; +use sp_runtime::traits::PostDispatchInfoOf; +use sp_runtime::DispatchErrorWithPostInfo; +use xcm_executor::traits::CallDispatcher; +moonbeam_runtime_common::impl_moonbeam_xcm_call!(); + +type Reserves = ( + // Relaychain (DOT) from Asset Hub + Case, + // Assets which the reserve is the same as the origin. + orml_xcm_support::MultiNativeAsset< + xcm_primitives::AbsoluteAndRelativeReserve, + >, +); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = Reserves; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = pallet_xcm_weight_trader::Trader; + type ResponseHandler = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type CallDispatcher = MoonbeamCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Our currencyId. We distinguish for now between SelfReserve, and Others, defined by their Id. +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum CurrencyId { + SelfReserve, + ForeignAsset(AssetId), +} + +// How to convert from CurrencyId to Location +pub struct CurrencyIdToLocation(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert> + for CurrencyIdToLocation +where + AssetXConverter: MaybeEquivalence, +{ + fn convert(currency: CurrencyId) -> Option { + match currency { + CurrencyId::SelfReserve => { + // For now and until Xtokens is adapted to handle 0.9.16 version we use + // the old anchoring here + // This is not a problem in either cases, since the view of the destination + // chain does not change + // TODO! change this to NewAnchoringSelfReserve once xtokens is adapted for it + let multi: Location = SelfReserve::get(); + Some(multi) + } + CurrencyId::ForeignAsset(asset) => AssetXConverter::convert_back(&asset), + } + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxAssetsForTransfer: usize = 2; + pub SelfLocation: Location = Location::here(); + pub SelfLocationAbsolute: Location = Location { + parents:1, + interior: [ + Parachain(MsgQueue::parachain_id().into()) + ].into() + }; +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: Location| -> Option { + match (location.parents, location.first_interior()) { + (1, Some(Parachain(1000u32))) => Some(50u128), + _ => None, + } + }; +} + +// The XCM message wrapper wrapper +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdConvert = + CurrencyIdToLocation>; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type UniversalLocation = UniversalLocation; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type MinXcmFee = ParachainMinFee; + type LocationsFilter = Everything; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type RateLimiter = (); + type RateLimiterId = (); +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 0; + pub const SpendPeriod: u32 = 0; + pub const TreasuryId: PalletId = PalletId(*b"pc/trsry"); + pub const MaxApprovals: u32 = 100; + pub TreasuryAccount: AccountId = Treasury::account_id(); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryId; + type Currency = Balances; + type ApproveOrigin = EnsureRoot; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type SpendPeriod = SpendPeriod; + type Burn = (); + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type ProposalBondMaximum = (); + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; // Same as Polkadot + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = ConstU32<0>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = ArgumentsBenchmarkHelper; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} + +// Pallet to provide the version, used to test runtime upgrade version changes +#[frame_support::pallet] +pub mod mock_version_changer { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_version)] + pub(super) type CurrentVersion = StorageValue<_, XcmVersion, ValueQuery>; + + impl Get for Pallet { + fn get() -> XcmVersion { + Self::current_version() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + VersionChanged(XcmVersion), + } + + impl Pallet { + pub fn set_version(version: XcmVersion) { + CurrentVersion::::put(version); + Self::deposit_event(Event::VersionChanged(version)); + } + } +} + +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl mock_version_changer::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +pub type LocalOriginToLocation = + xcm_primitives::SignedToAccountId20; + +parameter_types! { + pub MatcherLocation: Location = Location::here(); +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = frame_support::traits::Nothing; + type XcmExecutor = XcmExecutor; + // Do not allow teleports + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // We use a custom one to test runtime ugprades + type AdvertisedXcmVersion = XcmVersioner; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +// We instruct how to register the Assets +// In this case, we tell it to Create an Asset in pallet-assets +pub struct AssetRegistrar; +use frame_support::pallet_prelude::DispatchResult; +impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { + fn create_foreign_asset( + asset: AssetId, + min_balance: Balance, + metadata: AssetMetadata, + is_sufficient: bool, + ) -> DispatchResult { + Assets::force_create( + RuntimeOrigin::root(), + asset, + AssetManager::account_id(), + is_sufficient, + min_balance, + )?; + + Assets::force_set_metadata( + RuntimeOrigin::root(), + asset, + metadata.name, + metadata.symbol, + metadata.decimals, + false, + ) + } + + fn destroy_foreign_asset(asset: AssetId) -> DispatchResult { + // Mark the asset as destroying + Assets::start_destroy(RuntimeOrigin::root(), asset.into())?; + + Ok(()) + } + + fn destroy_asset_dispatch_info_weight(asset: AssetId) -> Weight { + RuntimeCall::Assets( + pallet_assets::Call::::start_destroy { + id: asset.into(), + }, + ) + .get_dispatch_info() + .weight + } +} + +#[derive(Clone, Default, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, +} + +impl pallet_asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetRegistrarMetadata = AssetMetadata; + type ForeignAssetType = AssetType; + type AssetRegistrar = AssetRegistrar; + type ForeignAssetModifierOrigin = EnsureRoot; + type WeightInfo = (); +} + +// 1 KSM should be enough +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +impl pallet_xcm_transactor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Transactor = MockTransactors; + type DerivativeAddressRegistrationOrigin = EnsureRoot; + type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot; + type CurrencyId = CurrencyId; + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type CurrencyIdToLocation = + CurrencyIdToLocation>; + type SelfLocation = SelfLocation; + type Weigher = xcm_builder::FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type XcmSender = XcmRouter; + type BaseXcmWeight = BaseXcmWeight; + type AssetTransactor = AssetTransactors; + type ReserveProvider = xcm_primitives::AbsoluteAndRelativeReserve; + type WeightInfo = (); + type HrmpManipulatorOrigin = EnsureRoot; + type HrmpOpenOrigin = EnsureRoot; + type MaxHrmpFee = xcm_builder::Case; +} + +parameter_types! { + pub RelayLocation: Location = Location::parent(); +} + +impl pallet_xcm_weight_trader::Config for Runtime { + type AccountIdToLocation = xcm_primitives::AccountIdToLocation; + type AddSupportedAssetOrigin = EnsureRoot; + type AssetLocationFilter = Everything; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type EditSupportedAssetOrigin = EnsureRoot; + type NativeLocation = SelfReserve; + type PauseSupportedAssetOrigin = EnsureRoot; + type RemoveSupportedAssetOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type ResumeSupportedAssetOrigin = EnsureRoot; + type WeightInfo = (); + type WeightToFee = WeightToFee; + type XcmFeesAccount = XcmFeesAccount; + #[cfg(feature = "runtime-benchmarks")] + type NotFilteredLocation = RelayLocation; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 1000; +} +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +use sp_core::U256; + +const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 160 KB. +const BLOCK_STORAGE_LIMIT: u64 = 160 * 1024; + +parameter_types! { + pub BlockGasLimit: U256 = U256::from(u64::MAX); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub GasLimitPovSizeRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(MAX_POV_SIZE) + }; + pub GasLimitStorageGrowthRatio: u64 = + BlockGasLimit::get().min(u64::MAX.into()).low_u64().saturating_div(BLOCK_STORAGE_LIMIT); +} + +impl pallet_evm::Config for Runtime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressNever; + + type AddressMapping = pallet_evm::IdentityAddressMapping; + type Currency = Balances; + type Runner = pallet_evm::runner::stack::Runner; + + type RuntimeEvent = RuntimeEvent; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = (); + type BlockGasLimit = BlockGasLimit; + type OnChargeTransaction = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type SuicideQuickClearLimit = ConstU32<0>; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; +} + +pub struct NormalFilter; +impl frame_support::traits::Contains for NormalFilter { + fn contains(c: &RuntimeCall) -> bool { + match c { + _ => true, + } + } +} + +// We need to use the encoding from the relay mock runtime +#[derive(Encode, Decode)] +pub enum RelayCall { + #[codec(index = 5u8)] + // the index should match the position of the module in `construct_runtime!` + Utility(UtilityCall), + #[codec(index = 6u8)] + // the index should match the position of the module in `construct_runtime!` + Hrmp(HrmpCall), +} + +#[derive(Encode, Decode)] +pub enum UtilityCall { + #[codec(index = 1u8)] + AsDerivative(u16), +} + +// HRMP call encoding, needed for xcm transactor pallet +#[derive(Encode, Decode)] +pub enum HrmpCall { + #[codec(index = 0u8)] + InitOpenChannel(ParaId, u32, u32), + #[codec(index = 1u8)] + AcceptOpenChannel(ParaId), + #[codec(index = 2u8)] + CloseChannel(HrmpChannelId), + #[codec(index = 6u8)] + CancelOpenRequest(HrmpChannelId, u32), +} + +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum MockTransactors { + Relay, +} + +impl xcm_primitives::XcmTransact for MockTransactors { + fn destination(self) -> Location { + match self { + MockTransactors::Relay => Location::parent(), + } + } +} + +impl xcm_primitives::UtilityEncodeCall for MockTransactors { + fn encode_call(self, call: xcm_primitives::UtilityAvailableCalls) -> Vec { + match self { + MockTransactors::Relay => match call { + xcm_primitives::UtilityAvailableCalls::AsDerivative(a, b) => { + let mut call = + RelayCall::Utility(UtilityCall::AsDerivative(a.clone())).encode(); + call.append(&mut b.clone()); + call + } + }, + } + } +} + +pub struct MockHrmpEncoder; +impl xcm_primitives::HrmpEncodeCall for MockHrmpEncoder { + fn hrmp_encode_call( + call: xcm_primitives::HrmpAvailableCalls, + ) -> Result, xcm::latest::Error> { + match call { + xcm_primitives::HrmpAvailableCalls::InitOpenChannel(a, b, c) => Ok(RelayCall::Hrmp( + HrmpCall::InitOpenChannel(a.clone(), b.clone(), c.clone()), + ) + .encode()), + xcm_primitives::HrmpAvailableCalls::AcceptOpenChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::AcceptOpenChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CloseChannel(a) => { + Ok(RelayCall::Hrmp(HrmpCall::CloseChannel(a.clone())).encode()) + } + xcm_primitives::HrmpAvailableCalls::CancelOpenRequest(a, b) => { + Ok(RelayCall::Hrmp(HrmpCall::CancelOpenRequest(a.clone(), b.clone())).encode()) + } + } + } +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub ReservedXcmpWeight: Weight = Weight::from_parts(u64::max_value(), 0); +} + +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo, +)] +pub enum ProxyType { + NotAllowed = 0, + Any = 1, +} + +impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {} + +impl InstanceFilter for ProxyType { + fn filter(&self, _c: &RuntimeCall) -> bool { + match self { + ProxyType::NotAllowed => false, + ProxyType::Any => true, + } + } + fn is_superset(&self, _o: &Self) -> bool { + false + } +} + +impl Default for ProxyType { + fn default() -> Self { + Self::NotAllowed + } +} + +parameter_types! { + pub const ProxyCost: u64 = 1; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyCost; + type ProxyDepositFactor = ProxyCost; + type MaxProxies = ConstU32<32>; + type WeightInfo = pallet_proxy::weights::SubstrateWeight; + type MaxPending = ConstU32<32>; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = ProxyCost; + type AnnouncementDepositFactor = ProxyCost; +} + +pub struct EthereumXcmEnsureProxy; +impl xcm_primitives::EnsureProxy for EthereumXcmEnsureProxy { + fn ensure_ok(delegator: AccountId, delegatee: AccountId) -> Result<(), &'static str> { + // The EVM implicitely contains an Any proxy, so we only allow for "Any" proxies + let def: pallet_proxy::ProxyDefinition = + pallet_proxy::Pallet::::find_proxy( + &delegator, + &delegatee, + Some(ProxyType::Any), + ) + .map_err(|_| "proxy error: expected `ProxyType::Any`")?; + // We only allow to use it for delay zero proxies, as the call will iMmediatly be executed + ensure!(def.delay.is_zero(), "proxy delay is Non-zero`"); + Ok(()) + } +} + +impl pallet_ethereum_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type XcmEthereumOrigin = pallet_ethereum_xcm::EnsureXcmEthereumTransaction; + type ReservedXcmpWeight = ReservedXcmpWeight; + type EnsureProxy = EthereumXcmEnsureProxy; + type ControllerOrigin = EnsureRoot; + type ForceOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlockU32; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_msg_queue, + XcmVersioner: mock_version_changer, + + PolkadotXcm: pallet_xcm, + Assets: pallet_assets, + CumulusXcm: cumulus_pallet_xcm, + XTokens: orml_xtokens, + AssetManager: pallet_asset_manager, + XcmTransactor: pallet_xcm_transactor, + XcmWeightTrader: pallet_xcm_weight_trader, + Treasury: pallet_treasury, + Proxy: pallet_proxy, + + Timestamp: pallet_timestamp, + EVM: pallet_evm, + Ethereum: pallet_ethereum, + EthereumXcm: pallet_ethereum_xcm, + } +); + +pub(crate) fn para_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion}; +use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade}; +pub(crate) fn on_runtime_upgrade() { + VersionUncheckedMigrateToV1::::on_runtime_upgrade(); +} + +pub(crate) fn para_roll_to(n: BlockNumber) { + while System::block_number() < n { + PolkadotXcm::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + PolkadotXcm::on_initialize(System::block_number()); + } +} diff --git a/tracing/3200/runtime/moonriver/tests/xcm_mock/relay_chain.rs b/tracing/3200/runtime/moonriver/tests/xcm_mock/relay_chain.rs new file mode 100644 index 00000000..f391b31d --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/xcm_mock/relay_chain.rs @@ -0,0 +1,430 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, IdentityLookup}, + AccountId32, +}; + +use frame_support::weights::{Weight, WeightMeter}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_runtime_parachains::{ + configuration, dmp, hrmp, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, paras, shared, +}; +use sp_runtime::transaction_validity::TransactionPriority; +use sp_runtime::Permill; +use xcm::latest::prelude::*; +use xcm_builder::{ + Account32Hash, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, + ChildSystemParachainAsSuperuser, FixedRateOfFungible, FixedWeightBounds, + FungibleAdapter as XcmCurrencyAdapter, IsConcrete, ProcessXcmMessage, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + WithComputedOrigin, +}; +use xcm_executor::{Config, XcmExecutor}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = BlockNumberFor; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); + type PalletsOrigin = OriginCaller; +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub KsmLocation: Location = Here.into(); + pub const KusamaNetwork: NetworkId = NetworkId::Kusama; + pub const AnyNetwork: Option = None; + pub UniversalLocation: InteriorLocation = Here; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + // Not enabled in the relay per se, but we enable it to test + // the transact_through_signed extrinsic + Account32Hash, +); + +pub type LocalAssetTransactor = + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1000u64, 1000u64); + pub KsmPerSecond: (AssetId, u128, u128) = (AssetId(KsmLocation::get()), 1, 1); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub MatcherLocation: Location = Location::here(); +} + +pub type XcmRouter = super::RelayChainXcmRouter; + +pub type XcmBarrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // Expected responses are OK. + AllowKnownQueryResponses, + WithComputedOrigin< + ( + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, + ), + UniversalLocation, + ConstU32<8>, + >, +); + +parameter_types! { + pub Kusama: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(KsmLocation::get()) }); + pub Statemine: Location = Parachain(1000).into(); + pub KusamaForStatemine: (AssetFilter, Location) = (Kusama::get(), Statemine::get()); +} + +pub type TrustedTeleporters = xcm_builder::Case; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = XcmBarrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub const FirstMessageFactorPercent: u64 = 100; +} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +/// A very dumb implementation of `EstimateNextSessionRotation`. At the moment of writing, this +/// is more to satisfy type requirements rather than to test anything. +pub struct TestNextSessionRotation; + +impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { + fn average_session_length() -> u32 { + 10 + } + + fn estimate_current_session_progress(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } + + fn estimate_next_session_rotation(_now: u32) -> (Option, Weight) { + (None, Weight::zero()) + } +} + +impl paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = TestNextSessionRotation; + type QueueFootprinter = (); + type OnNewHead = (); + type AssignCoretime = (); +} + +impl dmp::Config for Runtime {} + +parameter_types! { + pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); +} + +impl hrmp::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = TestHrmpWeightInfo; + type ChannelManager = frame_system::EnsureRoot; + type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +impl origin::Config for Runtime {} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlockU32; + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + Utility: pallet_utility, + Hrmp: hrmp, + Dmp: dmp, + Paras: paras, + Configuration: configuration, + } +); + +pub(crate) fn relay_events() -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| Some(e)) + .collect::>() +} + +use frame_support::traits::{OnFinalize, OnInitialize}; +pub(crate) fn relay_roll_to(n: BlockNumber) { + while System::block_number() < n { + XcmPallet::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + XcmPallet::on_initialize(System::block_number()); + } +} + +/// A weight info that is only suitable for testing. +pub struct TestHrmpWeightInfo; + +impl hrmp::WeightInfo for TestHrmpWeightInfo { + fn hrmp_accept_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn force_clean_hrmp(_: u32, _: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_close(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_process_hrmp_open(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_cancel_open_request(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_close_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn hrmp_init_open_channel() -> Weight { + Weight::from_parts(1, 0) + } + fn clean_open_channel_requests(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn force_open_hrmp_channel(_: u32) -> Weight { + Weight::from_parts(1, 0) + } + fn establish_system_channel() -> Weight { + Weight::from_parts(1, 0) + } + + fn poke_channel_deposits() -> Weight { + Weight::from_parts(1, 0) + } + + fn establish_channel_with_system() -> Weight { + Weight::from_parts(1, 0) + } +} diff --git a/tracing/3200/runtime/moonriver/tests/xcm_mock/statemine_like.rs b/tracing/3200/runtime/moonriver/tests/xcm_mock/statemine_like.rs new file mode 100644 index 00000000..f5d2b46c --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/xcm_mock/statemine_like.rs @@ -0,0 +1,607 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// 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 . + +//! Relay chain runtime mock. + +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, Get, Nothing}, + weights::Weight, +}; +use frame_system::{EnsureRoot, EnsureSigned}; + +use sp_core::H256; +use sp_runtime::{ + traits::{ConstU32, Hash, IdentityLookup}, + AccountId32, +}; + +use polkadot_core_primitives::BlockNumber as RelayBlockNumber; + +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_parachain::primitives::Sibling; +use sp_std::convert::TryFrom; +use xcm::latest::prelude::*; +use xcm::VersionedXcm; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + FungiblesAdapter, IsConcrete, NoChecking, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_simulator::{ + DmpMessageHandlerT as DmpMessageHandler, XcmpMessageFormat, + XcmpMessageHandlerT as XcmpMessageHandler, +}; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type AssetId = u128; + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type SingleBlockMigrations = (); + type MultiBlockMigrator = (); + type PreInherents = (); + type PostInherents = (); + type PostTransactions = (); +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeFreezeReason = (); +} + +// Required for runtime benchmarks +pallet_assets::runtime_benchmarks_enabled! { + pub struct BenchmarkHelper; + impl pallet_assets::BenchmarkHelper for BenchmarkHelper + where + AssetIdParameter: From, + { + fn create_asset_id_parameter(id: u32) -> AssetIdParameter { + (id as u128).into() + } + } +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; // 1 UNIT deposit to create asset + pub const ApprovalDeposit: Balance = 0; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; + pub const AssetAccountDeposit: Balance = 0; +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type AssetAccountDeposit = AssetAccountDeposit; + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<656>; + type AssetIdParameter = AssetId; + type CreateOrigin = AsEnsureOriginWithArg>; + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = BenchmarkHelper; + } +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); + pub Local: Location = Here.into(); + pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub KsmPerSecond: (xcm::latest::prelude::AssetId, u128, u128) = + (AssetId(KsmLocation::get()), 1, 1); +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the default `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting the native currency on this chain. +pub type CurrencyTransactor = FungibleAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + ConvertedConcreteId< + AssetId, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We only want to allow teleports of known assets. We use non-zero issuance as an indication + // that this asset is known. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; +/// Means for transacting assets on this chain. +pub type AssetTransactors = (CurrencyTransactor, FungiblesTransactor); + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when + // recognised. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `RuntimeOrigin::signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + pallet_xcm::XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = Weight::from_parts(100u64, 100u64); + pub const MaxInstructions: u32 = 100; +} + +pub struct ParentOrParentsExecutivePlurality; +impl Contains for ParentOrParentsExecutivePlurality { + fn contains(location: &Location) -> bool { + matches!( + location.unpack(), + (1, []) + | ( + 1, + [Plurality { + id: BodyId::Executive, + .. + }] + ) + ) + } +} + +pub struct ParentOrSiblings; +impl Contains for ParentOrSiblings { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (1, []) | (1, [_])) + } +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +parameter_types! { + pub MatcherLocation: Location = Location::here(); + pub const MaxAssetsIntoHolding: u32 = 64; + pub const RelayTokenLocation: Location = Location::parent(); +} + +// Copied from: +// +// https://github.com/paritytech/polkadot-sdk/blob/f4eb41773611008040c9d4d8a8e6b7323eccfca1/cumulus +// /parachains/common/src/xcm_config.rs#L118 +// +// The difference with the original "ConcreteAssetFromSystem" (which is used by AssetHub), +// is that in our tests we only need to check if the asset matches the relay one. +pub struct ConcreteAssetFromRelay(sp_std::marker::PhantomData); +impl> ContainsPair + for ConcreteAssetFromRelay +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + let is_relay = match origin.unpack() { + // The Relay Chain + (1, []) => true, + // Others + _ => false, + }; + asset.id.0 == AssetLocation::get() && is_relay + } +} + +pub type TrustedTeleporters = (ConcreteAssetFromRelay,); + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = + orml_xcm_support::MultiNativeAsset; + type IsTeleporter = TrustedTeleporters; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type CallDispatcher = RuntimeCall; + type AssetLocker = (); + type AssetExchanger = (); + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +pub type XcmRouter = super::ParachainXcmRouter; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[frame_support::pallet] +pub mod mock_msg_queue { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn parachain_id)] + pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + Self::parachain_id() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success(Option), + /// Some XCM failed. + Fail(Option, XcmError), + /// Bad XCM version used. + BadVersion(Option), + /// Bad XCM format used. + BadFormat(Option), + + // DMP + /// Downward message is invalid XCM. + InvalidFormat(MessageId), + /// Downward message is unsupported version of XCM. + UnsupportedVersion(MessageId), + /// Downward message executed with the given outcome. + ExecutedDownward(MessageId, Outcome), + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = Location::new(1, [Parachain(sender.into())]); + let mut id = [0u8; 32]; + id.copy_from_slice(hash.as_ref()); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut id, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => { + (Err(error.clone()), Event::Fail(Some(hash), error)) + } + Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => { + (Ok(used), Event::Fail(Some(hash), error)) + } + } + } + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion(Some(hash)), + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: Weight, + ) -> Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = &data_ref[..]; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_i, (_sent_at, data)) in iter.enumerate() { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_msg = VersionedXcm::::decode(&mut &data[..]) + .map(Xcm::::try_from); + match maybe_msg { + Err(_) => { + Self::deposit_event(Event::InvalidFormat(id)); + } + Ok(Err(())) => { + Self::deposit_event(Event::UnsupportedVersion(id)); + } + Ok(Ok(x)) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x, + &mut id, + limit, + Weight::zero(), + ); + + Self::deposit_event(Event::ExecutedDownward(id, outcome)); + } + } + } + limit + } + } +} +impl mock_msg_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +// Pallet to cover test cases for change https://github.com/paritytech/cumulus/pull/831 +#[frame_support::pallet] +pub mod mock_statemine_prefix { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn current_prefix)] + pub(super) type CurrentPrefix = StorageValue<_, Location, ValueQuery>; + + impl Get for Pallet { + fn get() -> Location { + Self::current_prefix() + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Changed Prefix + PrefixChanged(Location), + } + + impl Pallet { + pub fn set_prefix(prefix: Location) { + CurrentPrefix::::put(&prefix); + Self::deposit_event(Event::PrefixChanged(prefix)); + } + } +} + +impl mock_statemine_prefix::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +type Block = frame_system::mocking::MockBlockU32; +construct_runtime!( + pub enum Runtime { + System: frame_system, + Balances: pallet_balances, + PolkadotXcm: pallet_xcm, + CumulusXcm: cumulus_pallet_xcm, + MsgQueue: mock_msg_queue, + Assets: pallet_assets, + PrefixChanger: mock_statemine_prefix, + + } +); diff --git a/tracing/3200/runtime/moonriver/tests/xcm_tests.rs b/tracing/3200/runtime/moonriver/tests/xcm_tests.rs new file mode 100644 index 00000000..ceee8aa5 --- /dev/null +++ b/tracing/3200/runtime/moonriver/tests/xcm_tests.rs @@ -0,0 +1,4882 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Moonriver Runtime Xcm Tests + +mod xcm_mock; +use frame_support::{ + assert_ok, + traits::{PalletInfo, PalletInfoAccess}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + BoundedVec, +}; +use sp_core::ConstU32; +use sp_runtime::traits::MaybeEquivalence; +use xcm::latest::prelude::{ + AccountId32, AccountKey20, All, Asset as XcmAsset, AssetId as XcmAssetId, Assets as XcmAssets, + BuyExecution, ClearOrigin, DepositAsset, Fungible, GeneralIndex, Junction, Junctions, Limited, + Location, OriginKind, PalletInstance, Parachain, QueryResponse, Reanchorable, Response, + WeightLimit, WithdrawAsset, Xcm, +}; +use xcm::{IntoVersion, VersionedLocation, WrapVersion}; +use xcm_executor::traits::ConvertLocation; +use xcm_mock::parachain; +use xcm_mock::relay_chain; +use xcm_mock::*; +use xcm_simulator::TestExt; +mod common; +use cumulus_primitives_core::relay_chain::HrmpChannelId; +use pallet_xcm_transactor::{ + Currency, CurrencyPayment, HrmpInitParams, HrmpOperation, TransactWeights, +}; +use xcm_primitives::{UtilityEncodeCall, DEFAULT_PROOF_SIZE}; + +fn add_supported_asset(asset_type: parachain::AssetType, units_per_second: u128) -> Result<(), ()> { + let parachain::AssetType::Xcm(location_v3) = asset_type; + let VersionedLocation::V4(location_v4) = VersionedLocation::V3(location_v3) + .into_version(4) + .map_err(|_| ())? + else { + return Err(()); + }; + use frame_support::weights::WeightToFee as _; + let native_amount_per_second: u128 = + ::WeightToFee::weight_to_fee( + &Weight::from_parts( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + 0, + ), + ) + .try_into() + .map_err(|_| ())?; + let precision_factor = 10u128.pow(pallet_xcm_weight_trader::RELATIVE_PRICE_DECIMALS); + let relative_price: u128 = if units_per_second > 0u128 { + native_amount_per_second + .saturating_mul(precision_factor) + .saturating_div(units_per_second) + } else { + 0u128 + }; + pallet_xcm_weight_trader::SupportedAssets::::insert( + location_v4, + (true, relative_price), + ); + Ok(()) +} + +// Send a relay asset (like DOT) to a parachain A +#[test] +fn receive_relay_asset_from_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // Register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Verify that parachain received the asset + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +// Send relay asset (like DOT) back from Parachain A to relaychain +#[test] +fn send_relay_asset_to_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register relay asset in paraA + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // free execution + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // First send relay chain asset to Parachain like in previous test + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Lets gather the balance before sending back money + let mut balance_before_sending = 0; + Relay::execute_with(|| { + balance_before_sending = RelayBalances::free_balance(&RELAYALICE); + }); + + // We now send back some money to the relay + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: RELAYALICE.into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 123, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The balances in paraAlice should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); + + // Balances in the relay should have been received + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(&RELAYALICE) > balance_before_sending); + }); +} + +#[test] +fn send_relay_asset_to_para_b() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Register asset in paraA. Free execution + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // First send relay chain asset to Parachain A like in previous test + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); + + // Now send relay asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances should have been substracted + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 23); + }); + + // Para B balances should have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_to_para_b() { + MockNet::reset(); + + // This represents the asset in paraA + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register asset in paraB. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send para A asset from para A to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Native token is substracted in paraA + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Asset is minted in paraB + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); +} + +#[test] +fn send_para_a_asset_from_para_b_to_para_c() { + MockNet::reset(); + + // Represents para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in parachain B. Free execution + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Register para A asset in parachain C. Free execution + ParaC::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send para A asset from para B to para C + let dest = Location { + parents: 1, + interior: [ + Parachain(3), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // The message passed through parachainA so we needed to pay since its the native token + ParaC::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 96); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a() { + MockNet::reset(); + + // Para A asset + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + // Register para A asset in para B + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send para A asset to para B + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Balances have been substracted + ParaA::execute_with(|| { + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // Para B balances have been credited + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // Send back para A asset to para A + let dest = Location { + parents: 1, + interior: [ + Parachain(1), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaB::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + // Para A asset has been credited + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_and_back_to_para_a_with_new_reanchoring() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // Free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // Free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // This time we will force the new reanchoring by manually sending the + // Message through polkadotXCM pallet + + let dest = Location { + parents: 1, + interior: [Parachain(1)].into(), + }; + + let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]); + + let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![ + WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()), + ClearOrigin, + BuyExecution { + fees: (reanchored_para_a_balances, 100).into(), + weight_limit: Limited(80.into()), + }, + DepositAsset { + assets: All.into(), + beneficiary: Location::new( + 0, + [AccountKey20 { + network: None, + key: PARAALICE, + }], + ), + }, + ])); + ParaB::execute_with(|| { + // Send a message to the sovereign account in ParaA to withdraw + // and deposit asset + assert_ok!(ParachainPalletXcm::send( + parachain::RuntimeOrigin::root(), + Box::new(dest.into()), + Box::new(message), + )); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // This time we will force the new reanchoring by manually sending the + // Message through polkadotXCM pallet + + let dest = Location { + parents: 1, + interior: [Parachain(1)].into(), + }; + + let reanchored_para_a_balances = Location::new(0, [PalletInstance(1u8)]); + + let message = xcm::VersionedXcm::<()>::V4(Xcm(vec![ + WithdrawAsset((reanchored_para_a_balances.clone(), 100).into()), + ClearOrigin, + BuyExecution { + fees: (reanchored_para_a_balances, 100).into(), + weight_limit: Limited(80.into()), + }, + DepositAsset { + assets: All.into(), + beneficiary: Location::new( + 0, + [AccountKey20 { + network: None, + key: PARAALICE, + }], + ), + }, + ])); + ParaB::execute_with(|| { + // Send a message to the sovereign account in ParaA to withdraw + // and deposit asset + assert_ok!(ParachainPalletXcm::send( + parachain::RuntimeOrigin::root(), + Box::new(dest.into()), + Box::new(message), + )); + }); + + ParaA::execute_with(|| { + // Weight used is 4 + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 4 + ); + }); +} + +#[test] +fn receive_relay_asset_with_trader() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset( + source_location.clone(), + 2500000000000u128 + )); + }); + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // We are sending 100 tokens from relay. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Therefore with no refund, we should receive 10 tokens less + // Native trader fails for this, and we use the asset trader + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 100).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // non-free execution, not full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset( + source_location.clone(), + 2500000000000u128 + )); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // In destination chain, we only need 4 weight + // We put 10 weight, 6 of which should be refunded and 4 of which should go to treasury + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(10u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + // We are sending 100 tokens from para A. + // Amount spent in fees is Units per second * weight / 1_000_000_000_000 (weight per second) + // weight is 4 since we are executing 4 instructions with a unitweightcost of 1. + // Units per second should be 2_500_000_000_000_000 + // Since we set 10 weight in destination chain, 25 will be charged upfront + // 15 of those will be refunded, while 10 will go to treasury as the true weight used + // will be 4 + ParaB::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 90); + // Fee should have been received by treasury + assert_eq!(Assets::balance(source_id, &Treasury::account_id()), 10); + }); +} + +#[test] +fn send_para_a_asset_to_para_b_with_trader_and_fee() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + + ParaB::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + // With these units per second, 80K weight convrets to 1 asset unit + assert_ok!(add_supported_asset(source_location.clone(), 12500000u128)); + }); + + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + + // we use transfer_with_fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(800000u64, DEFAULT_PROOF_SIZE)) + )); + }); + ParaA::execute_with(|| { + // 100 tokens transferred plus 1 taken from fees + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 - 1 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received because trully the xcm instruction does not cost + // what it is specified + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 101); + }); +} + +#[test] +fn error_when_not_paying_enough() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + // This time we are gonna put a rather high number of units per second + // we know later we will divide by 1e12 + // Lets put 1e6 as units per second + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset( + source_location.clone(), + 2500000000000u128 + )); + }); + + // We are sending 100 tokens from relay. + // If we set the dest weight to be 1e7, we know the buy_execution will spend 1e7*1e6/1e12 = 10 + // Therefore with no refund, we should receive 10 tokens less + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 5).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // amount not received as it is not paying enough + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 0); + }); +} + +#[test] +fn transact_through_derivative_multilocation() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 3000 correspond to 4000003000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000003000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + // 4000000000 + 3000 we should have taken out 4000003000 tokens from the caller + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + false + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_derivative_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + // Let's construct the call to know how much weight it is going to require + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + // 4000000000 transact + 9000 correspond to 4000009000 tokens. 100 more for the transfer call + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_derivative( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::MockTransactors::Relay, + 0, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee weight mapping + fee_amount: Some(overall_weight as u128) + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + let event_found: Option = parachain::para_events() + .iter() + .find_map(|event| match event.clone() { + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::AssetsTrapped { + .. + }) => Some(event.clone()), + _ => None, + }); + // Assert that the events do not contain the assets being trapped + assert!(event_found.is_none()); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn transact_through_sovereign() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_fee_payer_none() { + MockNet::reset(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + None + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + }); + + let derivative_address = derivative_account_id(para_a_account(), 0); + + Relay::execute_with(|| { + // Transfer 100 tokens to derivative_address on the relay + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derivative_address.clone(), + 100u128 + )); + + // Transfer the XCM execution fee amount to ParaA's sovereign account + assert_ok!(RelayBalances::transfer_keep_alive( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 4000003000u128 + )); + }); + + // Check balances before the transact call + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000003000); + assert_eq!(RelayBalances::free_balance(&derivative_address), 100); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 0); + }); + + // Encode the call. Balances transfer of 100 relay tokens to RELAYBOB + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: RELAYBOB, + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + // The final call will be an AsDerivative using index 0 + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + // No fee_payer here. The sovereign account will pay the fees on destination. + None, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + // Check balances after the transact call are correct + Relay::execute_with(|| { + assert_eq!(RelayBalances::free_balance(¶_a_account()), 0); + assert_eq!(RelayBalances::free_balance(&derivative_address), 0); + assert_eq!(RelayBalances::free_balance(&RELAYBOB), 100); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000003100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000003000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000003000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000003000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(®istered_address) == 0); + }); +} + +#[test] +fn transact_through_sovereign_with_custom_fee_weight_refund() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 1u128)); + }); + + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 4000009100u128).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009100); + }); + + // Register address + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::register( + parachain::RuntimeOrigin::root(), + PARAALICE.into(), + 0, + )); + }); + + // Send to registered address + let registered_address = derivative_account_id(para_a_account(), 0); + let dest = Location { + parents: 1, + interior: [AccountId32 { + network: None, + id: registered_address.clone().into(), + }] + .into(), + }; + + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 4000009000); + }); + + // What we will do now is transfer this relay tokens from the derived account to the sovereign + // again + Relay::execute_with(|| { + // free execution,x full amount received + assert!(RelayBalances::free_balance(¶_a_account()) == 4000009000); + 0 + }); + + // We send the xcm transact operation to parent + let dest = Location { + parents: 1, + interior: /* Here */ [].into(), + }; + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let utility_bytes = parachain::MockTransactors::Relay.encode_call( + xcm_primitives::UtilityAvailableCalls::AsDerivative(0, encoded), + ); + + let total_weight = 4000009000u64; + // Root can directly pass the execution byes to the sovereign + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_sovereign( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(dest)), + Some(PARAALICE.into()), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + // 1-1 fee-weight mapping + fee_amount: Some(total_weight as u128) + }, + utility_bytes, + OriginKind::SovereignAccount, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // free execution,x full amount received + // 4000005186 refunded + 100 transferred = 4000005286 + assert_eq!(RelayBalances::free_balance(¶_a_account()), 4000005286); + + assert_eq!(RelayBalances::free_balance(®istered_address), 0); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_relay() { + MockNet::reset(); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A and set XCM version to 1 + ParaA::execute_with(|| { + parachain::XcmVersioner::set_version(1); + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + let response = Response::Version(2); + let querier: Location = ([]/* Here */).into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + // The router is mocked, and we cannot use WrapVersion in ChildParachainRouter. So we will force + // it directly here + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + Relay::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(RelayChainPalletXcm::force_default_xcm_version( + relay_chain::RuntimeOrigin::root(), + Some(2) + )); + + // Wrap version, which sets VersionedStorage + // This is necessary because the mock router does not use wrap_version, but + // this is not necessary in prod + assert_ok!(::wrap_version( + &Parachain(1).into(), + mock_message + )); + + // Transfer assets. Since it is an unknown destination, it will query for version + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + + // Let's advance the relay. This should trigger the subscription message + relay_chain::relay_roll_to(2); + + // queries should have been updated + assert!(RelayChainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 1, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the version change + assert!(relay_chain::relay_events().contains(&expected_supported_version)); + }); + + // ParaA changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaA::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in the relay + let expected_supported_version_2: relay_chain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 0, + interior: [Parachain(1)].into(), + }, + version: 2, + } + .into(); + + Relay::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(relay_chain::relay_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn test_automatic_versioning_on_runtime_upgrade_with_para_b() { + MockNet::reset(); + + let para_a_balances = Location::new(1, [Parachain(1), PalletInstance(1u8)]); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(¶_a_balances).expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"ParaAToken".to_vec(), + symbol: b"ParaA".to_vec(), + decimals: 18, + }; + let response = Response::Version(2); + let querier: Location = [] /* Here */ + .into(); + + // This is irrelevant, nothing will be done with this message, + // but we need to pass a message as an argument to trigger the storage change + let mock_message: Xcm<()> = Xcm(vec![QueryResponse { + query_id: 0, + response, + max_weight: Weight::zero(), + querier: Some(querier), + }]); + + ParaA::execute_with(|| { + // advertised version + parachain::XcmVersioner::set_version(2); + }); + + ParaB::execute_with(|| { + // Let's try with v0 + parachain::XcmVersioner::set_version(0); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + ParaA::execute_with(|| { + // This sets the default version, for not known destinations + assert_ok!(ParachainPalletXcm::force_default_xcm_version( + parachain::RuntimeOrigin::root(), + Some(2) + )); + // Wrap version, which sets VersionedStorage + assert_ok!(::wrap_version( + &Location::new(1, [Parachain(2)]).into(), + mock_message + )); + + parachain::para_roll_to(2); + + // queries should have been updated + assert!(ParachainPalletXcm::query(0).is_some()); + }); + + let expected_supported_version: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 0, + } + .into(); + + ParaA::execute_with(|| { + // Assert that the events vector contains the version change + assert!(parachain::para_events().contains(&expected_supported_version)); + }); + + // Let's ensure talking in v0 works + let dest = Location { + parents: 1, + interior: [ + Parachain(2), + AccountKey20 { + network: None, + key: PARAALICE.into(), + }, + ] + .into(), + }; + ParaA::execute_with(|| { + // free execution, full amount received + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::SelfReserve, + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80u64, DEFAULT_PROOF_SIZE)) + )); + // free execution, full amount received + assert_eq!( + ParaBalances::free_balance(&PARAALICE.into()), + INITIAL_BALANCE - 100 + ); + }); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 100); + }); + + // ParaB changes version to 2, and calls on_runtime_upgrade. This should notify the targets + // of the new version change + ParaB::execute_with(|| { + // Set version + parachain::XcmVersioner::set_version(2); + // Do runtime upgrade + parachain::on_runtime_upgrade(); + // Initialize block, to call on_initialize and notify targets + parachain::para_roll_to(2); + // Expect the event in the parachain + assert!(parachain::para_events().iter().any(|e| matches!( + e, + parachain::RuntimeEvent::PolkadotXcm(pallet_xcm::Event::VersionChangeNotified { + result: 2, + .. + }) + ))); + }); + + // This event should have been seen in para A + let expected_supported_version_2: parachain::RuntimeEvent = + pallet_xcm::Event::SupportedVersionChanged { + location: Location { + parents: 1, + interior: [Parachain(2)].into(), + }, + version: 2, + } + .into(); + + // Para A should have received the version change + ParaA::execute_with(|| { + // Assert that the events vector contains the new version change + assert!(parachain::para_events().contains(&expected_supported_version_2)); + }); +} + +#[test] +fn receive_asset_with_no_sufficients_not_possible_if_non_existent_account() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should not have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 0); + }); + + // Send native token to fresh_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + fresh_account.into(), + 100 + )); + }); + + // Re-send tokens + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn receive_assets_with_sufficients_true_allows_non_funded_account_to_receive_assets() { + MockNet::reset(); + + let fresh_account = [2u8; 20]; + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: fresh_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // parachain should have received assets + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!(Assets::balance(source_id, &fresh_account.into()), 123); + }); +} + +#[test] +fn evm_account_receiving_assets_should_handle_sufficients_ref_count() { + MockNet::reset(); + + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + // Evm account is self sufficient + ParaA::execute_with(|| { + assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Evm account sufficient ref count increased by 1. + ParaA::execute_with(|| { + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 2); + }); + + ParaA::execute_with(|| { + // Remove the account from the evm context. + parachain::EVM::remove_account(&evm_account()); + // Evm account sufficient ref count decreased by 1. + // TODO: since the suicided logic was introduced an smart contract account + // is not deleted completely until it's data is deleted. Data deletion + // will be implemented in a future release + // assert_eq!(parachain::System::account(evm_account_id).sufficients, 1); + }); +} + +#[test] +fn empty_account_should_not_be_reset() { + MockNet::reset(); + + // Test account has nonce 1 on genesis. + let mut sufficient_account = [0u8; 20]; + sufficient_account[0..20].copy_from_slice(&evm_account()[..]); + + let evm_account_id = parachain::AccountId::from(sufficient_account); + + let source_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_id: parachain::AssetId = source_location.clone().into(); + let asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + // register relay asset in parachain A + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata, + 1u128, + false + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + // Send native token to evm_account + ParaA::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + evm_account_id, + 100 + )); + }); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: sufficient_account, + } + .into(); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new(VersionedLocation::V4(dest.clone()).clone().into()), + Box::new(([] /* Here */, 123).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Empty the assets from the account. + // As this makes the account go below the `min_balance`, the account is considered dead + // at eyes of pallet-assets, and the consumer reference is decreased by 1 and is now Zero. + assert_ok!(parachain::Assets::transfer( + parachain::RuntimeOrigin::signed(evm_account_id), + source_id, + PARAALICE.into(), + 123 + )); + // Verify account asset balance is Zero. + assert_eq!( + parachain::Assets::balance(source_id, &evm_account_id.into()), + 0 + ); + // Because we no longer have consumer references, we can set the balance to Zero. + // This would reset the account if our ED were to be > than Zero. + assert_ok!(ParaBalances::force_set_balance( + parachain::RuntimeOrigin::root(), + evm_account_id, + 0, + )); + // Verify account native balance is Zero. + assert_eq!(ParaBalances::free_balance(&evm_account_id), 0); + // Remove the account from the evm context. + // This decreases the sufficients reference by 1 and now is Zero. + parachain::EVM::remove_account(&evm_account()); + // Verify reference count. + let account = parachain::System::account(evm_account_id); + assert_eq!(account.sufficients, 0); + assert_eq!(account.consumers, 0); + assert_eq!(account.providers, 1); + // We expect the account to be alive in a Zero ED context. + assert_eq!(parachain::System::account_nonce(evm_account_id), 1); + }); +} + +#[test] +fn test_statemine_like() { + MockNet::reset(); + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + let statemine_asset_a_balances = Location::new( + 1, + [ + Parachain(1000), + PalletInstance(5), + xcm::latest::prelude::GeneralIndex(0u128), + ], + ); + let source_location = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemine_asset_a_balances) + .expect("convert to v3"), + ); + let source_id: parachain::AssetId = source_location.clone().into(); + + let asset_metadata = parachain::AssetMetadata { + name: b"StatemineToken".to_vec(), + symbol: b"StatemineToken".to_vec(), + decimals: 12, + }; + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + source_location.clone(), + asset_metadata.clone(), + 1u128, + true + )); + assert_ok!(add_supported_asset(source_location.clone(), 0u128)); + }); + + Statemine::execute_with(|| { + // Set new prefix + statemine_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + assert_ok!(StatemineAssets::create( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 1 + )); + + assert_ok!(StatemineAssets::mint( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 0, + RELAYALICE, + 300000000000000 + )); + + // This is needed, since the asset is created as non-sufficient + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Actually send relay asset to parachain + let dest: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new(VersionedLocation::V4(dest).clone().into()), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + xcm::latest::prelude::GeneralIndex(0), + ], + 123 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + assert_eq!(Assets::balance(source_id, &PARAALICE.into()), 123); + }); +} + +#[test] +fn send_statemine_asset_from_para_a_to_statemine_with_relay_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemine asset + let statemine_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemine_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemine_asset).expect("convert to v3"), + ); + let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into(); + + let asset_metadata_statemine_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + assert_ok!(add_supported_asset(relay_location.clone(), 0u128)); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemine_location_asset.clone(), + asset_metadata_statemine_asset, + 1u128, + true + )); + assert_ok!(add_supported_asset(statemine_location_asset.clone(), 0u128)); + }); + + let parachain_beneficiary_from_relay: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send relay chain asset to Alice in Parachain A + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_relay) + .clone() + .into() + ), + Box::new(([] /* Here */, 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + Statemine::execute_with(|| { + // Set new prefix + statemine_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemineAssets::create( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemineAssets::mint( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Send some native statemine tokens to sovereign for fees. + // We can't pay fees with USDC as the asset is minted as non-sufficient. + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 100000000000000 + )); + + // Send statemine USDC asset to Alice in Parachain A + let parachain_beneficiary_from_statemine: Location = AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + // Send with new prefix + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_from_statemine) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + let statemine_beneficiary = Location { + parents: 1, + interior: [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ] + .into(), + }; + + ParaA::execute_with(|| { + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemine_asset_id, &PARAALICE.into()), + 125 + ); + + // Alice has received 200 Relay assets + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + Statemine::execute_with(|| { + // Check that BOB's balance is empty before the transfer + assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![]); + }); + + // Transfer USDC from Parachain A to Statemine using Relay asset as fee + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemine_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(statemine_beneficiary)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + }); + + ParaA::execute_with(|| { + // Alice has 100 USDC less + assert_eq!( + Assets::balance(source_statemine_asset_id, &PARAALICE.into()), + 25 + ); + + // Alice has 100 relay asset less + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemine::execute_with(|| { + // Check that BOB received 100 USDC on statemine + assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemine_via_xtokens_transfer() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemine_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemine_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemine::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_relay_id), + 100, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemine::execute_with(|| { + // Check that Bob received the tokens back in AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 100 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemine::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!(StatemineBalances::free_balance(RELAYBOB), INITIAL_BALANCE); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemine_via_xtokens_transfer_with_fee() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemine_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemine_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemine::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_with_fee( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + parachain::CurrencyId::ForeignAsset(source_relay_id), + 100, + 10, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 90); + }); + + Statemine::execute_with(|| { + // Free execution: check that Bob received the tokens back in AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 110 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemine::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 10 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 190); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemine_via_xtokens_transfer_multiasset() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemine_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemine_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs from AssetHub to ParaA (Moonbeam) + Statemine::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multiasset( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new((Location::parent(), 100).into()), + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(40000u64, DEFAULT_PROOF_SIZE)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemine::execute_with(|| { + // Check that Bob received the tokens back in AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 100 + ); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemine::execute_with(|| { + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!(StatemineBalances::free_balance(RELAYBOB), INITIAL_BALANCE); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemine_via_xtokens_transfer_multicurrencies() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemine asset + let statemine_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemine_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemine_asset).expect("convert to v3"), + ); + let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into(); + + let asset_metadata_statemine_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemine_location_asset.clone(), + asset_metadata_statemine_asset, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(statemine_asset.clone(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemine_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemine_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs and USDC from AssetHub to ParaA (Moonbeam) + Statemine::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + statemine_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemineAssets::create( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemineAssets::mint( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Now send relay tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + + // Send USDC + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemine_asset_id, &PARAALICE.into()), + 125 + ); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multicurrencies( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + vec![ + ( + parachain::CurrencyId::ForeignAsset(source_statemine_asset_id), + 100 + ), + (parachain::CurrencyId::ForeignAsset(source_relay_id), 100) + ], + 1, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemine::execute_with(|| { + // Check that Bob received relay tokens back in AssetHub + // (100 - MinXcmFee) + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 50 + ); + + // Check that BOB received 100 USDC on AssetHub + assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemine::execute_with(|| { + let bob_previous_balance = StatemineBalances::free_balance(RELAYBOB); + + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + bob_previous_balance - 100 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn send_dot_from_moonbeam_to_statemine_via_xtokens_transfer_multiassets() { + MockNet::reset(); + + // Relay asset + let relay_location = parachain::AssetType::Xcm(xcm::v3::Location::parent()); + let source_relay_id: parachain::AssetId = relay_location.clone().into(); + + let relay_asset_metadata = parachain::AssetMetadata { + name: b"RelayToken".to_vec(), + symbol: b"Relay".to_vec(), + decimals: 12, + }; + + // Statemine asset + let statemine_asset = Location::new( + 1, + [ + Parachain(1000u32), + PalletInstance(5u8), + GeneralIndex(10u128), + ], + ); + let statemine_location_asset = parachain::AssetType::Xcm( + xcm_builder::WithLatestLocationConverter::convert(&statemine_asset).expect("convert to v3"), + ); + let source_statemine_asset_id: parachain::AssetId = statemine_location_asset.clone().into(); + + let asset_metadata_statemine_asset = parachain::AssetMetadata { + name: b"USDC".to_vec(), + symbol: b"USDC".to_vec(), + decimals: 12, + }; + + let dest_para = Location::new(1, [Parachain(1)]); + + let sov = xcm_builder::SiblingParachainConvertsVia::< + polkadot_parachain::primitives::Sibling, + statemine_like::AccountId, + >::convert_location(&dest_para) + .unwrap(); + + ParaA::execute_with(|| { + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + relay_location.clone(), + relay_asset_metadata, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(Location::parent(), 0u128); + + assert_ok!(AssetManager::register_foreign_asset( + parachain::RuntimeOrigin::root(), + statemine_location_asset.clone(), + asset_metadata_statemine_asset, + 1u128, + true + )); + XcmWeightTrader::set_asset_price(statemine_asset.clone(), 0u128); + }); + + let parachain_beneficiary_absolute: Location = Junction::AccountKey20 { + network: None, + key: PARAALICE, + } + .into(); + + let statemine_beneficiary_absolute: Location = Junction::AccountId32 { + network: None, + id: RELAYALICE.into(), + } + .into(); + + // First we send relay chain asset to Alice in AssetHub (via teleport) + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_teleport_assets( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + Box::new(Parachain(1000).into()), + Box::new( + VersionedLocation::V4(statemine_beneficiary_absolute) + .clone() + .into() + ), + Box::new(([], 200).into()), + 0, + WeightLimit::Unlimited + )); + }); + + // Send DOTs and USDC from AssetHub to ParaA (Moonbeam) + Statemine::execute_with(|| { + // Check Alice received 200 tokens on AssetHub + assert_eq!( + StatemineBalances::free_balance(RELAYALICE), + INITIAL_BALANCE + 200 + ); + + assert_ok!(StatemineBalances::transfer_allow_death( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + sov, + 110000000000000 + )); + + statemine_like::PrefixChanger::set_prefix( + PalletInstance(::index() as u8).into(), + ); + + assert_ok!(StatemineAssets::create( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 1 + )); + + assert_ok!(StatemineAssets::mint( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + 10, + RELAYALICE, + 300000000000000 + )); + + // Now send relay tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new((Location::parent(), 200).into()), + 0, + WeightLimit::Unlimited + )); + + // Send USDC + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYALICE), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute.clone()) + .clone() + .into() + ), + Box::new( + ( + [ + xcm::latest::prelude::PalletInstance( + ::index() as u8 + ), + GeneralIndex(10), + ], + 125 + ) + .into() + ), + 0, + WeightLimit::Unlimited + )); + }); + + ParaA::execute_with(|| { + // Alice should have received the DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + + // Alice has received 125 USDC + assert_eq!( + Assets::balance(source_statemine_asset_id, &PARAALICE.into()), + 125 + ); + }); + + let dest = Location::new( + 1, + [ + Parachain(1000), + AccountId32 { + network: None, + id: RELAYBOB.into(), + }, + ], + ); + + let statemine_asset_to_send = XcmAsset { + id: XcmAssetId(statemine_asset), + fun: Fungible(100), + }; + + let relay_asset_to_send = XcmAsset { + id: XcmAssetId(Location::parent()), + fun: Fungible(100), + }; + + let assets_to_send: XcmAssets = + XcmAssets::from(vec![statemine_asset_to_send, relay_asset_to_send.clone()]); + + // For some reason the order of the assets is inverted when creating the array above. + // We need to use relay asset for fees, so we pick index 0. + assert_eq!(assets_to_send.get(0).unwrap(), &relay_asset_to_send); + + // Finally we test that we are able to send back the DOTs to AssetHub from the ParaA + ParaA::execute_with(|| { + assert_ok!(XTokens::transfer_multiassets( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(assets_to_send.into()), + 0, + Box::new(VersionedLocation::V4(dest)), + WeightLimit::Limited(Weight::from_parts(80_000_000u64, 100_000u64)) + )); + + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 100); + }); + + Statemine::execute_with(|| { + // Check that Bob received relay tokens back in AssetHub + // (100 - MinXcmFee) + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + INITIAL_BALANCE + 50 + ); + + // Check that BOB received 100 USDC on AssetHub + assert_eq!(StatemineAssets::account_balances(RELAYBOB), vec![(10, 100)]); + }); + + // Send back tokens from AH to ParaA from Bob's account + Statemine::execute_with(|| { + let bob_previous_balance = StatemineBalances::free_balance(RELAYBOB); + + // Now send those tokens to ParaA + assert_ok!(StatemineChainPalletXcm::limited_reserve_transfer_assets( + statemine_like::RuntimeOrigin::signed(RELAYBOB), + Box::new(Location::new(1, [Parachain(1)]).into()), + Box::new( + VersionedLocation::V4(parachain_beneficiary_absolute) + .clone() + .into() + ), + Box::new((Location::parent(), 100).into()), + 0, + WeightLimit::Unlimited + )); + + // 100 DOTs were deducted from Bob's account + assert_eq!( + StatemineBalances::free_balance(RELAYBOB), + bob_previous_balance - 100 + ); + }); + + ParaA::execute_with(|| { + // Alice should have received 100 DOTs + assert_eq!(Assets::balance(source_relay_id, &PARAALICE.into()), 200); + }); +} + +#[test] +fn transact_through_signed_multilocation() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + // Relay charges 1000 for every instruction, and we have 3, so 3000 + 3000.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4000.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + WEIGHT_REF_TIME_PER_SECOND as u128, + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000004100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000004100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000004000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + false + )); + }); + + Relay::execute_with(|| { + assert!(RelayBalances::free_balance(¶_a_account()) == 100); + + assert!(RelayBalances::free_balance(&derived) == 0); + }); +} + +#[test] +fn transact_through_signed_multilocation_custom_fee_and_weight_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + ParaA::execute_with(|| { + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_multilocation = parachain::SelfLocation::get(); + descend_origin_multilocation + .append_with(signed_origin) + .unwrap(); + + // To convert it to what the relay will see instead of us + descend_origin_multilocation + .reanchor(&Location::parent(), &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::Account32Hash::< + relay_chain::KusamaNetwork, + relay_chain::AccountId, + >::convert_location(&descend_origin_multilocation) + .unwrap(); + + Relay::execute_with(|| { + // free execution, full amount received + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(RelayBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(RelayBalances::free_balance(¶_a_account()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = ::PalletInfo::index::< + relay_chain::Balances, + >() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let total_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(Location::parent())), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(total_weight.into())) + }, + true + )); + }); + + Relay::execute_with(|| { + // 100 transferred + assert_eq!(RelayBalances::free_balance(¶_a_account()), 100); + + // 4000005186 refunded + assert_eq!(RelayBalances::free_balance(&derived), 4000005186); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + assert!(ParaBalances::free_balance(&derived) == 0); + + assert!(ParaBalances::free_balance(¶_a_account_20()) == 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_refund() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + ParaB::execute_with(|| { + // free execution, full amount received + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000009100u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000009100); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + // Then call bytes + let mut call_bytes = pallet_balances::Call::::transfer_allow_death { + // 100 to sovereign + dest: para_a_account_20(), + value: 100u32.into(), + } + .encode(); + encoded.append(&mut call_bytes); + + let overall_weight = 4000009000u64; + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: Some(overall_weight as u128) + }, + encoded, + // 4000000000 for transfer + 9000 for XCM + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: Some(Limited(overall_weight.into())) + }, + true + )); + }); + + ParaB::execute_with(|| { + // Check the derived account was refunded + assert_eq!(ParaBalances::free_balance(&derived), 8993); + + // Check the transfer was executed + assert_eq!(ParaBalances::free_balance(¶_a_account_20()), 100); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact { + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + // 4000000000 for transfer + 4000 for XCM + // 1-1 to fee + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer went through + assert!( + ParaBalances::free_balance(&PARAALICE.into()) + == parachain_b_alice_balances_before + 100 + ); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_no_proxy_fails() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let mut parachain_b_alice_balances_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + parachain_b_alice_balances_before = ParaBalances::free_balance(&PARAALICE.into()) + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V1(xcm_primitives::EthereumXcmTransactionV1 { + gas_limit: U256::from(21000), + fee_payment: xcm_primitives::EthereumXcmFee::Auto, + action: pallet_ethereum::TransactionAction::Call(PARAALICE.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer wasn't executed + assert!(ParaBalances::free_balance(&PARAALICE.into()) == parachain_b_alice_balances_before); + }); +} + +#[test] +fn transact_through_signed_multilocation_para_to_para_ethereum_proxy_succeeds() { + MockNet::reset(); + let mut ancestry = Location::parent(); + + let para_b_location = Location::new(1, [Parachain(2)]); + + let para_b_balances = Location::new(1, [Parachain(2), PalletInstance(1u8)]); + + ParaA::execute_with(|| { + // Root can set transact info + assert_ok!(XcmTransactor::set_transact_info( + parachain::RuntimeOrigin::root(), + // ParaB + Box::new(xcm::VersionedLocation::V4(para_b_location.clone())), + // Para charges 1000 for every instruction, and we have 3, so 3 + 3.into(), + 20000000000.into(), + // 4 instructions in transact through signed + Some(4.into()) + )); + // Root can set transact info + assert_ok!(XcmTransactor::set_fee_per_second( + parachain::RuntimeOrigin::root(), + Box::new(xcm::VersionedLocation::V4(para_b_balances.clone())), + parachain::ParaTokensPerSecond::get(), + )); + ancestry = parachain::UniversalLocation::get().into(); + }); + + // Let's construct the Junction that we will append with DescendOrigin + let signed_origin: Junctions = [AccountKey20 { + network: None, + key: PARAALICE, + }] + .into(); + + let mut descend_origin_location = parachain::SelfLocation::get(); + descend_origin_location.append_with(signed_origin).unwrap(); + + // To convert it to what the paraB will see instead of us + descend_origin_location + .reanchor(¶_b_location, &ancestry.interior) + .unwrap(); + + let derived = xcm_builder::HashedDescription::< + parachain::AccountId, + xcm_builder::DescribeFamily, + >::convert_location(&descend_origin_location) + .unwrap(); + + let transfer_recipient = evm_account(); + let mut transfer_recipient_balance_before = 0; + ParaB::execute_with(|| { + assert_ok!(ParaBalances::transfer_allow_death( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + derived.clone(), + 4000000104u128, + )); + // derived account has all funds + assert!(ParaBalances::free_balance(&derived) == 4000000104); + // sovereign account has 0 funds + assert!(ParaBalances::free_balance(¶_a_account_20()) == 0); + + transfer_recipient_balance_before = ParaBalances::free_balance(&transfer_recipient.into()); + + // Add proxy ALICE -> derived + let _ = parachain::Proxy::add_proxy_delegate( + &PARAALICE.into(), + derived, + parachain::ProxyType::Any, + 0, + ); + }); + + // Encode the call. Balances transact to para_a_account + // First index + let mut encoded: Vec = Vec::new(); + let index = + ::PalletInfo::index::() + .unwrap() as u8; + + encoded.push(index); + + use sp_core::U256; + // Let's do a EVM transfer + let eth_tx = + xcm_primitives::EthereumXcmTransaction::V2(xcm_primitives::EthereumXcmTransactionV2 { + gas_limit: U256::from(21000), + action: pallet_ethereum::TransactionAction::Call(transfer_recipient.into()), + value: U256::from(100), + input: BoundedVec::< + u8, + ConstU32<{ xcm_primitives::MAX_ETHEREUM_XCM_INPUT_SIZE }> + >::try_from(vec![]).unwrap(), + access_list: None, + }); + + // Then call bytes + let mut call_bytes = pallet_ethereum_xcm::Call::::transact_through_proxy { + transact_as: PARAALICE.into(), + xcm_transaction: eth_tx, + } + .encode(); + encoded.append(&mut call_bytes); + + ParaA::execute_with(|| { + assert_ok!(XcmTransactor::transact_through_signed( + parachain::RuntimeOrigin::signed(PARAALICE.into()), + Box::new(xcm::VersionedLocation::V4(para_b_location)), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + para_b_balances + ))), + fee_amount: None + }, + encoded, + TransactWeights { + transact_required_weight_at_most: 4000000000.into(), + overall_weight: None + }, + false + )); + }); + + ParaB::execute_with(|| { + // Make sure the EVM transfer was executed + assert!( + ParaBalances::free_balance(&transfer_recipient.into()) + == transfer_recipient_balance_before + 100 + ); + }); +} + +#[test] +fn hrmp_init_accept_through_root() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_b_account(), + 1000u128 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp init channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::InitOpen(HrmpInitParams { + para_id: 2u32.into(), + proposed_max_capacity: 1, + proposed_max_message_size: 1 + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelRequested { + sender: 1u32.into(), + recipient: 2u32.into(), + proposed_max_capacity: 1u32, + proposed_max_message_size: 1u32, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); + ParaB::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp accept channel + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Accept { + para_id: 1u32.into() + }, + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::OpenChannelAccepted { + sender: 1u32.into(), + recipient: 2u32.into(), + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +#[test] +fn hrmp_close_works() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(RelayBalances::transfer_allow_death( + relay_chain::RuntimeOrigin::signed(RELAYALICE), + para_a_account(), + 1000u128 + )); + assert_ok!(Hrmp::force_open_hrmp_channel( + relay_chain::RuntimeOrigin::root(), + 1u32.into(), + 2u32.into(), + 1u32, + 1u32 + )); + assert_ok!(Hrmp::force_process_hrmp_open( + relay_chain::RuntimeOrigin::root(), + 1u32 + )); + }); + + ParaA::execute_with(|| { + let total_fee = 1_000u128; + let total_weight: u64 = 1_000_000_000; + let tx_weight: u64 = 500_000_000; + // Root can send hrmp close + assert_ok!(XcmTransactor::hrmp_manage( + parachain::RuntimeOrigin::root(), + HrmpOperation::Close(HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into() + }), + CurrencyPayment { + currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::V4( + Location::parent() + ))), + fee_amount: Some(total_fee) + }, + TransactWeights { + transact_required_weight_at_most: tx_weight.into(), + overall_weight: Some(Limited(total_weight.into())) + } + )); + }); + Relay::execute_with(|| { + let expected_event: relay_chain::RuntimeEvent = + polkadot_runtime_parachains::hrmp::Event::ChannelClosed { + by_parachain: 1u32.into(), + channel_id: HrmpChannelId { + sender: 1u32.into(), + recipient: 2u32.into(), + }, + } + .into(); + assert!(relay_chain::relay_events().contains(&expected_event)); + }); +} + +use parity_scale_codec::{Decode, Encode}; +use sp_io::hashing::blake2_256; + +// Helper to derive accountIds +pub fn derivative_account_id(who: sp_runtime::AccountId32, index: u16) -> sp_runtime::AccountId32 { + let entropy = (b"modlpy/utilisuba", who, index).using_encoded(blake2_256); + sp_runtime::AccountId32::decode(&mut &entropy[..]).expect("valid account id") +} diff --git a/tracing/3200/rust-toolchain b/tracing/3200/rust-toolchain new file mode 100644 index 00000000..47a114dc --- /dev/null +++ b/tracing/3200/rust-toolchain @@ -0,0 +1,5 @@ +[toolchain] +channel = "1.77.0" +components = [ "rustfmt", "clippy", "rust-src" ] +targets = [ "wasm32-unknown-unknown" ] +profile = "minimal" diff --git a/tracing/3200/shared/primitives/ext/Cargo.toml b/tracing/3200/shared/primitives/ext/Cargo.toml new file mode 100644 index 00000000..fc6bbf5e --- /dev/null +++ b/tracing/3200/shared/primitives/ext/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "moonbeam-primitives-ext" +version = '0.1.0' +authors = ['PureStake'] +edition = '2018' +homepage = 'https://moonbeam.network' +license = 'GPL-3.0-only' +repository = 'https://github.com/PureStake/moonbeam/' + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethereum-types = { workspace = true } + +# Moonbeam +evm-tracing-events = { workspace = true } + +# Substrate +parity-scale-codec = { workspace = true } +sp-runtime-interface = { workspace = true } +sp-externalities = { workspace = true } +sp-std = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "ethereum-types/std", + "evm-tracing-events/std", + "sp-runtime-interface/std", + "sp-externalities/std", + "sp-std/std", +] \ No newline at end of file diff --git a/tracing/3200/shared/primitives/ext/src/lib.rs b/tracing/3200/shared/primitives/ext/src/lib.rs new file mode 100644 index 00000000..2e0fe897 --- /dev/null +++ b/tracing/3200/shared/primitives/ext/src/lib.rs @@ -0,0 +1,82 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Environmental-aware externalities for EVM tracing in Wasm runtime. This enables +//! capturing the - potentially large - trace output data in the host and keep +//! a low memory footprint in `--execution=wasm`. +//! +//! - The original trace Runtime Api call is wrapped `using` environmental (thread local). +//! - Arguments are scale-encoded known types in the host. +//! - Host functions will decode the input and emit an event `with` environmental. + +#![cfg_attr(not(feature = "std"), no_std)] +use sp_runtime_interface::runtime_interface; + +use parity_scale_codec::Decode; +use sp_std::vec::Vec; + +use evm_tracing_events::{Event, EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter}; + +#[runtime_interface] +pub trait MoonbeamExt { + fn raw_step(&mut self, _data: Vec) {} + + fn raw_gas(&mut self, _data: Vec) {} + + fn raw_return_value(&mut self, _data: Vec) {} + + fn call_list_entry(&mut self, _index: u32, _value: Vec) {} + + fn call_list_new(&mut self) {} + + // New design, proxy events. + /// An `Evm` event proxied by the Moonbeam runtime to this host function. + /// evm -> moonbeam_runtime -> host. + fn evm_event(&mut self, event: Vec) { + if let Ok(event) = EvmEvent::decode(&mut &event[..]) { + Event::Evm(event).emit(); + } + } + + /// A `Gasometer` event proxied by the Moonbeam runtime to this host function. + /// evm_gasometer -> moonbeam_runtime -> host. + fn gasometer_event(&mut self, event: Vec) { + if let Ok(event) = GasometerEvent::decode(&mut &event[..]) { + Event::Gasometer(event).emit(); + } + } + + /// A `Runtime` event proxied by the Moonbeam runtime to this host function. + /// evm_runtime -> moonbeam_runtime -> host. + fn runtime_event(&mut self, event: Vec) { + if let Ok(event) = RuntimeEvent::decode(&mut &event[..]) { + Event::Runtime(event).emit(); + } + } + + /// Allow the tracing module in the runtime to know how to filter Step event + /// content, as cloning the entire data is expensive and most of the time + /// not necessary. + fn step_event_filter(&self) -> StepEventFilter { + evm_tracing_events::step_event_filter().unwrap_or_default() + } + + /// An event to create a new CallList (currently a new transaction when tracing a block). + #[version(2)] + fn call_list_new(&mut self) { + Event::CallListNew().emit(); + } +} diff --git a/tracing/3200/shared/primitives/rpc/debug/Cargo.toml b/tracing/3200/shared/primitives/rpc/debug/Cargo.toml new file mode 100644 index 00000000..1dd84780 --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/debug/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "moonbeam-rpc-primitives-debug" +authors = [ "PureStake" ] +edition = "2018" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +repository = "https://github.com/PureStake/moonbeam/" +version = "0.1.0" + +[dependencies] +environmental = { workspace = true } +ethereum = { workspace = true, features = [ "with-codec" ] } +ethereum-types = { workspace = true } +hex = { workspace = true, optional = true, features = [ "serde" ] } +serde = { workspace = true, optional = true, features = [ "derive" ] } + +# Substrate +parity-scale-codec = { workspace = true } +sp-api = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +[features] +default = [ "std" ] + +before_700 = [] +_700_to_1200 = [] +runtime-2900 = [] +runtime-3000 = [] + +std = [ + "parity-scale-codec/std", + "environmental/std", + "ethereum-types/std", + "ethereum/std", + "hex", + "serde", + "sp-api/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/tracing/3200/shared/primitives/rpc/debug/src/lib.rs b/tracing/3200/shared/primitives/rpc/debug/src/lib.rs new file mode 100644 index 00000000..b66a4f9b --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/debug/src/lib.rs @@ -0,0 +1,129 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +use parity_scale_codec::{Decode, Encode}; + +#[cfg(feature = "before_700")] +use ethereum::Transaction; +#[cfg(feature = "_700_to_1200")] +use ethereum::TransactionV0 as Transaction; +#[cfg(all(not(feature = "before_700"), not(feature = "_700_to_1200")))] +use ethereum::TransactionV2 as Transaction; + +use ethereum_types::{H160, H256, U256}; +use sp_std::vec::Vec; + +#[cfg(feature = "runtime-3000")] +sp_api::decl_runtime_apis! { + #[api_version(6)] + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_call( + header: &Block::Header, + from: H160, + to: H160, + data: Vec, + value: U256, + gas_limit: U256, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + nonce: Option, + access_list: Option)>>, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[cfg(feature = "runtime-2900")] +sp_api::decl_runtime_apis! { + #[api_version(5)] + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + header: &Block::Header, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[cfg(all( + not(feature = "before_700"), + not(feature = "_700_to_1200"), + not(feature = "runtime-2900"), + not(feature = "runtime-3000") +))] +sp_api::decl_runtime_apis! { + #[api_version(4)] + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[cfg(any(feature = "before_700", feature = "_700_to_1200"))] +sp_api::decl_runtime_apis! { + pub trait DebugRuntimeApi { + fn trace_transaction( + extrinsics: Vec, + transaction: &Transaction, + ) -> Result<(), sp_runtime::DispatchError>; + + fn trace_block( + extrinsics: Vec, + known_transactions: Vec, + ) -> Result<(), sp_runtime::DispatchError>; + } +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode)] +pub enum TracerInput { + None, + Blockscout, + CallTracer, +} + +/// DebugRuntimeApi V2 result. Trace response is stored in client and runtime api call response is +/// empty. +#[derive(Debug)] +pub enum Response { + Single, + Block, +} diff --git a/tracing/3200/shared/primitives/rpc/evm-tracing-events/Cargo.toml b/tracing/3200/shared/primitives/rpc/evm-tracing-events/Cargo.toml new file mode 100644 index 00000000..d94d74a4 --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/evm-tracing-events/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "evm-tracing-events" +version = '0.1.0' +authors = ['PureStake'] +edition = '2018' +homepage = 'https://moonbeam.network' +license = 'GPL-3.0-only' +repository = 'https://github.com/PureStake/moonbeam/' + +[dependencies] +parity-scale-codec = { workspace = true } +sp-runtime-interface = { workspace = true } + +ethereum = { workspace = true, features = ["with-codec"] } +ethereum-types = { workspace = true } + +environmental = { workspace = true } + +evm = { workspace = true, features = ["with-codec"] } +evm-runtime = { workspace = true } +evm-gasometer = { workspace = true } + +[features] +default = ["std"] + +evm-tracing = ["evm/tracing", "evm-runtime/tracing", "evm-gasometer/tracing"] +std = [ + "parity-scale-codec/std", + "ethereum/std", + "ethereum-types/std", + "environmental/std", + "evm/std", + "evm-runtime/std", + "evm-gasometer/std", +] + +runtime-1600 = [] \ No newline at end of file diff --git a/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/evm.rs b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/evm.rs new file mode 100644 index 00000000..c93a1a6c --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/evm.rs @@ -0,0 +1,272 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +extern crate alloc; + +use alloc::vec::Vec; +use ethereum_types::{H160, H256, U256}; +use evm::ExitReason; +use parity_scale_codec::{Decode, Encode}; + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Transfer { + /// Source address. + pub source: H160, + /// Target address. + pub target: H160, + /// Transfer value. + pub value: U256, +} + +impl From for Transfer { + fn from(i: evm_runtime::Transfer) -> Self { + Self { + source: i.source, + target: i.target, + value: i.value, + } + } +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode)] +pub enum CreateScheme { + /// Legacy create scheme of `CREATE`. + Legacy { + /// Caller of the create. + caller: H160, + }, + /// Create scheme of `CREATE2`. + Create2 { + /// Caller of the create. + caller: H160, + /// Code hash. + code_hash: H256, + /// Salt. + salt: H256, + }, + /// Create at a fixed location. + Fixed(H160), +} + +impl From for CreateScheme { + fn from(i: evm_runtime::CreateScheme) -> Self { + match i { + evm_runtime::CreateScheme::Legacy { caller } => Self::Legacy { caller }, + evm_runtime::CreateScheme::Create2 { + caller, + code_hash, + salt, + } => Self::Create2 { + caller, + code_hash, + salt, + }, + evm_runtime::CreateScheme::Fixed(address) => Self::Fixed(address), + } + } +} + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] +pub enum EvmEvent { + Call { + code_address: H160, + transfer: Option, + input: Vec, + target_gas: Option, + is_static: bool, + context: super::Context, + }, + Create { + caller: H160, + address: H160, + scheme: CreateScheme, + value: U256, + init_code: Vec, + target_gas: Option, + }, + Suicide { + address: H160, + target: H160, + balance: U256, + }, + Exit { + reason: ExitReason, + return_value: Vec, + }, + TransactCall { + caller: H160, + address: H160, + value: U256, + data: Vec, + gas_limit: u64, + }, + TransactCreate { + caller: H160, + value: U256, + init_code: Vec, + gas_limit: u64, + address: H160, + }, + TransactCreate2 { + caller: H160, + value: U256, + init_code: Vec, + salt: H256, + gas_limit: u64, + address: H160, + }, + PrecompileSubcall { + code_address: H160, + transfer: Option, + input: Vec, + target_gas: Option, + is_static: bool, + context: super::Context, + }, + Log { + address: H160, + topics: Vec, + data: Vec, + }, +} + +#[cfg(feature = "evm-tracing")] +impl<'a> From> for EvmEvent { + fn from(i: evm::tracing::Event<'a>) -> Self { + match i { + evm::tracing::Event::Call { + code_address, + transfer, + input, + target_gas, + is_static, + context, + } => Self::Call { + code_address, + transfer: if let Some(transfer) = transfer { + Some(transfer.clone().into()) + } else { + None + }, + input: input.to_vec(), + target_gas, + is_static, + context: context.clone().into(), + }, + evm::tracing::Event::Create { + caller, + address, + scheme, + value, + init_code, + target_gas, + } => Self::Create { + caller, + address, + scheme: scheme.into(), + value, + init_code: init_code.to_vec(), + target_gas, + }, + evm::tracing::Event::Suicide { + address, + target, + balance, + } => Self::Suicide { + address, + target, + balance, + }, + evm::tracing::Event::Exit { + reason, + return_value, + } => Self::Exit { + reason: reason.clone(), + return_value: return_value.to_vec(), + }, + evm::tracing::Event::TransactCall { + caller, + address, + value, + data, + gas_limit, + } => Self::TransactCall { + caller, + address, + value, + data: data.to_vec(), + gas_limit, + }, + evm::tracing::Event::TransactCreate { + caller, + value, + init_code, + gas_limit, + address, + } => Self::TransactCreate { + caller, + value, + init_code: init_code.to_vec(), + gas_limit, + address, + }, + evm::tracing::Event::TransactCreate2 { + caller, + value, + init_code, + salt, + gas_limit, + address, + } => Self::TransactCreate2 { + caller, + value, + init_code: init_code.to_vec(), + salt, + gas_limit, + address, + }, + #[cfg(feature = "runtime-1600")] + evm::tracing::Event::PrecompileSubcall { + code_address, + transfer, + input, + target_gas, + is_static, + context, + } => Self::PrecompileSubcall { + code_address, + transfer: if let Some(transfer) = transfer { + Some(transfer.clone().into()) + } else { + None + }, + input: input.to_vec(), + target_gas, + is_static, + context: context.clone().into(), + }, + evm::tracing::Event::Log { + address, + topics, + data, + } => Self::Log { + address, + topics: topics.to_vec(), + data: data.to_vec(), + }, + } + } +} diff --git a/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs new file mode 100644 index 00000000..33a6f724 --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/gasometer.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +use parity_scale_codec::{Decode, Encode}; + +#[derive(Debug, Default, Copy, Clone, Encode, Decode, PartialEq, Eq)] +pub struct Snapshot { + pub gas_limit: u64, + pub memory_gas: u64, + pub used_gas: u64, + pub refunded_gas: i64, +} + +impl Snapshot { + pub fn gas(&self) -> u64 { + self.gas_limit - self.used_gas - self.memory_gas + } +} + +impl From for Snapshot { + fn from(snapshot: evm_gasometer::Snapshot) -> Self { + Self { + gas_limit: snapshot.gas_limit, + memory_gas: snapshot.memory_gas, + used_gas: snapshot.used_gas, + refunded_gas: snapshot.refunded_gas, + } + } +} + +impl From> for Snapshot { + fn from(snapshot_opt: Option) -> Self { + if let Some(snapshot) = snapshot_opt { + snapshot.into() + } else { + Snapshot::default() + } + } +} + +#[derive(Debug, Copy, Clone, Encode, Decode, PartialEq, Eq)] +pub enum GasometerEvent { + RecordCost { + cost: u64, + snapshot: Snapshot, + }, + RecordRefund { + refund: i64, + snapshot: Snapshot, + }, + RecordStipend { + stipend: u64, + snapshot: Snapshot, + }, + RecordDynamicCost { + gas_cost: u64, + memory_gas: u64, + gas_refund: i64, + snapshot: Snapshot, + }, + RecordTransaction { + cost: u64, + snapshot: Snapshot, + }, +} + +#[cfg(feature = "evm-tracing")] +impl From for GasometerEvent { + fn from(i: evm_gasometer::tracing::Event) -> Self { + match i { + evm_gasometer::tracing::Event::RecordCost { cost, snapshot } => Self::RecordCost { + cost, + snapshot: snapshot.into(), + }, + evm_gasometer::tracing::Event::RecordRefund { refund, snapshot } => { + Self::RecordRefund { + refund, + snapshot: snapshot.into(), + } + } + evm_gasometer::tracing::Event::RecordStipend { stipend, snapshot } => { + Self::RecordStipend { + stipend, + snapshot: snapshot.into(), + } + } + evm_gasometer::tracing::Event::RecordDynamicCost { + gas_cost, + memory_gas, + gas_refund, + snapshot, + } => Self::RecordDynamicCost { + gas_cost, + memory_gas, + gas_refund, + snapshot: snapshot.into(), + }, + evm_gasometer::tracing::Event::RecordTransaction { cost, snapshot } => { + Self::RecordTransaction { + cost, + snapshot: snapshot.into(), + } + } + } + } +} diff --git a/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/lib.rs b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/lib.rs new file mode 100644 index 00000000..68714acd --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/lib.rs @@ -0,0 +1,287 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! A Proxy in this context is an environmental trait implementor meant to be used for capturing +//! EVM trace events sent to a Host function from the Runtime. Works like: +//! - Runtime Api call `using` environmental. +//! - Runtime calls a Host function with some scale-encoded Evm event. +//! - Host function emits an additional event to this Listener. +//! - Proxy listens for the event and format the actual trace response. +//! +//! There are two proxy types: `Raw` and `CallList`. +//! - `Raw` - used for opcode-level traces. +//! - `CallList` - used for block tracing (stack of call stacks) and custom tracing outputs. +//! +//! The EVM event types may contain references and not implement Encode/Decode. +//! This module provide mirror types and conversion into them from the original events. + +#![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; + +pub mod evm; +pub mod gasometer; +pub mod runtime; + +pub use self::evm::EvmEvent; +pub use gasometer::GasometerEvent; +pub use runtime::RuntimeEvent; + +use ::evm::Opcode; +use alloc::vec::Vec; +use ethereum_types::{H160, U256}; +use parity_scale_codec::{Decode, Encode}; +use sp_runtime_interface::pass_by::PassByCodec; + +environmental::environmental!(listener: dyn Listener + 'static); + +pub fn using R>(l: &mut (dyn Listener + 'static), f: F) -> R { + listener::using(l, f) +} + +/// Allow to configure which data of the Step event +/// we want to keep or discard. Not discarding the data requires cloning the data +/// in the runtime which have a significant cost for each step. +#[derive(Clone, Copy, Eq, PartialEq, Debug, Encode, Decode, Default, PassByCodec)] +pub struct StepEventFilter { + pub enable_stack: bool, + pub enable_memory: bool, +} + +#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)] +pub enum Event { + Evm(evm::EvmEvent), + Gasometer(gasometer::GasometerEvent), + Runtime(runtime::RuntimeEvent), + CallListNew(), +} + +impl Event { + /// Access the global reference and call it's `event` method, passing the `Event` itself as + /// argument. + /// + /// This only works if we are `using` a global reference to a `Listener` implementor. + pub fn emit(self) { + listener::with(|listener| listener.event(self)); + } +} + +/// Main trait to proxy emitted messages. +/// Used 2 times : +/// - Inside the runtime to proxy the events throught the host functions +/// - Inside the client to forward those events to the client listener. +pub trait Listener { + fn event(&mut self, event: Event); + + /// Allow the runtime to know which data should be discarded and not cloned. + /// WARNING: It is only called once when the runtime tracing is instanciated to avoid + /// performing many ext calls. + fn step_event_filter(&self) -> StepEventFilter; +} + +pub fn step_event_filter() -> Option { + let mut filter = None; + listener::with(|listener| filter = Some(listener.step_event_filter())); + filter +} + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Context { + /// Execution address. + pub address: H160, + /// Caller of the EVM. + pub caller: H160, + /// Apparent value of the EVM. + pub apparent_value: U256, +} + +impl From for Context { + fn from(i: evm_runtime::Context) -> Self { + Self { + address: i.address, + caller: i.caller, + apparent_value: i.apparent_value, + } + } +} + +/// Converts an Opcode into its name, stored in a `Vec`. +pub fn opcodes_string(opcode: Opcode) -> Vec { + let tmp; + let out = match opcode { + Opcode(0) => "Stop", + Opcode(1) => "Add", + Opcode(2) => "Mul", + Opcode(3) => "Sub", + Opcode(4) => "Div", + Opcode(5) => "SDiv", + Opcode(6) => "Mod", + Opcode(7) => "SMod", + Opcode(8) => "AddMod", + Opcode(9) => "MulMod", + Opcode(10) => "Exp", + Opcode(11) => "SignExtend", + Opcode(16) => "Lt", + Opcode(17) => "Gt", + Opcode(18) => "Slt", + Opcode(19) => "Sgt", + Opcode(20) => "Eq", + Opcode(21) => "IsZero", + Opcode(22) => "And", + Opcode(23) => "Or", + Opcode(24) => "Xor", + Opcode(25) => "Not", + Opcode(26) => "Byte", + Opcode(27) => "Shl", + Opcode(28) => "Shr", + Opcode(29) => "Sar", + Opcode(32) => "Keccak256", + Opcode(48) => "Address", + Opcode(49) => "Balance", + Opcode(50) => "Origin", + Opcode(51) => "Caller", + Opcode(52) => "CallValue", + Opcode(53) => "CallDataLoad", + Opcode(54) => "CallDataSize", + Opcode(55) => "CallDataCopy", + Opcode(56) => "CodeSize", + Opcode(57) => "CodeCopy", + Opcode(58) => "GasPrice", + Opcode(59) => "ExtCodeSize", + Opcode(60) => "ExtCodeCopy", + Opcode(61) => "ReturnDataSize", + Opcode(62) => "ReturnDataCopy", + Opcode(63) => "ExtCodeHash", + Opcode(64) => "BlockHash", + Opcode(65) => "Coinbase", + Opcode(66) => "Timestamp", + Opcode(67) => "Number", + Opcode(68) => "Difficulty", + Opcode(69) => "GasLimit", + Opcode(70) => "ChainId", + Opcode(80) => "Pop", + Opcode(81) => "MLoad", + Opcode(82) => "MStore", + Opcode(83) => "MStore8", + Opcode(84) => "SLoad", + Opcode(85) => "SStore", + Opcode(86) => "Jump", + Opcode(87) => "JumpI", + Opcode(88) => "GetPc", + Opcode(89) => "MSize", + Opcode(90) => "Gas", + Opcode(91) => "JumpDest", + Opcode(92) => "TLoad", + Opcode(93) => "TStore", + Opcode(94) => "MCopy", + Opcode(96) => "Push1", + Opcode(97) => "Push2", + Opcode(98) => "Push3", + Opcode(99) => "Push4", + Opcode(100) => "Push5", + Opcode(101) => "Push6", + Opcode(102) => "Push7", + Opcode(103) => "Push8", + Opcode(104) => "Push9", + Opcode(105) => "Push10", + Opcode(106) => "Push11", + Opcode(107) => "Push12", + Opcode(108) => "Push13", + Opcode(109) => "Push14", + Opcode(110) => "Push15", + Opcode(111) => "Push16", + Opcode(112) => "Push17", + Opcode(113) => "Push18", + Opcode(114) => "Push19", + Opcode(115) => "Push20", + Opcode(116) => "Push21", + Opcode(117) => "Push22", + Opcode(118) => "Push23", + Opcode(119) => "Push24", + Opcode(120) => "Push25", + Opcode(121) => "Push26", + Opcode(122) => "Push27", + Opcode(123) => "Push28", + Opcode(124) => "Push29", + Opcode(125) => "Push30", + Opcode(126) => "Push31", + Opcode(127) => "Push32", + Opcode(128) => "Dup1", + Opcode(129) => "Dup2", + Opcode(130) => "Dup3", + Opcode(131) => "Dup4", + Opcode(132) => "Dup5", + Opcode(133) => "Dup6", + Opcode(134) => "Dup7", + Opcode(135) => "Dup8", + Opcode(136) => "Dup9", + Opcode(137) => "Dup10", + Opcode(138) => "Dup11", + Opcode(139) => "Dup12", + Opcode(140) => "Dup13", + Opcode(141) => "Dup14", + Opcode(142) => "Dup15", + Opcode(143) => "Dup16", + Opcode(144) => "Swap1", + Opcode(145) => "Swap2", + Opcode(146) => "Swap3", + Opcode(147) => "Swap4", + Opcode(148) => "Swap5", + Opcode(149) => "Swap6", + Opcode(150) => "Swap7", + Opcode(151) => "Swap8", + Opcode(152) => "Swap9", + Opcode(153) => "Swap10", + Opcode(154) => "Swap11", + Opcode(155) => "Swap12", + Opcode(156) => "Swap13", + Opcode(157) => "Swap14", + Opcode(158) => "Swap15", + Opcode(159) => "Swap16", + Opcode(160) => "Log0", + Opcode(161) => "Log1", + Opcode(162) => "Log2", + Opcode(163) => "Log3", + Opcode(164) => "Log4", + Opcode(176) => "JumpTo", + Opcode(177) => "JumpIf", + Opcode(178) => "JumpSub", + Opcode(180) => "JumpSubv", + Opcode(181) => "BeginSub", + Opcode(182) => "BeginData", + Opcode(184) => "ReturnSub", + Opcode(185) => "PutLocal", + Opcode(186) => "GetLocal", + Opcode(225) => "SLoadBytes", + Opcode(226) => "SStoreBytes", + Opcode(227) => "SSize", + Opcode(240) => "Create", + Opcode(241) => "Call", + Opcode(242) => "CallCode", + Opcode(243) => "Return", + Opcode(244) => "DelegateCall", + Opcode(245) => "Create2", + Opcode(250) => "StaticCall", + Opcode(252) => "TxExecGas", + Opcode(253) => "Revert", + Opcode(254) => "Invalid", + Opcode(255) => "SelfDestruct", + Opcode(n) => { + tmp = alloc::format!("Unknown({})", n); + &tmp + } + }; + out.as_bytes().to_vec() +} diff --git a/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/runtime.rs b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/runtime.rs new file mode 100644 index 00000000..d9ba718d --- /dev/null +++ b/tracing/3200/shared/primitives/rpc/evm-tracing-events/src/runtime.rs @@ -0,0 +1,156 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +extern crate alloc; + +use super::{opcodes_string, Context, StepEventFilter}; +use alloc::vec::Vec; +use ethereum_types::{H160, H256, U256}; +pub use evm::{ExitError, ExitReason, ExitSucceed, Opcode}; +use parity_scale_codec::{Decode, Encode}; + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Stack { + pub data: Vec, + pub limit: u64, +} + +impl From<&evm::Stack> for Stack { + fn from(i: &evm::Stack) -> Self { + Self { + data: i.data().clone(), + limit: i.limit() as u64, + } + } +} + +#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)] +pub struct Memory { + pub data: Vec, + pub effective_len: U256, + pub limit: u64, +} + +impl From<&evm::Memory> for Memory { + fn from(i: &evm::Memory) -> Self { + Self { + data: i.data().clone(), + effective_len: i.effective_len(), + limit: i.limit() as u64, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Encode, Decode)] +pub enum Capture { + /// The machine has exited. It cannot be executed again. + Exit(E), + /// The machine has trapped. It is waiting for external information, and can + /// be executed again. + Trap(T), +} + +pub type Trap = Vec; // Should hold the marshalled Opcode. + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] +pub enum RuntimeEvent { + Step { + context: Context, + // This needs to be marshalled in the runtime no matter what. + opcode: Vec, + // We can use ExitReason with `with-codec` feature, + position: Result, + stack: Option, + memory: Option, + }, + StepResult { + result: Result<(), Capture>, + return_value: Vec, + }, + SLoad { + address: H160, + index: H256, + value: H256, + }, + SStore { + address: H160, + index: H256, + value: H256, + }, +} + +#[cfg(feature = "evm-tracing")] +impl RuntimeEvent { + pub fn from_evm_event<'a>(i: evm_runtime::tracing::Event<'a>, filter: StepEventFilter) -> Self { + match i { + evm_runtime::tracing::Event::Step { + context, + opcode, + position, + stack, + memory, + } => Self::Step { + context: context.clone().into(), + opcode: opcodes_string(opcode), + position: match position { + Ok(position) => Ok(*position as u64), + Err(e) => Err(e.clone()), + }, + stack: if filter.enable_stack { + Some(stack.into()) + } else { + None + }, + memory: if filter.enable_memory { + Some(memory.into()) + } else { + None + }, + }, + evm_runtime::tracing::Event::StepResult { + result, + return_value, + } => Self::StepResult { + result: match result { + Ok(_) => Ok(()), + Err(capture) => match capture { + evm::Capture::Exit(e) => Err(Capture::Exit(e.clone())), + evm::Capture::Trap(t) => Err(Capture::Trap(opcodes_string(*t))), + }, + }, + return_value: return_value.to_vec(), + }, + evm_runtime::tracing::Event::SLoad { + address, + index, + value, + } => Self::SLoad { + address, + index, + value, + }, + evm_runtime::tracing::Event::SStore { + address, + index, + value, + } => Self::SStore { + address, + index, + value, + }, + } + } +} diff --git a/tracing/3200/shared/runtime/evm_tracer/Cargo.toml b/tracing/3200/shared/runtime/evm_tracer/Cargo.toml new file mode 100644 index 00000000..1b724f04 --- /dev/null +++ b/tracing/3200/shared/runtime/evm_tracer/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "moonbeam-evm-tracer" +authors = [ "PureStake" ] +edition = "2018" +homepage = "https://moonbeam.network" +license = "GPL-3.0-only" +repository = "https://github.com/PureStake/moonbeam/" +version = "0.1.0" + +[dependencies] +# In those shared code the branch is irrelevant as long as revers to a rust2018 workspace. +# Each version of the runtime will patch the Subtrate and Frontier dependencies to the correct +# git repo and branch. Since cargo don't want to patch with the same repo url, we use a dummy fork +# not used in the runtimes. + +# Moonbeam +evm-tracing-events = { workspace = true, features = [ "evm-tracing" ] } +moonbeam-primitives-ext = { workspace = true } + +# Substrate +parity-scale-codec = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +ethereum-types = { workspace = true } +evm = { workspace = true, features = [ "with-codec" ] } +evm-gasometer = { workspace = true } +evm-runtime = { workspace = true } +fp-evm = { workspace = true } +pallet-evm = { workspace = true } + +[features] +default = [ "std" ] +std = [ + "parity-scale-codec/std", + "ethereum-types/std", + "evm-gasometer/std", + "evm-runtime/std", + "evm-tracing-events/std", + "evm/std", + "evm/with-serde", + "fp-evm/std", + "moonbeam-primitives-ext/std", + "pallet-evm/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/tracing/3200/shared/runtime/evm_tracer/src/lib.rs b/tracing/3200/shared/runtime/evm_tracer/src/lib.rs new file mode 100644 index 00000000..5d998775 --- /dev/null +++ b/tracing/3200/shared/runtime/evm_tracer/src/lib.rs @@ -0,0 +1,117 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Substrate EVM tracing. +//! +//! The purpose of this crate is enable tracing the EVM opcode execution and will be used by +//! both Dapp developers - to get a granular view on their transactions - and indexers to access +//! the EVM callstack (internal transactions). +//! +//! Proxies EVM messages to the host functions. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod tracer { + use evm_tracing_events::{EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter}; + use parity_scale_codec::Encode; + + use evm::tracing::{using as evm_using, EventListener as EvmListener}; + use evm_gasometer::tracing::{using as gasometer_using, EventListener as GasometerListener}; + use evm_runtime::tracing::{using as runtime_using, EventListener as RuntimeListener}; + use sp_std::{cell::RefCell, rc::Rc}; + + struct ListenerProxy(pub Rc>); + impl GasometerListener for ListenerProxy { + fn event(&mut self, event: evm_gasometer::tracing::Event) { + self.0.borrow_mut().event(event); + } + } + + impl RuntimeListener for ListenerProxy { + fn event(&mut self, event: evm_runtime::tracing::Event) { + self.0.borrow_mut().event(event); + } + } + + impl EvmListener for ListenerProxy { + fn event(&mut self, event: evm::tracing::Event) { + self.0.borrow_mut().event(event); + } + } + + pub struct EvmTracer { + step_event_filter: StepEventFilter, + } + + impl EvmTracer { + pub fn new() -> Self { + Self { + step_event_filter: moonbeam_primitives_ext::moonbeam_ext::step_event_filter(), + } + } + + /// Setup event listeners and execute provided closure. + /// + /// Consume the tracer and return it alongside the return value of + /// the closure. + pub fn trace R>(self, f: F) { + let wrapped = Rc::new(RefCell::new(self)); + + let mut gasometer = ListenerProxy(Rc::clone(&wrapped)); + let mut runtime = ListenerProxy(Rc::clone(&wrapped)); + let mut evm = ListenerProxy(Rc::clone(&wrapped)); + + // Each line wraps the previous `f` into a `using` call. + // Listening to new events results in adding one new line. + // Order is irrelevant when registering listeners. + let f = || runtime_using(&mut runtime, f); + let f = || gasometer_using(&mut gasometer, f); + let f = || evm_using(&mut evm, f); + f(); + } + + pub fn emit_new() { + moonbeam_primitives_ext::moonbeam_ext::call_list_new(); + } + } + + impl EvmListener for EvmTracer { + /// Proxies `evm::tracing::Event` to the host. + fn event(&mut self, event: evm::tracing::Event) { + let event: EvmEvent = event.into(); + let message = event.encode(); + moonbeam_primitives_ext::moonbeam_ext::evm_event(message); + } + } + + impl GasometerListener for EvmTracer { + /// Proxies `evm_gasometer::tracing::Event` to the host. + fn event(&mut self, event: evm_gasometer::tracing::Event) { + let event: GasometerEvent = event.into(); + let message = event.encode(); + moonbeam_primitives_ext::moonbeam_ext::gasometer_event(message); + } + } + + impl RuntimeListener for EvmTracer { + /// Proxies `evm_runtime::tracing::Event` to the host. + fn event(&mut self, event: evm_runtime::tracing::Event) { + let event = RuntimeEvent::from_evm_event(event, self.step_event_filter); + let message = event.encode(); + moonbeam_primitives_ext::moonbeam_ext::runtime_event(message); + } + } +} diff --git a/wasm/moonbase-runtime-3200-substitute-tracing.wasm b/wasm/moonbase-runtime-3200-substitute-tracing.wasm new file mode 100644 index 0000000000000000000000000000000000000000..28fdc709587ba5a567d868c2f1d3ea2da7b3b901 GIT binary patch literal 2227447 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%0Dv<%y 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Πy5Bpx(0__6n) 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

QX(aejfwLjrI^``h|n|C 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

`0L{}lRQ1Mo>>nWw+DE8e7DC_kEPV@ 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

  • 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�!Jh~sr8z-N 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 z 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

    qjQNhrJ5`PYWQBns>gLj<`OW%%9VubfX#p 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

    M*o??qU zg%!C~9fK((0ZteIXmzNfR)Z{yY(OPvSyaUg^3AfSiX^0zbIv)ZlZppU zbv9clcT`2y{yFE@BL&>i^3C4DQ3cp=DT^rX#vM(eSw!)$;Z(LsV1JoQNU|(a0T{V+ z7gT?86SpbdWRa4e?C(OyMAt>hU~X6~0s>lnaxyCqr92Po7)A|E~t8cE=F<;8YPWSk{ngs7?U(T9JD`HIGWKqt21x4Ojd)QxQ(Pi z+2vTp!^onS#X6JykVY2k549}T$YPz9ki|+=$2xzAHA+4(Ba2?C2U(OyUBkhyDz3ZI z4+7I$Zt5VXqM~|L#RKJ(=D1C_Tp;Oy#X76AI;%4f1i?D1GfX472wv2NJkPs1V1|Z8 zc@sUG=(=G9wpsLi+%Kl>`{1}(4(U1Aw{yk+@$uMiNH`?4s+jJsf1ihY`$NLcTRIcc z>yW1F|Dn9+y18yUwOiCZy-I<|SAyF#Kjj3AvPOaouoH~qHhmk19AkNQ?UQnq`(9PU zK`qjFOv*q#{U!~Ek&Du<}79%nxl+r8fTLCj-9s5%S z18OITgE~B59Ymgv&G!HQ|Nm8lP^*_9Z-58^C2w}74j*#-c1nnK%kBtJ;Fnt5eBgnJ z5EL?g2z^KsGckT}1(hCtW{COJTImVy)~Qlep|Zi0S9NGrbuwWCSojsd1)sZ9IYwb? zcXxL;?Ou#isece;vF?NSLE3EHO9StP$uo?6>nSigV6kH`POvC%@|#v^wG%xlzE_0b3XOMHsIj^KiNquU4^-KDF@3quH6A`bM&ug~4T48Wd&MD`tbJqDD z6UOi2Nys@8@H1jjS5f*E* z{VLeA=)oY5a(|V;{CIu`2AKQ0$5pRa5==iG4%TWloLa5+dU-Xk<_*Oxt!-?!eoitd zZPiN}qxm)_Z=~CVko~QXyg?#c^;SnoQ@4;S|7x=#U#YiBo2!<5lVH)tDlJ!;Eap}T z?iZ`f#$s~^*}_4RYZi#?QebPB*dHLXW$zQ*FS=?rRxJnQ${))a|3GZaWn(ioW@9#H zV>ag1N--G2$D>i|1g()do^W*3;$DnXDQ^Ju5VF-UHzNBx;qimV4-#_c$?hzuRXq-3 z(Sv0&S<6~B(x8)_%k9S9xEptyEe~5h3S+TahJ<2`O>c6y8+W^LH}1wG!j&p`2zi9~ z%ZytH+{a@|fN+m_EaowfdCX(B zBtxfzMx)VawALYQUD)(rittSe*`KA^>Yil;j!%?b=utRev2Ej6#lapObW;|;r<^Tg z_xJm1ov+eSf(ZgW`rnt)O?`1+Fx&0slRX9#G*|9##2SgdM#IA2JJvCq&7}#Mk`usS zlu~zDJ>m$a{{bdA5d_GHBZ_EZdmMyG8q%$C*c+q`H^C3&OVUhl5jBvznT~@=vPc@6 z20|y{z7>up3@^7qfy6NanYQ5p@WDuDaquP6IGjiTJio8`k~h?Yy*!xXpqmG~&DpnG z{Q=^jcb2}rYOmKRW^w`0to1sq>er5>anwoTa3iD*dE-Y&8oyb@T;P^0;##W?m-6G` zAfBy`@>bvzT#3dpIdIO#*-f^jDGO$Ej^}nq z$2_3EC_&5hhh(vBK|EFGlFDaa5pc#q_rR5pls5)=$@GP0YiE+M$W}vhqGztyLUaxTG<0B&kt|lK@6YOqElaDC$&@!j;QF;rL zu7wV}k4H%8as(ORu5}a#n_#g?IJsbTo1hceY0nn=fs&@N*la#F1`y439CWv~5SF-b zXtIA0dDFSOqm<4hu=qK3g#RZ6KS0q$5i4K;2_3N1z{!vfI5@$QM3pp-NRa}I(BEso zI#-~AX!UwRqx0Oi~-eLVQ@7lZxoc}(B(vH~uTKRj1JFVM$7B#faS2y#r1 zKc3ag(B+HaO&?Iq3iP=Ty_Sy$D97|&_uiX6Rw?F(3o);HjYbm789tOC2QHx40yad3 zA%d__QpOEqXsP zuNTLC9{t*6A_}`N{SZ^1;0IQ!ggmA%riGNKgi@Mz;KcODf`_Izz4ss$5D+b~H6~PJ zRp>-Bo|>t&)@H#I>$L@kjwH2cplWm&X@XwK{TUNdA$PM85p2UBoRhl4K{ zUP40uXmnF(?!q~Ouj5+lmGov&62*k|TZjowz=O>PTM0@ar?|+JxLhumWK9oCrfVxl zr-y?1es_ibJbVB_ed!~8(kAC;O0P`inC@SmhL%75q`~y~Y4G0VTRPO&@-)DBDy-5` zvxu@Lt7`7RadEa6jI(jK+_k9!-uD%dFHN8K<#gY-E4#b9NbW^}dIGn2uai-O)nvFK zg%n1#6hFD&hX^8&?o7~(uY6|aDWxCJ&jl!vfjo%T$BHLGKS3uePDE})#ciIPguK$?0@>1u+xvkB8we#8byf78_Q{7eNJQd?7LZl%sFd5wKF4cyfdXtNE&ZKf-@@|Ss$4YL(BuXfXR~f{9Z>*jCqV8 z`9b2CX&Zik>_)nu2?uE%)HvFSC$hhI02!LHKAn)f@sT(4G+Lk2C_?PyHU4YRj)NU! zeMXtlkB^TCw$u-TcB7s_~V7DHo~n8n3w_TVEq@8ihQI_~Rg8QI0=+ta7}z zjz8=b9%$WS0fq8Gp-`wHl)MrplRMxg354wON-n8DF|a6W-FK~Tko|G|!yENFNbK1s z-XyqVAPyIvvcMu(Gsoqi0nP?kkXziT0$H==RK;@lj>xo@Hpk5?N>V&jrF_3$#>xr7o*EMV1CW^r^)zZyN&)v za6MYt^%gHuDH`QCt|bIBFnt*(m!jS|CY^M0 zTu@`u4=$I><#M@PuGSM+N*Zsb#xub+TdpkaHXcTGUEj`4Du7NsYT9A?L>}4nB{YG> zn^P`T%Xg(EFo7pH=Z8romCQ2lU=VPLgTdvgZVdOOPsG!-gA}5ql1UlI<~BW`N0!|> zJCg#k^#QqZ8#X}I2=1MvFYv=bDxePOi4Vr9l)M+?{{-aV(}%D8d%fI+TrQW@0cER< zyQ;vHQjX&|dfS<1WWe_0LZxHY#{(NkcBd!&_fG_%o=LpeGi~All#SxdeV32s$;W;T6m9?NGSBs!u!dU zKao53*m1?W7@#Vxb#D9_g>1~X?Gm_f%Ap_)c>k@=KL1ProVfn4abKL z9(RQp5^{#|VNTlE$T^5rMSPFGCFQ zp@u=5K}p7_0Oszbd#&8hj#SF4wP6kxN#Y=mgI0`H7N7)+H9T_Igi80?W@^c8MB06Q z5r!0W(Dy9n$R*WRnnOnlZNp2hW{@rKSGD?2(+XBBk9@y`Ca~DAuBu2s zOSOLOsAGx^l*ixP{)VzC&lo48i_iK>_t zz8AWq9!_;M7DK;tjQt_mepb~2l9?g9Qp63ykWXX*#Rw8LK(Zu^5Cb)cq608~00s?B z!W%xA!4WGzMntechf~#j9SlyL7fh`}KYcpCV_x8x4o<9di~(J^%e&*p1su%5u^F)_ zYYh0}qy-jbl+zYilu@{pNf19`xdEO`7F$5Cckz+$CR zZR;XMayXxa|2s;l)189I%S^j_ElbA_a@;fD1^hrzfiS@a@( zlQd_@mAef$I2=$=q=?N{DmuZEO82U|_Zl2$IgWB1<+z$pl}c|_9bVP_8d#xy(l-%# z114#t0>q{P0b<*b{RXS@u%wE~v0s`pMj1m(dXfq!CI=^GzJ1b{R53Z7k1u9E>BG5y zKOj0pM3tx#od7owSd>OUI3RJfOa>vr6?~EX1lg=1anPTSpgbcPdmn?#o1VttJ^mO>@ACM)m-xMJ0e{}tg3ISN%%tUKey}C^ zZN6p^o2-d51{0Dy5=bJ=7p80}rR?rhQx$~E-Icno>t49uvb#G7XJ^mbzpBoif7aTL zWEkUSFGyw?hnvl2v)OD`vX$JWXFB0pfb<|FkS!uPitMj?Nu!c0f0m45<&s4f@TaPl zjDvv35MF7xT(V5qN7ZRxjff^hsSAfja~chSBy_6Lgk+6~CPdS**=#nOjq7d-sm>p> z+qpLe(swZc<&eJn80y<0VVCaQskOF_|IW2vvN3c|di%vR4^IsB?E~d>Px|}C^vm$R z44;~I#PsLX{#vMSzZOW}wG0W6rNv{eyn|{`cIL{eTGpT$SV)vYKzPhpGuCW2qwd{g z*5?#E=|Hi|v@aPR2i=3&8_k2w*1ed==2j|h)47{=V?$5bJKf#g-5sRrn7HpeYb~YS z-EA$Uo_Mo`VF&j;J5)QsVk42gQmOzOei1u{h;B!W3p`Uy3ry2%F~tjM357i`$s1J;>}{ijA+@EbyyU+ShlpSX9q<@Fd0Hhe*oD( zg&nd5&Xtr>vR{#c-|!U!mcZi6OXGlvG2!KC3i-b=BP?AN5v=tM6lR3 zi?!BTYpu1`T5E0nT+p#iqgrdNwboi|t+m!3RWa0 z32F0!1RaQjE^p|QI(1JHbQ_ce{XcxI=VIzXKi7QvcY2*?GWBrbQjPHwxBJp+SU_f~ zR%6YiGK*IM$uCe~ku_PYAa1vvnwne9t)}KybE|0r z%i9k3^nc9O^T1N`dm#i+f(W4y=)TYkCU0(# zt@fEKhj}FV#a|xg#rB~TMthXN;yjv1^X5_&Q(sgu6($Hb>E^sVOv}G~JU}@we|jGL zFyCL!>GbiO{^hNz(&`gm`FHbWI6oG;Gr_1N4^R#a%*O-sG1Q0s#2>jorhY8+PVSeX z$jaS+ptC2#7w3XRd%Tu~z}suwBr_3{CA@OXXnRq5+~cC6z#j`T%e zB$~?;o$Oq?QWqp?y07bkW;Zrqj{ADlK*1f?E(bY|<32ShwiY75g*ra5D4t>xJ`W=Be=P7 zR9V}Ybp3hXe12-Ka5d9rz3m; z9iE{~kwi2reasLM5s85$3Re<5C*@%VyrjNNJejAYqtQvHeQ7@_RL75pPZ$xUO>*b{ zVZsVFnynhvTOC~-%NaK!Hc2A|?ibxwEcf0I$XKt))~TLB|HK4?q>m`q=E`QXjnzor zfZ;Z_v5w=65OyothJQCx11!32blVJgKK(k%n=9jhY&j7}M>)Dp<|b*}tq{3wu15Ep zm9p?sDQkgU&90w z=7)m9<#M@PE?XHna^%R7W6Uw;n1cJo9631d${eH+ti0jeH^s1UpY$!4@p7_)F4C}T#T_~i4|CtwBG{vw!W<&gYC<4_v`c6mmxS~==Y({&JQ3e zPmW^vp!6h&9K1LmWY7Z*bQU3zT!iSjADp?_nF zIaLz4UZkxyX3#GM61()d%a2!%qSZa9Ix z+@Vk&43frY3!JM1d^rvx@#VCRH+V?hxo2$}M?@Urg}p^?G&JdW7cnqHM`uGW@}Bc)@^#@ExQh@uA;& z9;GO+w8QgMvehdp9i?qiig=OkNuDq9pVF=M_Rn1TkW{YeYJd3>U->(cnbhe-UnO%J zskIiV-$mq&zPFKB5tt&V`hM%zMmp9-K2o+utdz}9lvQ5s<70*E^|CNlT1;{8?mn>! z@Bknvq|Xg8fqtO9bJFOiB__IMI`*ziayc|6f6&P$(1% zg+iUWJOc=VAlN}lS(K&{`b;{XOZdJvMMsj|lQ1zyDyG1_c-$S~3;V7_i(i-&sx4FL z@K53yTi+a(E3HKt<&RO@GU2%)wzP6f`v3lUe{7R~j;)A7QzU%%d%Nc^&EpJ9LYM6m zh}xaDI6)8rE;=JyeJ{(G7Ah@SUAnTQcv00Xxi~5a)_P?p*PFg*;?RHF^l52WkaOu+ z)9LN0sV>X6*l>c@H|+Hkil&Cby5<(&(g|(%G8yv0oGazNAI$b&J(hY-^rY}{$s_qw zQqLqG84k(9&O#eyl&)9EdUO@`6%}h1e_de^?S95QlNE?W01v@VD)pv9U) z#t)pgYcIQ?;9^P`>f;>Q@SAH_;^q3JcY{6~NZlpEjh`{CwtgIpdW18}Wx|FQd z{rCakOy;nd+d;8@#H4(%gZMC7SJN`Bt%4BWFj5U+(3Qy=;Bdd_6eROBZreEHUR;~T zq3GLCt-mM>3ZPXXGKw5CHa}quKoW>3u!RA4`_Ex~7xC5Eq6m=G&ngdr_VCT7z$2`3 z9c4=*AWbhm0!6aIb>Tz(j<;E`PFALe7%k#+?s%ewOJl15^FlrsxKFe2mSiRuAf7E<`WnGRu;rf8P<_}1He8|b=>gGu!kQEbZ6uT zAZI}3F7WZ{Cmt{!rug{+%-ijAUkX{!MAKG1RL(&+fM5;}O-j82jF*vN$1%Y6Xft9P z%<5@ron5v&dGOge38|jkjB0*~SCv6ugCar&>sgr@HX;LrEugiCLb1Fe)j~sE!GES^ zrtwELFk9nbC^hF%#BvoiDTVR{R0@oEN5m{QBDhi}#3yUi{HXC>SOVOv?6Iq`|p|7pXBJt zSiKEVd8Dc@s$F#cF3ZKC6@P=S3tK0zNi2Scg<{w~thHE@B?S@6Z?|rYUs=I27vKVuW5z60 z!qAIqA-DY1{(Nf?18%E$OKK~SjD~#(v_*%JFb9OlpHZ<+88>^iM4qsdVPEN$y(h(B zEdlfj$m?a1xc$+3g2?FTWs(2|tRx6^3ds>KQI3t`l%w~G>&XGb)bm@~v>x5S{C2wa z|3?wNa2%#xkqpDG3O-9huJcOzpFk|(RtiE&X!WOg?Q)BM`3hsMOj1=>H zElpL6tg)EF(!_Br=Ms=GnVFv&X;k3|fK@c!<&?a+KlXCbz{v*`=CoJ`rENou%%GoY zE^eHNw3tb4&bNoOSkrrasG(2h!MiX>dH=&GSF?(Er`cA*4`?_RshfO9AaHV8I7*Le zpY*5Y7kqV_zf$THz}%9Kc{qQ+IiJQfmwt+5j|Fe_h-4gy6eK6%j{$Ixe7%9eHAArc z5$}kUM^-1LpcSwht)wWc1Y}4}z(??+x=3N1_>#ESdcnLHl%(Dv^HySz8^pvYR|Xjz zrXSBRv0Q9NJz*VoryurMt#A{q2GaBVnm09xzm^(vXO=Ptr?y<@TEL-3jKV@raR?rn zs9|TWAXp$Lyfy;M4Sz%?8EEIg+fTj~P+Z5jcQVUhNH2yTic1lmkyDkk`EI#8kip1_mtbE$BdusKhY7z9}&1jsBjxUgP(36 zF)e2^f808=tJ?a5pxG#ouCu>R);^iMUM&G4EkgGFb!N8*FY6P>t3!XQ=%EgR7rROQ z(gKf}#mHO^->qP0)`@|G1HJ^ug(z7z5;HFZ2LkEK15y(T3tG>Z+wezAa8O|W1dR4! zID;`g(e`sKSFy#MPhCgPaSKF1efb+p)-JBlVmRhs7fOGEnVwXWNeew&GNfXrJ&^2v zs?h-t2VOLneh`OST_HabJZVk3>zM=jAPtEW#_e&BY`{r|$`_SWOe$)%J9B*ls?Dc| zn%YqmY?T(s#1ouyjp|GP`r@VP$-1d&oh+GCa&d~U%O@ZEJriW|&pW@8ofzXz!n*V2 zjO0oLIdRw5J&Ln>g%{bB;~z-uo2PTN*SQ5Bj?+Z3xbTGIEncFyBKKX*A_;Tv7)K~J zs(H-GMBV;+>)-WVg))T+hJv1UG`v6LuMlqOBM1`;->}&kr&iSQ_&xJerlBFYX$7Z3 z{&H2=8yqfi$;v@(FB6FqXA=xD`uXXiPQcEgeGSnjs)-ccW z7PnOUuVM~L+>K-Uy8&6Avy+t5$fklTHxugX9N0K*=6S(Ln85-$_5tgd`Wwk0*%{33 zwIbB>F2&c$BeAh&W0;5yK&_NVDD6-=tjZ28`{nmSyLrc!PBteQkLm+=9CtM}`B%rT ziHR*|{I5sWqGNngNY~snSaU=CXQR)K6kZ)Y%+|!TgjpSa=tG&6%q2DFWcUyWAmlkn#0nEV8teTi zVwqcI1E){Q^CRf^5jf;~$A}|6S=qa#&JvW{sqso9q6QV>qqz@Cj9Ny~Q z$PmbYeRb%18>z{z5I4Ql>?=0ALH=c;kL8HPKc$3LWu!M-PJSG|h){Xe+@%Opr?mP6 zK+^XjU73(A(3EpUN)Mt1dfp*@d`TR9yXOj{L+VbJdBr~5HVa~fhxi;@qLGYq%*Cnr zp?gl-KxlMbdwK=2@~f{$4B5w%q-WLAfR5F+>dKZu#+(muJ}BKFN)6ihd|2R4Vv5p4-;xD} z7x6Np%BD(xF&x=I8O0h`iUr*DDRbtl0VU^P^rT!LKUwP`K8H?6JVt>*%Dm_Y&e`j{ z&`%Y$Wx!CD%0ghUHJ2d4uf~}=lkYJ+-}=6g;4QXAf-m|!gM3{4;wIl80Zw77a>bD3 z_T)p9yxZeYDg~Kk0W4yaic8Ph1K4m0Kb}x#ioOtFML^Wh`BQD-zGM~{uTJgnK&`J8 z>l>e@6othS=iIuf@@c>pFlaAYgIn_>jbn-&C*_Ov5&S%LP8{1S4Y!G8GzP<dHDHUVGI z<6&x3RcF^$YcnIiy4(8fQ2Y0lk<#G?$n~?;*+06m)*$#X1nWy6Pqi6PKA(w;lpl;aM-NK$)~h}U)?Pc6=i zZ6uOK@gZi|piId~_aSl09nIxGhHy_d?+`PnYG|)bI;p;+|MNgFBW1=K;{2QiE`TUd zjZYA=?Pcm^SO?kpA=OAZ&wAzMz7C~PboAd)v5UQK2}hDmCI^ z+;m*P(UAUHc*aG=S81%=jJ93c1NqifK+cLOTGC99?Xi>0G!&DA)IURe2U3M0KSdE< zms)SU-+!KUhY4&m;8d&Gd$fPyCfwe}CB)q3;_cC{@sSn@Hel_&B4 zCXQv44!Q_9hqnyCCH0gKbj!QQD_5bcK@5*6KsNF5=|g23XQ4$VmSQW+DF=QJXfqKd z!cj?FWCE0mr)X;(YY#>o-cv6`@-{&LQmsTe>m%2c=?nC@*g?cWk))c>5D3AIl9yuk z$9k79dH7xlC%>-{4n6NfrohhVZ1QX^Ucl$-(t4gV8CgP~4+aN)Y!1~KZhC(>3EjaF zo^4mtNq^j9FZ@pCz{gvvGGOfIy_wMBpS6BtU3E4dq!Eg2dXMVFYHN`D*hVfFqC# zL{TDAK@+S{Og{Kki4OgiC0n7Zi^X+PkX2vvFNz)qIPl6Jno<0h zsnW|V4JSG>Sz64oxv${1K$XQDndTX&hMkRDo&HzpN!R{5pStGy2wHAxq0vDq6sH6y z2nkCtXP)6ozfF1H75(OvQWcDG515_`Tb2URLoTNbLreim0=Ir7J{)5;h? zhhN=&rHeW|`qY@h{m zqJ&qk@m$d*tQU6_5a*iLfDzHJ){9bg=tH%5T0=>%eGLta6}^L8vl6sPZ<X1_Ubk$XybGaGX-O-S|;qm0rFEXJ1z zFbwCbJsY3Jq~GdO_wfibqg~2+^TXvS@R#9>sgV;a<0MX4GZAiGc^$s*x(O&u6#P$k zd5d>(`-q~8=|)Z9>$-*IsPXc7eZ2C*J_NFY_fs>Fi!oeNvHm!}QcUog%^F-k9Hz}BUXe-82{#Fk&U zQ^fI zNT>-*Dm~&xyh&Ip+IRR2oNJcc7S1^RT(m7uH*9R_>87i~uQP zOxkTnDLK#)d!}8MAsS*{Snj*#x7pLB3r5bToO=fg_v&HDp2m#IA^i0`1qV=YM0Z!?rFixG^b$5-vm z3y6Ol)Nr)PDOe5SnulM;MAYMlqk1CYy9 ztmVRaD4D@nTfIBJ_y-)gLEqNeBYi?w)Ww;a>d>5#35>rLIY50q2l%LyTXxZ?kmpUg z9L6vR$n|}T|Dv5(W6g}F*Uy2Nf9S}-5yPC$y~{sCDoC0k-l@5RMKQBXmjpVA7zgFzLOw=?K~KB&!cMpVr%+Vd$9r1NZFemGevuFJ zAB1zvoCfVRDoHh%6VWX=pN!#)mNIJ68@YwlJ~b56>*z*DEuheATB34^_jH>*#gJo$P{GxHPuo7thJdv3EsU>sF&( zHLBi+t8+6XCKiWdR!ey-;SD&ju%(Vf{ZA|+IREWk7W#mS1&qGPv>CA4 z;H0n|jGjuIzL^YpBk(Gf!BPCjjap5+{}{1Rrzp8_>60G{)pV2WV(7C6<+4rE{37nE zXE*1&bkvoyd=unL1I&@Yb>KJQg}A?>L9_^>n3oFRj>H<{lYhtE&W~#yG0v!zjlN~5 zcYhXkKAPF=<600BuU7z20crXp#nw$?Of+)Ez_cFDBZA!+Aa*Ba&wTaJ9E~cdU53I4 zBCFP-kCnDO$88JI>wdo!$3&8xI~I&+SfWCcISnGGC4Ec8h%g1E7?mR4kIZMUc zUO44Jv&{qe=BJX$|e3Kw$D<`|OT&Pg2urfHE=5=QhT zOB)+^4E4p*(X!(MNP^M$Vze23+mKs1{G5%SBP>yS+u>-bUo0Abkpp!FOl7+`u>M1^5rn)b8y)+bnW1R(m{asL-;`3_Df^mfiv3HC_ zfY)H(0YL@X4@}j)p!66r4Zi38cq!C|RJ7;(ZQNa}Nv&Qb+uG^t7k31-F z-LMm^ni%p&kfLBnn_4M1CCrIa-afDp6-~#>%G#aPi1{vcN&oKrA|@j^q=X zE(o1thiB?H@kqCxfo>Mj$`X&Vs^YfNIlS4r(e!7UaWpvDP*jJz4%0|AoirBI+Yo=_kfnrcQ{lm)XDDbgJYR^4K80W zT1?dAT$wd8tnJ;Zk=ch=J)({5FkdYKzgy#pj>{9By$39R%zw^ahEh>H9#D1VPn*|B zR{!v+z{umGoZKXVm)ya^mEUy$O+d20hKXL(?{qP&#-k*^Xrk#@q7I;vK-K!3% z&yj04ivB1&+)A9CWF&PF6CmvS)DO=CJ5cUIqL~J=Rj(5;SWJs7rum+Z%Wi~7xKsTU zQTnlJiw~P4YYar^IJBPwAAw&k*8i`2C{E%E6)Lr`r`_Ymuo+2ap7%Ng{O z<&hKi^DLGDr3kbRR8eYnSc{Z``hYchrJ#{I1#=YLX?2(_N#2r;$YP3`K`ezx4+f;5?()(HX)KFYCya4KIJIG0KIC<2UxS=m^5?}aq28q_sdf1uwT=u80B7#?1|(wGfTl;eQe?4(IKC4NPnNJX zmag1Bw1<$XmY^n$d@6i~nj|_HoT?fe;a>uoP8|A?{c>>JnGRGFWBo3MzH06zJk}r~ zuHnZy?AJ@?fPxIR<4)>YO!QNdnX zbgiWIf~kw|cmV09k$b?!yopK!gkLL-Hp~AWl=Hl(UCd{#<1wN9iavpA1`5o9ocDn8 z27=e3NudqSJlDWRtj}#O8HAAWE4;f#({n)Id~ZGZQM}P#vlmQtP(A_#OJr-3!v=B} z;hL>_3Orp?pLwZ9^EBwq=FGlJYU70h*yj{dGch1LVJ?SO_5?=$G^jaZzi5dS9*e+m z@@MR<{nT>U$bm|&!3fPIUD^@ulXp@!`p5E$?l@en{(<_I+%AMlxrMTM0m-wkeRy5P ztKT2O7w_Ikm(Ot0kGrS~_toG`W5Deo>>oMKHfBiUcLUFS!tE?`OyTtvl^aO$)Ou8H z?Ro8HI?g>kUV*bzdeOsc#%Ru?#v|^XG^*h>8?uTQ=|-*PfB@x)fL@4-0L5qm)o(VE z{h!KtQv@g=L4uZpi;#gyJhK1VXmVSM09CkpIofCBhvFy!>f`cPi~4Z-S)2gXFU>7X z{0O|8Wz@j4iue6v6FC8@V3$7+x<89sX7(n0k-h_Y^wZYx4ERgNPk%ZZiJ(LF`z36_ zxN%7b3n$0vXJ3Wpk@x-Doubb4{c1mV!q4|BxTaYS-!H{&%LwQ>5_>B>=G$@z=yHCp z>^ z2nX=(;DYt?St=j~ZQbi;qJ%43FlWCu-Gi;fD?w|Z>OMXDBqgL`{H4$lauz5RfK?3E zLAsGNSg?WQLx1wSYR<5xNR1`%(17qm%nCNn`WMDHGC5XUm6uvM7gG_Vmq}1d*QKR^ zzcNe7^+^ZVK4hOxP0){OK&s3_4gbLjX{*N{-__8eBFWmD5g8Z*40_uBnXW15G4*Fe zgP;e)JWQc1Ogoiy0K&e(9t8_BX#)r3lO>3F2$|F%VMBn9A8BZMP0>gnW>-6Mw5MVm zVi{G$fh9VqgSpV~rU&9usZ}YY7i)u;$Sb`}WYB-6i=daOfGJ`IzAF3HEFJpr?C+GN zI5b;Rvni`iM1eNvjPXJe@@eo954eGIQ8XBaJW|P2vgt+U>V&{I66k!=Hamd-@DP5kk*I>JmB-k0} zDtZ^Nsl0x7Art;I__Qp4(|%R0*wkUjLL6jfr&2P?+-(_O3cZn=oy%vp;Eog7b>FTI zC^cm$WwsEnofF&-F1aLiY0#~j-Zyxj`p7FU;6>8N9kX)DI7jumin`HLLzm ziTKHIU)qd%YX7VFSYx;9-43+WeFlQKC{_F>k~A{Q7S}^_+Vv3W$V}w6S8}p5Lox6u zf3}`#tBOV!;j-9q!(`Z=tayy?-yzK{vx#_O=TK0qv!~9hzcOvg|w=jlU3-GNjNb0ignXOzTQp^ z46N`(gw~D-M%-$VutNjqptw%##RuIUmBk{%7XXzlkp!zLIZsqJ_Ts*-C*%LPxqM^d zt_$K2Bi>%d-AqZ!6>_D1RQIooQp)TY?kM}eU%Wv-I@k8%`s35CN|q|N?vbO9yQwbS zLYRG+!Qh#jw`Q!fJQRFyrBI8dLcWW=)b1S$3Z*1f|A)z;H`eTa*9NZ}isD31^kHK6 zT6L^pm8ko*8BIIUT=XNP3A(t}%UK>y6g7Rmh>fS^4RqaXr$HQS8R@ZMtJ*eO&g0v3 zdG^YQ+01<>o#!Se3U>5qisl3#nWH4bjyxv{5Txg#CYYUZ^MnV+F& zS}b7;Y#8KW{5Y!$j!eU2qB?nFT5XdGd`b#7lmuK)zqsbZUdRX{wiVuG1cuwjKEv9PV z0ri#@f@Bi~byO@1%?&8UdyNGOqk&+*+aYytF~UG@?yH>ChiABE{<%&UUke1Q00xt9 zc157NbFgsI)lq)kS5?B)-X6M#`^?vTm(-f46e5shtl`CykNF3Y^Jk01>gb#ogI zqJGUEvI));4(J-0V=8&S;-YiTKU(HN>E^Yd6vG+E(*CQ2-lym-PPdwOJl2DE|QCa4|% z^6T!&!zli7*o~VtzL4)*<@wT(eGHv`nGhekk{$%&#eerFR%9S=_Ty9 z2@`udMrbXuM+v3=){1jp8*jgO%(~Sc@`#I01-8k4+sQ|S)|opbQj}mJPd%3*V-l*= zD?YE@u*4*YZGgyX17nATrqhzykek9v&KcY`_C}OD>o$i?Z)zU`M99z9=x(b9h_vJ@ zn>rGd2utP1xZW=>4Gp_S9_o*{fM2x{1&JcGQ}veQkLh9r$96Lp$AR&u;2@jIRv7~s zsPK5j!*teqGb?4KSY}z*ZH$gi&oNt=wOEUx)i7%v<_wlgl4M{xtjt`ed&QYo-<^hI zLT4>A^ofo2(S`r%x4Q`|J72h^+f~^3CN~KqR;(FdYspjbk6ax#vjr9hEmE`q?Vbys zAebkq#EGQ=dWNl+!l|$1hY@m zRy@*L!!-VQtB0-k!Ij}7lQKKr*fuOSB0ij7s1>VG^^$P~+6)9o3y}R+*SZS%N;5?U zywQYty#V}xFA&tLK>q;0vD9r(v5A>|(taN1W0;^Bezu-|MZ=8^{6!EtkO*K!zsi~; zRqP>38U_^L*|qxm6%sg7ow}5%3ay9kt{}vV7W9y zsaNyu?gGaQvAzgj#dn5aUw8{j*jt`2H%I_CwlCC-Zm!_xmh^8lYW%ivO)=clN8~NW z44Ha;%AJD^qo9(}h8+NA)hiPGj;Mt;hXqu*ij`GYxSR!%MD9tdpWOj^uADpyoGU)n z%m%bjn>;}p7q1cn)C``0DyT0~&VWoJ$w%S*5!AX*!X9ZD8rm0#m5-Asy@nlnR=pjA zH3#R6E_*LJ^IyYe~&9;wc`p})5nS_jckw6Vk z!^1)MyZgbBzbiRt;>_B9C~6SJJ6$6(hL>6$SV247dKVT6;vde*t`EDVF#JP?b_ty} zSt0f00)^!+%_1tA&`o*K;;l!TpSWWnj=HWmnLiJ`|B$ib*?HTiAVxeItmVJ!f>>m~7nP;D9T$cnA~i}AId|L*5A)px+bCcD z&JT7#7wpC)=BQfv*BzBQ?N#tNlF1h&0qrYhTp(I3b z?*aYW`i-iZ6^cu!a$!9I!3|9 zFz5;pn+vS64VFb+iV3;^P66bgz!y)F>7%NZ$X;Z_@!vGVm2Hei*tt>~8x0^6of1*Ru1anm@GRK)64I0x>CT%H!au(FwV_PYd@qQ=L1gjI?SdE0oo< z&)k>Qqz=blN8>eztEzKb(y+sH5**@AB+n6=cXgT1nM>Q)(_;uS#TwIwR4v|BX@$h* zlee0$i1ImjVm`G$UMm4p2ctyUDA(GVCtHL3FHWDgn-}c+Ffayi30nsP2~ynd5Icw} zF$7u*?jIc>(?EEi@g6^uOre-;xxzaUc=aDo<8U#{#^M}_i?7);W5K|T=JOpZoBp5kpU64S(hIO- z4j~f?x!;hh27obhhN~Eiai{^6iv)7{s*Z|xu!w#&7vC8mYKw`$7l%4(IM~sOE(*g% zyOQEok3hQ;hnF%Ltm>Y^ME88XC#0z%`s*jOczaeUTN^!VLuqFs0`2uxJ9*8%* zwJgTa-S-&6b|LU`_joaCZz)f02wj~(vt6KmNscqi@mSobdW($mWv%7%CJh54VIE2l zp<$V@V?6Qv?J`Q9L!4W~%9>QQ=Ua5C|K`IH(S#VLg2q{*!ty}Eku5F4+D%LHd2qQS>V0cta33}s%}u0 zk_X-HeS!A^3nxM|Ue>a`s!I-i>AH8fL-j|)SVU%-Y7f40N$2~>@JwO@6fKBVlnZSb zIU&p{^Uf>i)|9)Dszr0UMWgPnBgj7B8$K^1+|5U#YW%qKLD`Xv5IaK75Ku2rcv6m% zB8B7Zk_wfO8hSm91ZB#PFK!J$#!Z_$M`LLLh{yL^f3Agh}Zf#Qe9I5-j{ zCRn&5Et-|ZwG{~1g^7}?=u>~W^MT76R&76(6tR1=jnNG5a1*?`p@n5NS#b_Cq>JJU z87%o&deJ{rK*Np_)bc|xOmB*~BZ3OZ`?DIF3o8U^9uE=W!YyV@@Tt#g3eGAE(jqe$ zhh?F-q9WM{`vicXUZ(qk=!A)H087|vEd!blp~4F|-J^$?D# zw%q{C%Q<+zc)R{g;l|qw2Dc-j*h#X@Kt?=g@ zoB8R;&(VqNnlPWR8r3!S+{`3MCb6_EdfZ}YDK>Te!7+pd*8{5`PG2XPIV=O}D1Z9p z1K&-D*k}#lXmSH1V`;;M0%Sqz?kgs%9q!@0zYQlXT8ALeTJaVIL#p7JLMUigTZDrz zP*+M{S1;Hm+`a>5Y@yxgO{Wi|gu~6O1iakcTfF!Xd$ub8ywGE>G{k`>Pi#%<524&@ zR_w@!?#9Z)`M4mx<~W_C;4~DXOLAtyEwqPqFk!1mCAT*Vv_H{oQ9}T*-AvKg!${K* zO*5i5;f!8h4|q#Xu$pM}nOrCs6%W*VH#&^W3epE|u$}b>u2v7DW1$x)zpg#^n|EoU z7vvu7_s$A18-unO-P=VQ7q*NvMp^)+UG_eH8yFM6LH78Q*q*S64eAPLC z2TIEf_9X=mFndXuS4OS`a}aT@osWUB4@U;)UV$teIf2xvK_B@50l%a~U)UJGR3hMd z%vKSr!Cxj0$dL?tT)K*LG)Ne&4_e{TAF}aPSJFKU0gcl3F|I$my6SphQD39@m+~+WU<3g153#`o} z_Gs=m+;QmlKM3u}V{T^}GnQEJsn0e0V2XZi$5QyOY)JZtD5F7}eQ;VK?(?a0PI&^c zOYLLY9=o2PtKM-d03lMh22b;w>Ya}1!q@Zi8&Lehd8}t2g$@%X*9+VUiS&T`UmiCeRwz}V4`HbH%NCu&+hv06eqtl6$5XLfTQVSTSD;ZpLSVA;%bY($0ZF=cRbHYkr&rI>^_Wsk({ zHg8Zp=13}(RsrECS7Gd;HGyM?jUxwDv43e8b#w!fgd;9j3==ko67-Hs8jZrrIW}r% zH80%TR9?mkizJ4%7B@|xr@MCi2Q1Lns6aL1{%7Y`HPOZKfpLv0tjL_?v1u^V(wa%s zjeigD27wtH2pP~kW#^d+)=?iOSY?y%s^W-W!PhPFABKwXxs_nR*jS$c@_Tf9Iulj~ zw?+#|FG9j`1`%c1!%y$u*B7X8i*FJb8@+mr5t20bFXQpov&2>{+IV>B*faa&3dh+*X)Ua>nLTBkdt=@1Fz{MzUYYox*5PXkKcp?^tN^Z(-xY}iYjk*PlVo~P2c+0# zezJNUF;~Yn)z3|+5;c>y%GVy0yML}=0ns0wxAR9Y!e0^1GCZOy!D6rlU`_S4Es|2L z#z?yeDSi)c+8{wWkT39{svlqLPrXK1Wz7kVVq!89$S)x@Px)ZhS}8QH_p1REqH}VX zkAD`SKKouxDueK(m|M&`%9VRj-Fdmo@q<=_84GP5wsj=L$S#ro48eFqagC@;Ivi|| zyeMIube5rwm1jDX4%?Vv^gVtKpeugOKG4mhVSgY?X=#7f&^II&kAs)K)zxAwO6&gF z{U#v4w~id2=2`xw8Mbg*f};7!OUvfd5vA9VhIjiXbddmzo{1)7l%FVJzh)h!HYW=Rr^#MdhN zuro++qze_YZMj+9!ZTT4{E22EfK$c)phr$9|LQA|4-Hv-Tr>-==WLD~}u9cWR0Ya6otJPGLPCIs-%QBRX%`iljx4<@DvV(m?HU>@ErASUNu{96G) zm*as|Zc^EqK3u>>5?M_CyxVP0|{&3r(=Gs=9?$LfY2!NxgAXZ1iJ4 z8v^0)KEo??;tA0}ROg*Vd&dmhd2*=25JqgXZBttOEqw=F^`%YKI6zwG%-9jwIU*1? zvem+k2s(*h5w;uR$My~f=!0nR411PAm4xGKjYi&~)JgYW+^^X=Xy3ss_$FV?KS)t^ zsWA}kO7CDt3a38@==$Nxia%3ZvQ1#D1Vv!GNO*}bsB1FtyRiur8?l`J)hR2?Cn7&- zP_H(^zz)bCK%BS(RB@FK97%YvRP8ETnzETdnQLFU_bI?Id=O@FPZl`IIU$5{A{9ix z?cWPa_s$G)(y+CP>$Mxep<{r`M~KualyP$>A;6mi$ayv#u%M9fG0IRuX^gI;4Ii%c z(FwuK*9(=f@Q-~5)NAJ8fF*%DFj=QA_95YnOHRuJ!@bSaG^MfF<8#ppV=Zt^IZ$(G zPDh&6*7c<23D}PH><0X(3UTZ^z8^a9{UoF!Vi^qT>Z3X@ zVc6-PT0&`%iSYQdVo3a8vTrdUKgPRk0&XKoejO@ka0Pl_{ zd1?&PMKn!5T(9Jo=MdIvBrHis0ufl$sVZO4{=~ID?yOU7Obi5cR)n0#-qg@_pV?Fz6PORE z7ZV^eqFsKp#L5SSwTB-*7etq!Y3*DEAX0*m?_rHZXERM0FKaAY^Y#~wI9dZDXj3jp zzp0;*lIwJ;vVauf71yH_fYsG;WV|Q%+2HccT3g*nf$E$ku);#`DMg3a*C+Kpn$FlliFgh$+@Q5I(ZS(PE{41Qu!=WBl8ZbqGuCJ-#9|k3X2=Q|_a2$%;wn&iz|@+c3D);P{%AilIB9b_AbOCVMMmz9e`d=l?7LLvl)quD=qH}0 zqO(IWg!!2kW=C?Q$36n&z?9fM20%}d)TxILJuZKeI#C-=hm=-hS!0r%xsoFTAVZ3c zn+Y;^`R>)CSzBuX_l3V!{WIl|9}PU$tHqlXDx;|_2cJ6p&`rNxuun1V6p8i8ui(y1 zps4Sfg2;J_(26mbrK0RT?)fFell40%lr&-jAO_Tz{qK)VUUKd*AsrB^Hy>U*no)1c zmO`<~#+ID1gZA^&_b`)$iSdx>ROqAw7FT!5`3k5JlXet)aN3vSxH)(2Ms#++P;@0<$* zOIvC)p}ue%s4N;yz$Tq1ef9L+D+aWtcy%wUIJsd?xzkbH%M4dPB!W*sE zq_hc#h$c>V=o;YQ+Ye5qX}4@7Zn|JtJD}CKzIluG)gBMkyuctb0oeBxSTHCJxju5c~gRH`36a zaEh=FqrS+|_GbA3>6d1!0=E0-*8SWz@k>mJdDH!Tk#M%0d2)k8a&a(4#5Ioz<0Ug< z;dKyT!cE=Wk3@(c77K_h65^q7CtyPfghA?<;yX%fcBFdK2xn!@d}BF07;dcOmWc%f{M#L41(*0sNvhqY#vAQ#NL#W@tNQMYAgK&W=rOuMTFTB<22we{m-jwVxbE>J+qXcAEG`A6HE>7942sZ!tprr> z74iHeck2cSERSQbYaA|{<#0a7dk?^4pT4`2=tkey4$-viOF z(^zj2{=cC%X@YDKfH=GC1Iln81yvuOwKkBO`#4-96tTe%NQjKN59D&sO8MpJeoBRD zd}mHykSAC&2hRyOHP?|+}=iP91t!Q8+vt|*a#h`Bh@ViLL*gW%K1K84< z+h<^6g(yfW{$~#jY=yd|SY3)n6$H(+af$=P3g?bIxG+Q!iC@(2?^6-qC-m(J-lojqh5)V+rCUqA*9>l-Ecpvhetgp$1B%2{{-9l{!1-Mj&$L@c9ewokGn$TTV6A`vNH<9z(S+Yoi*XKY5rbg3WkNU zqFrBqc(gP+14|=h^CKdWUNww=20D{vqXQ}b;i8@3T{5L^9@952v9j=W#3%BfcyT#$ z8@%pcC5p=t@mpEBvxjZP_|D+pVwnv`6F4t~6`g~EakNdAEfx7`-w{{TXFuz?;gVJ! z1df_3&cOa={pd4C?iTJ0{*53N8!Cf;{gczr;>!MV4i0R%6>5i4fivTZ(+S7o6s~O> zzw1Bz4h_-{X$>pX`kVmr5^gG?T%p#mg6>VtsM5W`dn}6ujC=iYEpB^40}WWL!EgJ7 z#6px*azQAc)vg+(x-P8sB+-9ZQN==IDiv81eCYP)#D{Jhm({zM&rNnpZJo9Y#t_1| zV1jjalJncCiK5;3G~2L^5An%W$Ww_!trCXHtPnGkd1+Y!az)l6%XD9&*(^;1OeuWA z!QmfgZaGSn4_Re}r}?F4r0d@%t(2ZsGGzYNfzwj$B-=25!uf+MEFtQhME zn+VfNVZu6@AR!wWIaNG=tT7*FTh{?(i7s9&E>}NbaSu4F<58zquR{(-+>>w;#Y_1r z4VoAZ#yggUhMVI=%vdD?{Gfslhi~0;3t09x5qyoMa0-n57QtqO$ab?$46%B zg5UDI1r`BUDe?8yL13Q5&Ow3%SpQK=gLRSoK8B`x1%5x;>JOo6^-t>8XqSmBv|?Mn zbZHeAg;#EPOpNjld$BPLdt#SaHyBCaGD@(bxTDjwuV^g5|Ce&03e%|h9wp6$2Y3*? zJFOMRUIu?%jK{7RBTs<23;;-02uMI^6K1<=HObw=sCkCtX;cuvbM!1T)5$7p77sa58 z;fCb^XC0g1*O{idVhO|jUaGrfWp}9wol2Nb$VOZiLEZG&?L_t&{YZ+!PVMV~L(Ovw z1!rS)n~`IkmBJC%Fr!+}>tDVXY8R_tEZdp^7C>!~kmgyWf7s z_23kw9BNMSiU=AyRP5DDat*ga*3_D+mt7d6L!Tm5CK<2LvNl)Vk&_~PjwvfgNNqJp zv@q)osa1SwQxxl*~Q7pV@cQq4CSUAgaTD+}2+(qLGQbzU4%yWcECk z76@<^+?TUoK&ly57d=g`nn0D5Yhlpf0UKuW*l->Ku+lB3nWv@HvTZ4SPL8``cG~2D z6g3&gq8z+v(%2hDNsUOWIoFX<9Y$Mb?RQ$yy6Zv|_1)pr#nmf_wd@D$hROz}g1o%$ z1;Ohu0*cWP5E9AJ?Wqsyi-QSd+KgAyeZV^1jKxH0l|wZiufwc_o?$dEI>>k1mi>^G zx8GvHk2vFt`1vzsM})oe(@$isJ_pcKqKG&dm#@0>BZ1}mA1a2MxIaO_C1_2{e+YzU zIG;}Ns0aURHWRQwfOMc4K%Zxzq7|JNICmmgG{#ctU?#S`{#W8;br(jiCdw7uWhpY~ z#Ei?S`yYxgJb7tOsB;B(x-1nU$s0gD(K{pukUzk+8oeT^T%jCpL9jZ_L4z&0Ejf@ftxaGJV~CPxes zw`Q$ovLF-!lq`ND2w?PdUsMJH1$lIi0F%{)Kn)b%+*#T?Bd$(>RhBY1I~xYSyz2xR zlI5%Nnmdlws`YZV<6^z$!TVp~CfI*fqo@p7a^tBts|m(}f;Kn<`WksQ{A^y_EC^!w^pxBx7ql2}*0hkd4%&HOM)$EszF;b3Ko%{X z9|rDW|3xU;X`ujK2!(pf5&Hq)cIa>o_kx@s`D`W5xXis!Q{#0bj2F_Ln0U<*SMe#E z4#Q(Zy;*9gmu`4%O;v>4DSA0ZPemFKKXUt#LxWC74<}WH7E;3|KT!qLM^=xIcPWjL z=(|}^smwhrS8q~0o(#j>6&Y$+c9*1hQ~!7{@S*>T4AnM{E62`ATkjCC)kbJ_6V32P zsYpSpeLZj33UA5xNIliQ1Avi-nyAk}-`rH;?FA>GVYVY}7(=I#)7j)pEqb)V<+3PB zvq{($@&Dr3$={%|;8rfhC8`u;L`vIF+@9chObwF$k33Y*D!Lbw2o+e?(& z6M2)^Z70# j~ujMiM(|CMlMp7PbY!)l%QPnNXu5hHJ}Be%QNaUOs&kd5dbh&D5b zYsNewFRvTKnHW#N6SJUEyG=!vFdy+b58pXsphN@~Fk^Bfhsj3-dJymp%$UnkNL|vU znZd{08Q~ftJ?R^$FF6#l0X9TJ=e>t0>75Y!t~7zaN#%tm(5c;z8F!+Q_(dcF6t|vW z?baAkNJD1;<_*^3ghNp%7##ouwSq=iQ~zR>!@Xz8GSum;CfV}%jagvci?czB+GAZ}s+bs8na1xFXDh)^GNMD*dC1vr7d5DYXN z)l0ya-nr6K@-U}qov@O!*c!wr4V~P314>Fc!?N6d*0tl1r6re(2G9psn5ldr2J%bK zd@NbkfN-2wCr-F97U!VGC;ka{H4e>GM$lsvGitCPD3^;=oWq2;@g=ze*GUxReEhkbw`l zDH++#GS3ntV*MKdS3H3KF}EG%Fo588$!=@g$lhMLUg|}NI7u67ntO=8zz!T(pR&Kw z&JSL4=)(2MZ>9AotS7RnmDy3y@sfF)h4$5~JvB1DEt_5-sXln$tlm*7kRPewyEhw* z*p#hxGAFs@AVOhgSFq?Q;Sa>5;PW|H1h$fWbyMSbLNn9Q>EWcIrFL+D=FFe|JvrcH z{1rM*qZ(?^{g`MoaWkc8629YJhvH)d`ESjKfj3g$8vmz$Hmi-=Ea?<(lv=3|PrBa5 z8P=5{Hb%ZJ{-1RPf7Y&1C)z~*Dr5aC&=Qu2ybRId(Oln(+8u|sOAw*Rjh_B-P$uj< zI3_A2!~Gx6&bA^jlZse98Wr5_CFOezJOm^EB_j!#0HIb;{lr0oUs6L@7Th$rTJ2^C zIU0c0iVObPnIR@rpi~3S0#kuQ&`sugBRZN1FHRE-T$yj3=AmSOITxl>myVWQ@0sz|i;gyWBYGAuS;dw2%SLCf_!1Kg2{xk@=(zwRlwLsFce)v*WnH(&2vbb-+F7(6Th{W!+Q009S%8C0P- z)qy5HJ{G_PNrrvow-UY~G3x)Zu9!hL1&>u@*lp#`3hLJuOmeWNdVV2YhsRq=5Ij8@ z!@UU`Uh#O(b|BbHr+QLxW3 zi4rVKSo-_s1e}O&j5H_zZ%Ky!m&kL}bhF1r!}wqp+gWT!mlvJaz7a;}h=b8;p%`87 zqgZvn86O6WE(Su6jkLVg{n7eIOi!sQ4k{A340oSTsF{bYPP-dDH5Q*PnEi5`*wfT792QWe1 zbK1Z2WZsvVs^NwFNPj1D^dV1LtzE|k#QXT)D_S$+@}kdRubkdeJyca^Gw?@}pheDT z2EJ4g$5AA>Gs+7t@!XvDCbo=0>K#08p}AwNI`FWIUOJxKC=Pkb^4 zZWL8fwdCg1eiJo?^CC_Y(UWue2|0`uAi!|2xAScmP$LSK!x$K`zFcP~(yJ1_!JOdG zT3h+k|Eq)c*(0_W5UlR|0Ws4;$9v1J|0|~w>54l|JKWcGEO|%#M(X8=KIGiuLbv^7 z`3gEGtpK`#)aSnG7G=cVOcK%??bVn9!j4%cyr?y_qIWq?rVlb#>B_qvDMaJxnz4w( zR|TSIZx-?y-WVktg3A5?50~H@#A&F}BPuJS%njMfw)K|h2bYj*>3%1u#SGu_yfl+e z$o;O?uZ49R*SJwY&FZtvhr9{9O-xkdehqoBtMqjcH#&@jeaDhG2o*VQzE-S77B!DZA^FhL0I6dGjj0uWXv~5#2O{AV9WhsK38Z8`Qo*VGK zF;vAE@=1=E!dI2w^(`uwtv3;{vwP4Rh9f<}Yc}!>7mxUMs=K=fdtqAZjRC2k z{hy5({nz>kMu~GFql>6BzI`5lS`5ZM8Mar8m<@e_*s^%vJn2+;7p zi0_!@;IG~g`i?I1LTN93ScBXFn>m2a+{EfxEneu_!{`0>2uWG;c=t}dhf9^&!}@`b z@(Wl)(vckWPI_sa2Aq%sdM@5_TOd+0+BTKsF?5Y2X(=ta<}?Jn(CTxpjcW5oqH637 zAwYqyo6YQ>vd``OcU0B&JxC%5phu_xL{#s}N0zqd5c1n zuk=f=?9D9$`vxip4F_1Q^F&FX{!m|^K+p2IU|cbzj|+5vB#tG*9m36GrFAdRCBmJS zWhcG13vq%m#S>OH{bfnxxl9)rh_GwHyKOl~sB4=AkJy zF#}a#rs^+hZJ8>CH*8b2XR{y(f*=UGtZ)!gqJ)_L|F5x*+u*{x-+P0)C%Hd0zZJCD zw|gr{QHWBQH+N{N)`}$!lLk>Yxegk8Y!??qj9>Ki5&@At_So=8AA0p|hzY)l1{8_D5EBeuoen8_mj$tUJl=W0k^%Pp^nVRZYF0*7;o~^YUg&sqWA^S%% zTgSmV30tyyE%v{<0X8lfzB*hqdT2h8Rv(c@jNq1 zxujB3T9P+e#Id?5CDFCDZUwnAgo0s{M9x`%z3XoxM{baZErU-Q6KI%xgGrh<51|{n-Zmz){L_d#SZD1$%{xFjL&XLEI#n$@x=>AQS_TWs1Ks5 z2MkZ2s!x!n=nt3jFli5yU#z32Cg0Q=QxnZ1mrnAd=dV!?h@0q>Cw)vuPch+32ouVL zr%>jkf;p*PPO6yGOALpR;WqdQ+`}i-XM@9(B;qpM^OzS7!%ZC+j(#r`MNgSyO48n| zri|e`5@*(!V0-jLl}sOVbC-@p;!qxPFhPGlM1K_c(EkLZagUzpKY1vsulc?Q%7gSl zWb!yYq53GVI-NKoKbpY^4M%2TU|zV*rw<&G$K*2HW~V25!XXN4%$+Is`6&pjy+^3n zvU{=zmq$S2$eSA?lJxv%UW;9zlpX;B6|6;R#X4_-Vqi*ct46e9pIt~L`V&%s(VtJS zT8uHq7-Nhv#u(#CWs9C_vAy_OYpu;$17f7sP?k{}HmPJ-tkq(eio}uW&#zWRQ53}r z6C-2egc}?o=~D*=@m5@(X1YBC>V`6*R|FYcn|Y&fEe$*wmjotLY)Ug4+(+k zS*K-2gMY%Yy}y z(ypFYtGZJzPu4x$$B~*a*EouTEE4w3cr#KJ5DW4=ku}e0J^zcGz_`>VFzW-o>w|uD z!;MhWixX{|5cNTRMh%DX}SsX~L%5v#&X&Po6$kKbrhrEJr{;EWF@;vZjS`dw0Cv zrJ{+AcUfEB#=BVhdsoG}SfnN_R(>@3_HL8@Rt6c=|2DZh7wD(IPwN+8$Ntu*+n2QB zk972mk~I&bWPA2?Pcu%4eR7>7kGK^)DPZ+5!NNh7A45ki8xR2^0To6P zS#*kc@q;Q(X=uU1M^+{?Gcz+YGo_g;qkkrEA&Hp+^b!>T*(vx zPxZB3{W;L8q#CInT(LkE2&yDb?lataxHtlDtB4i2vb6|F@)2KooF!{M%F2mV>Q~^3 zb??311;G?-?}8V^c<&2d@Pb)KsdmzfWtr_qoTheE1CnJJmao40YW(@VSG$_dOg82r zj%8d8HywLyxlz}%!T{sFw~g}>-R8D!TbDv$0*euJbg)NYf)13)D-b2)44KAwcluRP zN<|zNY;S^8>_E;BIfA+NfT{DsF^4;Cz0G_aZ1+5{L(e?KHU7e3ZgWF!7U?cW3?fds z=2@iW%&`!k8Fy70kkEIGvvR>7?SMOU1b^iCqa~vf0Z%siEFL9RQoEO%Ni+xGPP^0F zm?jmH^qht!g%oVq&~9vkyet-l*WKP1j$7)GhJ6o((ZO{bKHxEq9Y07!@fsT|{OupGNnUVx$l7!PsF38|G+ z4hY6W9FWl5krTA|M>CxA0u+0)u-G&F(UcdQ*s~LXY4%JO3p~33-IG)_2H-IJrsQANh(dVS0ED(a*^WkG++L#IG=SB7%U6D9qp zFvp+zT$EIV?LD~Sd7D?Yur~@T&`Y2P&yc1M$)69t%jI%?lb8NTOdpg9lgD!>u8DdV zT>^|0-@CAm0mc|(j6)pa5QjL#Ar5nj&~3X{Y7D5HzPw;h%T1i@|FN;QlvDVAht&}WaeKnWpcF^gFYC#BeCk(w~wwv4CF=5kDN4Ax2q ziA#5N$aZvGi0l-4&_S}h6BNr`?#T-orfy2!l)Ne1!Vxy@-lzy}k%-uy40F1~(fD(n z=|jXZ5An<3Kg=0C`-aUzLhPk!BGSbIxKGvnUb+CB(hf-g~dys2ZyjRYT&v3VT+pHF^jlMb%hQHC8A5eb3k@ zN>hSZMeYwdEo($p1A<{A8BK%jP1a<^U^zTDR&0-RTRkm*_{~k&BZ`;`td-H3GGSLv zEwv}qh=tBENuJ|4j-xEm*C~}oqY-Ev$8GPCwb_<5Bd;-_&u%J#VTcUl#5j~jt+iHJ zWvz9Fo}7B`#nRfXN*rmrfULdNnt^GOl7{KylgK3WEt--E-F7tm$jIz&ew6dugSiD~ z=!@a3yUh8v?VVEuUksx-5{WbCYXs_97P?)InZxCo1XZXMmZ?ywS}PS>y1YU~P!?TY zp<;AuRZ(sY)cQ{+(B+ZBDY{VcTbK(vM$Gzod}d1+f0}7350molH z?3}<{>R=ldn~IXgpdm<`iL!OHa~!AUl*H%F(Yhzc95*h^iAv>!bIwU&njlu`!79|z zL2d~H24gUxQ~3(d!gCn82>>&ivMs8QVn)wxr6W3`qtU3Mfy6(}#yq;EPkJ81vu%|Z zkl3EBLbr|YfQN-HuS9{OSCK8 zBYSmBs;gtNz3S?Djmwv50cI88h|M!s=6V}%+SQYuSJ#%imCIIFsJf7dg8a^|AvIZ^ zX;+xa-eR*>xDONC`_-HhXL2C4vnv_6j1UA7NC4V_i63~F;KU5D2|V;%x$iba`Op57 z05NEC+M%KhB^*H#fe2SPS)v6tDB?e+JHb6H(K!ZBs@ZbNEvfDLf)31NdAEP*;e6HPP$g%lx@aDpsz5V7SI zRuTQF$cmK#58bY)sk&auPnTDu6w!Bdd8LXl`md@iw&M>B+%Zjzutz zRhPu!Gq3I0lT{*XzE{@~k_rx@EO7#a9c1Z2=aKL*g&8a(dU#=}HIO*7t7piX=UT5W zRo&V4h%0t@=saM-3A_r;j?$8jAZ*K`q~|W2C26s}Uwu8u65Fe;9GT0Xo^j8vxY(Ct z*W0{)wQ)BtYzb?Cuyf@62a0;QDGy-z1iMwU{_Rjqu(lCv6W2nxEa zkdYa4;k`|&Z735;ejbw}3NA(E0XZ1!|=Qn_ITLlBrc zIa7tYVNP`czx43Ul-7EP-j;hB!>|yBg)mG;UzqOc{zWPPMo$cCds39Z3@?GupA(@M zre}L&z(b^n@yUfSu2(4OkjjWaa!3#u3KK#UQ(~<$W1~O6d;*QQQfTCAL}cZ2?qK?O zAxs`Pb&A{<*w#hPr6LunD2mt@+DSM~)5&Z?BPC7I(9qD>=s%H=#h?LR32D;B_U7tH z4i_%FNc-qj*t23Ckz2+(P9tl2Xt8PcXlRG=zX8gjw1%0vs!eQKY3#0>?j1x^Cvk5$ zY2K#N6q&&YHSG}Robt;n_j>fO(;FFS$~f(?E_a&}DPp-NMa@PMHWiH=8B#=wYL|d1 zIiK&nKqio7JYP*yDXo;&AZGfeY%}F3^27@aH2Q zo++ppK()QfwIn^4`BIiO+@xfC+_j&-CY=zgv?_2fmRXVU#U@AA455#FjS`sZ8bxjk zqfn?@rN<;?*G}sTnPZk4pam*Ga(*;1jNV$p*tI`k2+2zYjSvpuYeeRlXBFFv-HT!O zVwXsfAI(kgU{kEJ3zlDxQVHW3qxq4wc1G)6M;G;sX@GF5Z&9UaC)oP8;i$DADFo;7*Qe(g({JS@lZ39X(t{oQ=wBwdL% zUEfdN)J3Feo?Wm(nA;$r`BUm~^P}&RQY3VX%uLKn3fv#L!GFt|$#2MT91NFJ&_Ok? zn(M9x0H$d)8A3XCa9GyN8$84_)^+fl*TH!@bX+|gzE>U!ajD_iZ*-N1I0sZSCXdN0 zr(DqFL3uS}@}Rs{%2n6wJP~|I^H+*%EaKmiE<&}#-;)FQMbvSj5u?S-qj5o$F7{g#3gE6)<_sX%XhgR4xFflSVFl_;N zMDtV9D#E%PG0+fn%X2=|^VBuGX@1n|BKF=k&N1HcJ$}fN#)HYpG8iE=t$nga>$IG6 zmQv1dA&H$Sr8LX3EUorQoYy|>qb4j2Lm-yV&luuVYJ1wXMN7N1OS^ij)oQg`69lzS z`?OE{TCLU=UHCxy&@L-S074H$Dm|fV`oOZ#!4V!6N*v3p_9*SM-3u$!zAy}3nR{5+ znqEi~c0~^y-J7k}3?CH+T_H)&d-MoH3iPNjlmOu7PuRXhnRZu7t3RP>h-K*AODRC;bV*0Sb0w|^t(}V#@dM+gf zUCJyIHM78cF?&~ONVwvMo+prSI_b;}o9UHv;bq*O%!1;c?14cG22fd0DAaa0yKR{Y z_!>&+!4FGdLFqu}dEkODvLM0>R+1lT045QVqmduBUMK(aT8X_FaiQ>YCBP)c(a6lq zI5WHX(!nDm|F!N~E7-)Q?vuOoS=GrzN|N~Z7RILB+u~PI z{JfB+94c|JDppbU^jIbDRZ+I8C|gyOttuL!rVCX0uE>j2ju>;PJpj|e-HVmeh@vQp z;{EK2Bes+^7_fijKIl?38L_>&THVv?#)wt7!a`C9V;Gh!Ou;o^@;fP=0UjPNrJ$@j=r4zmOJ4B7 z_OjNGV++4rl$80^N=Q@gF1W+zMH5mpjSeMwn{U?t_koTh9`TEELS)BQu$adjMpngW zY~@Y)Cu6Zc$0FBw=Ko6mn>wi~IO*IB2rw;8f zAS~!@C=dA{lq4VY$QmxRLIJQ=%jY!+YC+m71IHUQj-gR&h5fnKq9*M{Nm@uv*?zUU z7KS03+oGiFq9jsGYI}OLp<@4oJp&(X(O2@M*Hj`+RR$W5MT`z>%~2GV5uyQviZW0} zQ+@v;ey7VV1EJ zpk-?>YNA^_DFdmAvZ&9dtXHQjkg~x3JTM<@q!(jRQ^mm~J>LQA2dplH+Qh6Un55@) zj7fTK1(vD;OGVL<*o@d!1urvj5}3e)XT|Ct10*9Oqkr^R-*lDyRq{5qzx*oJ$u}k@ zhTiVKQVr@tZl|4n{ZNwfL8lMeNy)>@QsigSznel0Axss;b?=Ml??jR$6HqKr11f4j z16d=x$2k@3ZmK$_B${#^Piwp7O_`-#_WF31C3G*R{5)%`{0;d`WLFSW=B&!DY{<%^#Cd@MhBRp%y*%eG2jl3&U&((67-Qp@g6?3F zp8o&~p+C1OI);s|Z&P2C^s2AAWot!bODEHpmzSBFJSm8lvk=BCg`v_4i?W(@@0(Zw zLe@MA{)y<3MWTL#W^3FpuOJ7JdtlPNtktTm&wgM1>W>yfn(k-mSFu}bNW`@t)ta8! z?y6QiUOSfZ_tknM1{*DQtirYIWdL6M%c~r4hirDg+<^Qpy12 zQG+V{10hWsq*^sC5HEfb!2P~X0F+88XRu+Slu{M=XX|K_UatY*z)_ROR;%?=;3!vY zS-hBpH02*BvJ9L&ld)z%bJB35g*oTsF?M%FZ_QrW zD|_|VTFb_^+|@ggraa0#GBH9KsmM*3lCwyY-pNIf8I8O~zaJ&-yy=(x5GOr_r|TzO zk1P$|ue+Zn1naodqt?=2gW>6F{H~}er}Q|2)Rdd#9aaDQB&WXEUdAfvJpQ~%vp09z zl~dHDb^6ECul|`1N@<(RGY$_&-hh53IhDGn5)KUrHEBR7&o5dKED2J!oG>3ukVJ}p zdFFtA7myBm(+!>HT8j!A5PHJ}?EzAU#$W|nu%KVQwICD-G_)83=7R~6tZwuJAx$}z z!6EjNo>RPQTF*(ypEu=B17#Rw8T8LiXnc#_wDj-vn1lLr7fp{@YmC9;J}oWhoZm%; z8eF^+FvR#G$P8OdzUUVSG_)9_Uu+61tF>0Dg&I|+2x3yglpgx!IfwpF;)t|%y-9{I z9GU~NEkDvfuY*oP#<4%&G$7ly6(NWqSkW)Pp#{l7WrP=1OiGwyf__^#A%`E7Fj@7> zZD>JA&|^fD8T89#v>+phB8)1o$U$X<7dx0?i;0hv5uxS}Ug7^^DWB|6|I!C>>7^*! z+j^;U`kVqowo++)g7MxT)>=28+b&Nj(Wmr$!J66m-beZ;6=j`v_-S(#W3>Ue?dMln|zpHN|17_CzHe zS<8!_%ngF3w8qs6vV&xq-)YIBCVa6RR8=^2+1d-iZAWTwVUEw5(l;&1Dl8#9v2c3|wOYGc?(Kv|NHCU;>X{Z+G=2dBlw zL;gxUn$?6nG5B8F%|G>=7}(<_7&u$J48IW|2p4G$cqNcSzOmP)gj=KnW5Sno)mbGv zn~OZL=~K&WIES-%=;hbO}h1dhxrULeVFFQuXtMQ%7m>Qz}oNR>mYdWNeSB(iGoYWk=NUzeFyWCz2|G3xxNoAUsr zT(IpbEZp^1L@cd>rN3J!tQ9EZ!;PLd;f^GULsCqh_I1#5ptyY#Q9UD`3MxHb zLxQqxpUeof9K)Pp6yo@19LyGBHCd6;T?Q+MojmaO@``#Oz#}I*5=2e1FG>8XH6Asa z?_GlfRF(n4PDZT3&i6izuSL7x5$f0z+Fw(hy7ZWUNSe{CAq}d}nzq10^*a=|0lTjP zAnpwcKB=%TgAgEOX#f&~iDbYv7a=(h$i0s5p}H))QX`=`7&hMbNfq3@odnFkP32T4 zPs72BqrWYRo~O<}$rRVFD=Wa_P}@<8`yt5wI(!Z}&_pyL)UW*g`8FPaS?KQpx}`pO z>x@(#Qvmq3BVg4N+ekSAidw7%1{2i)MZ3aII$N5cQL_Ap z5aNMqntjM3eUVu9I^)fEmH?iYigV5YT&)z8J#HH&%-~Q!X3Y1$t)YOc1F;0VUSpFf z%n%~Q3JkEy%|q~Ui>ojiD*}t7p;INm8j7CxEeS{0MU#mhoCi8X(xY?i?ojj5K@dIE zE)a2+UjAweUO$weMl2;~PqpPxdCyN-Z!4{_MU5~iE;r+te}8l!z+F8&8{ zz9FHIrbiYTAm@-QQNoVz(LVfWd3zdMFR`@dVfnwa5?CTmpyx! zM@`Sm-ecg*Ruf~5T9@VUWS?=p3alFg^E3smP;@&4wY|kjtB{!3d|y$=SiTW5R@P~? zSE#vn(t)y_jtHVC805^sY>Nzn=iMHYQP>W~OqE_rg@aaIU`b`lq*1gAuQ}Oz|k-0qFnG#^|n&;BgPX& zlQFZP&2$>Z4tBv3P1ubwQ5Uj)GLhO1fSV+BfDvV5^fuO^y*7^?8RMhWGpz&c|wa!2(g5 z4`s(HFD^|w(Om|JcFdxtr{^T%|8x|Wm)B-kEIRW%XwT)-Z0+ghr*^fhidCdTXskap$Ji?jDlyBvyIVD=#2i@AuGsTyp*jaC6_uBwXA#kWWO0vA4t5Z#afTJ zxhm9ZdCX^bw9zymInhg#swZ>$_W8@*dcA&|7!L@$VIGd_MO^eU6iYS4ARq*i{P zp6TQ7iY5JBv&bWuy&v^2<@n8hBblcHD-H8;`(qx@RRn6ejXO+-gZE5Cf@sq(1I{@j z_DO}f{H)#pdC8}lFX8_5!U|4OYllJE#lu1efXm5u7j~9+jBpOtMV9UQYfNnNWp5`k zg75VV5?ZPTOqYV%E)VsBOlPISOr}vyy@6v|&Bl3lSnF(X%O#7?e#$i zYD7@zW&wJ3{GM9bbi1xBS4KVM-OBxUgAv2639bNi zLS#NxrqUzLx;m$^ws;SoBUtffb{7U4GZ+qa8Y3JLil+Za&7{pXbWm@Is_@!IEg^QL zs8~Z~qF%UAqZSmv75x?wS2y8UghzN32sMlfUTY|^l?tIJe^!B7uqAvJAST}hP#5Z* z9OGm7o~=~7?lxIgp(`+?wur9P5U&6gg8wy3bHHzZ#gCx6KyDnEc~gN{FPJusuN6`g z;ot`!9Nq#)a57bj1_c8J8*U~r(^9I4T>xK8cc)ExZ&}ETLfIBx?FPtjAe_=pM>xj7 zQ`!9KfN}5K0R)<1`Plp|GmFbXpi6@aaziVKn&70Fsd7_TU!)0y@)q@$pzyR=x`GyN zrCQD(g$8$F;P0(UL=e@6L78Urh!2*33W-0n@bi2_vrjnMqIDL^&*ZN494jDUCc9u0 z;QLeN8cf}p;nwDsPn?(W00J9%&TJ;bBWMm z^QT9Z(Bnv0e?YD(n%v{?b{_~sDc$wor@PdD$&bHa9g@0aF|wDAU_`G(rD<6rcZ>B7 zG!Z9ZGp$lmbiFE_9SHo5+7HnWrVh(84Ew19r~KlK^!lipGsiDaXRBmmAvN$UTB5jR z?3&K1bkX~Jk_>^7@S5trk&3zp9B`($)d@=+K}W2X`qzm>e&A_H1B`M+7%k8fn1;&6 z!lCsWV!5nG8$t5il7BmRe{IBCW9TNz=Ja-ucc9qw$0#Y1^Rvma6a+>(VryLgBt__` zE*$ZLkh__Neqsgn?kDw4+YO;pT3)f12v!8z>ecz=H!`UgBoA6RC~Me_x!YKuA~MH{ zr6BU!T{m;kX&1B+NJnkPHdWNlHBjh7Iy`RTh>D)?om^PP8F2u?J7F4pi*M&_jh@y!O@eftUkh zJJK{DJnFZ5N+=iC>G04Y+VnTwHy5g?yn)ANd#8;kCpW=RHGXmc-#DdrQrB9YILgmX zBX!&jUvlhAfdVn=lbe_i#u|2G4!1hXBC$+gH6lAA6cd+oV3l!EqJz zTKa$TE0innp|;U_9=57br9MFm0-amK1XNA74L2CFNROI0qX9sIRl*ckgif~!D#B)s zfMXxvL1-bZjmdRfQP&%WXYwJW4|<}>ugZ&WSqH&2IkBhs-dYFdfa1Idj)1H&Nhewt zD*QT;Rq@bh*H0d@vd5XWo(v9L-^3dh5;_iQ$OmG>CNdy1fbXt6i90}g>f=^bE@I)* z5XGB1H`IUdY@=8FU5#}qSM>0nUgz3fR_Rcpn-L#2VDi%x+uX%a5fQ zd!CDdlEhdy(mQWgPZ@ z4up2#kjmq-12G%!Bxr1nVB6ujHBVzG`3O9Qrm7Ba$Nh%?I}V?;}c|S1^vO_1p9YDf?VIdI9obDYk?z zg4G@LT#f=akZcORYlQaml`gP^wP%MmCU%M=JtuLFMJWb8`YHZ7s4wZ;tBU#bwq$97 z>3|I{i+Isjm28S|?9Wpcj3e(X&Xs4u-Wd=N$fuC5x~t!dHvksn6r9J6K$*sP8789f z7O>-zu%Qt1-^1-h#q>kc{&77DUJn#{^TN?Kq7#(r(>E7Y|Gv^A(Uop!d* zYbk>oWR_>_<+G+2!P^9WF99nhClv32N;nB^6@PhXXR!O%D|709>u`^TCn@UK+Bd)x zHp2;Bk>{yh&yrtronzY6F;`;i@33LQRpegp@c+rO_fivk?Q^cG?DS3LTHy?P-nAaj z%{$@*`ly40R=t-N-L(h>cozuBUMdEX2WcyFZ}EE$bN>GoEv2B{<|yZqA9q{W7~wtb zE8CKgmdH5MiGKqW9l_!R@YGz>% z4kib{nHY_2P!liZ42p(LY{it8`Nle!ttmNUj_mjSx)9AJAS(&W0$-N)JyQ6w!-(&1 zcY*72^ zTcBp_eqYd^0ApR#2iG7C)cZ$4!p}sl>+l#sb{Jd7L78DPIhbf`w0K`WYeKx*E@KtH zi6;Tof*Y6V`@y9CI_{`wpIzF4gdSLawid_u!9iys_Wj34a2pg?|??8bdQtrT>i za#Tkk;(BTOc)`Xh^h$5U=}EbZARJ z@`ohEyLL4L-eoFiMNDO9Yc?$GlHxGcb?su=7Q#XvrLr)_5aL}dfU>He{Np)n2li;O z(Qg~K)w!wTFjjD5QdU2t3=-~+`Gsyo4*8_e zwMfYY(ELa@!fOr+l}?~385*1}pNOGqUeK#js!lB%B7kfS5zMFVUF<#^> zi=V_}lkP+)4hmS*6;slV0QS4fN74^jKay6D=_>o zQ)z5JTWI!MtOsR8V&#Q^I_fsRLIzHx$_fmhfX~hVixG9+F$}ktwZzyRL*I*epHsl@ z7)cdSskeWGqWhdVtgYtoDuqQ|NV`Eaaw+GjB+%&&JO))~uH_MII#v$8QML>@&XqI1 zmI{P>bqvCQS7k)=C$v((TWm+PKJ0oI6&C*0L7Mns`@{Z+(~mV<6w=e##CMrs7SkT} zGzxVB2c#@WY~iVs4a@Us?RsX4g(u8bM3XPoO;>8ovbZe>vwl0q_`0P)ZO4#3Ux!9g z`jMxO^+-743&7iUi~vEItlSkQK|H&QCh-bE9!h|#Dra<_jGr59Hqn>@=4@e+ej z9{g6upZx?a6iI>QlObcyYCawoJq7m4;5jc+E*$v zWC_cl*5A&1y`%xMH&_K%_ z%8vNh<}+qqx5Up!d2T^pIQk4m$_&>gm2@1(x^WL%MQ=YYJ+C6Hv{xE$K&hdyDGr#W z{Fc~-s%24K*(ky48kLRTI#`Y$;;&cP#s5^)(D#AAg$nX#Ap`WO1W}0uKr70y!9ICK zHIXDwU$laGHf$#=A_`6!%9h@YQ*ns|k{`KF3zD~`!&Q4sBA8?$87Wmo_n#@jv6^9=}z zHDi#RHJ16*s7=`a1DA4s7xdPvWkP}GPCfQs7x|1$oHSqE#bbjs^M{c}`YyKR$vRRKZexzu=4J`in8J#mz6vW_S%*R2gRUKLvgLs@)gjPQawP+ z*c*yqT8N4ofI6U4UUW7bC)p@Ti(w1`hp-wn-!%s<6yIYX`2q#k^ob(R-bMjMSQPAN5*AIetwltb%>Lj;WY6N zjn&@9tA}}#vymBTOgB<+mDeL{Q0#o`a{PF7-i*}@Z1I2Q8kT}p6?7EYV@Z>OD}v!7 zSh~4=djFlNem_4?-~`X?;53r|vH{RMI-RyN$JtTQx_y?Gisk@(^^r~r!y_oIXo2T? z0~eF6{C%6|;EbkDH=P5?1Afu?x9UuF5mX{rt(#3})QJ%q{*}VGM#>v2JFbyR?k-QB z_G!g_bUCRYo282lUHAI3eZnNCYP3s*y(CXMO2~fOrt2|^o}JwWP~MREgtvhzLE#c= z8X{C?kG>H3p{!fTyBv(r%K?Zl2ls+G*b`mA^1gqyWSB!BYJ?~e3mztN|23u1hTP>m zITwP5oyGia3#%R$Q4p=)PkbmJD`()Ny-_+rpitMf^~a)f?7$?%NGgX;f>5aT&LIs0 z*X0MuK~o%I^B}|cHoV)B5EFSvqleV{i!aC7*TBKVm6ocLYy%yH>zqQcOOkB^DV@ws zW{$^h6HnQFdL=VV`HDnU*=$09>w^;hRfN=hRMFo8A?+L3e9VtJ8}Va}lefcS!aCH3?rc z@W6XJ5|ex3d>JDMOv*+cBDdrrHr}y!f0YaWC-l97ZNL{a&vx9!1(rWBMo+sslckz_&cr|YMUOjzP^eGUxemHl?Rwv*s`68jeg1}#NHdZ-K!@4MYVkFqsw31FgsRr_ zGh3zn;cVx-8B`Y9?m+e)n^Rk9SSOr3#U|PXpC#XS5?cA4nQTXefD3 zh)-bfKAof!T7AAIA$0yCG|JuyAe4R2TWvg7}h}wE*nG!D2>wRdOn928A>U$xTQ6`1gn_t0< z{*53YKrfIJ66PB{=MQd$F_29fxtS|RdJl>ezH$*B*m6cd&@GDWsBhq4@4`=pRGFT+ zehgRKteF54-#xg}E1_r4FTxI9yRa3N{2kCdtVrmGFBJ$2iU|{X&$>@QsBj2x%4z@M zusR|SlfR-35ZF)#SUAY*wG;T)iHL))tcn5y+WcMv@y<*`Z+1rj5k?jcK>jEwdKBeTj2YH| zv8tr!lM?u!GRoYObLy}K7JfBif4Zcvx!7d@;&&mh0&$Y7K&M~RE;h1MbwsCaH8G3f zHg>BcwUsiYmJ(yBG5{9G?~vNUL`#NMbJ(G6iXkn|MQ9Wp2x6Em0M%e9KUs|npGpLH z%M3lB;LKE{1yAMoYvIEIpIOV&^gR~fn_Qy(Y-`z`AkzODLQ#D4>C}$;PNu|Qs1mJV z4@vLbCyCXV(mR@6V>YWTh!j#~Qy3uh;U7e^uL(D-DTen@+N;@xRGFi@t#+866C)Pr zZ1#HGaGD2}fFY_0Yp^^Fs90~7-8|D-^4U)+`Ba~TW2ndKi) z#49uf7WnPN8!U3|$w6Y_^f%d_Dj+ogjWE#_q;F3@Xu!xjxd448^LYaLdhgGQRZ210 zg2aNBqY!1yu`hQiZJmUtv;?7Cap>tNvdPJcbsYXk|5=Lz-Aa1!?*!=thAXvO_+_TA zCim#BW*tAVugv@~e&7e~dDl-`*oe&T|%HXFa`lMYFI3<%a;eY})PBwqD zhpHtk>xc4azSO}Lt{JAwow7M!4Y@6vd@}41VswRpY5G5RZi-gRlUJwNvE;%7=y4B#t z?tueAPW@$|`e2e-Ta9-E9w{}r1q8YxMg+S1A31LnkfI+35;fzMa4!x zPV)(JiBPPIV~)ARQKxjS2?iR^mB}BEtLf9)E6V-}x1jTuK6;bO@gW*;r93>uJ z@1F-)zJ*q*-h?UId|eYK`b4UFbV^&oDKk5Hm%yGib_#m0L{Wq1bIKh}{&kl~gHy~#Q5fD_g0Gm`N*ekg~+dfJ2L zG~=V9m`Q6jpxE;{N9JahpFO@WlnvDTP=;$H7WzI+8G_jL!STeN3ceb<^@CTA0`A5E z`Lb!qtc)01%ky1b5GPI&9+gQ;K;{6$7PufR|I}Is$=ac=VVAzm2^fFDXZ$^kQ_Q*?L^`@GqMRA8M(Vhi(~#INqEp2C2iQI< z-tPng!0}N*O{9pJQCwnJvun1 zVxQ@8fz*gTc+)z0@S=r&f&*USKiO@3f>(jEENi^V0>AMI^s^{~pKZ+|Du6oSz;6w9 zX5eM_>}u1N{ws=$)2rAUi4?xd%`9{~R(OnLGyWWu#w)r}89QO^B;b6k>~wD=TZcwv z=G1*7S*B=IdA4Ci4;jcni>%+MSB#RRB*&GwsYOxFT>;y$(3;S0mx1RCE+R? zEat^d!kU&(8PXbNz=+8!>a1&cok-|#pC6r+gb>4?px4ZYwnZUy( z%MaYSy*+|-7Fw3NhD`oJODVb(~=SZB;#%d76dOOy%T8I5GEOs%U*yAPC6nUp_38&v@Cr z3T{5)&iog+@FAf-cscTz+@~@{jv=S~)qK>9S_O{q#^1EX#w1$tT?UHza_3ZSwlWwpwA7r}dd59?d&HQsbN!#fHesOk; zPoUmN@OO*fu!J_;%K)R~0ESX+oRqz-v?0Mb#n-hZQEA^!YE#y>mw&l|17qG&e*#9u zO8JF<@!*6dL?P=B5ZP{iT%JZqYuHvsD$`NA`s8yt)w!BS{|i{I{ws{D9qBYG19KRa zX`HJeSX2sJ3JBnRkOm3~BB}>>RyOBmu%9+;FZPLnBN5cnmWw@K1JCA&0;Mh@cM+Zg z<@v2q5|LwHi1^=0bSXnEgvNcvwR{g?$+)Pd8~8-(VNx20N61c&q&4s?GRaq zBjoG3b-1V(euOS35FZl^H>kY7TeWM+OZJtglco?kkk!|-47Qg9vGgB{*&bRo&jt!@ zDuo)7sB*`yQOYEO+*au++VM+}q{!+Ad(mRj^_CB#c~ld?nE{?*_DG)}g+G<^4NtPA z68!`ycVwxZVj6M;qUWLVtP+1IPKontyuux#)>^7;B>^;tUJjkw^*qP$nvg`SeO;|G zBt4~TKC+kpg6zFuYT~#~}X6Op7D5@#}SR-x7R8dgO$WlF1IW><`^PtnTY|h(mhu$AL4z zkE8s#K^Y^zXPR9C>e(M`0b~~3Dgpgos>a(1CIcOR3Fxcaphjh}#hD%%1Ki{bY(TE+ z0NzG`yg8eC6h#PTIn_R0LH^?HAmj@C9k4lR+6x4;mVQ|Q19#6XdJ-+^tkcUz(9OeA z)PJ2%O;}-N@k&@6K9s{{CXf(5HiEO$`}h<+QABx(r-v+B=aRbx1gPtLmHRJMZ7vt| z;(1`%nDHe5eita&Gk2%pp3q}e%lC^Vw-@QOAUPHK&KqVx^^~~Tnju9#D&AQ zX?r?aO8jitkXcRoKuk6h?VMM`{)K;#6V)62<*MjTll z0KdkJlZ8juRRvbYfEvFzDKZ$|jb2?fm>=?YBSk3JL2fe25A?PJz;y0#Gi#XxCierR zy~}bxg6s&lz6tp;=2_&#!tPYv0jQ8%YmWvPZYPxtN7eM-oaGNdtBxPlSQoIM3P;`S z_AelLo^bgO^RyEe)Su}iuA@D+J$r8|u#oC`PHL3=76W1|EFvx)0H{D$zhc&K8XUzS z`&5_~&!gCHYv!;tsGTFq7BxE$Vhh5Gh8atVMg;!g10BM=1^_K@GeIn>w!SWE6)>lzC4q>B)@Bb_;fbFWC|aPC95tWr8Ad3dPzI z5&QtM6Z_KpJCHUJBz@we8Ne|mT3fyL7jMO1+yo%!ZHSNJgWrGx@c`o_E~r@{-w=t1 zG@;Vk(HCy*q?Q$=f5f?vzQPkF9B2*jK_E@P!rFwxM2wokcu)7N;e3tOT!l0`LgvQ? z=R5bo9$wDtvH8!Ci6$h2Z}d|ZpFP9TGpxU&4op1iEoIw-9HL$H0U{57XDg1N@JD{z zNb!PaG(@*N_H&Nf4D1Vf)g=d}Ki?M0GH`@W9T~hKRJ6LeW4G|~`+&1<0V=%wl9j7? z^s@(UjYulwsd>iWu@vc0O18rxE}@63f;_2n`s&vt1u293`Gq`2ln5!1P37I4V7*K6 z7kGxXSYr-*Jv#Q0`+&ICj|FEdFuht;0vy;XLroHE|a42*{=s5qTIn6_M}N{5S5a>b#%z(}EZ`z&O!5x;u97 ztoZ(^sazSJ{L*sVcdP2rg;Vox#Wz6ip6w(#h0V~3UUVfhbxqnCg*=d`Innt8$yIi3 zL)AFIDWc)y5n={79U7GYjYx&lYaW{#DE^4JxS!I1xlMVSYJYPekb)oK1Opb7F$A<| zw>KL`3Ai>ljf)61smFo{-Ytpk3V>qb*R{XN3`_F-!Pq?m0|2C>#En9y5*1{Jsq%)E z)Q5tt&O$OZN>{RjcW?$qB`|4q4xUwJ1ySRZKyDKG>RU(~1!jaJsk#}}?zFU;2hvMm zc?0Sh-S~>kZ7C}B-Z;eO8cyxgr9N+O?AMD!Q24;IkZg_8Etoy{$Qq5l!*rj6``d*^ z24lZResuzS0s(F?^{wgsMy}^rfq=VZd_%MG`Kof-O(d&?0u~;)Z1(6lonk%uaDZ%9 zW!DQP^sh@7m1gPJHxF~TNGTBkurSl@;(wJ=*a)o1@ejrUn*^Pm=_@u;JR+$FKeZwgSG^K^)h33(QdL_(Ur+ z9orSw=Qd2SqB+bR!48A&Ni-R@Oc(>H8! zZ!}+GE1PQoXFT)0D?>+gRMcWSj=6?m64`c~3qMMBRdna1{Q`OD&j{GeG0+ymO|n}) zat2D3Uu;J~ZH2W*qUo%jE0$cAIx&2)%Ub;mR#>rCW7%mn^2r$_Q5axaK@+eLcu;$oM5nl{oQQweZ=%UMf(H7^` zj8T^1r%Ycj0Hfhk>4iZ}YGu|MJ<~m-x2hqq`_|;#dvZXX1TPXlX4nt&?i`Wd(5p=W zyM9$4EdXm4&iZX;B-jT9T~!M+EmH@lO1f5wi%sz$VGLpES__WpJHn0}*jpsd;)3sr zRY`%BI2(yp7|RC7a^S=5UDEQ`i?>=9cvKdK_k;d2$f4jiCY~$7JP71Z)q0phveVZb zcsvpL&K33tC}CfR zX%yVr&0ou$8aDZ${k!`KwZKY0%M%_gBef5N-}l*};agb9We~lBXLSeiANhN8QUtWT zWlhaYU;iZxis z6B_t6m3Aa0J~d&Lyn70rR3}kxF;fz#mr~fDh^#0I&O>sfFeI8-+2nXG?@@3DuYGd4 z3{9vP{#zxYQui4`=tKqlXC;&<&#RzJ9T>^H&R%T1e=ufEzH^U+LRCZlqm8GF^h!tl zp=#Wx2SQilgK%FLRco>3zq5$P@&CPS|**e*k=oh_U_V8~uZg zGn-e`r5Y(tC{U&p1(c&j2(*Go=tsiU8_Y7UyFoky2XP{elsbxtvj%1tb>or+%IHA_l zzOWHA@-(0pj+U+qm>(`)R?^XuaF4;Pi>zDooVhON3x@tsy$oyohw#?KY;P8Oi_jbqXCVfg>{M3aykPZ)byth1 zgF)pUVnaY}+Y4PpgTOhFDF4)k25pkN1!n){u5SOGl=Wk|dwSdL*iv42=YV)DcM*vO z9Nxyt9y(VF3&bF+RA;qP z$eF63z+{EmgcHTY_!DVxodw!V!zx3P-6YE|mph39u#qx;PJ~emdAd%+V^0fp7!*Z+ zdMWS=<|5&jBS5n5p;JieAS4A@MEFO0od*qzHTj-nyh$rGVK35&hdWJq@n@c0!pnR zJXGG4ow>@)<(>Ew6doz^XsO+ZrJI^zEfC$S`0VUK&fCnDU75hud7+idAwl-=wNv@h zv{T)XAYD!TOM?feS;Fbt+O7PC>lCTZY=Yx|gc_xoVlRwl7)=l~ao;{o17uGTA#$G9 z17*CLfHv7a^wN=D1R4=SYjcL6naKfg1S1JnV<*`^c&1wyeb>q^ZgrDq7tBHWw7L9K zvIhu5LLdPdCGoVI+Ni+86s5RTHx_X*_?pn)-lt7CO(j)01Fhqa23B=EC|d2o#hxS$ zW>=`N9(tUtEd813)J(j(?$_8q$gAV<&qKljva`iRE)h5Ev}8ke`09I%Dx2Z$>$~t@ zlTDJ>#aCZG0J~As!D#0(sH4DpOGd8W^I>|WDvT8;i7(#aq86=Ufu0L;`QA&f9ZTuPLgT3|z06$r@Yzfr}+sqwLG z)`p_-pod*Af!5@;F{|p$)8>~@=W%M}9;f1;{SCF>Iks=HLaJv6IW&4lZ|xQ*x}*A~ zfFA&bM3pwR%HAn}5mT&vzUHoM<_L(+U(Tdti2*`*I_2INxzUGQKur+>0zCopt<*nd zO?BI`Hu5iLvt(C&(~4YSW`bT&5YsW|p~<}7Eay-aoriv6miZLJg|ebq?r+$aw1ce* z-n2Ky6}NPCdXnRMiBHp}Rg-OrUn%=JdQT@MM`J4JgE|qmOZNq(tvb#730`OCV>u%? zXZe*kJrT;7ZkRhXm*d9Uh(gnIl%n;>uBLC7(^njl!j9cr9SamsggC~=95`V z%-b6^;=sPXD&nkVdf{+xzbo{kC&JHbX_ugD` zEnRlO*BIiZEBh9c0Jw8?gm*JGVKu?nlF1ZFHPFTIXgyA6FsmMxFF1T;TwfJci=P?W z&2Gz(iHNbyMZR~SC;r*gH-1>zG;HM(a{nHL@}N8F_$wj`YK`RxdfW}jU=RKvn_X412eL7P=s4`krV6s6$wu*6-pLe6G?^=l<2pn@4afbDQZyV` zTr%(#%G`LV#7H6nd&7I2s$|s4Qk5*CMpZIWM^m!C@$I811g=R#m}j@qQyOxKLn&J8 zKudsI1hdIl<#6jfaIyFZ-PVSI`1zZ{TD@in#XKb%(L;l+g0U(l7t=@_jx%6Ud{p%0 z>l`yI?am_#t#)-W%mlM?`O7P^uR>Ii8c0y&2o=(G$0faJ10Idh`a@$8iN5#!+94j7 zdFV4HC~`x(TaA**DVFlcKApZMu2l}JjAGm5BzG_f6Qz_FFnOQPdK4NjFX*t5J=Td$ z62>{i`v=XJ@LM45+!&462~>^4RbU;ZZV+{k^bQc--rbleh;bi1;#@1sz6qBeAn$t+ zSAtqOH_!)>`;2r)w_=b`resJMIt}7zSL_J0q&P$5uiKwx7TgU}g!;DAi9y1STIRPS zx7Ef~&>}rlrx!pPY&Q@HsYu=>4_Ia+Q)yb8=l%tlg3^ig*1S+oK3^@pv9@YjwOMBE zZ&xti;3L9I)wmtU7h}iSg`eZwY!`GLAGg#vB93pzVRF=$S$3T$3^8zR`jr`t3pWAd zyRgAuD2wWd-bJZ3fnFJdGi{`je~XV(p#ELxf#sM=;E~RN3`bvph3Xd3m$&YV+uP~Z z&7yzC()oAhW&1$#)^#nKi{?Ynkpc66A7Eg8fG)@rBPFk#x)=$+Au#vMD({>XxS-(j zxXw7}l9!jAx938;opo#);UFypJk(sc2{JJQFHvI1hoPu*lx4-v4x%R)0koBv*IR3)7Jl;f%NA18eMh3VmosnfYS_A7#@F8X@@@wFpUdf}a;yi$}d)l|VoB*xkAi0Aln@d>k;T`d?Jt7r!5mi?}t*zYU;B=73?nI*tL zs6fRX&z8>UMZe9d&1R$b-WY+9Rp{GnI-^wKpGIqUBOlKe&bu*K1lI z1*JXM1Xev$YKWVx(WAFc=5%cuca^*eOKp^C3`ySf4~$e;1_aX=FRRS$7{%0~m2XAM zq)O^RcG3#479{Ofa7?CA+ryLNoJB?*OfKT`ymF!7ORUO!UsQe&8+IS*x&R><4xJ^-SV}Gsoy$ITBx{vctbD1O!y1c6uz1w-*`)MOPxxdman_yNGCfQA6#< zn+Y$S{L5RUeeAyKkg^c|Eqfx2tOzWfp6=krn1nR8ck2Gl`*LHnYTjmNTpxm8+OsJV zQS2U`L^2*HnR`p=wl*U(KFR^1X03o~M;q=xrJ7~q#L5*#JuTe6D0=5c0l%2~+&vYZ z2l$@h0+{fzZz6*JN^*cni?+Pp4(fVP_62R|=#~7bl9fCV3G0ylm~KEB>X!Lv>9m!0lKMrM{f)!#At6TafpCL8QNyO(*nIxM8uQskAK6D5S!T0;e3G9hMZL;m2Mca>2%q*t*1_R0+AFa1JU89BuR z10=2@(D4dlGF1e*aFW-0bsHh9`c08vU6NXP2I7Kn+ohtjaa zFZ_}iq#qCPva|;!%F7*>$8gfRn6)bje8;sw2&DzmrVCe8Cde!*%sMkSX0%0&a7%8# z1V1n8WJDl%4(~ukVH11}uhU*edZOFMXTMGqipc+t>1BZ9>=%f|k#V3sUSR+=#TE9!c`ut+v7VDN z&oLXddHXQ0m+^i5_=zT3#R)GEs#U~2SrpGIP>jgcgLI5+k~BO%8^X&r>5%5%Mc`dR zg#Ys_;3L}^97M$MBNtZ zr97g}INQMr8GlFxv{js&(@VHog`2%>Gb`6_Q}ynJF_Z^BiG=`?^3>aFHz9re=a0n> zs|m|+pk9E0mAxo|Pw(sMRTq$jKd{9=eQ&G;^T;sz1oe_TPoIs*BopT)@E%|A-CBsz zwX4T>ARIr#!**LXkvONgC9h4hrT_p5PH z7oRKzgYA_mTb`PVJqcUP6V@fXFsem9VehBBlQNn#LYwDGB~2>F2{_0X^hlag)rV=bms9OTJY&gh{(-@w4M`K=OQP9rH!>rX zTro=ju@GnTUByd)y~ea9gEv*d@mX486LhSX`(weO^1^+tX$9jyNazMST|{}v6K1St ztu@FZ<0UOSvLwVDvlOBs`wgnu{a^v;e;Av~a(M(C__SK^a+;u#;A&RaZXGU)!=@PR zm%RyhPsYy@x0`-71&oIH`nW%^RhENnNEIfVs4jL9GKWuRaRxBPZZ3>cJ`q4^U<|5J zR@~tl+0F)BpnVSra~LnwWPjsV^KqWI;25p{%$j*KA>zLD9k9CNh2F^F5Jf!-YVdvhRwmQORCt79@XEbLW}dQ!W$~(Bq!a z$gbKM0nIa_W)W6$<6J?xN2x?eV|aI@@sO9MvkA}KD6yeEO;alXtDq0=Cn`A`OY7ko zg!qL81%$`gXaV1aK5$>#3GQE5F>6i@KyU~vkWmvZ>Ck!}ozM4Id@&nFU7~k;R)jIl zV_wb6f+dnM^~(qzS}BAc%^&VH)j%tCBU@OT#R$vMHUpw)qB|fyE{KAXKsBbot6LsV zQMvSIvpU_3^al|yp}B(IEy5o+&Ka$i@|dco=vmXic<-NB>Mr40S4TtU}rWg@-hQ= zGg8j6Tg+VRXNI_Sc^*mT;aUn9S!U;kp>UKWjQXPBh~MNEwdTQY)E%fInJ5kg^AAEP zbiI;F@72~tU+wMaP*R7X8v2s68Qt>T=Tt|p7k>D`*O55pa2Ias03x~oYlUqrPo=oE zP&Qw;YM1*cwp5Gmn~uY(*qRuvPzo6xclqxdb|3zl#h{0T6d%;qic*}1q`;uo&GCRJ{d7l0d8)+BBR>MzDfo|j8mCzhdIL7zk5$z=Yi7en|A)qs^tFmrp@SoDed8+g>u_%o_J^RgmgKM zPiIkiDuL`f3x!uIO-MW=&+845*%FrtY$jQp&O)qbsP#lVC8Gy+B5*g%S!k?Vc=5&J zTy!wWmo|%?>bpd&9){|BCFM&t=Hjt*ZY18cOqD2)2<`jV)=XYKJ1agp2D0e&`bN-V z@YFR^d4Zy26f(J4d@vqODPE?G=#Tvc36H7-gcd^ZYqZ#*mfM2=6?WanRFayc#M#P= zj>UBrSNxF1kT=7%Lkl~(VQ{|V6?7@8%1NQOl&K66EJ-sHCy`GXs=q=vlY(cvSvLQ3 zKFsuY5QR}XDcPv1{-8OGGH(Tr7~}SeMO2~?9pgsMvJi8?a){}eb+g3F%5E)Fg;YBB z3TI)uD_*T3oaKsfzooL6V#cC@eBCVFGL;2`qfAVeo3PJJG7r8Toa0L(l0%kLH%o?? z2@G4vLV)yM@xAO^rf`;`RVXW6ViDae&8crA)aX1dk6?;Y8|l<48gegepj2fsw9wg> z$P`u*7p=z#3#&eCuw=ixH4~U@Gyf9CmBy12_Tm6PuA8Mjq=au~ zfZe?V{e%El3ly^i#x~ARla)+_S#^~t(++2o)*H;yn9D`wuOgNN z4V-*j>P_V$W3$m~CF`u{boun(^Q>_}&I}LjPHJ>OAg!iJo#k1P^`Cj>=IE$*Ux<(Fh0JyzP0am1a6-vfQfesf z^k#S2EUvB)#o#Pw2}~S1;J2t0h@Glex`F|fTl-UM@`*q8{ogp=aIb(ux_&Tz=H#Nj z<%|qW3GlbTXV@^E7$W&N+D;(hK&;2|P#Q53HLj(r=}$IP3oFye3AFS0JqVx!VP64~ z8am157L>V=Iha%Ej|Fs6bpH_f`+IwAxGTT+RdY3k^~_;-)!ax|jg!6#F(OLdM@d#RknIc~Rzi7B7?qbtX-%{`}f< zMd(I%HowDJV~^jPk25&LDgqzmX0SJ}b;JXEI2_8Y8rE$Hr$LSGW~BHEe#)fe7+{7i zkP=A?K#|aw>M_LmAr@qpmG(i9Qr&|QY?qyF#_Q%52$MXoCqfvfNpAU#)vs0KcYp~P zt|YbYM7bktffv}W9%X^t zLxAp@>-Y;0u>cR;e=Wd0aELigjm+d|=Y3Udt32d;(D}P1yDLwz-;pm-A~%05#)PbrCEA?wof?Y$OnXQAOLnVU zp&m4d`|MCAbO1$i3P1>nYRqs7HzZu4_)K^n9eUbd&OSt`*xk3MHB<{sreCtLKD^!22AH5^bmNJ#9$qLR*w`} z2;~jkcg|ll7DI?>Fkhpl4-hRKLbHYlJ?dPEIn&|y6&GbG2PMOaknx-16`=xf5Z|oZ zG2_SYf4eLde#NdV8XN)O&CZWYm;7`9;`IUgn>Tb@ZE5U6cr>`1Wxn%U9yh&1w6AvJ zz>XFdd5Fv6b`FSU-mXK2&Md1>eW6W;F5-HP8Z%-(!n$3Z6`{3(5URvR0Q=4%ZB2-= zyga15;wDHIu2F?R9qV{)O4*5q7$%5sU0C*lfk=}d1c<@V_}2)+H{JoeMx}U-SXiZ? z0XE9wOumNx>&ajvl0v%4@*#E{Z-aX@-Ub^TILsBOJwX5IagK1U(sdAUHCp&`aGJt| z-p%?8Mx}XG#9+VpmcIoqKRrp4W~TP=TDS6to~{|GN-hilJK5RuW{vM7Y1)bs!2g*O zcjsdgud9q(JNK7%Kb#QCkv3Aggc2pt&1Hj^lgp61nZ4Dyr5uKwWi!bhmzlSZSDqk){eYBmd#oQ3LLdnAsKLgqOuEg=^dDH6R2`WQuE3`5ruqjHTg zHCQTD0>mc+D);qfTQJxasRQ}5mrJno6BDY>dTZsdkk>M4=Q?|HvxsfCu~73dvrHpr zQ4aD1jUPML&%96=z%h@4{OJEBzGc6bz*td15V|yyV01U+?-l)t$hAbu5+bFPQl=yW z?*)Sfga+$rp5s{>LPM&DG)|YeFJS&95fHPK1cf%QPsXJqG^!TQROl9I}$(^%=M%r z*I9jX{bmB|*V<6zS|56<%Ku)-6;)Tc)>_*pS6Zy!NNSQ?Ij>zmMy~U#%u)5>%N(32 z9aO>v@J6j4qcO!8V=1LX(y|J&ZoQVl8rAE7w=fJYrTE^y>DayZ-uw67d+*Am;f zd+&XE@4ffld;i{h?|qr5%7FxIhyne*+}{u4snOqWntNf~?%sQ^=;Hf#<&rL?^u|js zz4zXGFYI1QDWxz>ojaCaF{!AisHmu@ybdcXD=W{kva+&5DfQf`JW1tOR9040VD9d{ z_eYZAdmq-glS)W?bl;@quWvl{OZ3Qgh^Ocjnf|2FpF4E+Wcu_52s3AWqXk+0 z)HNx^A=4ocMd_rmAk+UY?E#|b!#QghDl!GpA+rW;&?@p=BEym`qBH$@1q9I>GL4}z z^uOr`@f3}xJ{_6n$n+_tQ!=Fq5Yg#HIG@f*%XG(2b0^d1K?J4WH?E4d`IJTsJ(B61 zlLlw%92z|~jl3y6hfGAcR<2UaeQcu9;S_V~!VGU*fbwt;dB;wq=Ly5%XFuIXk`sX^!ez1$m{J`^%z5L4%zlbUciD!#mQ3uG`y zRFUCZPqF-O@E*tr%C;*(Q}&m(E8z=z2Z2H{UM`~gRh{+N1$+T;abpD4aPNVWS<2Y` z4N>yr=gu*@lrz5U&eFy#-<0FeNQtc&;|qX`F2*V6H$j<`rVfxGW+F^LpCv;)gKV|B z3^APn>cl{tsc3mU*mHLGlhW--vhJ3w?d+|^E?y~gpUf_=j1Rw>J;1|+C3ys%yGo?< zhuw9RNF9{!>#}!tD7_GP_5h^)oO9ONQ+WBEl>c=M)9XANbLegtvUfDq$ll%EJ)4TI zyQMcViY6C!GIZ!Qa+@Ge4Z6ruLRP1uvkCCi^+zea}7-Nhvc5_ZzO_$R69bSSER*y=PowGB^8r*FZG&+3D56%Rn6u-IXrP?FH z^)Vst;e}oTL4T1u$)!59iYm@KIm*AqJy34Rq#mXDEq?mxA&@1I=cDFAqg2C3RE552 zwlI?WOQlfslZ3KsY&FPjPk3nE+r-hkQU zkuC_wRooLFSrkMVLjEoc^okJ{BkcOTd{j#4ba*W=XpBQ>l>ZTw0D8p$fLb|7xB#MY z6<6d2)QX^14V2&9d>3|o0;5)zdFmUzWR8LypkT)5L=_5Lo`xsNi6|aYu;&LPIg(T6b@$wjQ8XfWB_CxCjSBP|k6kEU(q!>#K(h(dM zj}#ldT(0;=FP8ToMSyKK1G#i0PYwDkw}DZ_|}P9Cr^n+ zFe@X?NHfwBPl+Cmj5KK`5{XDgMBWHCf(eiqUS^= zQ4v>B5q(rKeWD^FPgF!j^qxiDCnT$QqMH?yJp!T}2s+3i&&r?;lISMpstFrF{zy34 zLp0Qcd}u*bhz1{Ar_ca0>Bop2YAd;OC=^>!)$%SMUslKFMAVS(Bh6e!+ZlyMFdanb zzR{6<#7{$HGz`gsD41y&LIik%`5Uc_U@e}t;nR^~DoG+8@l@!C@ChlQ1Kp?Ow~H;( z4;8xm_dlzXuSfccsu64i8^QdJjEs)_M3qHC`mv;+>_4%47=hqiHL=)r-7`SuZUl>} zB(faK-@S^{(^IV$fM4oJ9KhmsW z?)%#vw5orQuvsPAE@5S|sA}m%-e+g60_i%lh#FVK6LTQUfl4P&)k<3yZEA{sVi-gs zk?Ta2&7ozPj;zImL;T{4m>k^i%;Sd{F1E$a@GOqISlN>7FT)}lj74XHomdYmh%FNc zi3x-Q%JEYSAQvaPN=L97ocJ(>4_SupwvmA{4!Umy8^JskN758qI)u>4Tx{J5mOyg^ z3-Z@GrBz%t6>y0SiPK!N|H)HR6=_DWNE2zTR;%T51fn1glD+^eiN-N-^#|QghCMvk z^30!=*&K&GJ?u1<0Rm9fqH=la@fdQ7G^|Vrh=Muj0TLQIbf0aQ*y;}T_y$>KOFhLt2Q_CMP*bKeMNWg!?$LbE+SBba@%!xs6oNI0J! z9){%4_U!PJKf9Ctvp)7`1oPAvTO%W$;#82M&zCa31hssr#T$)|WFNu&WMw0m%H>rp z@8XeS@g}NTJkkvMM9;JAMqEW29TDBQmBlO$DV8mg>_17fo|lpQwN8spRK-@yQL-6Z zv#5$RUPEi)Tf|fF%~PKgSsYKrx1e|d+Ym0ABE$?h0S`@z7I|bOyG&+tEE1c9rG)_^ z4QdEko+Eu42G*zZEA?uKKYx01CL{+hq=xwN>GW!dFTIw0=}B5d^|!1AT|bZ@?K&-2 zzxw;eV{P+Wjt(u;W{!Y0Cia@ClstOLQ zC%`}BAuN(aj56eL5_59n#3n-?Cp7u%GHlX?H?cK=VuCzI zqL4$hmO42@o+dcCn;2nb) z={21@mL>V|)dB>Hbnqi)0FB(g#4NwWxDKcZImVZ!n7r^ae2$v>r-^2|P!oWdHbGa# zoHF2Zd!QP$5kJNc?Koq8ivP_bu^fLEnJ}M5JQb4tumliG3|S%vB~z3@QPQJii4q+p zG9@u3H%fe%O_@QNNin0%a-_Yk5~=IDQb)QSN!HzxwVl2H1SdqHySs&OuH8*ey7ngB zCnJ-ti{RP`JW`nY2VdifDvD(PYs9|ljn8OoO zj2&AH!Wd&b!Xk`+;N*=PiOFC$@nwV+x#=62dyHCZt+iHKWYXqNt(DeVYpr$ChCmgB zwbokeyaG;JeVJ10@J&POthIU#@YGN8)OQ#D{1}0d?(VkM0Wrsy7txd%kw!>6^njy+ zxT^`-E$E|-6H(Gcm^2Y5Sjhc##@7;mR`;7NdLH)>a-f|hp(IE+oFli3P#goj zi8^A8zQntIXcwMN{s*DdjApZrltrnpKmySz*fq%hvwKFf-7toMM-dRp4YY29te@;n zMfR^n9IC*g06XYl%;ztfOa!3R0imcdDMdV>b)UaJQu>uj?n|=tWPmohUH*cQ<>mHr zs0A;$*%lY&nwBa|NRfy2NJnHpu+6^M4W0^u%ljOF+$m0iigDfw5AsFaf z)n=p-j2n>X#A-P*BeU5oXEdA5azyruDJzSWT?^G@ zqRMx?$DibM4lM_=bc~fBZ0gfj$;{_S*IyK}Y+AP>?OFJ#+SvuI*>?Qov}^NI7SM(k zG*7q{vVZI$a)bPJt!uOISO(H$ zN+}C6fBsUv#NeKWWOr;9W2H_3j;q?{s;;#yNosau>llsAdWcYwKS+~_(_cFLV3VU~ z5#l_Vkl&pin}Y~j$4KKnM54%F&t`HqWu>uZ;Zu5uJV8UYP?Ui_-Y!~=%WExH3{?mp zV&H@-5d{eyWcnNcu8t*iOq?J^5;FaWV`w266)|n_&KKZu=0n*MW|T7Ie%y z=wrn#AApL^MpUhHD(Jtj)nxqCTnR)TOca`#C^XbG#gfdy#@|eonmpfAnR+u(X#528mv=J64VbZF zO6M6XrsSC@E=p&j)c6VJnJ6y~woM0lezM4%-iu7XbEs($%Ql$NJD_ly-&JY_?M znS;%O4)Xjw$q>T;A&eO-W}>wG1he!`ewwjjil1P%Rli=aw2(8UKfS>4PTfl6VQX*K zoobX=PB`mHgaTRdIjMyCrT}zZS4DSXI&67$3A$9Eb%3 zO{*K8+I6Cm^JbLLeJ2@uoGjNhxiCd^Ul&as33J>`4j34P(}_E=U@sBXus<8Jj2UnY z_ae>{QUl0c&;lmO3+;AO(*e>qvzH~c+YYS8%lLJ{_FmwQXk*ALMHH)M37pZoK`t3u z|A?rsl;I0Z{I3AgL%|#V1jr{<$(C|hq5InPL0XD?@9#F1WFm~uhU^1limYb{BSYBa z&-M)Qk{swLL}A2F{_c~V{MnvZliY7T&=ZsO#A1@hQPRC`WgT?#+cW|{$(NBYVFb~A z)^>}lvsUVY%(CZI^WnIqHj?G(C4b%OoGic6`9tFH$xr5-Cmn8Kk}TyrYNDuVmMo1) z6SXF28S*rtlVKA`WR(ngnuy)Z(#j4cbnz%62cBT)C=wN+gYjIvI+W;OJm)fsOme#C zkoRdI*BofW@0Hx>7$&P@khp5nJfsjL9!}aikPbd@$L2;F6iSKx7<^4xLo=O6$ zM74U63l7l8>U9Zv~{ZkarOh%piZsz^D2D1VG0DP|%aiBmepG9obJ zX*>mHJPnTmF8`j0#pGfdwM<)xaDr-(AT!7fZY3F{jm|<3IcyE1f|avm5MioNEeK@g z6S@!5TGrOd;=zd?@fw@z6J0MG104_y53A5jG!j9UeA_*XPvrh7q~I`-`}=v4Kqp90 zKyCsY;Ks3VaC1b#=A}rL-U~W-3lU5fT~qrt(;2})5$hix?;_Fl`tj+atYFMeDl9Bc zD==5ANURsEbXZ`dF!hZQYLo>l#DEz>NeBSA!KwwA8W}mN5FZBlsERU9X!LD7om_I% zVvMI5IY!w>kQE02X^=)krU?|?2WixT-eD{?4UHKtEizgFKq&?bETk2c_ptyFSW#BJ zV`i>;R{lD(Sc0gA5PFU-VyzvF6=+)lffB||0j7z5{r?ibI=!rPR;v{gt5;DedrB}j zP#Sml)k^^m@c*t~-R`52{XNdQZsp|x7=T4tP`VG+f(ViB?lm|Nr9M`xAgsE-?*6d_ zh-;tdzHY%!bD}k(RwOX{*+R=)tpOShdA9S?UYSCJ>77i*K z4KZhA4HLZ#z$kVgBSVGmiO(cEJ!g(665#WMW~&KknE4h$xWjd1GMP+vl67#W`&!oX zBfVB@N5jM~88O)<+1iG(&XFxU(!Ef-Kh@ZjJdZ6Wyzq|>MI$7Oho%u?(?WU~B(+SK7M*gt-GtE8WE&v1nCH|R z8V4XiQqb9(U9IY>N%!@wZ?;PU<@h30Yu`jLPgvRDc#UuIRT3hoq!Q+f?t<#yl{J~% zh%dp}K?Bk4cDwbhZ~7J`kXHBg?Z%CKeq;obLkF`17%ZEY&DXb8Wy&~Z)N#XBqRL@FqRLy{-M1HXAG9?PTV4HVwe34ekFS!y z*lNHQzFOJU6`lXLip|9f&8_Xx0LX-|R(8dL&cC$7$5iub0txhZH zr`W58@MOEvTL4f%ufGolV8|*5Pxrxy!hMJ&mKah> zm@Z_gROWps&I(TN39=KfCvLbH|sHzFjI)D>2#L5OS@m_ z98H`~9PDlu5i!PCSx9WH=A#K+?bqvc>b!=>vZC{;A7hLm9UUE=T5BfyK+)*vIOIg1 z4f&ys{!#AWeDF-ELsrx>YYo7u{#AgmO+Fxh>C@H89Bf$uxj44dWgax&Lz; zSOPGnX&gwDnLjh3jSh)TrHGPJK4;?WX`-rNJsXr4{cKXj!%ruhc6c7caI1Mi@O4Msj62o~j zwN|g>r)uMLE5yj;DS20#Z&fjAA&5B;s3gR_m@5jCH)WH)8o?r|7P=63t{h(P& zDS@PDAQA;U!5pW6H(;hfW;=EOjm}U0rWR=iPGZg>;APfqHg~HKbEQ}*f(;XCm4q<>wd}K%($fF=fVH{+P zA;tgz03ZMW0EWyA&8(mR7PuoOe|zwiepv=Kydnk@>EJwbM&<~^XdpNLQ$QSxIFT8} z33FgKZ;*A{6T$}yUK<#izSXfF1hwSW0S&iFa|0Md31$(K7g`dfz|mqX8ZY5hsL2Ls|arXl}4qOZH3 zhW;PxOPx6ZVnDHB?IctAl&?a6)5Z4Q$DyOfj=1t;-9QbU*UcNZJdC!=<~mJkT1kuO)S7U4J<9d17J~s{xBkDVS&co6Cjj&*?Hg} zR-FNxR9bdZA6qxh&||VdGZ;L2Vw{1}*kAO6!ZEQwWd-Re4w88s&>3=L$=P7g2l zI+1>|zfNP3=+(-n|e?2q{{7}YM$aQQ7Z;s=4!=oq8MiCRA@kW#Le;xKK zT5#oSpgXvh`i7PycRU*how#@A$PkqmZ;n_s*Q7>|M7+FsI%wrrROxU9o8=%~c*={i5kL`D;`d9$?gn8)z^2VT!Rw4r)o1q>i#4JDT@BZo> zr$?W1)~bA@=*378_szYQ&e9cFUjIvea++QK<(#Fo==3!}@@*g55C8V0h>rhpva`{p z#-hnd9fm%26q=~!SUo9kg$9&4taoHF4f`o3grZ(OXJRGPzr+4T#e0sz!jz0@A(g~; zk-YCT{R8FWZ%ffVIf4Ga`AOfg6ROAQSkP)9_5%3VOPf;dL4!*csX5?mLu2vV*iX|} zTgw~N*r_zT9LJS_flA5L!8>p_-MFd4H_aaKM!?|ojWd9smgYA0v@;RiD#CtW25k_3 zZcIBeh5MZ09i&QS{^mX0K$N_6n6gJliN=TN9z`3_CAN@I(^eIPSbCHknjc=xXVq(z zfR*l4%V2=zM#Xt~u!NH`H7T**jSUw!M_KL={o#t_#QL=cv)5{1vKRj_XI(eP`&|is zM7xC?hLk4cmkE7z*}XIeT1~KYWs_6m2Q-yR^`hjW3wwBIA|llbImRVlB|5kqqHLj$i}eRAqZ}XZ6r2tdAj-;E zF_D4`XP``M=OOTxQt(DRrnl=l zL1OK`0eQe{etzZ=ufEG)z}gdzBvwD;7DKj&8M#<)FRtij;?4hex2f)CXcQtuaq*

    Cou&ta8#STHb2vJ_9%|NVM^=%-i==-V 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

    6sV2UFUw-Sf=r*<8 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

  • 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%0DT}m>EO5S} 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 z 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