From 86b6f0c1d862134456945dd003c9facbeb3965a4 Mon Sep 17 00:00:00 2001 From: Shamil Gadelshin Date: Tue, 24 Feb 2026 19:15:57 +0300 Subject: [PATCH 01/43] Revert "Update base call filter" This reverts commit 138e8924195640f4916d83534b79313cbc1a3be6. --- runtime/src/base_call_filter.rs | 96 --------------------------------- runtime/src/lib.rs | 50 +++++++++++++++-- 2 files changed, 45 insertions(+), 101 deletions(-) delete mode 100644 runtime/src/base_call_filter.rs diff --git a/runtime/src/base_call_filter.rs b/runtime/src/base_call_filter.rs deleted file mode 100644 index 8d76c422c1..0000000000 --- a/runtime/src/base_call_filter.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::RuntimeCall; -use crate::Vec; -use crate::pallet_proxy; -use crate::pallet_utility; -use frame_support::traits::Contains; -use sp_std::boxed::Box; -use sp_std::vec; -pub struct NoNestingCallFilter; - -impl Contains for NoNestingCallFilter { - fn contains(call: &RuntimeCall) -> bool { - let calls = match call { - RuntimeCall::Utility(inner) => { - let calls = match inner { - pallet_utility::Call::force_batch { calls } => calls, - pallet_utility::Call::batch { calls } => calls, - pallet_utility::Call::batch_all { calls } => calls, - _ => return true, - }; - - calls - .iter() - .map(|call| Box::new(call.clone())) - .collect::>() - } - RuntimeCall::Proxy(inner) => { - let call = match inner { - pallet_proxy::Call::proxy { call, .. } => call, - pallet_proxy::Call::proxy_announced { call, .. } => call, - _ => return true, - }; - - vec![call.clone()] - } - RuntimeCall::Multisig(inner) => { - let call = match inner { - pallet_multisig::Call::as_multi { call, .. } => call, - pallet_multisig::Call::as_multi_threshold_1 { call, .. } => call, - _ => return true, - }; - - vec![call.clone()] - } - RuntimeCall::Crowdloan(inner) => { - let call = match inner { - pallet_crowdloan::Call::create { - call: Some(call), .. - } => call, - _ => return true, - }; - - vec![call.clone()] - } - RuntimeCall::Scheduler(inner) => { - let call = match inner { - pallet_scheduler::Call::schedule { call, .. } => call, - pallet_scheduler::Call::schedule_after { call, .. } => call, - pallet_scheduler::Call::schedule_named { call, .. } => call, - pallet_scheduler::Call::schedule_named_after { call, .. } => call, - _ => return true, - }; - - vec![call.clone()] - } - _ => return true, - }; - - !calls.iter().any(|call| { - matches!(&**call, RuntimeCall::Utility(inner) if matches!(inner, pallet_utility::Call::force_batch { .. } | pallet_utility::Call::batch_all { .. } | pallet_utility::Call::batch { .. })) || - matches!(&**call, RuntimeCall::Proxy(inner) if matches!(inner, pallet_proxy::Call::proxy { .. } | pallet_proxy::Call::proxy_announced { .. })) || - matches!(&**call, RuntimeCall::Multisig(inner) if matches!(inner, pallet_multisig::Call::as_multi { .. } | pallet_multisig::Call::as_multi_threshold_1 { .. })) || - matches!(&**call, RuntimeCall::Crowdloan(inner) if matches!(inner, pallet_crowdloan::Call::create { .. } )) || - matches!(&**call, RuntimeCall::Scheduler(inner) if matches!(inner, pallet_scheduler::Call::schedule {..} | pallet_scheduler::Call::schedule_after { .. } | pallet_scheduler::Call::schedule_named {.. } | pallet_scheduler::Call::schedule_named_after { .. } )) || - matches!(&**call, RuntimeCall::Sudo(inner) if matches!(inner, pallet_sudo::Call::sudo {..} | pallet_sudo::Call::sudo_as { .. } | pallet_sudo::Call::sudo_unchecked_weight { .. } )) - }) - } -} - -pub struct SafeModeWhitelistedCalls; -impl Contains for SafeModeWhitelistedCalls { - fn contains(call: &RuntimeCall) -> bool { - matches!( - call, - RuntimeCall::Sudo(_) - | RuntimeCall::Multisig(_) - | RuntimeCall::System(_) - | RuntimeCall::SafeMode(_) - | RuntimeCall::Timestamp(_) - | RuntimeCall::SubtensorModule( - pallet_subtensor::Call::set_weights { .. } - | pallet_subtensor::Call::serve_axon { .. } - ) - | RuntimeCall::Commitments(pallet_commitments::Call::set_commitment { .. }) - ) - } -} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 460a84e049..2c6729067d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -10,7 +10,6 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use core::num::NonZeroU64; -mod base_call_filter; pub mod check_nonce; mod migrations; pub mod sudo_wrapper; @@ -78,9 +77,6 @@ use subtensor_runtime_common::{AlphaCurrency, AuthorshipInfo, TaoCurrency, time: use subtensor_swap_interface::{Order, SwapHandler}; // A few exports that help ease life for downstream crates. -use crate::base_call_filter::NoNestingCallFilter; -use crate::base_call_filter::SafeModeWhitelistedCalls; -use core::marker::PhantomData; pub use frame_support::{ StorageValue, construct_runtime, parameter_types, traits::{ @@ -100,12 +96,15 @@ pub use pallet_balances::Call as BalancesCall; use pallet_commitments::GetCommitments; pub use pallet_timestamp::Call as TimestampCall; use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier}; -use scale_info::TypeInfo; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; use subtensor_transaction_fee::{SubtensorTxFeeHandler, TransactionFeeHandler}; +use core::marker::PhantomData; + +use scale_info::TypeInfo; + // Frontier use fp_rpc::TransactionStatus; use pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction}; @@ -278,6 +277,28 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +pub struct NoNestingCallFilter; + +impl Contains for NoNestingCallFilter { + fn contains(call: &RuntimeCall) -> bool { + match call { + RuntimeCall::Utility(inner) => { + let calls = match inner { + pallet_utility::Call::force_batch { calls } => calls, + pallet_utility::Call::batch { calls } => calls, + pallet_utility::Call::batch_all { calls } => calls, + _ => &Vec::new(), + }; + + !calls.iter().any(|call| { + matches!(call, RuntimeCall::Utility(inner) if matches!(inner, pallet_utility::Call::force_batch { .. } | pallet_utility::Call::batch_all { .. } | pallet_utility::Call::batch { .. })) + }) + } + _ => true, + } + } +} + // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { @@ -411,6 +432,25 @@ parameter_types! { pub const DisallowPermissionlessRelease: Option = None; } +pub struct SafeModeWhitelistedCalls; +impl Contains for SafeModeWhitelistedCalls { + fn contains(call: &RuntimeCall) -> bool { + matches!( + call, + RuntimeCall::Sudo(_) + | RuntimeCall::Multisig(_) + | RuntimeCall::System(_) + | RuntimeCall::SafeMode(_) + | RuntimeCall::Timestamp(_) + | RuntimeCall::SubtensorModule( + pallet_subtensor::Call::set_weights { .. } + | pallet_subtensor::Call::serve_axon { .. } + ) + | RuntimeCall::Commitments(pallet_commitments::Call::set_commitment { .. }) + ) + } +} + impl pallet_safe_mode::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; From 7d5626d9757124d699472ba8878eaa0615e19ca0 Mon Sep 17 00:00:00 2001 From: Shamil Gadelshin Date: Tue, 24 Feb 2026 19:47:40 +0300 Subject: [PATCH 02/43] Bump spec version. --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2c6729067d..453472a6a7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -242,7 +242,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 380, + spec_version: 381, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 9e17b0e6a5c01222e715d314712b0d1431c5925c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 24 Feb 2026 16:49:28 -0500 Subject: [PATCH 03/43] cargo fmt --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 919468c1ef..4e5dbc8376 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -241,7 +241,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 377, + spec_version: 378, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 818647f63f3f3ce026ec6828e5d6166361337851 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 24 Feb 2026 17:03:19 -0500 Subject: [PATCH 04/43] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4e5dbc8376..5a7b5119ff 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -241,7 +241,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 378, + spec_version: 381, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From e9cda43135a79f40e1426aa33fc55f24bf14c13a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 24 Feb 2026 17:03:19 -0500 Subject: [PATCH 05/43] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4e5dbc8376..5a7b5119ff 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -241,7 +241,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 378, + spec_version: 381, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 996b98dfefe138bc065d0eba6146d0db87015b47 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 25 Feb 2026 11:37:48 -0500 Subject: [PATCH 06/43] Revert "Merge pull request #2290 from opentensor/feat/balancer_swap" This reverts commit 30cccbb550d9b0d6642a46f39b6ae1623bcf9ac3, reversing changes made to a5ec868422fd5af6da27d9551c931fc068c42a83. --- Cargo.lock | 232 +- Cargo.toml | 1 - chain-extensions/src/lib.rs | 4 +- chain-extensions/src/mock.rs | 2 + chain-extensions/src/tests.rs | 4 +- pallets/admin-utils/src/tests/mock.rs | 2 + pallets/subtensor/src/benchmarks.rs | 68 +- .../subtensor/src/coinbase/block_emission.rs | 84 +- pallets/subtensor/src/coinbase/root.rs | 2 + .../subtensor/src/coinbase/run_coinbase.rs | 12 +- pallets/subtensor/src/lib.rs | 14 +- pallets/subtensor/src/macros/dispatches.rs | 70 +- .../src/migrations/migrate_cleanup_swap_v3.rs | 70 - pallets/subtensor/src/migrations/mod.rs | 1 - pallets/subtensor/src/rpc_info/subnet_info.rs | 3 +- pallets/subtensor/src/staking/helpers.rs | 20 +- pallets/subtensor/src/staking/move_stake.rs | 15 +- pallets/subtensor/src/staking/remove_stake.rs | 5 +- pallets/subtensor/src/staking/stake_utils.rs | 60 +- pallets/subtensor/src/subnets/subnet.rs | 2 + pallets/subtensor/src/tests/claim_root.rs | 48 +- pallets/subtensor/src/tests/coinbase.rs | 142 +- pallets/subtensor/src/tests/migration.rs | 54 +- pallets/subtensor/src/tests/mock.rs | 2 + pallets/subtensor/src/tests/move_stake.rs | 5 +- pallets/subtensor/src/tests/networks.rs | 481 ++- pallets/subtensor/src/tests/staking.rs | 342 +- pallets/subtensor/src/tests/subnet.rs | 57 + pallets/swap-interface/src/lib.rs | 11 +- pallets/swap-interface/src/order.rs | 10 +- pallets/swap/Cargo.toml | 5 - pallets/swap/rpc/src/lib.rs | 16 +- pallets/swap/runtime-api/Cargo.toml | 2 - pallets/swap/runtime-api/src/lib.rs | 14 +- pallets/swap/src/benchmarking.rs | 130 +- pallets/swap/src/lib.rs | 6 + pallets/swap/src/mock.rs | 74 +- pallets/swap/src/pallet/balancer.rs | 1095 ------ pallets/swap/src/pallet/hooks.rs | 30 - pallets/swap/src/pallet/impls.rs | 1019 ++++- .../migrations/migrate_swapv3_to_balancer.rs | 81 - pallets/swap/src/pallet/migrations/mod.rs | 25 - pallets/swap/src/pallet/mod.rs | 558 ++- pallets/swap/src/pallet/swap_step.rs | 523 ++- pallets/swap/src/pallet/tests.rs | 3315 +++++++++++++---- pallets/swap/src/position.rs | 198 + pallets/swap/src/tick.rs | 2198 +++++++++++ pallets/swap/src/weights.rs | 56 + pallets/transaction-fee/src/lib.rs | 10 +- pallets/transaction-fee/src/tests/mock.rs | 2 + pallets/transaction-fee/src/tests/mod.rs | 7 +- precompiles/src/alpha.rs | 10 +- runtime/Cargo.toml | 2 - runtime/src/lib.rs | 34 +- 54 files changed, 8151 insertions(+), 3082 deletions(-) delete mode 100644 pallets/subtensor/src/migrations/migrate_cleanup_swap_v3.rs delete mode 100644 pallets/swap/src/pallet/balancer.rs delete mode 100644 pallets/swap/src/pallet/hooks.rs delete mode 100644 pallets/swap/src/pallet/migrations/migrate_swapv3_to_balancer.rs delete mode 100644 pallets/swap/src/pallet/migrations/mod.rs create mode 100644 pallets/swap/src/position.rs create mode 100644 pallets/swap/src/tick.rs diff --git a/Cargo.lock b/Cargo.lock index 71fe31e5f4..a2fe04437c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,17 +71,6 @@ dependencies = [ "subtle 2.6.1", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.12" @@ -508,7 +497,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ - "ahash 0.8.12", + "ahash", "ark-ff 0.5.0", "ark-poly 0.5.0", "ark-serialize 0.5.0", @@ -743,7 +732,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ - "ahash 0.8.12", + "ahash", "ark-ff 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", @@ -1680,29 +1669,6 @@ dependencies = [ "piper", ] -[[package]] -name = "borsh" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" -dependencies = [ - "borsh-derive", - "cfg_aliases 0.2.1", -] - -[[package]] -name = "borsh-derive" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" -dependencies = [ - "once_cell", - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "bounded-collections" version = "0.1.9" @@ -1989,28 +1955,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bytemuck" version = "1.24.0" @@ -5759,9 +5703,6 @@ 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" @@ -5769,7 +5710,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.12", + "ahash", ] [[package]] @@ -5778,7 +5719,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.12", + "ahash", "allocator-api2", "serde", ] @@ -8435,7 +8376,6 @@ dependencies = [ "polkadot-runtime-common", "precompile-utils", "rand_chacha 0.3.1", - "safe-math", "scale-info", "serde_json", "sha2 0.10.9", @@ -8654,7 +8594,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.106", @@ -10913,9 +10853,6 @@ dependencies = [ "log", "pallet-subtensor-swap-runtime-api", "parity-scale-codec", - "rand 0.8.5", - "rayon", - "safe-bigmath", "safe-math", "scale-info", "serde", @@ -10952,7 +10889,6 @@ dependencies = [ "frame-support", "parity-scale-codec", "scale-info", - "serde", "sp-api", "sp-std", "subtensor-macros", @@ -13557,26 +13493,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "quanta" version = "0.12.6" @@ -13685,29 +13601,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "quoth" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d9da82a5dc3ff2fb2eee43d2b434fb197a9bf6a2a243850505b61584f888d2" -dependencies = [ - "quoth-macros", - "regex", - "rust_decimal", - "safe-string", -] - -[[package]] -name = "quoth-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58547202bec9896e773db7ef04b4d47c444f9c97bc4386f36e55718c347db440" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "r-efi" version = "5.3.0" @@ -13986,15 +13879,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - [[package]] name = "resolv-conf" version = "0.7.5" @@ -14049,35 +13933,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rlp" version = "0.5.2" @@ -14313,22 +14168,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" -[[package]] -name = "rust_decimal" -version = "1.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" -dependencies = [ - "arrayvec 0.7.6", - "borsh", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", -] - [[package]] name = "rustc-demangle" version = "0.1.26" @@ -14584,17 +14423,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "safe-bigmath" -version = "0.3.0" -source = "git+https://github.com/sam0x17/safe-bigmath#1da0a09c5bcf143fa7c464b431bfaeff5476b080" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", - "quoth", -] - [[package]] name = "safe-math" version = "0.1.0" @@ -14614,12 +14442,6 @@ dependencies = [ "rustc_version 0.2.3", ] -[[package]] -name = "safe-string" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fc51f1e562058dee569383bfdb5a58752bfeb7fa7f0823f5c07c4c45381b5a" - [[package]] name = "safe_arch" version = "0.7.4" @@ -15041,7 +14863,7 @@ name = "sc-consensus-grandpa" version = "0.36.0" source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" dependencies = [ - "ahash 0.8.12", + "ahash", "array-bytes 6.2.3", "async-trait", "dyn-clone", @@ -15344,7 +15166,7 @@ name = "sc-network-gossip" version = "0.51.0" source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" dependencies = [ - "ahash 0.8.12", + "ahash", "futures", "futures-timer", "log", @@ -16057,7 +15879,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" dependencies = [ - "ahash 0.8.12", + "ahash", "cfg-if", "hashbrown 0.13.2", ] @@ -16121,12 +15943,6 @@ dependencies = [ "sha2 0.10.9", ] -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "sec1" version = "0.7.3" @@ -16558,32 +16374,6 @@ dependencies = [ "wide", ] -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "similar" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" -dependencies = [ - "bstr", - "unicode-segmentation", -] - -[[package]] -name = "similar-asserts" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b441962c817e33508847a22bd82f03a30cff43642dc2fae8b050566121eb9a" -dependencies = [ - "console", - "similar", -] - [[package]] name = "simple-dns" version = "0.9.3" @@ -17664,7 +17454,7 @@ name = "sp-trie" version = "40.0.0" source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" dependencies = [ - "ahash 0.8.12", + "ahash", "foldhash 0.1.5", "hash-db", "hashbrown 0.15.5", @@ -18312,7 +18102,7 @@ dependencies = [ name = "subtensor-macros" version = "0.1.0" dependencies = [ - "ahash 0.8.12", + "ahash", "proc-macro2", "quote", "syn 2.0.106", @@ -19907,7 +19697,7 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c128c039340ffd50d4195c3f8ce31aac357f06804cfc494c8b9508d4b30dca4" dependencies = [ - "ahash 0.8.12", + "ahash", "hashbrown 0.14.5", "string-interner", ] diff --git a/Cargo.toml b/Cargo.toml index d1784b025b..efc22431fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,6 @@ pallet-subtensor-swap-runtime-api = { path = "pallets/swap/runtime-api", default pallet-subtensor-swap-rpc = { path = "pallets/swap/rpc", default-features = false } procedural-fork = { path = "support/procedural-fork", default-features = false } safe-math = { path = "primitives/safe-math", default-features = false } -safe-bigmath = { package = "safe-bigmath", default-features = false, git = "https://github.com/sam0x17/safe-bigmath" } share-pool = { path = "primitives/share-pool", default-features = false } subtensor-macros = { path = "support/macros", default-features = false } subtensor-custom-rpc = { default-features = false, path = "pallets/subtensor/rpc" } diff --git a/chain-extensions/src/lib.rs b/chain-extensions/src/lib.rs index 2e2eb807fa..eaaee70d27 100644 --- a/chain-extensions/src/lib.rs +++ b/chain-extensions/src/lib.rs @@ -18,7 +18,7 @@ use pallet_subtensor_proxy as pallet_proxy; use pallet_subtensor_proxy::WeightInfo; use sp_runtime::{DispatchError, Weight, traits::StaticLookup}; use sp_std::marker::PhantomData; -use substrate_fixed::types::U64F64; +use substrate_fixed::types::U96F32; use subtensor_runtime_common::{AlphaCurrency, NetUid, ProxyType, TaoCurrency}; use subtensor_swap_interface::SwapHandler; @@ -520,7 +520,7 @@ where netuid.into(), ); - let price = current_alpha_price.saturating_mul(U64F64::from_num(1_000_000_000)); + let price = current_alpha_price.saturating_mul(U96F32::from_num(1_000_000_000)); let price: u64 = price.saturating_to_num(); let encoded_result = price.encode(); diff --git a/chain-extensions/src/mock.rs b/chain-extensions/src/mock.rs index a1e6334b1b..45c7811adb 100644 --- a/chain-extensions/src/mock.rs +++ b/chain-extensions/src/mock.rs @@ -426,6 +426,7 @@ impl pallet_subtensor::Config for Test { parameter_types! { pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap"); pub const SwapMaxFeeRate: u16 = 10000; // 15.26% + pub const SwapMaxPositions: u32 = 100; pub const SwapMinimumLiquidity: u64 = 1_000; pub const SwapMinimumReserve: NonZeroU64 = NonZeroU64::new(100).unwrap(); } @@ -437,6 +438,7 @@ impl pallet_subtensor_swap::Config for Test { type TaoReserve = TaoCurrencyReserve; type AlphaReserve = AlphaCurrencyReserve; type MaxFeeRate = SwapMaxFeeRate; + type MaxPositions = SwapMaxPositions; type MinimumLiquidity = SwapMinimumLiquidity; type MinimumReserve = SwapMinimumReserve; type WeightInfo = (); diff --git a/chain-extensions/src/tests.rs b/chain-extensions/src/tests.rs index f3abfa2c91..bd6f46c8ab 100644 --- a/chain-extensions/src/tests.rs +++ b/chain-extensions/src/tests.rs @@ -10,7 +10,7 @@ use pallet_subtensor::DefaultMinStake; use sp_core::Get; use sp_core::U256; use sp_runtime::DispatchError; -use substrate_fixed::types::U64F64; +use substrate_fixed::types::U96F32; use subtensor_runtime_common::{AlphaCurrency, Currency as CurrencyTrait, NetUid, TaoCurrency}; use subtensor_swap_interface::SwapHandler; @@ -985,7 +985,7 @@ fn get_alpha_price_returns_encoded_price() { as SwapHandler>::current_alpha_price( netuid.into(), ); - let expected_price_scaled = expected_price.saturating_mul(U64F64::from_num(1_000_000_000)); + let expected_price_scaled = expected_price.saturating_mul(U96F32::from_num(1_000_000_000)); let expected_price_u64: u64 = expected_price_scaled.saturating_to_num(); let mut env = MockEnv::new(FunctionId::GetAlphaPriceV1, caller, netuid.encode()); diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 19d2e891cd..2d51ecf105 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -331,6 +331,7 @@ impl pallet_balances::Config for Test { parameter_types! { pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap"); pub const SwapMaxFeeRate: u16 = 10000; // 15.26% + pub const SwapMaxPositions: u32 = 100; pub const SwapMinimumLiquidity: u64 = 1_000; pub const SwapMinimumReserve: NonZeroU64 = NonZeroU64::new(1_000_000).unwrap(); } @@ -342,6 +343,7 @@ impl pallet_subtensor_swap::Config for Test { type TaoReserve = pallet_subtensor::TaoCurrencyReserve; type AlphaReserve = pallet_subtensor::AlphaCurrencyReserve; type MaxFeeRate = SwapMaxFeeRate; + type MaxPositions = SwapMaxPositions; type MinimumLiquidity = SwapMinimumLiquidity; type MinimumReserve = SwapMinimumReserve; type WeightInfo = (); diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index a43a468bef..b370b6dbe1 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -16,9 +16,7 @@ use sp_runtime::{ }; use sp_std::collections::btree_set::BTreeSet; use sp_std::vec; -use substrate_fixed::types::U64F64; use subtensor_runtime_common::{AlphaCurrency, NetUid, TaoCurrency}; -use subtensor_swap_interface::SwapHandler; #[benchmarks( where @@ -68,8 +66,6 @@ mod pallet_benchmarks { Subtensor::::set_max_registrations_per_block(netuid, 4096); Subtensor::::set_target_registrations_per_interval(netuid, 4096); Subtensor::::set_commit_reveal_weights_enabled(netuid, false); - SubnetTAO::::insert(netuid, TaoCurrency::from(1_000_000_000_000_u64)); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1_000_000_000_000_000_u64)); let mut seed: u32 = 1; let mut dests = Vec::new(); @@ -733,12 +729,13 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - let initial_balance = 900_000_000_000; - Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), initial_balance); + let amount = 900_000_000_000; + let limit = TaoCurrency::from(6_000_000_000); + let amount_to_be_staked = TaoCurrency::from(44_000_000_000); + Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount); - // Price = 0.01 - let tao_reserve = TaoCurrency::from(1_000_000_000_000); - let alpha_in = AlphaCurrency::from(100_000_000_000_000); + let tao_reserve = TaoCurrency::from(150_000_000_000); + let alpha_in = AlphaCurrency::from(100_000_000_000); SubnetTAO::::insert(netuid, tao_reserve); SubnetAlphaIn::::insert(netuid, alpha_in); @@ -748,23 +745,14 @@ mod pallet_benchmarks { hotkey.clone() )); - // Read current price and set limit price 0.1% higher, which is certainly getting hit - // by swapping 100 TAO - let current_price = T::SwapInterface::current_alpha_price(netuid); - let limit = current_price - .saturating_mul(U64F64::saturating_from_num(1_001_000_000)) - .saturating_to_num::(); - let amount_to_be_staked = TaoCurrency::from(100_000_000_000); - - // Allow partial (worst case) #[extrinsic_call] _( RawOrigin::Signed(coldkey.clone()), hotkey, netuid, amount_to_be_staked, - limit.into(), - true, + limit, + false, ); } @@ -841,9 +829,9 @@ mod pallet_benchmarks { let hotkey: T::AccountId = account("Alice", 0, seed); Subtensor::::set_burn(netuid, 1.into()); - // Price = 0.01 - let tao_reserve = TaoCurrency::from(1_000_000_000_000); - let alpha_in = AlphaCurrency::from(100_000_000_000_000); + let limit = TaoCurrency::from(1_000_000_000); + let tao_reserve = TaoCurrency::from(150_000_000_000); + let alpha_in = AlphaCurrency::from(100_000_000_000); SubnetTAO::::insert(netuid, tao_reserve); SubnetAlphaIn::::insert(netuid, alpha_in); @@ -866,13 +854,7 @@ mod pallet_benchmarks { u64_staked_amt.into() )); - // Read current price and set limit price 0.01% lower, which is certainly getting hit - // by swapping 100 Alpha - let current_price = T::SwapInterface::current_alpha_price(netuid); - let limit = current_price - .saturating_mul(U64F64::saturating_from_num(999_900_000)) - .saturating_to_num::(); - let amount_unstaked = AlphaCurrency::from(100_000_000_000); + let amount_unstaked = AlphaCurrency::from(30_000_000_000); // Remove stake limit for benchmark StakingOperationRateLimiter::::remove((hotkey.clone(), coldkey.clone(), netuid)); @@ -883,8 +865,8 @@ mod pallet_benchmarks { hotkey.clone(), netuid, amount_unstaked, - limit.into(), - true, + limit, + false, ); } @@ -1338,9 +1320,8 @@ mod pallet_benchmarks { let hotkey: T::AccountId = account("Alice", 0, seed); Subtensor::::set_burn(netuid, 1.into()); - // Price = 0.01 - SubnetTAO::::insert(netuid, TaoCurrency::from(1_000_000_000_000)); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(100_000_000_000_000)); + SubnetTAO::::insert(netuid, TaoCurrency::from(150_000_000_000)); + SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(100_000_000_000)); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 1000000u32.into()); @@ -1387,8 +1368,9 @@ mod pallet_benchmarks { let hotkey: T::AccountId = account("Alice", 0, seed); Subtensor::::set_burn(netuid, 1.into()); - let tao_reserve = TaoCurrency::from(1_000_000_000_000); - let alpha_in = AlphaCurrency::from(100_000_000_000_000); + let limit = TaoCurrency::from(1_000_000_000); + let tao_reserve = TaoCurrency::from(150_000_000_000); + let alpha_in = AlphaCurrency::from(100_000_000_000); SubnetTAO::::insert(netuid, tao_reserve); SubnetAlphaIn::::insert(netuid, alpha_in); @@ -1401,13 +1383,7 @@ mod pallet_benchmarks { hotkey.clone() )); - // Read current price and set limit price 50% lower, which is not getting hit - // by swapping 1 TAO - let current_price = T::SwapInterface::current_alpha_price(netuid); - let limit = current_price - .saturating_mul(U64F64::saturating_from_num(500_000_000)) - .saturating_to_num::(); - let u64_staked_amt = 1_000_000_000; + let u64_staked_amt = 100_000_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), u64_staked_amt); assert_ok!(Subtensor::::add_stake( @@ -1424,7 +1400,7 @@ mod pallet_benchmarks { RawOrigin::Signed(coldkey.clone()), hotkey.clone(), netuid, - Some(limit.into()), + Some(limit), ); } @@ -1754,7 +1730,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1000.into()); + Subtensor::::set_burn(netuid, 1.into()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); diff --git a/pallets/subtensor/src/coinbase/block_emission.rs b/pallets/subtensor/src/coinbase/block_emission.rs index c499fe3117..3aefef927f 100644 --- a/pallets/subtensor/src/coinbase/block_emission.rs +++ b/pallets/subtensor/src/coinbase/block_emission.rs @@ -1,90 +1,10 @@ use super::*; use frame_support::traits::Get; use safe_math::*; -use substrate_fixed::{ - transcendental::log2, - types::{I96F32, U64F64}, -}; -use subtensor_runtime_common::{NetUid, TaoCurrency}; -use subtensor_swap_interface::SwapHandler; +use substrate_fixed::{transcendental::log2, types::I96F32}; +use subtensor_runtime_common::TaoCurrency; impl Pallet { - /// Calculates the dynamic TAO emission for a given subnet. - /// - /// This function determines the three terms tao_in, alpha_in, alpha_out - /// which are consecutively, 1) the amount of tao injected into the pool - /// 2) the amount of alpha injected into the pool, and 3) the amount of alpha - /// left to be distributed towards miners/validators/owners per block. - /// - /// # Arguments - /// * `netuid` - The unique identifier of the subnet. - /// * `tao_emission` - The amount of tao to distribute for this subnet. - /// * `alpha_block_emission` - The maximum alpha emission allowed for the block. - /// - /// # Returns - /// * `(u64, u64, u64)` - A tuple containing: - /// - `tao_in_emission`: The adjusted TAO emission always lower or equal to tao_emission - /// - `alpha_in_emission`: The adjusted alpha emission amount to be added into the pool. - /// - `alpha_out_emission`: The remaining alpha emission after adjustments to be distributed to miners/validators. - /// - /// The algorithm ensures that the pool injection of tao_in_emission, alpha_in_emission does not effect the pool price - /// It also ensures that the total amount of alpha_in_emission + alpha_out_emission sum to 2 * alpha_block_emission - /// It also ensures that 1 < alpha_out_emission < 2 * alpha_block_emission and 0 < alpha_in_emission < alpha_block_emission. - pub fn get_dynamic_tao_emission( - netuid: NetUid, - tao_emission: u64, - alpha_block_emission: u64, - ) -> (u64, u64, u64) { - // Init terms. - let mut tao_in_emission: U64F64 = U64F64::saturating_from_num(tao_emission); - let float_alpha_block_emission: U64F64 = U64F64::saturating_from_num(alpha_block_emission); - - // Get alpha price for subnet. - let alpha_price = T::SwapInterface::current_alpha_price(netuid.into()); - log::debug!("{netuid:?} - alpha_price: {alpha_price:?}"); - - // Get initial alpha_in - let mut alpha_in_emission: U64F64 = U64F64::saturating_from_num(tao_emission) - .checked_div(alpha_price) - .unwrap_or(float_alpha_block_emission); - - // Check if we are emitting too much alpha_in - if alpha_in_emission >= float_alpha_block_emission { - log::debug!( - "{netuid:?} - alpha_in_emission: {alpha_in_emission:?} > alpha_block_emission: {float_alpha_block_emission:?}" - ); - - // Scale down tao_in - // tao_in_emission = alpha_price.saturating_mul(float_alpha_block_emission); - - // Set to max alpha_block_emission - alpha_in_emission = float_alpha_block_emission; - } - - // Avoid rounding errors. - let zero = U64F64::saturating_from_num(0); - let one = U64F64::saturating_from_num(1); - if tao_in_emission < one || alpha_in_emission < one { - alpha_in_emission = zero; - tao_in_emission = zero; - } - - // Set Alpha in emission. - let alpha_out_emission = float_alpha_block_emission; - - // Log results. - log::debug!("{netuid:?} - tao_in_emission: {tao_in_emission:?}"); - log::debug!("{netuid:?} - alpha_in_emission: {alpha_in_emission:?}"); - log::debug!("{netuid:?} - alpha_out_emission: {alpha_out_emission:?}"); - - // Return result. - ( - tao_in_emission.saturating_to_num::(), - alpha_in_emission.saturating_to_num::(), - alpha_out_emission.saturating_to_num::(), - ) - } - /// Calculates the block emission based on the total issuance. /// /// This function computes the block emission by applying a logarithmic function diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index ba7d54ed3c..83567b6f57 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -213,6 +213,7 @@ impl Pallet { Self::finalize_all_subnet_root_dividends(netuid); // --- Perform the cleanup before removing the network. + T::SwapInterface::dissolve_all_liquidity_providers(netuid)?; Self::destroy_alpha_in_out_stakes(netuid)?; T::SwapInterface::clear_protocol_liquidity(netuid)?; T::CommitmentsInterface::purge_netuid(netuid); @@ -299,6 +300,7 @@ impl Pallet { SubnetMovingPrice::::remove(netuid); SubnetTaoFlow::::remove(netuid); SubnetEmaTaoFlow::::remove(netuid); + SubnetTaoProvided::::remove(netuid); // --- 13. Token / mechanism / registration toggles. TokenSymbol::::remove(netuid); diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index f40d4e704b..2091946598 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -67,8 +67,7 @@ impl Pallet { let tao_to_swap_with: TaoCurrency = tou64!(excess_tao.get(netuid_i).unwrap_or(&asfloat!(0))).into(); - let (actual_injected_tao, actual_injected_alpha) = - T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); + T::SwapInterface::adjust_protocol_liquidity(*netuid_i, tao_in_i, alpha_in_i); if tao_to_swap_with > TaoCurrency::ZERO { let buy_swap_result = Self::swap_tao_for_alpha( @@ -88,8 +87,7 @@ impl Pallet { AlphaCurrency::from(tou64!(*alpha_in.get(netuid_i).unwrap_or(&asfloat!(0)))); SubnetAlphaInEmission::::insert(*netuid_i, alpha_in_i); SubnetAlphaIn::::mutate(*netuid_i, |total| { - // Reserves also received fees in addition to alpha_in_i - *total = total.saturating_add(actual_injected_alpha); + *total = total.saturating_add(alpha_in_i); }); // Inject TAO in. @@ -97,8 +95,7 @@ impl Pallet { tou64!(*tao_in.get(netuid_i).unwrap_or(&asfloat!(0))).into(); SubnetTaoInEmission::::insert(*netuid_i, injected_tao); SubnetTAO::::mutate(*netuid_i, |total| { - // Reserves also received fees in addition to injected_tao - *total = total.saturating_add(actual_injected_tao); + *total = total.saturating_add(injected_tao); }); TotalStake::::mutate(|total| { *total = total.saturating_add(injected_tao); @@ -143,8 +140,7 @@ impl Pallet { log::debug!("alpha_emission_i: {alpha_emission_i:?}"); // Get subnet price. - let price_i: U96F32 = - U96F32::saturating_from_num(T::SwapInterface::current_alpha_price(netuid_i.into())); + let price_i: U96F32 = T::SwapInterface::current_alpha_price(netuid_i.into()); log::debug!("price_i: {price_i:?}"); let mut tao_in_i: U96F32 = tao_emission_i; diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index c137b92371..69645c0419 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1289,6 +1289,11 @@ pub mod pallet { pub type SubnetTAO = StorageMap<_, Identity, NetUid, TaoCurrency, ValueQuery, DefaultZeroTao>; + /// --- MAP ( netuid ) --> tao_in_user_subnet | Returns the amount of TAO in the subnet reserve provided by users as liquidity. + #[pallet::storage] + pub type SubnetTaoProvided = + StorageMap<_, Identity, NetUid, TaoCurrency, ValueQuery, DefaultZeroTao>; + /// --- MAP ( netuid ) --> alpha_in_emission | Returns the amount of alph in emission into the pool per block. #[pallet::storage] pub type SubnetAlphaInEmission = @@ -1309,6 +1314,11 @@ pub mod pallet { pub type SubnetAlphaIn = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; + /// --- MAP ( netuid ) --> alpha_supply_user_in_pool | Returns the amount of alpha in the pool provided by users as liquidity. + #[pallet::storage] + pub type SubnetAlphaInProvided = + StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; + /// --- MAP ( netuid ) --> alpha_supply_in_subnet | Returns the amount of alpha in the subnet. #[pallet::storage] pub type SubnetAlphaOut = @@ -2552,7 +2562,7 @@ pub struct TaoCurrencyReserve(PhantomData); impl CurrencyReserve for TaoCurrencyReserve { #![deny(clippy::expect_used)] fn reserve(netuid: NetUid) -> TaoCurrency { - SubnetTAO::::get(netuid) + SubnetTAO::::get(netuid).saturating_add(SubnetTaoProvided::::get(netuid)) } fn increase_provided(netuid: NetUid, tao: TaoCurrency) { @@ -2570,7 +2580,7 @@ pub struct AlphaCurrencyReserve(PhantomData); impl CurrencyReserve for AlphaCurrencyReserve { #![deny(clippy::expect_used)] fn reserve(netuid: NetUid) -> AlphaCurrency { - SubnetAlphaIn::::get(netuid) + SubnetAlphaIn::::get(netuid).saturating_add(SubnetAlphaInProvided::::get(netuid)) } fn increase_provided(netuid: NetUid, alpha: AlphaCurrency) { diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 6330e07d1c..3e2f14a3df 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -710,9 +710,9 @@ mod dispatches { /// - Errors stemming from transaction pallet. /// #[pallet::call_index(2)] - #[pallet::weight((Weight::from_parts(523_200_000, 0) - .saturating_add(T::DbWeight::get().reads(20_u64)) - .saturating_add(T::DbWeight::get().writes(14_u64)), DispatchClass::Normal, Pays::Yes))] + #[pallet::weight((Weight::from_parts(340_800_000, 0) + .saturating_add(T::DbWeight::get().reads(25_u64)) + .saturating_add(T::DbWeight::get().writes(16_u64)), DispatchClass::Normal, Pays::Yes))] pub fn add_stake( origin: OriginFor, hotkey: T::AccountId, @@ -1040,9 +1040,9 @@ mod dispatches { /// User register a new subnetwork via burning token #[pallet::call_index(7)] - #[pallet::weight((Weight::from_parts(315_200_000, 0) - .saturating_add(T::DbWeight::get().reads(34_u64)) - .saturating_add(T::DbWeight::get().writes(29_u64)), DispatchClass::Normal, Pays::Yes))] + #[pallet::weight((Weight::from_parts(354_200_000, 0) + .saturating_add(T::DbWeight::get().reads(47_u64)) + .saturating_add(T::DbWeight::get().writes(40_u64)), DispatchClass::Normal, Pays::Yes))] pub fn burned_register( origin: OriginFor, netuid: NetUid, @@ -1211,9 +1211,9 @@ mod dispatches { /// User register a new subnetwork #[pallet::call_index(59)] - #[pallet::weight((Weight::from_parts(238_500_000, 0) + #[pallet::weight((Weight::from_parts(235_400_000, 0) .saturating_add(T::DbWeight::get().reads(36_u64)) - .saturating_add(T::DbWeight::get().writes(50_u64)), DispatchClass::Normal, Pays::Yes))] + .saturating_add(T::DbWeight::get().writes(52_u64)), DispatchClass::Normal, Pays::Yes))] pub fn register_network(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { Self::do_register_network(origin, &hotkey, 1, None) } @@ -1420,9 +1420,9 @@ mod dispatches { /// User register a new subnetwork #[pallet::call_index(79)] - #[pallet::weight((Weight::from_parts(235_700_000, 0) + #[pallet::weight((Weight::from_parts(396_000_000, 0) .saturating_add(T::DbWeight::get().reads(35_u64)) - .saturating_add(T::DbWeight::get().writes(49_u64)), DispatchClass::Normal, Pays::Yes))] + .saturating_add(T::DbWeight::get().writes(51_u64)), DispatchClass::Normal, Pays::Yes))] pub fn register_network_with_identity( origin: OriginFor, hotkey: T::AccountId, @@ -1490,9 +1490,9 @@ mod dispatches { /// * `TxRateLimitExceeded`: /// - Thrown if key has hit transaction rate limit #[pallet::call_index(84)] - #[pallet::weight((Weight::from_parts(486_500_000, 0) - .saturating_add(T::DbWeight::get().reads(35_u64)) - .saturating_add(T::DbWeight::get().writes(23_u64)), DispatchClass::Normal, Pays::Yes))] + #[pallet::weight((Weight::from_parts(358_500_000, 0) + .saturating_add(T::DbWeight::get().reads(41_u64)) + .saturating_add(T::DbWeight::get().writes(26_u64)), DispatchClass::Normal, Pays::Yes))] pub fn unstake_all_alpha(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { Self::do_unstake_all_alpha(origin, hotkey) } @@ -1519,8 +1519,8 @@ mod dispatches { /// - The alpha stake amount to move. /// #[pallet::call_index(85)] - #[pallet::weight((Weight::from_parts(168_200_000, 0) - .saturating_add(T::DbWeight::get().reads(16_u64)) + #[pallet::weight((Weight::from_parts(164_300_000, 0) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)), DispatchClass::Normal, Pays::Yes))] pub fn move_stake( origin: T::RuntimeOrigin, @@ -1562,8 +1562,8 @@ mod dispatches { /// # Events /// May emit a `StakeTransferred` event on success. #[pallet::call_index(86)] - #[pallet::weight((Weight::from_parts(163_400_000, 0) - .saturating_add(T::DbWeight::get().reads(14_u64)) + #[pallet::weight((Weight::from_parts(160_300_000, 0) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)), DispatchClass::Normal, Pays::Yes))] pub fn transfer_stake( origin: T::RuntimeOrigin, @@ -1604,9 +1604,9 @@ mod dispatches { /// May emit a `StakeSwapped` event on success. #[pallet::call_index(87)] #[pallet::weight(( - Weight::from_parts(453_800_000, 0) - .saturating_add(T::DbWeight::get().reads(31_u64)) - .saturating_add(T::DbWeight::get().writes(21_u64)), + Weight::from_parts(351_300_000, 0) + .saturating_add(T::DbWeight::get().reads(37_u64)) + .saturating_add(T::DbWeight::get().writes(24_u64)), DispatchClass::Normal, Pays::Yes ))] @@ -1669,9 +1669,9 @@ mod dispatches { /// - Errors stemming from transaction pallet. /// #[pallet::call_index(88)] - #[pallet::weight((Weight::from_parts(713_200_000, 0) - .saturating_add(T::DbWeight::get().reads(20_u64)) - .saturating_add(T::DbWeight::get().writes(14_u64)), DispatchClass::Normal, Pays::Yes))] + #[pallet::weight((Weight::from_parts(402_900_000, 0) + .saturating_add(T::DbWeight::get().reads(25_u64)) + .saturating_add(T::DbWeight::get().writes(16_u64)), DispatchClass::Normal, Pays::Yes))] pub fn add_stake_limit( origin: OriginFor, hotkey: T::AccountId, @@ -1734,9 +1734,9 @@ mod dispatches { /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. /// #[pallet::call_index(89)] - #[pallet::weight((Weight::from_parts(611_100_000, 0) - .saturating_add(T::DbWeight::get().reads(23_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)), DispatchClass::Normal, Pays::Yes))] + #[pallet::weight((Weight::from_parts(377_400_000, 0) + .saturating_add(T::DbWeight::get().reads(29_u64)) + .saturating_add(T::DbWeight::get().writes(15_u64)), DispatchClass::Normal, Pays::Yes))] pub fn remove_stake_limit( origin: OriginFor, hotkey: T::AccountId, @@ -1778,9 +1778,9 @@ mod dispatches { /// May emit a `StakeSwapped` event on success. #[pallet::call_index(90)] #[pallet::weight(( - Weight::from_parts(661_800_000, 0) - .saturating_add(T::DbWeight::get().reads(31_u64)) - .saturating_add(T::DbWeight::get().writes(21_u64)), + Weight::from_parts(411_500_000, 0) + .saturating_add(T::DbWeight::get().reads(37_u64)) + .saturating_add(T::DbWeight::get().writes(24_u64)), DispatchClass::Normal, Pays::Yes ))] @@ -1956,9 +1956,9 @@ mod dispatches { /// at which or better (higher) the staking should execute. /// Without limit_price it remove all the stake similar to `remove_stake` extrinsic #[pallet::call_index(103)] - #[pallet::weight((Weight::from_parts(615_000_000, 10142) - .saturating_add(T::DbWeight::get().reads(23_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)), DispatchClass::Normal, Pays::Yes))] + #[pallet::weight((Weight::from_parts(395_300_000, 10142) + .saturating_add(T::DbWeight::get().reads(29_u64)) + .saturating_add(T::DbWeight::get().writes(15_u64)), DispatchClass::Normal, Pays::Yes))] pub fn remove_stake_full_limit( origin: T::RuntimeOrigin, hotkey: T::AccountId, @@ -2554,9 +2554,9 @@ mod dispatches { /// alpha token first and immediately burn the acquired amount of alpha (aka Subnet buyback). #[pallet::call_index(132)] #[pallet::weight(( - Weight::from_parts(757_700_000, 8556) - .saturating_add(T::DbWeight::get().reads(23_u64)) - .saturating_add(T::DbWeight::get().writes(15_u64)), + Weight::from_parts(368_000_000, 8556) + .saturating_add(T::DbWeight::get().reads(28_u64)) + .saturating_add(T::DbWeight::get().writes(17_u64)), DispatchClass::Normal, Pays::Yes ))] diff --git a/pallets/subtensor/src/migrations/migrate_cleanup_swap_v3.rs b/pallets/subtensor/src/migrations/migrate_cleanup_swap_v3.rs deleted file mode 100644 index 13edf21033..0000000000 --- a/pallets/subtensor/src/migrations/migrate_cleanup_swap_v3.rs +++ /dev/null @@ -1,70 +0,0 @@ -use super::*; -use crate::HasMigrationRun; -use frame_support::{storage_alias, traits::Get, weights::Weight}; -use scale_info::prelude::string::String; - -pub mod deprecated_swap_maps { - use super::*; - - /// --- MAP ( netuid ) --> tao_in_user_subnet | Returns the amount of TAO in the subnet reserve provided by users as liquidity. - #[storage_alias] - pub type SubnetTaoProvided = - StorageMap, Identity, NetUid, TaoCurrency, ValueQuery>; - - /// --- MAP ( netuid ) --> alpha_supply_user_in_pool | Returns the amount of alpha in the pool provided by users as liquidity. - #[storage_alias] - pub type SubnetAlphaInProvided = - StorageMap, Identity, NetUid, AlphaCurrency, ValueQuery>; -} - -pub fn migrate_cleanup_swap_v3() -> Weight { - let migration_name = b"migrate_cleanup_swap_v3".to_vec(); - let mut weight = T::DbWeight::get().reads(1); - - if HasMigrationRun::::get(&migration_name) { - log::info!( - "Migration '{:?}' has already run. Skipping.", - String::from_utf8_lossy(&migration_name) - ); - return weight; - } - - log::info!( - "Running migration '{}'", - String::from_utf8_lossy(&migration_name), - ); - - // ------------------------------ - // Step 1: Move provided to reserves - // ------------------------------ - for (netuid, tao_provided) in deprecated_swap_maps::SubnetTaoProvided::::iter() { - SubnetTAO::::mutate(netuid, |total| { - *total = total.saturating_add(tao_provided); - }); - } - for (netuid, alpha_provided) in deprecated_swap_maps::SubnetAlphaInProvided::::iter() { - SubnetAlphaIn::::mutate(netuid, |total| { - *total = total.saturating_add(alpha_provided); - }); - } - - // ------------------------------ - // Step 2: Remove Map entries - // ------------------------------ - remove_prefix::("SubtensorModule", "SubnetTaoProvided", &mut weight); - remove_prefix::("SubtensorModule", "SubnetAlphaInProvided", &mut weight); - - // ------------------------------ - // Step 3: Mark Migration as Completed - // ------------------------------ - - HasMigrationRun::::insert(&migration_name, true); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); - - log::info!( - "Migration '{:?}' completed successfully.", - String::from_utf8_lossy(&migration_name) - ); - - weight -} diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs index 087c787424..23a2899b94 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -5,7 +5,6 @@ use sp_io::KillStorageResult; use sp_io::hashing::twox_128; use sp_io::storage::clear_prefix; pub mod migrate_auto_stake_destination; -pub mod migrate_cleanup_swap_v3; pub mod migrate_clear_rank_trust_pruning_maps; pub mod migrate_coldkey_swap_scheduled; pub mod migrate_coldkey_swap_scheduled_to_announcements; diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 7169561d30..6a7966b4fb 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -365,6 +365,7 @@ impl Pallet { let subnet_token_enabled = Self::get_subtoken_enabled(netuid); let transfers_enabled = Self::get_transfer_toggle(netuid); let bonds_reset = Self::get_bonds_reset(netuid); + let user_liquidity_enabled: bool = Self::is_user_liquidity_enabled(netuid); Some(SubnetHyperparamsV2 { rho: rho.into(), @@ -399,7 +400,7 @@ impl Pallet { subnet_is_active: subnet_token_enabled, transfers_enabled, bonds_reset_enabled: bonds_reset, - user_liquidity_enabled: false, + user_liquidity_enabled, }) } diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 998d4f0086..099f8e26b6 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -6,7 +6,7 @@ use frame_support::traits::{ }, }; use safe_math::*; -use substrate_fixed::types::{U64F64, U96F32}; +use substrate_fixed::types::U96F32; use subtensor_runtime_common::{NetUid, TaoCurrency}; use subtensor_swap_interface::{Order, SwapHandler}; @@ -48,13 +48,15 @@ impl Pallet { Self::get_all_subnet_netuids() .into_iter() .map(|netuid| { - let alpha = U64F64::saturating_from_num(Self::get_stake_for_hotkey_on_subnet( + let alpha = U96F32::saturating_from_num(Self::get_stake_for_hotkey_on_subnet( hotkey, netuid, )); - let alpha_price = T::SwapInterface::current_alpha_price(netuid.into()); + let alpha_price = U96F32::saturating_from_num( + T::SwapInterface::current_alpha_price(netuid.into()), + ); alpha.saturating_mul(alpha_price) }) - .sum::() + .sum::() .saturating_to_num::() .into() } @@ -74,7 +76,7 @@ impl Pallet { let order = GetTaoForAlpha::::with_amount(alpha_stake); T::SwapInterface::sim_swap(netuid.into(), order) .map(|r| { - let fee: u64 = U64F64::saturating_from_num(r.fee_paid) + let fee: u64 = U96F32::saturating_from_num(r.fee_paid) .saturating_mul(T::SwapInterface::current_alpha_price( netuid.into(), )) @@ -108,7 +110,7 @@ impl Pallet { let order = GetTaoForAlpha::::with_amount(alpha_stake); T::SwapInterface::sim_swap(netuid.into(), order) .map(|r| { - let fee: u64 = U64F64::saturating_from_num(r.fee_paid) + let fee: u64 = U96F32::saturating_from_num(r.fee_paid) .saturating_mul(T::SwapInterface::current_alpha_price( netuid.into(), )) @@ -221,7 +223,7 @@ impl Pallet { let alpha_stake = Self::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid); let min_alpha_stake = - U64F64::saturating_from_num(Self::get_nominator_min_required_stake()) + U96F32::saturating_from_num(Self::get_nominator_min_required_stake()) .safe_div(T::SwapInterface::current_alpha_price(netuid)) .saturating_to_num::(); if alpha_stake > 0.into() && alpha_stake < min_alpha_stake.into() { @@ -350,6 +352,10 @@ impl Pallet { Ok(credit) } + pub fn is_user_liquidity_enabled(netuid: NetUid) -> bool { + T::SwapInterface::is_user_liquidity_enabled(netuid) + } + pub fn recycle_subnet_alpha(netuid: NetUid, amount: AlphaCurrency) { // TODO: record recycled alpha in a tracker SubnetAlphaOut::::mutate(netuid, |total| { diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs index 76d9c95d3a..a1d9b46d5b 100644 --- a/pallets/subtensor/src/staking/move_stake.rs +++ b/pallets/subtensor/src/staking/move_stake.rs @@ -418,8 +418,7 @@ impl Pallet { /// /// In the corner case when SubnetTAO(2) == SubnetTAO(1), no slippage is going to occur. /// - /// TODO: This formula only works for a single swap step, so it is not 100% correct for swap v3 or balancers. - /// We need an updated one. + /// TODO: This formula only works for a single swap step, so it is not 100% correct for swap v3. We need an updated one. /// pub fn get_max_amount_move( origin_netuid: NetUid, @@ -472,8 +471,10 @@ impl Pallet { } // Corner case: SubnetTAO for any of two subnets is zero - let subnet_tao_1 = SubnetTAO::::get(origin_netuid); - let subnet_tao_2 = SubnetTAO::::get(destination_netuid); + let subnet_tao_1 = SubnetTAO::::get(origin_netuid) + .saturating_add(SubnetTaoProvided::::get(origin_netuid)); + let subnet_tao_2 = SubnetTAO::::get(destination_netuid) + .saturating_add(SubnetTaoProvided::::get(destination_netuid)); if subnet_tao_1.is_zero() || subnet_tao_2.is_zero() { return Err(Error::::ZeroMaxStakeAmount.into()); } @@ -481,8 +482,10 @@ impl Pallet { let subnet_tao_2_float: U64F64 = U64F64::saturating_from_num(subnet_tao_2); // Corner case: SubnetAlphaIn for any of two subnets is zero - let alpha_in_1 = SubnetAlphaIn::::get(origin_netuid); - let alpha_in_2 = SubnetAlphaIn::::get(destination_netuid); + let alpha_in_1 = SubnetAlphaIn::::get(origin_netuid) + .saturating_add(SubnetAlphaInProvided::::get(origin_netuid)); + let alpha_in_2 = SubnetAlphaIn::::get(destination_netuid) + .saturating_add(SubnetAlphaInProvided::::get(destination_netuid)); if alpha_in_1.is_zero() || alpha_in_2.is_zero() { return Err(Error::::ZeroMaxStakeAmount.into()); } diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 735ec804df..74a6bf34a6 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -463,9 +463,7 @@ impl Pallet { .saturating_to_num::(); owner_emission_tao = if owner_alpha_u64 > 0 { - let cur_price: U96F32 = U96F32::saturating_from_num( - T::SwapInterface::current_alpha_price(netuid.into()), - ); + let cur_price: U96F32 = T::SwapInterface::current_alpha_price(netuid.into()); let val_u64 = U96F32::from_num(owner_alpha_u64) .saturating_mul(cur_price) .floor() @@ -583,6 +581,7 @@ impl Pallet { } // 7.c) Remove α‑in/α‑out counters (fully destroyed). SubnetAlphaIn::::remove(netuid); + SubnetAlphaInProvided::::remove(netuid); SubnetAlphaOut::::remove(netuid); // Clear the locked balance on the subnet. diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index d030ee2d76..cf90131c4e 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -18,7 +18,13 @@ impl Pallet { /// # Returns /// * `u64` - The total alpha issuance for the specified subnet. pub fn get_alpha_issuance(netuid: NetUid) -> AlphaCurrency { - SubnetAlphaIn::::get(netuid).saturating_add(SubnetAlphaOut::::get(netuid)) + SubnetAlphaIn::::get(netuid) + .saturating_add(SubnetAlphaInProvided::::get(netuid)) + .saturating_add(SubnetAlphaOut::::get(netuid)) + } + + pub fn get_protocol_tao(netuid: NetUid) -> TaoCurrency { + T::SwapInterface::get_protocol_tao(netuid) } pub fn get_moving_alpha_price(netuid: NetUid) -> U96F32 { @@ -57,10 +63,10 @@ impl Pallet { // Because alpha = b / (b + h), where b and h > 0, alpha < 1, so 1 - alpha > 0. // We can use unsigned type here: U96F32 let one_minus_alpha: U96F32 = U96F32::saturating_from_num(1.0).saturating_sub(alpha); - let current_price: U96F32 = alpha.saturating_mul(U96F32::saturating_from_num( + let current_price: U96F32 = alpha.saturating_mul( T::SwapInterface::current_alpha_price(netuid.into()) - .min(U64F64::saturating_from_num(1.0)), - )); + .min(U96F32::saturating_from_num(1.0)), + ); let current_moving: U96F32 = one_minus_alpha.saturating_mul(Self::get_moving_alpha_price(netuid)); // Convert batch to signed I96F32 to avoid migration of SubnetMovingPrice for now`` @@ -923,7 +929,7 @@ impl Pallet { let current_price = ::SwapInterface::current_alpha_price(netuid.into()); let tao_equivalent: TaoCurrency = current_price - .saturating_mul(U64F64::saturating_from_num(actual_alpha_moved)) + .saturating_mul(U96F32::saturating_from_num(actual_alpha_moved)) .saturating_to_num::() .into(); @@ -1252,34 +1258,42 @@ impl Pallet { } pub fn increase_provided_tao_reserve(netuid: NetUid, tao: TaoCurrency) { - if !tao.is_zero() { - SubnetTAO::::mutate(netuid, |total| { - *total = total.saturating_add(tao); - }); - } + SubnetTaoProvided::::mutate(netuid, |total| { + *total = total.saturating_add(tao); + }); } pub fn decrease_provided_tao_reserve(netuid: NetUid, tao: TaoCurrency) { - if !tao.is_zero() { - SubnetTAO::::mutate(netuid, |total| { - *total = total.saturating_sub(tao); - }); + // First, decrease SubnetTaoProvided, then deduct the rest from SubnetTAO + let subnet_tao = SubnetTAO::::get(netuid); + let subnet_tao_provided = SubnetTaoProvided::::get(netuid); + let remainder = subnet_tao_provided.saturating_sub(tao); + let carry_over = tao.saturating_sub(subnet_tao_provided); + if carry_over.is_zero() { + SubnetTaoProvided::::set(netuid, remainder); + } else { + SubnetTaoProvided::::set(netuid, TaoCurrency::ZERO); + SubnetTAO::::set(netuid, subnet_tao.saturating_sub(carry_over)); } } pub fn increase_provided_alpha_reserve(netuid: NetUid, alpha: AlphaCurrency) { - if !alpha.is_zero() { - SubnetAlphaIn::::mutate(netuid, |total| { - *total = total.saturating_add(alpha); - }); - } + SubnetAlphaInProvided::::mutate(netuid, |total| { + *total = total.saturating_add(alpha); + }); } pub fn decrease_provided_alpha_reserve(netuid: NetUid, alpha: AlphaCurrency) { - if !alpha.is_zero() { - SubnetAlphaIn::::mutate(netuid, |total| { - *total = total.saturating_sub(alpha); - }); + // First, decrease SubnetAlphaInProvided, then deduct the rest from SubnetAlphaIn + let subnet_alpha = SubnetAlphaIn::::get(netuid); + let subnet_alpha_provided = SubnetAlphaInProvided::::get(netuid); + let remainder = subnet_alpha_provided.saturating_sub(alpha); + let carry_over = alpha.saturating_sub(subnet_alpha_provided); + if carry_over.is_zero() { + SubnetAlphaInProvided::::set(netuid, remainder); + } else { + SubnetAlphaInProvided::::set(netuid, AlphaCurrency::ZERO); + SubnetAlphaIn::::set(netuid, subnet_alpha.saturating_sub(carry_over)); } } diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 86462dd06d..ecb5ce0452 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -217,6 +217,8 @@ impl Pallet { SubnetOwner::::insert(netuid_to_register, coldkey.clone()); SubnetOwnerHotkey::::insert(netuid_to_register, hotkey.clone()); SubnetLocked::::insert(netuid_to_register, actual_tao_lock_amount); + SubnetTaoProvided::::insert(netuid_to_register, TaoCurrency::ZERO); + SubnetAlphaInProvided::::insert(netuid_to_register, AlphaCurrency::ZERO); SubnetAlphaOut::::insert(netuid_to_register, AlphaCurrency::ZERO); SubnetVolume::::insert(netuid_to_register, 0u128); RAORecycledForRegistration::::insert( diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 9d08c65e3c..6bcaee2fca 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -19,7 +19,7 @@ use frame_support::{assert_err, assert_noop, assert_ok}; use sp_core::{H256, U256}; use sp_runtime::DispatchError; use std::collections::BTreeSet; -use substrate_fixed::types::{I96F32, U96F32}; +use substrate_fixed::types::{I96F32, U64F64, U96F32}; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, TaoCurrency}; use subtensor_swap_interface::SwapHandler; @@ -758,7 +758,6 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { }); } -/// cargo test --package pallet-subtensor --lib -- tests::claim_root::test_claim_root_with_run_coinbase --exact --nocapture #[test] fn test_claim_root_with_run_coinbase() { new_test_ext(1).execute_with(|| { @@ -791,15 +790,10 @@ fn test_claim_root_with_run_coinbase() { // Set moving price > 1.0 and price > 1.0 // So we turn ON root sell SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); - let tao = TaoCurrency::from(10_000_000_000_000_u64); - let alpha = AlphaCurrency::from(1_000_000_000_000_u64); - SubnetTAO::::insert(netuid, tao); - SubnetAlphaIn::::insert(netuid, alpha); - let current_price = - ::SwapInterface::current_alpha_price(netuid.into()) - .saturating_to_num::(); - assert_eq!(current_price, 10.0f64); - RootClaimableThreshold::::insert(netuid, I96F32::from_num(0)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); // Make sure we are root selling, so we have root alpha divs. let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); @@ -907,15 +901,10 @@ fn test_claim_root_with_block_emissions() { // Set moving price > 1.0 and price > 1.0 // So we turn ON root sell SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); - let tao = TaoCurrency::from(10_000_000_000_000_u64); - let alpha = AlphaCurrency::from(1_000_000_000_000_u64); - SubnetTAO::::insert(netuid, tao); - SubnetAlphaIn::::insert(netuid, alpha); - let current_price = - ::SwapInterface::current_alpha_price(netuid.into()) - .saturating_to_num::(); - assert_eq!(current_price, 10.0f64); - RootClaimableThreshold::::insert(netuid, I96F32::from_num(0)); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); // Make sure we are root selling, so we have root alpha divs. let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); @@ -1031,21 +1020,16 @@ fn test_claim_root_coinbase_distribution() { initial_total_hotkey_alpha.into(), ); + let initial_alpha_issuance = SubtensorModule::get_alpha_issuance(netuid); + let alpha_emissions: AlphaCurrency = 1_000_000_000u64.into(); + // Set moving price > 1.0 and price > 1.0 // So we turn ON root sell SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); - let tao = TaoCurrency::from(100_000_000_000_u64); - let alpha = AlphaCurrency::from(100_000_000_000_u64); - SubnetTAO::::insert(netuid, tao); - SubnetAlphaIn::::insert(netuid, alpha); - // let current_price = - // ::SwapInterface::current_alpha_price(netuid.into()) - // .saturating_to_num::(); - // assert_eq!(current_price, 2.0f64); - RootClaimableThreshold::::insert(netuid, I96F32::from_num(0)); - - let initial_alpha_issuance = SubtensorModule::get_alpha_issuance(netuid); - let alpha_emissions: AlphaCurrency = 1_000_000_000u64.into(); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); // Make sure we are root selling, so we have root alpha divs. let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 4e4caf2e9c..093444e955 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -12,6 +12,7 @@ use crate::*; use alloc::collections::BTreeMap; use approx::assert_abs_diff_eq; use frame_support::assert_ok; +use pallet_subtensor_swap::position::PositionId; use sp_core::U256; use substrate_fixed::{ transcendental::sqrt, @@ -191,8 +192,20 @@ fn test_coinbase_tao_issuance_different_prices() { mock::setup_reserves(netuid2, initial_tao.into(), initial_alpha2.into()); // Force the swap to initialize - ::SwapInterface::init_swap(netuid1, None); - ::SwapInterface::init_swap(netuid2, None); + SubtensorModule::swap_tao_for_alpha( + netuid1, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); + SubtensorModule::swap_tao_for_alpha( + netuid2, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); // Make subnets dynamic. SubnetMechanism::::insert(netuid1, 1); @@ -255,8 +268,20 @@ fn test_coinbase_tao_issuance_different_prices() { // mock::setup_reserves(netuid2, initial_tao.into(), initial_alpha2.into()); // // Force the swap to initialize -// ::SwapInterface::init_swap(netuid1); -// ::SwapInterface::init_swap(netuid2); +// SubtensorModule::swap_tao_for_alpha( +// netuid1, +// TaoCurrency::ZERO, +// 1_000_000_000_000.into(), +// false, +// ) +// .unwrap(); +// SubtensorModule::swap_tao_for_alpha( +// netuid2, +// TaoCurrency::ZERO, +// 1_000_000_000_000.into(), +// false, +// ) +// .unwrap(); // // Set subnet prices to reversed proportion to ensure they don't affect emissions. // SubnetMovingPrice::::insert(netuid1, I96F32::from_num(2)); @@ -561,8 +586,20 @@ fn test_coinbase_alpha_issuance_with_cap_trigger_and_block_emission() { SubnetTaoFlow::::insert(netuid2, 200_000_000_i64); // Force the swap to initialize - ::SwapInterface::init_swap(netuid1, None); - ::SwapInterface::init_swap(netuid2, None); + SubtensorModule::swap_tao_for_alpha( + netuid1, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); + SubtensorModule::swap_tao_for_alpha( + netuid2, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); // Get the prices before the run_coinbase let price_1_before = ::SwapInterface::current_alpha_price(netuid1); @@ -2662,6 +2699,54 @@ fn test_run_coinbase_not_started_start_after() { }); } +/// Test that coinbase updates protocol position liquidity +/// cargo test --package pallet-subtensor --lib -- tests::coinbase::test_coinbase_v3_liquidity_update --exact --show-output +#[test] +fn test_coinbase_v3_liquidity_update() { + new_test_ext(1).execute_with(|| { + let owner_hotkey = U256::from(1); + let owner_coldkey = U256::from(2); + + // add network + let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + + // Force the swap to initialize + SubtensorModule::swap_tao_for_alpha( + netuid, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); + + let protocol_account_id = pallet_subtensor_swap::Pallet::::protocol_account_id(); + let position = pallet_subtensor_swap::Positions::::get(( + netuid, + protocol_account_id, + PositionId::from(1), + )) + .unwrap(); + let liquidity_before = position.liquidity; + + // Enable emissions and run coinbase (which will increase position liquidity) + let emission: u64 = 1_234_567; + // Set the TAO flow to non-zero + SubnetTaoFlow::::insert(netuid, 8348383_i64); + FirstEmissionBlockNumber::::insert(netuid, 0); + SubtensorModule::run_coinbase(U96F32::from_num(emission)); + + let position_after = pallet_subtensor_swap::Positions::::get(( + netuid, + protocol_account_id, + PositionId::from(1), + )) + .unwrap(); + let liquidity_after = position_after.liquidity; + + assert!(liquidity_before < liquidity_after); + }); +} + // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_alpha_childkey_parentkey_with_burn --exact --show-output --nocapture #[test] fn test_drain_alpha_childkey_parentkey_with_burn() { @@ -2955,8 +3040,10 @@ fn test_mining_emission_distribution_with_no_root_sell() { // Make root sell NOT happen // set price very low, e.g. a lot of alpha in //SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1_000_000_000_000_000)); - let alpha = AlphaCurrency::from(1_000_000_000_000_000_000_u64); - SubnetAlphaIn::::insert(netuid, alpha); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(0.01), + ); // Make sure we ARE NOT root selling, so we do not have root alpha divs. let root_sell_flag = SubtensorModule::get_network_root_sell_flag(&[netuid]); @@ -3148,8 +3235,10 @@ fn test_mining_emission_distribution_with_root_sell() { // Make root sell happen // Set moving price > 1.0 // Set price > 1.0 - let alpha = AlphaCurrency::from(100_000_000_000_000); - SubnetAlphaIn::::insert(netuid, alpha); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); @@ -3275,7 +3364,7 @@ fn test_coinbase_subnet_terms_with_alpha_in_gt_alpha_emission() { AlphaCurrency::from(1_000_000_000_000_000), ); // Initialize swap v3 - Swap::maybe_initialize_palswap(netuid0, None); + Swap::maybe_initialize_v3(netuid0); // Set netuid0 to have price tao_emission / price > alpha_emission let alpha_emission = U96F32::saturating_from_num( @@ -3286,19 +3375,14 @@ fn test_coinbase_subnet_terms_with_alpha_in_gt_alpha_emission() { ); let price_to_set: U64F64 = U64F64::saturating_from_num(0.01); let price_to_set_fixed: U96F32 = U96F32::saturating_from_num(price_to_set); + let sqrt_price_to_set: U64F64 = sqrt(price_to_set).unwrap(); let tao_emission: U96F32 = U96F32::saturating_from_num(alpha_emission) .saturating_mul(price_to_set_fixed) .saturating_add(U96F32::saturating_from_num(0.01)); // Set the price - let tao = TaoCurrency::from(1_000_000_000_u64); - let alpha = AlphaCurrency::from( - (U64F64::saturating_from_num(u64::from(tao)) / price_to_set).to_num::(), - ); - SubnetTAO::::insert(netuid0, tao); - SubnetAlphaIn::::insert(netuid0, alpha); - + pallet_subtensor_swap::AlphaSqrtPrice::::insert(netuid0, sqrt_price_to_set); // Check the price is set assert_abs_diff_eq!( pallet_subtensor_swap::Pallet::::current_alpha_price(netuid0).to_num::(), @@ -3356,7 +3440,7 @@ fn test_coinbase_subnet_terms_with_alpha_in_lte_alpha_emission() { AlphaCurrency::from(1_000_000_000_000_000), ); // Initialize swap v3 - Swap::maybe_initialize_palswap(netuid0, None); + Swap::maybe_initialize_v3(netuid0); let alpha_emission = U96F32::saturating_from_num( SubtensorModule::get_block_emission_for_issuance( @@ -3366,7 +3450,7 @@ fn test_coinbase_subnet_terms_with_alpha_in_lte_alpha_emission() { ); let tao_emission = U96F32::saturating_from_num(34566756_u64); - let price: U96F32 = U96F32::saturating_from_num(Swap::current_alpha_price(netuid0)); + let price: U96F32 = Swap::current_alpha_price(netuid0); let subnet_emissions = BTreeMap::from([(netuid0, tao_emission)]); @@ -3419,7 +3503,7 @@ fn test_coinbase_inject_and_maybe_swap_does_not_skew_reserves() { AlphaCurrency::from(1_000_000_000_000_000), ); // Initialize swap v3 - Swap::maybe_initialize_palswap(netuid0, None); + Swap::maybe_initialize_v3(netuid0); let tao_in = BTreeMap::from([(netuid0, U96F32::saturating_from_num(123))]); let alpha_in = BTreeMap::from([(netuid0, U96F32::saturating_from_num(456))]); @@ -3553,7 +3637,7 @@ fn test_coinbase_emit_to_subnets_with_no_root_sell() { AlphaCurrency::from(1_000_000_000_000_000), ); // Initialize swap v3 - Swap::maybe_initialize_palswap(netuid0, None); + Swap::maybe_initialize_v3(netuid0); let tao_emission = U96F32::saturating_from_num(12345678); let subnet_emissions = BTreeMap::from([(netuid0, tao_emission)]); @@ -3567,7 +3651,7 @@ fn test_coinbase_emit_to_subnets_with_no_root_sell() { ) .unwrap_or(0), ); - let price: U96F32 = U96F32::saturating_from_num(Swap::current_alpha_price(netuid0)); + let price: U96F32 = Swap::current_alpha_price(netuid0); let (tao_in, alpha_in, alpha_out, excess_tao) = SubtensorModule::get_subnet_terms(&subnet_emissions); // Based on the price, we should have NO excess TAO @@ -3644,7 +3728,7 @@ fn test_coinbase_emit_to_subnets_with_root_sell() { AlphaCurrency::from(1_000_000_000_000_000), ); // Initialize swap v3 - Swap::maybe_initialize_palswap(netuid0, None); + Swap::maybe_initialize_v3(netuid0); let tao_emission = U96F32::saturating_from_num(12345678); let subnet_emissions = BTreeMap::from([(netuid0, tao_emission)]); @@ -3658,7 +3742,7 @@ fn test_coinbase_emit_to_subnets_with_root_sell() { ) .unwrap_or(0), ); - let price: U96F32 = U96F32::saturating_from_num(Swap::current_alpha_price(netuid0)); + let price: U96F32 = Swap::current_alpha_price(netuid0); let (tao_in, alpha_in, alpha_out, excess_tao) = SubtensorModule::get_subnet_terms(&subnet_emissions); // Based on the price, we should have NO excess TAO @@ -3773,10 +3857,10 @@ fn test_pending_emission_start_call_not_done() { // Make root sell happen // Set moving price > 1.0 // Set price > 1.0 - let tao = TaoCurrency::from(10_000_000_000_u64); - let alpha = AlphaCurrency::from(1_000_000_000_u64); - SubnetTAO::::insert(netuid, tao); - SubnetAlphaIn::::insert(netuid, alpha); + pallet_subtensor_swap::AlphaSqrtPrice::::insert( + netuid, + U64F64::saturating_from_num(10.0), + ); SubnetMovingPrice::::insert(netuid, I96F32::from_num(2)); diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index 04c9ffbaf6..beec7a3cba 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -2727,6 +2727,9 @@ fn test_migrate_reset_unactive_sn() { RAORecycledForRegistration::::get(netuid), actual_tao_lock_amount_less_pool_tao ); + assert!(pallet_subtensor_swap::AlphaSqrtPrice::::contains_key( + *netuid + )); assert_eq!(PendingOwnerCut::::get(netuid), AlphaCurrency::ZERO); assert_ne!(SubnetTAO::::get(netuid), initial_tao); assert_ne!(SubnetAlphaIn::::get(netuid), initial_alpha); @@ -2797,6 +2800,9 @@ fn test_migrate_reset_unactive_sn() { SubnetAlphaOutEmission::::get(netuid), AlphaCurrency::ZERO ); + assert!(pallet_subtensor_swap::AlphaSqrtPrice::::contains_key( + *netuid + )); assert_ne!(PendingOwnerCut::::get(netuid), AlphaCurrency::ZERO); assert_ne!(SubnetTAO::::get(netuid), initial_tao); assert_ne!(SubnetAlphaIn::::get(netuid), initial_alpha); @@ -2962,54 +2968,6 @@ fn test_migrate_remove_unknown_neuron_axon_cert_prom() { } } -// cargo test --package pallet-subtensor --lib -- tests::migration::test_migrate_cleanup_swap_v3 --exact --nocapture -#[test] -fn test_migrate_cleanup_swap_v3() { - use crate::migrations::migrate_cleanup_swap_v3::deprecated_swap_maps; - use substrate_fixed::types::U64F64; - - new_test_ext(1).execute_with(|| { - let migration = crate::migrations::migrate_cleanup_swap_v3::migrate_cleanup_swap_v3::; - - const MIGRATION_NAME: &str = "migrate_cleanup_swap_v3"; - - let provided: u64 = 9876; - let reserves: u64 = 1_000_000; - - SubnetTAO::::insert(NetUid::from(1), TaoCurrency::from(reserves)); - SubnetAlphaIn::::insert(NetUid::from(1), AlphaCurrency::from(reserves)); - - // Insert deprecated maps values - deprecated_swap_maps::SubnetTaoProvided::::insert( - NetUid::from(1), - TaoCurrency::from(provided), - ); - deprecated_swap_maps::SubnetAlphaInProvided::::insert( - NetUid::from(1), - AlphaCurrency::from(provided), - ); - - // Run migration - let weight = migration(); - - // Test that values are removed from state - assert!(!deprecated_swap_maps::SubnetTaoProvided::::contains_key(NetUid::from(1)),); - assert!( - !deprecated_swap_maps::SubnetAlphaInProvided::::contains_key(NetUid::from(1)), - ); - - // Provided got added to reserves - assert_eq!( - u64::from(SubnetTAO::::get(NetUid::from(1))), - reserves + provided - ); - assert_eq!( - u64::from(SubnetAlphaIn::::get(NetUid::from(1))), - reserves + provided - ); - }); -} - #[test] fn test_migrate_coldkey_swap_scheduled_to_announcements() { new_test_ext(1000).execute_with(|| { diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 94ae2d240d..d36875ced1 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -317,6 +317,7 @@ impl crate::Config for Test { parameter_types! { pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap"); pub const SwapMaxFeeRate: u16 = 10000; // 15.26% + pub const SwapMaxPositions: u32 = 100; pub const SwapMinimumLiquidity: u64 = 1_000; pub const SwapMinimumReserve: NonZeroU64 = NonZeroU64::new(100).unwrap(); } @@ -328,6 +329,7 @@ impl pallet_subtensor_swap::Config for Test { type TaoReserve = TaoCurrencyReserve; type AlphaReserve = AlphaCurrencyReserve; type MaxFeeRate = SwapMaxFeeRate; + type MaxPositions = SwapMaxPositions; type MinimumLiquidity = SwapMinimumLiquidity; type MinimumReserve = SwapMinimumReserve; type WeightInfo = (); diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs index 9c9f92d8ac..57be08e2df 100644 --- a/pallets/subtensor/src/tests/move_stake.rs +++ b/pallets/subtensor/src/tests/move_stake.rs @@ -619,9 +619,8 @@ fn test_do_move_event_emission() { // Move stake and capture events System::reset_events(); - let current_price = U96F32::from_num( - ::SwapInterface::current_alpha_price(netuid.into()), - ); + let current_price = + ::SwapInterface::current_alpha_price(netuid.into()); let tao_equivalent = (current_price * U96F32::from_num(alpha)).to_num::(); // no fee conversion assert_ok!(SubtensorModule::do_move_stake( RuntimeOrigin::signed(coldkey), diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index fe141c040f..aa45fb441a 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -6,16 +6,10 @@ use crate::*; use frame_support::{assert_err, assert_ok}; use frame_system::Config; use sp_core::U256; -use sp_std::collections::{ - //btree_map::BTreeMap, - vec_deque::VecDeque, -}; +use sp_std::collections::{btree_map::BTreeMap, vec_deque::VecDeque}; use substrate_fixed::types::{I96F32, U64F64, U96F32}; use subtensor_runtime_common::{MechId, NetUidStorageIndex, TaoCurrency}; -use subtensor_swap_interface::{ - //Order, - SwapHandler, -}; +use subtensor_swap_interface::{Order, SwapHandler}; #[test] fn test_registration_ok() { @@ -253,9 +247,8 @@ fn dissolve_owner_cut_refund_logic() { // Use the current alpha price to estimate the TAO equivalent. let owner_emission_tao = { - let price: U96F32 = U96F32::from_num( - ::SwapInterface::current_alpha_price(net.into()), - ); + let price: U96F32 = + ::SwapInterface::current_alpha_price(net.into()); U96F32::from_num(owner_alpha_u64) .saturating_mul(price) .floor() @@ -372,6 +365,8 @@ fn dissolve_clears_all_per_subnet_storages() { // Token / price / provided reserves TokenSymbol::::insert(net, b"XX".to_vec()); SubnetMovingPrice::::insert(net, substrate_fixed::types::I96F32::from_num(1)); + SubnetTaoProvided::::insert(net, TaoCurrency::from(1)); + SubnetAlphaInProvided::::insert(net, AlphaCurrency::from(1)); // TAO Flow SubnetTaoFlow::::insert(net, 0i64); @@ -534,6 +529,8 @@ fn dissolve_clears_all_per_subnet_storages() { // Token / price / provided reserves assert!(!TokenSymbol::::contains_key(net)); assert!(!SubnetMovingPrice::::contains_key(net)); + assert!(!SubnetTaoProvided::::contains_key(net)); + assert!(!SubnetAlphaInProvided::::contains_key(net)); // Subnet locks assert!(!TransferToggle::::contains_key(net)); @@ -910,9 +907,8 @@ fn destroy_alpha_out_many_stakers_complex_distribution() { let owner_emission_tao: u64 = { // Fallback matches the pallet's fallback - let price: U96F32 = U96F32::from_num( - ::SwapInterface::current_alpha_price(netuid.into()), - ); + let price: U96F32 = + ::SwapInterface::current_alpha_price(netuid.into()); U96F32::from_num(owner_alpha_u64) .saturating_mul(price) .floor() @@ -991,9 +987,8 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { .saturating_to_num::(); let owner_emission_tao_u64 = { - let price: U96F32 = U96F32::from_num( - ::SwapInterface::current_alpha_price(netuid.into()), - ); + let price: U96F32 = + ::SwapInterface::current_alpha_price(netuid.into()); U96F32::from_num(owner_alpha_u64) .saturating_mul(price) .floor() @@ -1780,6 +1775,458 @@ fn test_tempo_greater_than_weight_set_rate_limit() { }) } +#[allow(clippy::indexing_slicing)] +#[test] +fn massive_dissolve_refund_and_reregistration_flow_is_lossless_and_cleans_state() { + new_test_ext(0).execute_with(|| { + // ──────────────────────────────────────────────────────────────────── + // 0) Constants and helpers (distinct hotkeys & coldkeys) + // ──────────────────────────────────────────────────────────────────── + const NUM_NETS: usize = 4; + + // Six LP coldkeys + let cold_lps: [U256; 6] = [ + U256::from(3001), + U256::from(3002), + U256::from(3003), + U256::from(3004), + U256::from(3005), + U256::from(3006), + ]; + + // For each coldkey, define two DISTINCT hotkeys it owns. + let mut cold_to_hots: BTreeMap = BTreeMap::new(); + for &c in cold_lps.iter() { + let h1 = U256::from(c.low_u64().saturating_add(100_000)); + let h2 = U256::from(c.low_u64().saturating_add(200_000)); + cold_to_hots.insert(c, [h1, h2]); + } + + // Distinct τ pot sizes per net. + let pots: [u64; NUM_NETS] = [12_345, 23_456, 34_567, 45_678]; + + let lp_sets_per_net: [&[U256]; NUM_NETS] = [ + &cold_lps[0..4], // net0: A,B,C,D + &cold_lps[2..6], // net1: C,D,E,F + &cold_lps[0..6], // net2: A..F + &cold_lps[1..5], // net3: B,C,D,E + ]; + + // Multiple bands/sizes → many positions per cold across nets, using mixed hotkeys. + // let bands: [i32; 3] = [5, 13, 30]; + // let liqs: [u64; 3] = [400_000, 700_000, 1_100_000]; + + // TODO: Revise when user liquidity is available + // Helper: add a V3 position via a (hot, cold) pair. + // let add_pos = |net: NetUid, hot: U256, cold: U256, band: i32, liq: u64| { + // let ct = pallet_subtensor_swap::CurrentTick::::get(net); + // let lo = ct.saturating_sub(band); + // let hi = ct.saturating_add(band); + // pallet_subtensor_swap::EnabledUserLiquidity::::insert(net, true); + // assert_ok!(pallet_subtensor_swap::Pallet::::add_liquidity( + // RuntimeOrigin::signed(cold), + // hot, + // net, + // lo, + // hi, + // liq + // )); + // }; + + // ──────────────────────────────────────────────────────────────────── + // 1) Create many subnets, enable V3, fix price at tick=0 (sqrt≈1) + // ──────────────────────────────────────────────────────────────────── + let mut nets: Vec = Vec::new(); + for i in 0..NUM_NETS { + let owner_hot = U256::from(10_000 + (i as u64)); + let owner_cold = U256::from(20_000 + (i as u64)); + let net = add_dynamic_network(&owner_hot, &owner_cold); + SubtensorModule::set_max_registrations_per_block(net, 1_000u16); + SubtensorModule::set_target_registrations_per_interval(net, 1_000u16); + Emission::::insert(net, Vec::::new()); + SubtensorModule::set_subnet_locked_balance(net, TaoCurrency::from(0)); + + assert_ok!( + pallet_subtensor_swap::Pallet::::toggle_user_liquidity( + RuntimeOrigin::root(), + net, + true + ) + ); + + // Price/tick pinned so LP math stays stable (sqrt(1)). + let ct0 = pallet_subtensor_swap::tick::TickIndex::new_unchecked(0); + let sqrt1 = ct0.try_to_sqrt_price().expect("sqrt(1) price"); + pallet_subtensor_swap::CurrentTick::::set(net, ct0); + pallet_subtensor_swap::AlphaSqrtPrice::::set(net, sqrt1); + + nets.push(net); + } + + // Map net → index for quick lookups. + let mut net_index: BTreeMap = BTreeMap::new(); + for (i, &n) in nets.iter().enumerate() { + net_index.insert(n, i); + } + + // ──────────────────────────────────────────────────────────────────── + // 2) Pre-create a handful of small (hot, cold) pairs so accounts exist + // ──────────────────────────────────────────────────────────────────── + for id in 0u64..10 { + let cold_acc = U256::from(1_000_000 + id); + let hot_acc = U256::from(2_000_000 + id); + for &net in nets.iter() { + register_ok_neuron(net, hot_acc, cold_acc, 100_000 + id); + } + } + + // ──────────────────────────────────────────────────────────────────── + // 3) LPs per net: register each (hot, cold), massive τ prefund, and stake + // ──────────────────────────────────────────────────────────────────── + for &cold in cold_lps.iter() { + SubtensorModule::add_balance_to_coldkey_account(&cold, u64::MAX); + } + + // τ balances before LP adds (after staking): + let mut tao_before: BTreeMap = BTreeMap::new(); + + // Ordered α snapshot per net at **pair granularity** (pre‑LP): + let mut alpha_pairs_per_net: BTreeMap> = BTreeMap::new(); + + // Register both hotkeys for each participating cold on each net and stake τ→α. + for (ni, &net) in nets.iter().enumerate() { + let participants = lp_sets_per_net[ni]; + for &cold in participants.iter() { + let [hot1, hot2] = cold_to_hots[&cold]; + + // Ensure (hot, cold) neurons exist on this net. + register_ok_neuron( + net, + hot1, + cold, + (ni as u64) * 10_000 + (hot1.low_u64() % 10_000), + ); + register_ok_neuron( + net, + hot2, + cold, + (ni as u64) * 10_000 + (hot2.low_u64() % 10_000) + 1, + ); + + // Stake τ (split across the two hotkeys). + let base: u64 = + 5_000_000 + ((ni as u64) * 1_000_000) + ((cold.low_u64() % 10) * 250_000); + let stake1: u64 = base.saturating_mul(3) / 5; // 60% + let stake2: u64 = base.saturating_sub(stake1); // 40% + + assert_ok!(SubtensorModule::do_add_stake( + RuntimeOrigin::signed(cold), + hot1, + net, + stake1.into() + )); + assert_ok!(SubtensorModule::do_add_stake( + RuntimeOrigin::signed(cold), + hot2, + net, + stake2.into() + )); + } + } + + // Record τ balances now (post‑stake, pre‑LP). + for &cold in cold_lps.iter() { + tao_before.insert(cold, SubtensorModule::get_coldkey_balance(&cold)); + } + + // Capture **pair‑level** α snapshot per net (pre‑LP). + for ((hot, cold, net), amt) in Alpha::::iter() { + if let Some(&ni) = net_index.get(&net) + && lp_sets_per_net[ni].contains(&cold) { + let a: u128 = amt.saturating_to_num(); + if a > 0 { + alpha_pairs_per_net + .entry(net) + .or_default() + .push(((hot, cold), a)); + } + } + } + + // ──────────────────────────────────────────────────────────────────── + // 4) Add many V3 positions per cold across nets, alternating hotkeys + // ──────────────────────────────────────────────────────────────────── + // TODO: Revise when user liquidity is available + // for (ni, &net) in nets.iter().enumerate() { + // let participants = lp_sets_per_net[ni]; + // for (pi, &cold) in participants.iter().enumerate() { + // let [hot1, hot2] = cold_to_hots[&cold]; + // let hots = [hot1, hot2]; + // for k in 0..3 { + // let band = bands[(pi + k) % bands.len()]; + // let liq = liqs[(ni + k) % liqs.len()]; + // let hot = hots[k % hots.len()]; + // add_pos(net, hot, cold, band, liq); + // } + // } + // } + + // Snapshot τ balances AFTER LP adds (to measure actual principal debit). + let mut tao_after_adds: BTreeMap = BTreeMap::new(); + for &cold in cold_lps.iter() { + tao_after_adds.insert(cold, SubtensorModule::get_coldkey_balance(&cold)); + } + + // ──────────────────────────────────────────────────────────────────── + // 5) Compute Hamilton-apportionment BASE shares per cold and total leftover + // from the **pair-level** pre‑LP α snapshot; also count pairs per cold. + // ──────────────────────────────────────────────────────────────────── + let mut base_share_cold: BTreeMap = + cold_lps.iter().copied().map(|c| (c, 0_u64)).collect(); + let mut pair_count_cold: BTreeMap = + cold_lps.iter().copied().map(|c| (c, 0_u32)).collect(); + + let mut leftover_total: u64 = 0; + + for (ni, &net) in nets.iter().enumerate() { + let pot = pots[ni]; + let pairs = alpha_pairs_per_net.get(&net).cloned().unwrap_or_default(); + if pot == 0 || pairs.is_empty() { + continue; + } + let total_alpha: u128 = pairs.iter().map(|(_, a)| *a).sum(); + if total_alpha == 0 { + continue; + } + + let mut base_sum_net: u64 = 0; + for ((_, cold), a) in pairs.iter().copied() { + // quota = a * pot / total_alpha + let prod: u128 = a.saturating_mul(pot as u128); + let base: u64 = (prod / total_alpha) as u64; + base_sum_net = base_sum_net.saturating_add(base); + *base_share_cold.entry(cold).or_default() = + base_share_cold[&cold].saturating_add(base); + *pair_count_cold.entry(cold).or_default() += 1; + } + let leftover_net = pot.saturating_sub(base_sum_net); + leftover_total = leftover_total.saturating_add(leftover_net); + } + + // ──────────────────────────────────────────────────────────────────── + // 6) Seed τ pots and dissolve *all* networks (liquidates LPs + refunds) + // ──────────────────────────────────────────────────────────────────── + for (ni, &net) in nets.iter().enumerate() { + SubnetTAO::::insert(net, TaoCurrency::from(pots[ni])); + } + for &net in nets.iter() { + assert_ok!(SubtensorModule::do_dissolve_network(net)); + } + + // ──────────────────────────────────────────────────────────────────── + // 7) Assertions: τ balances, α gone, nets removed, swap state clean + // (Hamilton invariants enforced at cold-level without relying on tie-break) + // ──────────────────────────────────────────────────────────────────── + // Collect actual pot credits per cold (principal cancels out against adds when comparing before→after). + let mut actual_pot_cold: BTreeMap = + cold_lps.iter().copied().map(|c| (c, 0_u64)).collect(); + for &cold in cold_lps.iter() { + let before = tao_before[&cold]; + let after = SubtensorModule::get_coldkey_balance(&cold); + actual_pot_cold.insert(cold, after.saturating_sub(before)); + } + + // (a) Sum of actual pot credits equals total pots. + let total_actual: u64 = actual_pot_cold.values().copied().sum(); + let total_pots: u64 = pots.iter().copied().sum(); + assert_eq!( + total_actual, total_pots, + "total τ pot credited across colds must equal sum of pots" + ); + + // (b) Each cold’s pot is within Hamilton bounds: base ≤ actual ≤ base + #pairs. + let mut extra_accum: u64 = 0; + for &cold in cold_lps.iter() { + let base = *base_share_cold.get(&cold).unwrap_or(&0); + let pairs = *pair_count_cold.get(&cold).unwrap_or(&0) as u64; + let actual = *actual_pot_cold.get(&cold).unwrap_or(&0); + + assert!( + actual >= base, + "cold {cold:?} actual pot {actual} is below base {base}" + ); + assert!( + actual <= base.saturating_add(pairs), + "cold {cold:?} actual pot {actual} exceeds base + pairs ({base} + {pairs})" + ); + + extra_accum = extra_accum.saturating_add(actual.saturating_sub(base)); + } + + // (c) The total “extra beyond base” equals the computed leftover_total across nets. + assert_eq!( + extra_accum, leftover_total, + "sum of extras beyond base must equal total leftover" + ); + + // (d) τ principal was fully refunded (compare after_adds → after). + for &cold in cold_lps.iter() { + let before = tao_before[&cold]; + let mid = tao_after_adds[&cold]; + let after = SubtensorModule::get_coldkey_balance(&cold); + let principal_actual = before.saturating_sub(mid); + let actual_pot = after.saturating_sub(before); + assert_eq!( + after.saturating_sub(mid), + principal_actual.saturating_add(actual_pot), + "cold {cold:?} τ balance incorrect vs 'after_adds'" + ); + } + + // For each dissolved net, check α ledgers gone, network removed, and swap state clean. + for &net in nets.iter() { + assert!( + Alpha::::iter().all(|((_h, _c, n), _)| n != net), + "alpha ledger not fully cleared for net {net:?}" + ); + assert!( + !SubtensorModule::if_subnet_exist(net), + "subnet {net:?} still exists" + ); + assert!( + pallet_subtensor_swap::Ticks::::iter_prefix(net) + .next() + .is_none(), + "ticks not cleared for net {net:?}" + ); + assert!( + !pallet_subtensor_swap::Positions::::iter() + .any(|((n, _owner, _pid), _)| n == net), + "swap positions not fully cleared for net {net:?}" + ); + assert_eq!( + pallet_subtensor_swap::FeeGlobalTao::::get(net).saturating_to_num::(), + 0, + "FeeGlobalTao nonzero for net {net:?}" + ); + assert_eq!( + pallet_subtensor_swap::FeeGlobalAlpha::::get(net).saturating_to_num::(), + 0, + "FeeGlobalAlpha nonzero for net {net:?}" + ); + assert_eq!( + pallet_subtensor_swap::CurrentLiquidity::::get(net), + 0, + "CurrentLiquidity not zero for net {net:?}" + ); + assert!( + !pallet_subtensor_swap::SwapV3Initialized::::get(net), + "SwapV3Initialized still set" + ); + assert!( + !pallet_subtensor_swap::EnabledUserLiquidity::::get(net), + "EnabledUserLiquidity still set" + ); + assert!( + pallet_subtensor_swap::TickIndexBitmapWords::::iter_prefix((net,)) + .next() + .is_none(), + "TickIndexBitmapWords not cleared for net {net:?}" + ); + } + + // ──────────────────────────────────────────────────────────────────── + // 8) Re-register a fresh subnet and re‑stake using the pallet’s min rule + // Assert αΔ equals the sim-swap result for the exact τ staked. + // ──────────────────────────────────────────────────────────────────── + let new_owner_hot = U256::from(99_000); + let new_owner_cold = U256::from(99_001); + let net_new = add_dynamic_network(&new_owner_hot, &new_owner_cold); + SubtensorModule::set_max_registrations_per_block(net_new, 1_000u16); + SubtensorModule::set_target_registrations_per_interval(net_new, 1_000u16); + Emission::::insert(net_new, Vec::::new()); + SubtensorModule::set_subnet_locked_balance(net_new, TaoCurrency::from(0)); + + assert_ok!( + pallet_subtensor_swap::Pallet::::toggle_user_liquidity( + RuntimeOrigin::root(), + net_new, + true + ) + ); + let ct0 = pallet_subtensor_swap::tick::TickIndex::new_unchecked(0); + let sqrt1 = ct0.try_to_sqrt_price().expect("sqrt(1)"); + pallet_subtensor_swap::CurrentTick::::set(net_new, ct0); + pallet_subtensor_swap::AlphaSqrtPrice::::set(net_new, sqrt1); + + // Compute the exact min stake per the pallet rule: DefaultMinStake + fee(DefaultMinStake). + let min_stake = DefaultMinStake::::get(); + let order = GetAlphaForTao::::with_amount(min_stake); + let fee_for_min = pallet_subtensor_swap::Pallet::::sim_swap( + net_new, + order, + ) + .map(|r| r.fee_paid) + .unwrap_or_else(|_e| { + as subtensor_swap_interface::SwapHandler>::approx_fee_amount(net_new, min_stake) + }); + let min_amount_required = min_stake.saturating_add(fee_for_min).to_u64(); + + // Re‑stake from three coldkeys; choose a specific DISTINCT hotkey per cold. + for &cold in &cold_lps[0..3] { + let [hot1, _hot2] = cold_to_hots[&cold]; + register_ok_neuron(net_new, hot1, cold, 7777); + + let before_tao = SubtensorModule::get_coldkey_balance(&cold); + let a_prev: u64 = Alpha::::get((hot1, cold, net_new)).saturating_to_num(); + + // Expected α for this exact τ, using the same sim path as the pallet. + let order = GetAlphaForTao::::with_amount(min_amount_required); + let expected_alpha_out = pallet_subtensor_swap::Pallet::::sim_swap( + net_new, + order, + ) + .map(|r| r.amount_paid_out) + .expect("sim_swap must succeed for fresh net and min amount"); + + assert_ok!(SubtensorModule::do_add_stake( + RuntimeOrigin::signed(cold), + hot1, + net_new, + min_amount_required.into() + )); + + let after_tao = SubtensorModule::get_coldkey_balance(&cold); + let a_new: u64 = Alpha::::get((hot1, cold, net_new)).saturating_to_num(); + let a_delta = a_new.saturating_sub(a_prev); + + // τ decreased by exactly the amount we sent. + assert_eq!( + after_tao, + before_tao.saturating_sub(min_amount_required), + "τ did not decrease by the min required restake amount for cold {cold:?}" + ); + + // α minted equals the simulated swap’s net out for that same τ. + assert_eq!( + a_delta, expected_alpha_out.to_u64(), + "α minted mismatch for cold {cold:?} (hot {hot1:?}) on new net (αΔ {a_delta}, expected {expected_alpha_out})" + ); + } + + // Ensure V3 still functional on new net: add a small position for the first cold using its hot1 + // TODO: Revise when user liquidity is available + // let who_cold = cold_lps[0]; + // let [who_hot, _] = cold_to_hots[&who_cold]; + // add_pos(net_new, who_hot, who_cold, 8, 123_456); + // assert!( + // pallet_subtensor_swap::Positions::::iter() + // .any(|((n, owner, _pid), _)| n == net_new && owner == who_cold), + // "new position not recorded on the re-registered net" + // ); + }); +} + #[test] fn dissolve_clears_all_mechanism_scoped_maps_for_all_mechanisms() { new_test_ext(0).execute_with(|| { diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 86ba26c2e2..4bbdc0866a 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -6,9 +6,9 @@ use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays use frame_support::sp_runtime::DispatchError; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use frame_system::RawOrigin; +use pallet_subtensor_swap::tick::TickIndex; use safe_math::FixedExt; use sp_core::{Get, H256, U256}; -// use sp_runtime::traits::Dispatchable; use substrate_fixed::traits::FromFixed; use substrate_fixed::types::{I96F32, I110F18, U64F64, U96F32}; use subtensor_runtime_common::{ @@ -572,7 +572,13 @@ fn test_add_stake_partial_below_min_stake_fails() { mock::setup_reserves(netuid, (amount * 10).into(), (amount * 10).into()); // Force the swap to initialize - ::SwapInterface::init_swap(netuid, None); + SubtensorModule::swap_tao_for_alpha( + netuid, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); // Get the current price (should be 1.0) let current_price = @@ -711,10 +717,8 @@ fn test_remove_stake_total_balance_no_change() { ); // Add subnet TAO for the equivalent amount added at price - let amount_tao = U96F32::from_num(amount) - * U96F32::from_num( - ::SwapInterface::current_alpha_price(netuid.into()), - ); + let amount_tao = U96F32::saturating_from_num(amount) + * ::SwapInterface::current_alpha_price(netuid.into()); SubnetTAO::::mutate(netuid, |v| { *v += amount_tao.saturating_to_num::().into() }); @@ -799,7 +803,7 @@ fn test_add_stake_insufficient_liquidity_one_side_ok() { SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked); // Set the liquidity at lowest possible value so that all staking requests fail - let reserve_alpha = 1_000_000_000_u64; + let reserve_alpha = u64::from(mock::SwapMinimumReserve::get()); let reserve_tao = u64::from(mock::SwapMinimumReserve::get()) - 1; mock::setup_reserves(netuid, reserve_tao.into(), reserve_alpha.into()); @@ -883,9 +887,9 @@ fn test_remove_stake_insufficient_liquidity() { Error::::InsufficientLiquidity ); - // Mock more liquidity - remove becomes successful - SubnetTAO::::insert(netuid, TaoCurrency::from(amount_staked + 1)); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(1)); + // Mock provided liquidity - remove becomes successful + SubnetTaoProvided::::insert(netuid, TaoCurrency::from(amount_staked + 1)); + SubnetAlphaInProvided::::insert(netuid, AlphaCurrency::from(1)); assert_ok!(SubtensorModule::remove_stake( RuntimeOrigin::signed(coldkey), hotkey, @@ -2181,9 +2185,8 @@ fn test_get_total_delegated_stake_after_unstaking() { netuid, unstake_amount_alpha.into() )); - let current_price = U96F32::from_num( - ::SwapInterface::current_alpha_price(netuid.into()), - ); + let current_price = + ::SwapInterface::current_alpha_price(netuid.into()); // Calculate the expected delegated stake let unstake_amount = @@ -2861,15 +2864,8 @@ fn test_max_amount_add_dynamic() { pallet_subtensor_swap::Error::::PriceLimitExceeded, )), ), - ( - 150_000_000_000, - 100_000_000_000, - 1_500_000_000, - Err(DispatchError::from( - pallet_subtensor_swap::Error::::PriceLimitExceeded, - )), - ), - (150_000_000_000, 100_000_000_000, 1_500_000_001, Ok(49)), + (150_000_000_000, 100_000_000_000, 1_500_000_000, Ok(5)), + (150_000_000_000, 100_000_000_000, 1_500_000_001, Ok(51)), ( 150_000_000_000, 100_000_000_000, @@ -2892,7 +2888,13 @@ fn test_max_amount_add_dynamic() { SubnetAlphaIn::::insert(netuid, alpha_in); // Force the swap to initialize - ::SwapInterface::init_swap(netuid, None); + SubtensorModule::swap_tao_for_alpha( + netuid, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); if !alpha_in.is_zero() { let expected_price = U96F32::from_num(tao_in) / U96F32::from_num(alpha_in); @@ -3028,16 +3030,13 @@ fn test_max_amount_remove_dynamic() { (10_000_000_000, 10_000_000_000, 0, Ok(u64::MAX)), // Low bounds (numbers are empirical, it is only important that result // is sharply decreasing when limit price increases) - (1_000, 1_000, 0, Ok(u64::MAX)), - (1_001, 1_001, 0, Ok(u64::MAX)), - (1_001, 1_001, 1, Ok(17_646)), - (1_001, 1_001, 2, Ok(17_646)), - (1_001, 1_001, 1_001, Ok(17_646)), - (1_001, 1_001, 10_000, Ok(17_646)), - (1_001, 1_001, 100_000, Ok(17_646)), - (1_001, 1_001, 1_000_000, Ok(17_646)), - (1_001, 1_001, 10_000_000, Ok(9_103)), - (1_001, 1_001, 100_000_000, Ok(2_186)), + (1_000, 1_000, 0, Ok(4_308_000_000_000)), + (1_001, 1_001, 0, Ok(4_310_000_000_000)), + (1_001, 1_001, 1, Ok(31_750_000)), + (1_001, 1_001, 2, Ok(22_500_000)), + (1_001, 1_001, 1_001, Ok(1_000_000)), + (1_001, 1_001, 10_000, Ok(316_000)), + (1_001, 1_001, 100_000, Ok(100_000)), // Basic math (1_000_000, 1_000_000, 250_000_000, Ok(1_010_000)), (1_000_000, 1_000_000, 62_500_000, Ok(3_030_000)), @@ -3084,7 +3083,7 @@ fn test_max_amount_remove_dynamic() { 21_000_000_000_000_000, 1_000_000, 21_000_000_000_000_000, - Ok(17_630_088), + Ok(30_700_000), ), (21_000_000_000_000_000, 1_000_000, u64::MAX, Ok(67_000)), ( @@ -3122,7 +3121,7 @@ fn test_max_amount_remove_dynamic() { SubnetAlphaIn::::insert(netuid, alpha_in); if !alpha_in.is_zero() { - let expected_price = U64F64::from_num(tao_in) / U64F64::from_num(alpha_in); + let expected_price = I96F32::from_num(tao_in) / I96F32::from_num(alpha_in); assert_eq!( ::SwapInterface::current_alpha_price(netuid.into()), expected_price @@ -3311,7 +3310,7 @@ fn test_max_amount_move_stable_dynamic() { dynamic_netuid, TaoCurrency::from(2_000_000_000) ), - Err(pallet_subtensor_swap::Error::::PriceLimitExceeded.into()) + Err(Error::::ZeroMaxStakeAmount.into()) ); // 3.0 price => max is 0 @@ -3681,27 +3680,29 @@ fn test_max_amount_move_dynamic_dynamic() { expected_max_swappable, precision, )| { + let alpha_in_1 = AlphaCurrency::from(alpha_in_1); + let alpha_in_2 = AlphaCurrency::from(alpha_in_2); let expected_max_swappable = AlphaCurrency::from(expected_max_swappable); // Forse-set alpha in and tao reserve to achieve relative price of subnets SubnetTAO::::insert(origin_netuid, TaoCurrency::from(tao_in_1)); - SubnetAlphaIn::::insert(origin_netuid, AlphaCurrency::from(alpha_in_1)); + SubnetAlphaIn::::insert(origin_netuid, alpha_in_1); SubnetTAO::::insert(destination_netuid, TaoCurrency::from(tao_in_2)); - SubnetAlphaIn::::insert(destination_netuid, AlphaCurrency::from(alpha_in_2)); + SubnetAlphaIn::::insert(destination_netuid, alpha_in_2); if !alpha_in_1.is_zero() && !alpha_in_2.is_zero() { - let origin_price = tao_in_1 as f64 / alpha_in_1 as f64; - let dest_price = tao_in_2 as f64 / alpha_in_2 as f64; - if dest_price != 0. { + let origin_price = + I96F32::from_num(tao_in_1) / I96F32::from_num(u64::from(alpha_in_1)); + let dest_price = + I96F32::from_num(tao_in_2) / I96F32::from_num(u64::from(alpha_in_2)); + if dest_price != 0 { let expected_price = origin_price / dest_price; - assert_abs_diff_eq!( - (::SwapInterface::current_alpha_price( + assert_eq!( + ::SwapInterface::current_alpha_price( origin_netuid.into() ) / ::SwapInterface::current_alpha_price( destination_netuid.into() - )) - .to_num::(), - expected_price, - epsilon = 0.000_000_001 + ), + expected_price ); } } @@ -3798,7 +3799,7 @@ fn test_add_stake_limit_fill_or_kill() { new_test_ext(1).execute_with(|| { let hotkey_account_id = U256::from(533453); let coldkey_account_id = U256::from(55453); - let amount = 300_000_000_000; // over the maximum + let amount = 900_000_000_000; // over the maximum // add network let netuid = add_dynamic_network(&hotkey_account_id, &coldkey_account_id); @@ -3818,7 +3819,9 @@ fn test_add_stake_limit_fill_or_kill() { SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount); // Setup limit price so that it doesn't peak above 4x of current price - let limit_price = TaoCurrency::from(6_000_000_000); + // The amount that can be executed at this price is 450 TAO only + // Alpha produced will be equal to 25 = 100 - 450*100/(150+450) + let limit_price = TaoCurrency::from(24_000_000_000); // Add stake with slippage safety and check if it fails assert_noop!( @@ -3834,7 +3837,7 @@ fn test_add_stake_limit_fill_or_kill() { ); // Lower the amount and it should succeed now - let amount_ok = TaoCurrency::from(150_000_000_000); // fits the maximum + let amount_ok = TaoCurrency::from(450_000_000_000); // fits the maximum assert_ok!(SubtensorModule::add_stake_limit( RuntimeOrigin::signed(coldkey_account_id), hotkey_account_id, @@ -4574,15 +4577,13 @@ fn test_stake_into_subnet_low_amount() { false, false, )); - let expected_stake = (amount as f64) * 0.997 / current_price; + let expected_stake = AlphaCurrency::from(((amount as f64) * 0.997 / current_price) as u64); // Check if stake has increased assert_abs_diff_eq!( - u64::from(SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( - &hotkey, &coldkey, netuid - )) as f64, + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid), expected_stake, - epsilon = expected_stake / 100. + epsilon = expected_stake / 100.into() ); }); } @@ -4854,9 +4855,34 @@ fn test_unstake_full_amount() { }); } +fn price_to_tick(price: f64) -> TickIndex { + let price_sqrt: U64F64 = U64F64::from_num(price.sqrt()); + // Handle potential errors in the conversion + match TickIndex::try_from_sqrt_price(price_sqrt) { + Ok(mut tick) => { + // Ensure the tick is within bounds + if tick > TickIndex::MAX { + tick = TickIndex::MAX; + } else if tick < TickIndex::MIN { + tick = TickIndex::MIN; + } + tick + } + // Default to a reasonable value when conversion fails + Err(_) => { + if price > 1.0 { + TickIndex::MAX + } else { + TickIndex::MIN + } + } + } +} + /// Test correctness of swap fees: /// 1. TAO is not minted or burned /// 2. Fees match FeeRate +/// #[test] fn test_swap_fees_tao_correctness() { new_test_ext(1).execute_with(|| { @@ -4872,6 +4898,9 @@ fn test_swap_fees_tao_correctness() { let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); SubtensorModule::add_balance_to_coldkey_account(&owner_coldkey, owner_balance_before); SubtensorModule::add_balance_to_coldkey_account(&coldkey, user_balance_before); + let fee_rate = pallet_subtensor_swap::FeeRate::::get(NetUid::from(netuid)) as f64 + / u16::MAX as f64; + pallet_subtensor_swap::EnabledUserLiquidity::::insert(NetUid::from(netuid), true); // Forse-set alpha in and tao reserve to make price equal 0.25 let tao_reserve = TaoCurrency::from(100_000_000_000); @@ -4900,6 +4929,18 @@ fn test_swap_fees_tao_correctness() { .to_num::() + 0.0001; let limit_price = current_price + 0.01; + let tick_low = price_to_tick(current_price); + let tick_high = price_to_tick(limit_price); + let liquidity = amount; + + assert_ok!(::SwapInterface::do_add_liquidity( + netuid.into(), + &owner_coldkey, + &owner_hotkey, + tick_low, + tick_high, + liquidity, + )); // Limit-buy and then sell all alpha for user to hit owner liquidity assert_ok!(SubtensorModule::add_stake_limit( @@ -5189,6 +5230,181 @@ fn test_default_min_stake_sufficiency() { }); } +/// Test that modify_position always credits fees +/// +/// cargo test --package pallet-subtensor --lib -- tests::staking::test_update_position_fees --exact --show-output +#[test] +fn test_update_position_fees() { + // Test cases: add or remove liquidity during modification + [false, true].into_iter().for_each(|add| { + new_test_ext(1).execute_with(|| { + let owner_hotkey = U256::from(1); + let owner_coldkey = U256::from(2); + let coldkey = U256::from(4); + let amount = 1_000_000_000; + + // add network + let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + SubtensorModule::add_balance_to_coldkey_account(&owner_coldkey, amount * 10); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount * 100); + pallet_subtensor_swap::EnabledUserLiquidity::::insert(NetUid::from(netuid), true); + + // Forse-set alpha in and tao reserve to make price equal 0.25 + let tao_reserve = TaoCurrency::from(100_000_000_000); + let alpha_in = AlphaCurrency::from(400_000_000_000); + mock::setup_reserves(netuid, tao_reserve, alpha_in); + + // Get alpha for owner + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(owner_coldkey), + owner_hotkey, + netuid, + amount.into(), + )); + + // Add owner coldkey Alpha as concentrated liquidity + // between current price current price + 0.01 + let current_price = + ::SwapInterface::current_alpha_price(netuid.into()) + .to_num::() + + 0.0001; + let limit_price = current_price + 0.001; + let tick_low = price_to_tick(current_price); + let tick_high = price_to_tick(limit_price); + let liquidity = amount; + + let (position_id, _, _) = ::SwapInterface::do_add_liquidity( + NetUid::from(netuid), + &owner_coldkey, + &owner_hotkey, + tick_low, + tick_high, + liquidity, + ) + .unwrap(); + + // Buy and then sell all alpha for user to hit owner liquidity + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey), + owner_hotkey, + netuid, + amount.into(), + )); + + remove_stake_rate_limit_for_tests(&owner_hotkey, &coldkey, netuid); + + let user_alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &owner_hotkey, + &coldkey, + netuid, + ); + assert_ok!(SubtensorModule::remove_stake( + RuntimeOrigin::signed(coldkey), + owner_hotkey, + netuid, + user_alpha, + )); + + // Modify position - fees should be collected and paid to the owner + let owner_tao_before = SubtensorModule::get_coldkey_balance(&owner_coldkey); + let owner_alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &owner_hotkey, + &owner_coldkey, + netuid, + ); + + // Make small modification + let delta = + ::MinimumLiquidity::get() + as i64 + * (if add { 1 } else { -1 }); + assert_ok!(Swap::modify_position( + RuntimeOrigin::signed(owner_coldkey), + owner_hotkey, + netuid.into(), + position_id.into(), + delta, + )); + + // Check ending owner TAO and alpha + let owner_tao_after_add = SubtensorModule::get_coldkey_balance(&owner_coldkey); + let owner_alpha_after_add = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &owner_hotkey, + &owner_coldkey, + netuid, + ); + + assert!(owner_tao_after_add > owner_tao_before); + assert!(owner_alpha_after_add > owner_alpha_before); // always greater because of claimed fees + + // Make small modification again - should not claim more fees + assert_ok!(Swap::modify_position( + RuntimeOrigin::signed(owner_coldkey), + owner_hotkey, + netuid.into(), + position_id.into(), + delta, + )); + + // Check ending owner TAO and alpha + let owner_tao_after_repeat = SubtensorModule::get_coldkey_balance(&owner_coldkey); + let owner_alpha_after_repeat = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &owner_hotkey, + &owner_coldkey, + netuid, + ); + + assert!(owner_tao_after_add == owner_tao_after_repeat); + if add { + assert!(owner_alpha_after_add > owner_alpha_after_repeat); + } else { + assert!(owner_alpha_after_add < owner_alpha_after_repeat); + } + }); + }); +} + +// TODO: Revise when user liquidity is available +// fn setup_positions(netuid: NetUid) { +// for (coldkey, hotkey, low_price, high_price, liquidity) in [ +// (2, 12, 0.1, 0.20, 1_000_000_000_000_u64), +// (3, 13, 0.15, 0.25, 200_000_000_000_u64), +// (4, 14, 0.25, 0.5, 3_000_000_000_000_u64), +// (5, 15, 0.3, 0.6, 300_000_000_000_u64), +// (6, 16, 0.4, 0.7, 8_000_000_000_000_u64), +// (7, 17, 0.5, 0.8, 600_000_000_000_u64), +// (8, 18, 0.6, 0.9, 700_000_000_000_u64), +// (9, 19, 0.7, 1.0, 100_000_000_000_u64), +// (10, 20, 0.8, 1.1, 300_000_000_000_u64), +// ] { +// SubtensorModule::create_account_if_non_existent(&U256::from(coldkey), &U256::from(hotkey)); +// SubtensorModule::add_balance_to_coldkey_account( +// &U256::from(coldkey), +// 1_000_000_000_000_000, +// ); +// SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( +// &U256::from(hotkey), +// &U256::from(coldkey), +// netuid.into(), +// 1_000_000_000_000_000.into(), +// ); + +// let tick_low = price_to_tick(low_price); +// let tick_high = price_to_tick(high_price); +// let add_lq_call = SwapCall::::add_liquidity { +// hotkey: U256::from(hotkey), +// netuid: netuid.into(), +// tick_low, +// tick_high, +// liquidity, +// }; +// assert_ok!( +// RuntimeCall::Swap(add_lq_call).dispatch(RuntimeOrigin::signed(U256::from(coldkey))) +// ); +// } +// } + #[test] fn test_large_swap() { new_test_ext(1).execute_with(|| { @@ -5199,13 +5415,19 @@ fn test_large_swap() { // add network let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); - let tao = TaoCurrency::from(100_000_000u64); - let alpha = AlphaCurrency::from(1_000_000_000_000_000_u64); - SubnetTAO::::insert(netuid, tao); - SubnetAlphaIn::::insert(netuid, alpha); + pallet_subtensor_swap::EnabledUserLiquidity::::insert(NetUid::from(netuid), true); // Force the swap to initialize - ::SwapInterface::init_swap(netuid, None); + SubtensorModule::swap_tao_for_alpha( + netuid, + TaoCurrency::ZERO, + 1_000_000_000_000.into(), + false, + ) + .unwrap(); + + // TODO: Revise when user liquidity is available + // setup_positions(netuid.into()); let swap_amount = TaoCurrency::from(100_000_000_000_000); assert_ok!(SubtensorModule::add_stake( diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index 4eb13fe5fb..a547b30a14 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -714,6 +714,63 @@ fn test_subtoken_enable_ok_for_burn_register_before_enable() { }); } +// #[test] +// fn test_user_liquidity_access_control() { +// new_test_ext(1).execute_with(|| { +// let owner_hotkey = U256::from(1); +// let owner_coldkey = U256::from(2); +// let not_owner = U256::from(999); // arbitrary non-owner + +// // add network +// let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + +// // Not owner, not root: should fail +// assert_noop!( +// Swap::toggle_user_liquidity(RuntimeOrigin::signed(not_owner), netuid, true), +// DispatchError::BadOrigin +// ); + +// // Subnet owner can enable +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::signed(owner_coldkey), +// netuid, +// true +// )); +// assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); + +// // Root can disable +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid, +// false +// )); +// assert!(!pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); + +// // Root can enable again +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid, +// true +// )); +// assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); + +// // Subnet owner cannot disable (only root can disable) +// assert_noop!( +// Swap::toggle_user_liquidity(RuntimeOrigin::signed(owner_coldkey), netuid, false), +// DispatchError::BadOrigin +// ); +// assert!(pallet_subtensor_swap::EnabledUserLiquidity::::get( +// NetUid::from(netuid) +// )); +// }); +// } + // cargo test --package pallet-subtensor --lib -- tests::subnet::test_no_duplicates_in_symbol_static --exact --show-output #[test] fn test_no_duplicates_in_symbol_static() { diff --git a/pallets/swap-interface/src/lib.rs b/pallets/swap-interface/src/lib.rs index 6e6ad7101a..76e149b4b7 100644 --- a/pallets/swap-interface/src/lib.rs +++ b/pallets/swap-interface/src/lib.rs @@ -2,7 +2,7 @@ use core::ops::Neg; use frame_support::pallet_prelude::*; -use substrate_fixed::types::U64F64; +use substrate_fixed::types::U96F32; use subtensor_macros::freeze_struct; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, TaoCurrency}; @@ -38,16 +38,19 @@ pub trait SwapHandler { Self: SwapEngine; fn approx_fee_amount(netuid: NetUid, amount: T) -> T; - fn current_alpha_price(netuid: NetUid) -> U64F64; + fn current_alpha_price(netuid: NetUid) -> U96F32; + fn get_protocol_tao(netuid: NetUid) -> TaoCurrency; fn max_price() -> C; fn min_price() -> C; fn adjust_protocol_liquidity( netuid: NetUid, tao_delta: TaoCurrency, alpha_delta: AlphaCurrency, - ) -> (TaoCurrency, AlphaCurrency); + ); + fn is_user_liquidity_enabled(netuid: NetUid) -> bool; + fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult; + fn toggle_user_liquidity(netuid: NetUid, enabled: bool); fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult; - fn init_swap(netuid: NetUid, maybe_price: Option); } pub trait DefaultPriceLimit diff --git a/pallets/swap-interface/src/order.rs b/pallets/swap-interface/src/order.rs index fc3f2acefe..1576283fd5 100644 --- a/pallets/swap-interface/src/order.rs +++ b/pallets/swap-interface/src/order.rs @@ -11,7 +11,7 @@ pub trait Order: Clone { fn with_amount(amount: impl Into) -> Self; fn amount(&self) -> Self::PaidIn; - fn is_beyond_price_limit(&self, current_price: U64F64, limit_price: U64F64) -> bool; + fn is_beyond_price_limit(&self, alpha_sqrt_price: U64F64, limit_sqrt_price: U64F64) -> bool; } #[derive(Clone, Default)] @@ -45,8 +45,8 @@ where self.amount } - fn is_beyond_price_limit(&self, current_price: U64F64, limit_price: U64F64) -> bool { - current_price < limit_price + fn is_beyond_price_limit(&self, alpha_sqrt_price: U64F64, limit_sqrt_price: U64F64) -> bool { + alpha_sqrt_price < limit_sqrt_price } } @@ -81,7 +81,7 @@ where self.amount } - fn is_beyond_price_limit(&self, current_price: U64F64, limit_price: U64F64) -> bool { - current_price > limit_price + fn is_beyond_price_limit(&self, alpha_sqrt_price: U64F64, limit_sqrt_price: U64F64) -> bool { + alpha_sqrt_price > limit_sqrt_price } } diff --git a/pallets/swap/Cargo.toml b/pallets/swap/Cargo.toml index 45389874a1..7de8e49c1d 100644 --- a/pallets/swap/Cargo.toml +++ b/pallets/swap/Cargo.toml @@ -12,7 +12,6 @@ frame-support.workspace = true frame-system.workspace = true log.workspace = true safe-math.workspace = true -safe-bigmath.workspace = true scale-info = { workspace = true, features = ["derive"] } serde = { workspace = true, optional = true } sp-arithmetic.workspace = true @@ -29,8 +28,6 @@ subtensor-swap-interface.workspace = true [dev-dependencies] sp-tracing.workspace = true -rand = { version = "0.8", default-features = false } -rayon = "1.10" [lints] workspace = true @@ -45,9 +42,7 @@ std = [ "frame-system/std", "log/std", "pallet-subtensor-swap-runtime-api/std", - "rand/std", "safe-math/std", - "safe-bigmath/std", "scale-info/std", "serde/std", "sp-arithmetic/std", diff --git a/pallets/swap/rpc/src/lib.rs b/pallets/swap/rpc/src/lib.rs index a58334dea8..b83a083ad5 100644 --- a/pallets/swap/rpc/src/lib.rs +++ b/pallets/swap/rpc/src/lib.rs @@ -13,14 +13,12 @@ use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use subtensor_runtime_common::{AlphaCurrency, NetUid, TaoCurrency}; -pub use pallet_subtensor_swap_runtime_api::{SubnetPrice, SwapRuntimeApi}; +pub use pallet_subtensor_swap_runtime_api::SwapRuntimeApi; #[rpc(client, server)] pub trait SwapRpcApi { #[method(name = "swap_currentAlphaPrice")] fn current_alpha_price(&self, netuid: NetUid, at: Option) -> RpcResult; - #[method(name = "swap_currentAlphaPriceAll")] - fn current_alpha_price_all(&self, at: Option) -> RpcResult>; #[method(name = "swap_simSwapTaoForAlpha")] fn sim_swap_tao_for_alpha( &self, @@ -94,18 +92,6 @@ where }) } - fn current_alpha_price_all( - &self, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.current_alpha_price_all(at).map_err(|e| { - Error::RuntimeError(format!("Unable to get all current alpha prices: {e:?}")).into() - }) - } - fn sim_swap_tao_for_alpha( &self, netuid: NetUid, diff --git a/pallets/swap/runtime-api/Cargo.toml b/pallets/swap/runtime-api/Cargo.toml index 50f92d19e2..042875fdd0 100644 --- a/pallets/swap/runtime-api/Cargo.toml +++ b/pallets/swap/runtime-api/Cargo.toml @@ -7,7 +7,6 @@ edition.workspace = true [dependencies] codec = { workspace = true, features = ["derive"] } frame-support.workspace = true -serde.workspace = true scale-info.workspace = true sp-api.workspace = true sp-std.workspace = true @@ -21,7 +20,6 @@ std = [ "codec/std", "frame-support/std", "scale-info/std", - "serde/std", "sp-api/std", "sp-std/std", "subtensor-runtime-common/std", diff --git a/pallets/swap/runtime-api/src/lib.rs b/pallets/swap/runtime-api/src/lib.rs index ce61a93dc6..01d2ccf23e 100644 --- a/pallets/swap/runtime-api/src/lib.rs +++ b/pallets/swap/runtime-api/src/lib.rs @@ -1,33 +1,21 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_prelude::*; -use scale_info::prelude::vec::Vec; -use serde::{Deserialize, Serialize}; use subtensor_macros::freeze_struct; use subtensor_runtime_common::{AlphaCurrency, NetUid, TaoCurrency}; -#[freeze_struct("ee2ba1ec4ee58ae6")] +#[freeze_struct("3a4fd213b5de5eb6")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] pub struct SimSwapResult { pub tao_amount: TaoCurrency, pub alpha_amount: AlphaCurrency, pub tao_fee: TaoCurrency, pub alpha_fee: AlphaCurrency, - pub tao_slippage: TaoCurrency, - pub alpha_slippage: AlphaCurrency, -} - -#[freeze_struct("d7bbb761fc2b2eac")] -#[derive(Decode, Deserialize, Encode, PartialEq, Eq, Clone, Debug, Serialize, TypeInfo)] -pub struct SubnetPrice { - pub netuid: NetUid, - pub price: u64, } sp_api::decl_runtime_apis! { pub trait SwapRuntimeApi { fn current_alpha_price(netuid: NetUid) -> u64; - fn current_alpha_price_all() -> Vec; fn sim_swap_tao_for_alpha(netuid: NetUid, tao: TaoCurrency) -> SimSwapResult; fn sim_swap_alpha_for_tao(netuid: NetUid, alpha: AlphaCurrency) -> SimSwapResult; } diff --git a/pallets/swap/src/benchmarking.rs b/pallets/swap/src/benchmarking.rs index c4a6afa87e..a17ac59141 100644 --- a/pallets/swap/src/benchmarking.rs +++ b/pallets/swap/src/benchmarking.rs @@ -2,16 +2,22 @@ #![allow(clippy::unwrap_used)] #![allow(clippy::multiple_bound_locations)] +use core::marker::PhantomData; + use frame_benchmarking::v2::*; +use frame_support::traits::Get; use frame_system::RawOrigin; +use substrate_fixed::types::{I64F64, U64F64}; use subtensor_runtime_common::NetUid; -use crate::pallet::{Call, Config, Pallet}; - -#[allow(dead_code)] -fn init_swap(netuid: NetUid) { - let _ = Pallet::::maybe_initialize_palswap(netuid, None); -} +use crate::{ + pallet::{ + AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, Pallet, Positions, + SwapV3Initialized, + }, + position::{Position, PositionId}, + tick::TickIndex, +}; #[benchmarks(where T: Config)] mod benchmarks { @@ -26,5 +32,117 @@ mod benchmarks { set_fee_rate(RawOrigin::Root, netuid, rate); } + // TODO: Revise when user liquidity is available + // #[benchmark] + // fn add_liquidity() { + // let netuid = NetUid::from(1); + + // if !SwapV3Initialized::::get(netuid) { + // SwapV3Initialized::::insert(netuid, true); + // AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); + // CurrentTick::::insert(netuid, TickIndex::new(0).unwrap()); + // CurrentLiquidity::::insert(netuid, T::MinimumLiquidity::get()); + // } + + // let caller: T::AccountId = whitelisted_caller(); + // let hotkey: T::AccountId = account("hotkey", 0, 0); + // let tick_low = TickIndex::new_unchecked(-1000); + // let tick_high = TickIndex::new_unchecked(1000); + + // #[extrinsic_call] + // add_liquidity( + // RawOrigin::Signed(caller), + // hotkey, + // netuid, + // tick_low, + // tick_high, + // 1000, + // ); + // } + + #[benchmark] + fn remove_liquidity() { + let netuid = NetUid::from(1); + + if !SwapV3Initialized::::get(netuid) { + SwapV3Initialized::::insert(netuid, true); + AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); + CurrentTick::::insert(netuid, TickIndex::new(0).unwrap()); + CurrentLiquidity::::insert(netuid, T::MinimumLiquidity::get()); + } + + let caller: T::AccountId = whitelisted_caller(); + let hotkey: T::AccountId = account("hotkey", 0, 0); + let id = PositionId::from(1u128); + + Positions::::insert( + (netuid, caller.clone(), id), + Position { + id, + netuid, + tick_low: TickIndex::new(-10000).unwrap(), + tick_high: TickIndex::new(10000).unwrap(), + liquidity: 1000, + fees_tao: I64F64::from_num(0), + fees_alpha: I64F64::from_num(0), + _phantom: PhantomData, + }, + ); + + #[extrinsic_call] + remove_liquidity(RawOrigin::Signed(caller), hotkey, netuid.into(), id.into()); + } + + #[benchmark] + fn modify_position() { + let netuid = NetUid::from(1); + + if !SwapV3Initialized::::get(netuid) { + SwapV3Initialized::::insert(netuid, true); + AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1)); + CurrentTick::::insert(netuid, TickIndex::new(0).unwrap()); + CurrentLiquidity::::insert(netuid, T::MinimumLiquidity::get()); + } + + let caller: T::AccountId = whitelisted_caller(); + let hotkey: T::AccountId = account("hotkey", 0, 0); + let id = PositionId::from(1u128); + + Positions::::insert( + (netuid, caller.clone(), id), + Position { + id, + netuid, + tick_low: TickIndex::new(-10000).unwrap(), + tick_high: TickIndex::new(10000).unwrap(), + liquidity: 10000, + fees_tao: I64F64::from_num(0), + fees_alpha: I64F64::from_num(0), + _phantom: PhantomData, + }, + ); + + #[extrinsic_call] + modify_position( + RawOrigin::Signed(caller), + hotkey, + netuid.into(), + id.into(), + -5000, + ); + } + + // #[benchmark] + // fn toggle_user_liquidity() { + // let netuid = NetUid::from(101); + + // assert!(!EnabledUserLiquidity::::get(netuid)); + + // #[extrinsic_call] + // toggle_user_liquidity(RawOrigin::Root, netuid.into(), true); + + // assert!(EnabledUserLiquidity::::get(netuid)); + // } + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/swap/src/lib.rs b/pallets/swap/src/lib.rs index b51c3351dc..6257df852b 100644 --- a/pallets/swap/src/lib.rs +++ b/pallets/swap/src/lib.rs @@ -1,6 +1,10 @@ #![cfg_attr(not(feature = "std"), no_std)] +use substrate_fixed::types::U64F64; + pub mod pallet; +pub mod position; +pub mod tick; pub mod weights; pub use pallet::*; @@ -10,3 +14,5 @@ pub mod benchmarking; #[cfg(test)] pub(crate) mod mock; + +type SqrtPrice = U64F64; diff --git a/pallets/swap/src/mock.rs b/pallets/swap/src/mock.rs index 3c5e424442..aacdf90835 100644 --- a/pallets/swap/src/mock.rs +++ b/pallets/swap/src/mock.rs @@ -14,18 +14,14 @@ use sp_runtime::{ BuildStorage, Vec, traits::{BlakeTwo256, IdentityLookup}, }; -use std::{cell::RefCell, collections::HashMap}; +use substrate_fixed::types::U64F64; use subtensor_runtime_common::{ - AlphaCurrency, - BalanceOps, - // Currency, - CurrencyReserve, - NetUid, - SubnetInfo, - TaoCurrency, + AlphaCurrency, BalanceOps, Currency, CurrencyReserve, NetUid, SubnetInfo, TaoCurrency, }; use subtensor_swap_interface::Order; +use crate::pallet::{EnabledUserLiquidity, FeeGlobalAlpha, FeeGlobalTao}; + construct_runtime!( pub enum Test { System: frame_system = 0, @@ -86,38 +82,16 @@ impl system::Config for Test { parameter_types! { pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap"); pub const MaxFeeRate: u16 = 10000; // 15.26% + pub const MaxPositions: u32 = 100; pub const MinimumLiquidity: u64 = 1_000; pub const MinimumReserves: NonZeroU64 = NonZeroU64::new(1).unwrap(); } -thread_local! { - // maps netuid -> mocked tao reserve - static MOCK_TAO_RESERVES: RefCell> = - RefCell::new(HashMap::new()); - // maps netuid -> mocked alpha reserve - static MOCK_ALPHA_RESERVES: RefCell> = - RefCell::new(HashMap::new()); -} - #[derive(Clone)] pub struct TaoReserve; -impl TaoReserve { - pub fn set_mock_reserve(netuid: NetUid, value: TaoCurrency) { - MOCK_TAO_RESERVES.with(|m| { - m.borrow_mut().insert(netuid, value); - }); - } -} - impl CurrencyReserve for TaoReserve { fn reserve(netuid: NetUid) -> TaoCurrency { - // If test has set an override, use it - if let Some(val) = MOCK_TAO_RESERVES.with(|m| m.borrow().get(&netuid).cloned()) { - return val; - } - - // Otherwise, fall back to our defaults match netuid.into() { 123u16 => 10_000, WRAPPING_FEES_NETUID => 100_000_000_000, @@ -133,22 +107,8 @@ impl CurrencyReserve for TaoReserve { #[derive(Clone)] pub struct AlphaReserve; -impl AlphaReserve { - pub fn set_mock_reserve(netuid: NetUid, value: AlphaCurrency) { - MOCK_ALPHA_RESERVES.with(|m| { - m.borrow_mut().insert(netuid, value); - }); - } -} - impl CurrencyReserve for AlphaReserve { fn reserve(netuid: NetUid) -> AlphaCurrency { - // If test has set an override, use it - if let Some(val) = MOCK_ALPHA_RESERVES.with(|m| m.borrow().get(&netuid).cloned()) { - return val; - } - - // Otherwise, fall back to our defaults match netuid.into() { 123u16 => 10_000.into(), WRAPPING_FEES_NETUID => 400_000_000_000.into(), @@ -163,7 +123,22 @@ impl CurrencyReserve for AlphaReserve { pub type GetAlphaForTao = subtensor_swap_interface::GetAlphaForTao; pub type GetTaoForAlpha = subtensor_swap_interface::GetTaoForAlpha; -#[allow(dead_code)] +pub(crate) trait GlobalFeeInfo: Currency { + fn global_fee(&self, netuid: NetUid) -> U64F64; +} + +impl GlobalFeeInfo for TaoCurrency { + fn global_fee(&self, netuid: NetUid) -> U64F64 { + FeeGlobalTao::::get(netuid) + } +} + +impl GlobalFeeInfo for AlphaCurrency { + fn global_fee(&self, netuid: NetUid) -> U64F64 { + FeeGlobalAlpha::::get(netuid) + } +} + pub(crate) trait TestExt { fn approx_expected_swap_output( sqrt_current_price: f64, @@ -302,6 +277,7 @@ impl crate::pallet::Config for Test { type BalanceOps = MockBalanceOps; type ProtocolId = SwapProtocolId; type MaxFeeRate = MaxFeeRate; + type MaxPositions = MaxPositions; type MinimumLiquidity = MinimumLiquidity; type MinimumReserve = MinimumReserves; type WeightInfo = (); @@ -316,6 +292,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut ext = sp_io::TestExternalities::new(storage); ext.execute_with(|| { System::set_block_number(1); + + for netuid in 0u16..=100 { + // enable V3 for this range of netuids + EnabledUserLiquidity::::set(NetUid::from(netuid), true); + } + EnabledUserLiquidity::::set(NetUid::from(WRAPPING_FEES_NETUID), true); }); ext } diff --git a/pallets/swap/src/pallet/balancer.rs b/pallets/swap/src/pallet/balancer.rs deleted file mode 100644 index 1e1386bd41..0000000000 --- a/pallets/swap/src/pallet/balancer.rs +++ /dev/null @@ -1,1095 +0,0 @@ -// Balancer swap -// -// Unlike uniswap v2 or v3, it allows adding liquidity disproportionally to price. This is -// achieved by introducing the weights w1 and w2 so that w1 + w2 = 1. In these formulas x -// means base currency (alpha) and y means quote currency (tao). The w1 weight in the code -// below is referred as weight_base, and w2 as weight_quote. Because of the w1 + w2 = 1 -// constraint, only weight_quote is stored, and weight_base is always calculated. -// -// The formulas used for pool operation are following: -// -// Price: p = (w1*y) / (w2*x) -// -// Reserve deltas / (or -1 * payouts) in swaps are computed by: -// -// if ∆x is given (sell) ∆y = y * ((x / (x+∆x))^(w1/w2) - 1) -// if ∆y is given (buy) ∆x = x * ((y / (y+∆y))^(w2/w1) - 1) -// -// When swaps are executing the orders with slippage control, we need to know what amount -// we can swap before the price reaches the limit value of p': -// -// If p' < p (sell): ∆x = x * ((p / p')^w2 - 1) -// If p' < p (buy): ∆y = y * ((p' / p)^w1 - 1) -// -// In order to initialize weights with existing reserve values and price: -// -// w1 = px / (px + y) -// w2 = y / (px + y) -// -// Weights are adjusted when some amounts are added to the reserves. This prevents price -// from changing. -// -// new_w1 = p * (x + ∆x) / (p * (x + ∆x) + y + ∆y) -// new_w2 = (y + ∆y) / (p * (x + ∆x) + y + ∆y) -// -// Weights are limited to stay within [0.1, 0.9] range to avoid precision issues in exponentiation. -// Practically, these limitations will not be achieved, but if they are, the swap will not allow injection -// that will push the weights out of this interval because we prefer chain and swap stability over success -// of a single injection. Currently, we only allow the protocol to inject disproportionally to price, and -// the amount of disproportion will not cause weigths to get far from 0.5. -// - -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::pallet_prelude::*; -use safe_bigmath::*; -use safe_math::*; -use sp_arithmetic::Perquintill; -use sp_core::U256; -use sp_runtime::Saturating; -use sp_std::ops::Neg; -use substrate_fixed::types::U64F64; -use subtensor_macros::freeze_struct; - -/// Balancer implements all high complexity math for swap operations such as: -/// - Swapping x for y, which includes limit orders -/// - Adding and removing liquidity (including unbalanced) -/// -/// Notation used in this file: -/// - x: Base reserve (alplha reserve) -/// - y: Quote reserve (tao reserve) -/// - ∆x: Alpha paid in/out -/// - ∆y: Tao paid in/out -/// - w1: Base weight (a.k.a weight_base) -/// - w2: Quote weight (a.k.a weight_quote) -#[freeze_struct("33a4fb0774da77c7")] -#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct Balancer { - quote: Perquintill, -} - -/// Accuracy matches to 18 decimal digits used to represent weights -pub const ACCURACY: u64 = 1_000_000_000_000_000_000_u64; -/// Lower imit of weights is 0.01 -pub const MIN_WEIGHT: Perquintill = Perquintill::from_parts(ACCURACY / 100); -/// 1.0 in Perquintill -pub const ONE: Perquintill = Perquintill::from_parts(ACCURACY); - -#[derive(Debug)] -pub enum BalancerError { - /// The provided weight value is out of range - InvalidValue, -} - -impl Default for Balancer { - /// The default value of weights is 0.5 for pool initialization - fn default() -> Self { - Self { - quote: Perquintill::from_rational(1u128, 2u128), - } - } -} - -impl Balancer { - /// Creates a new instance of balancer with a given quote weight - pub fn new(quote: Perquintill) -> Result { - if Self::check_constraints(quote) { - Ok(Balancer { quote }) - } else { - Err(BalancerError::InvalidValue) - } - } - - /// Constraints limit balancer weights within certain range of values: - /// - Both weights are above minimum - /// - Sum of weights is equal to 1.0 - fn check_constraints(quote: Perquintill) -> bool { - let base = ONE.saturating_sub(quote); - (base >= MIN_WEIGHT) && (quote >= MIN_WEIGHT) - } - - /// We store quote weight as Perquintill - pub fn get_quote_weight(&self) -> Perquintill { - self.quote - } - - /// Base weight is calculated as 1.0 - quote_weight - pub fn get_base_weight(&self) -> Perquintill { - ONE.saturating_sub(self.quote) - } - - /// Sets quote currency weight in the balancer. - /// Because sum of weights is always 1.0, there is no need to - /// store base currency weight - pub fn set_quote_weight(&mut self, new_value: Perquintill) -> Result<(), BalancerError> { - if Self::check_constraints(new_value) { - self.quote = new_value; - Ok(()) - } else { - Err(BalancerError::InvalidValue) - } - } - - /// If base_quote is true, calculate (x / (x + ∆x))^(weight_base / weight_quote), - /// otherwise, calculate (x / (x + ∆x))^(weight_quote / weight_base) - /// - /// Here we use SafeInt from bigmath crate for high-precision exponentiation, - /// which exposes the function pow_ratio_scaled. - /// - /// Note: ∆x may be negative - fn exp_scaled(&self, x: u64, dx: i128, base_quote: bool) -> U64F64 { - let x_plus_dx = if dx >= 0 { - x.saturating_add(dx as u64) - } else { - x.saturating_sub(dx.neg() as u64) - }; - - if x_plus_dx == 0 { - return U64F64::saturating_from_num(0); - } - let w1: u128 = self.get_base_weight().deconstruct() as u128; - let w2: u128 = self.get_quote_weight().deconstruct() as u128; - - let precision = 1024; - let x_safe = SafeInt::from(x); - let w1_safe = SafeInt::from(w1); - let w2_safe = SafeInt::from(w2); - let perquintill_scale = SafeInt::from(ACCURACY as u128); - let denominator = SafeInt::from(x_plus_dx); - log::debug!("x = {:?}", x); - log::debug!("dx = {:?}", dx); - log::debug!("x_safe = {:?}", x_safe); - log::debug!("denominator = {:?}", denominator); - log::debug!("w1_safe = {:?}", w1_safe); - log::debug!("w2_safe = {:?}", w2_safe); - log::debug!("precision = {:?}", precision); - log::debug!("perquintill_scale = {:?}", perquintill_scale); - - let maybe_result_safe_int = if base_quote { - SafeInt::pow_ratio_scaled( - &x_safe, - &denominator, - &w1_safe, - &w2_safe, - precision, - &perquintill_scale, - ) - } else { - SafeInt::pow_ratio_scaled( - &x_safe, - &denominator, - &w2_safe, - &w1_safe, - precision, - &perquintill_scale, - ) - }; - - if let Some(result_safe_int) = maybe_result_safe_int - && let Some(result_u64) = result_safe_int.to_u64() - { - return U64F64::saturating_from_num(result_u64) - .safe_div(U64F64::saturating_from_num(ACCURACY)); - } - U64F64::saturating_from_num(0) - } - - /// Calculates exponent of (x / (x + ∆x)) ^ (w_base/w_quote) - /// This method is used in sell swaps - /// (∆x is given by user, ∆y is paid out by the pool) - pub fn exp_base_quote(&self, x: u64, dx: u64) -> U64F64 { - self.exp_scaled(x, dx as i128, true) - } - - /// Calculates exponent of (y / (y + ∆y)) ^ (w_quote/w_base) - /// This method is used in buy swaps - /// (∆y is given by user, ∆x is paid out by the pool) - pub fn exp_quote_base(&self, y: u64, dy: u64) -> U64F64 { - self.exp_scaled(y, dy as i128, false) - } - - /// Calculates price as (w1/w2) * (y/x), where - /// - w1 is base weight - /// - w2 is quote weight - /// - x is base reserve - /// - y is quote reserve - pub fn calculate_price(&self, x: u64, y: u64) -> U64F64 { - let w2_fixed = U64F64::saturating_from_num(self.get_quote_weight().deconstruct()); - let w1_fixed = U64F64::saturating_from_num(self.get_base_weight().deconstruct()); - let x_fixed = U64F64::saturating_from_num(x); - let y_fixed = U64F64::saturating_from_num(y); - w1_fixed - .safe_div(w2_fixed) - .saturating_mul(y_fixed.safe_div(x_fixed)) - } - - /// Multiply a u128 value by a Perquintill with u128 result rounded to the - /// nearest integer - fn mul_perquintill_round(p: Perquintill, value: u128) -> u128 { - let parts = p.deconstruct() as u128; - let acc = ACCURACY as u128; - - let num = U256::from(value).saturating_mul(U256::from(parts)); - let den = U256::from(acc); - - // Add 0.5 before integer division to achieve rounding to the nearest - // integer - let zero = U256::from(0); - let res = num - .saturating_add(den.checked_div(U256::from(2u8)).unwrap_or(zero)) - .checked_div(den) - .unwrap_or(zero); - res.min(U256::from(u128::MAX)) - .try_into() - .unwrap_or_default() - } - - /// When liquidity is added to balancer swap, it may be added with arbitrary proportion, - /// not necessarily in the proportion of price, like with uniswap v2 or v3. In order to - /// stay within balancer pool invariant, the weights need to be updated. Invariant: - /// - /// L = x ^ weight_base * y ^ weight_quote - /// - /// Note that weights must remain within the proper range (both be above MIN_WEIGHT), - /// so only reasonably small disproportions of updates are appropriate. - pub fn update_weights_for_added_liquidity( - &mut self, - tao_reserve: u64, - alpha_reserve: u64, - tao_delta: u64, - alpha_delta: u64, - ) -> Result<(), BalancerError> { - // Calculate new to-be reserves (do not update here) - let tao_reserve_u128 = u64::from(tao_reserve) as u128; - let alpha_reserve_u128 = u64::from(alpha_reserve) as u128; - let tao_delta_u128 = u64::from(tao_delta) as u128; - let alpha_delta_u128 = u64::from(alpha_delta) as u128; - let new_tao_reserve_u128 = tao_reserve_u128.saturating_add(tao_delta_u128); - let new_alpha_reserve_u128 = alpha_reserve_u128.saturating_add(alpha_delta_u128); - - // Calculate new weights - let quantity_1: u128 = Self::mul_perquintill_round( - self.get_base_weight(), - tao_reserve_u128.saturating_mul(new_alpha_reserve_u128), - ); - let quantity_2: u128 = Self::mul_perquintill_round( - self.get_quote_weight(), - alpha_reserve_u128.saturating_mul(new_tao_reserve_u128), - ); - let q_sum = quantity_1.saturating_add(quantity_2); - - // Calculate new reserve weights - let new_reserve_weight = if q_sum != 0 { - // Both TAO and Alpha are non-zero, normal case - Perquintill::from_rational(quantity_2, q_sum) - } else { - // Either TAO or Alpha reserve were and/or remain zero => Initialize weights to 0.5 - Perquintill::from_rational(1u128, 2u128) - }; - - self.set_quote_weight(new_reserve_weight) - } - - /// Calculates quote delta needed to reach the price up when byuing - /// This method is needed for limit orders. - /// - /// Formula is: - /// ∆y = y * ((price_new / price)^weight_base - 1) - /// price_new >= price - pub fn calculate_quote_delta_in( - &self, - current_price: U64F64, - target_price: U64F64, - reserve: u64, - ) -> u64 { - let base_numerator: u128 = target_price.to_bits(); - let base_denominator: u128 = current_price.to_bits(); - let w1_fixed: u128 = self.get_base_weight().deconstruct() as u128; - let scale: u128 = 10u128.pow(18); - - let maybe_exp_result = SafeInt::pow_ratio_scaled( - &SafeInt::from(base_numerator), - &SafeInt::from(base_denominator), - &SafeInt::from(w1_fixed), - &SafeInt::from(ACCURACY), - 1024, - &SafeInt::from(scale), - ); - - if let Some(exp_result_safe_int) = maybe_exp_result { - let reserve_fixed = U64F64::saturating_from_num(reserve); - let one = U64F64::saturating_from_num(1); - let scale_fixed = U64F64::saturating_from_num(scale); - let exp_result_fixed = if let Some(exp_result_u64) = exp_result_safe_int.to_u64() { - U64F64::saturating_from_num(exp_result_u64) - } else if u64::MAX < exp_result_safe_int { - U64F64::saturating_from_num(u64::MAX) - } else { - U64F64::saturating_from_num(0) - }; - reserve_fixed - .saturating_mul(exp_result_fixed.safe_div(scale_fixed).saturating_sub(one)) - .saturating_to_num::() - } else { - 0u64 - } - } - - /// Calculates base delta needed to reach the price down when selling - /// This method is needed for limit orders. - /// - /// Formula is: - /// ∆x = x * ((price / price_new)^weight_quote - 1) - /// price_new <= price - pub fn calculate_base_delta_in( - &self, - current_price: U64F64, - target_price: U64F64, - reserve: u64, - ) -> u64 { - let base_numerator: u128 = current_price.to_bits(); - let base_denominator: u128 = target_price.to_bits(); - let w2_fixed: u128 = self.get_quote_weight().deconstruct() as u128; - let scale: u128 = 10u128.pow(18); - - let maybe_exp_result = SafeInt::pow_ratio_scaled( - &SafeInt::from(base_numerator), - &SafeInt::from(base_denominator), - &SafeInt::from(w2_fixed), - &SafeInt::from(ACCURACY), - 1024, - &SafeInt::from(scale), - ); - - if let Some(exp_result_safe_int) = maybe_exp_result { - let one = U64F64::saturating_from_num(1); - let scale_fixed = U64F64::saturating_from_num(scale); - let reserve_fixed = U64F64::saturating_from_num(reserve); - let exp_result_fixed = if let Some(exp_result_u64) = exp_result_safe_int.to_u64() { - U64F64::saturating_from_num(exp_result_u64) - } else if u64::MAX < exp_result_safe_int { - U64F64::saturating_from_num(u64::MAX) - } else { - U64F64::saturating_from_num(0) - }; - reserve_fixed - .saturating_mul(exp_result_fixed.safe_div(scale_fixed).saturating_sub(one)) - .saturating_to_num::() - } else { - 0u64 - } - } - - /// Calculates amount of Alpha that needs to be sold to get a given amount of TAO - pub fn get_base_needed_for_quote( - &self, - tao_reserve: u64, - alpha_reserve: u64, - delta_tao: u64, - ) -> u64 { - let e = self.exp_scaled(tao_reserve, (delta_tao as i128).neg(), false); - let one = U64F64::from_num(1); - let alpha_reserve_fixed = U64F64::from_num(alpha_reserve); - // e > 1 in this case - alpha_reserve_fixed - .saturating_mul(e.saturating_sub(one)) - .saturating_to_num::() - } -} - -// cargo test --package pallet-subtensor-swap --lib -- pallet::balancer::tests --nocapture -#[cfg(test)] -#[allow(clippy::expect_used, clippy::unwrap_used)] -#[cfg(feature = "std")] -mod tests { - use crate::pallet::Balancer; - use crate::pallet::balancer::*; - use approx::assert_abs_diff_eq; - use sp_arithmetic::Perquintill; - - // Helper: convert Perquintill to f64 for comparison - fn perquintill_to_f64(p: Perquintill) -> f64 { - let parts = p.deconstruct() as f64; - parts / ACCURACY as f64 - } - - // Helper: convert U64F64 to f64 for comparison - fn f(v: U64F64) -> f64 { - v.to_num::() - } - - #[test] - fn test_perquintill_power() { - const PRECISION: u32 = 4096; - const PERQUINTILL: u128 = ACCURACY as u128; - - let x = SafeInt::from(21_000_000_000_000_000u64); - let delta = SafeInt::from(7_000_000_000_000_000u64); - let w1 = SafeInt::from(600_000_000_000_000_000u128); - let w2 = SafeInt::from(400_000_000_000_000_000u128); - let denominator = &x + δ - assert_eq!(w1.clone() + w2.clone(), SafeInt::from(PERQUINTILL)); - - let perquintill_result = SafeInt::pow_ratio_scaled( - &x, - &denominator, - &w1, - &w2, - PRECISION, - &SafeInt::from(PERQUINTILL), - ) - .expect("perquintill integer result"); - - assert_eq!( - perquintill_result, - SafeInt::from(649_519_052_838_328_985u128) - ); - let readable = safe_bigmath::SafeDec::<18>::from_raw(perquintill_result); - assert_eq!(format!("{}", readable), "0.649519052838328985"); - } - - /// Validate realistic values that can be calculated with f64 precision - #[test] - fn test_exp_base_quote_happy_path() { - // Outer test cases: w_quote - [ - Perquintill::from_rational(500_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_000_000_001_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(499_999_999_999_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_000_000_100_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_000_001_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_000_010_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_000_100_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_001_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_010_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(500_100_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(501_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(510_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(100_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(100_000_000_001_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(200_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(300_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(400_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(600_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(700_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(800_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(899_999_999_999_u128, 1_000_000_000_000_u128), - Perquintill::from_rational(900_000_000_000_u128, 1_000_000_000_000_u128), - Perquintill::from_rational( - 102_337_248_363_782_924_u128, - 1_000_000_000_000_000_000_u128, - ), - ] - .into_iter() - .for_each(|w_quote| { - // Inner test cases: y, x, ∆x - [ - (1_000_u64, 1_000_u64, 0_u64), - (1_000_u64, 1_000_u64, 1_u64), - (1_500_u64, 1_000_u64, 1_u64), - ( - 1_000_000_000_000_u64, - 100_000_000_000_000_u64, - 100_000_000_u64, - ), - ( - 1_000_000_000_000_u64, - 100_000_000_000_000_u64, - 100_000_000_u64, - ), - ( - 100_000_000_000_u64, - 100_000_000_000_000_u64, - 100_000_000_u64, - ), - (100_000_000_000_u64, 100_000_000_000_000_u64, 1_000_000_u64), - ( - 100_000_000_000_u64, - 100_000_000_000_000_u64, - 1_000_000_000_000_u64, - ), - ( - 1_000_000_000_u64, - 100_000_000_000_000_u64, - 1_000_000_000_000_u64, - ), - ( - 1_000_000_u64, - 100_000_000_000_000_u64, - 1_000_000_000_000_u64, - ), - (1_000_u64, 100_000_000_000_000_u64, 1_000_000_000_000_u64), - (1_000_u64, 100_000_000_000_000_u64, 1_000_000_000_u64), - (1_000_u64, 100_000_000_000_000_u64, 1_000_000_u64), - (1_000_u64, 100_000_000_000_000_u64, 1_000_u64), - (1_000_u64, 100_000_000_000_000_u64, 100_000_000_000_000_u64), - (10_u64, 100_000_000_000_000_u64, 100_000_000_000_000_u64), - // Extreme values of ∆x for small x - (1_000_000_000_u64, 4_000_000_000_u64, 1_000_000_000_000_u64), - (1_000_000_000_000_u64, 1_000_u64, 1_000_000_000_000_u64), - ( - 5_628_038_062_729_553_u64, - 400_775_553_u64, - 14_446_633_907_665_582_u64, - ), - ( - 5_600_000_000_000_000_u64, - 400_000_000_u64, - 14_000_000_000_000_000_u64, - ), - ] - .into_iter() - .for_each(|(y, x, dx)| { - let bal = Balancer::new(w_quote).unwrap(); - let e1 = bal.exp_base_quote(x, dx); - let e2 = bal.exp_quote_base(x, dx); - let one = U64F64::from_num(1); - let y_fixed = U64F64::from_num(y); - let dy1 = y_fixed * (one - e1); - let dy2 = y_fixed * (one - e2); - - let w1 = perquintill_to_f64(bal.get_base_weight()); - let w2 = perquintill_to_f64(bal.get_quote_weight()); - let e1_expected = (x as f64 / (x as f64 + dx as f64)).powf(w1 / w2); - let dy1_expected = y as f64 * (1. - e1_expected); - let e2_expected = (x as f64 / (x as f64 + dx as f64)).powf(w2 / w1); - let dy2_expected = y as f64 * (1. - e2_expected); - - // Start tolerance with 0.001 rao - let mut eps1 = 0.001; - let mut eps2 = 0.001; - - // If swapping more than 100k tao/alpha, relax tolerance to 1.0 rao - if dy1_expected > 100_000_000_000_000_f64 { - eps1 = 1.0; - } - if dy2_expected > 100_000_000_000_000_f64 { - eps2 = 1.0; - } - assert_abs_diff_eq!(f(dy1), dy1_expected, epsilon = eps1); - assert_abs_diff_eq!(f(dy2), dy2_expected, epsilon = eps2); - }) - }); - } - - /// This test exercises practical application edge cases of exp_base_quote - /// The practical formula where this function is used: - /// ∆y = y * (exp_base_quote(x, ∆x) - 1) - /// - /// The test validates that two different sets of parameters produce (sensibly) - /// different results - /// - #[test] - fn test_exp_base_quote_dy_precision() { - // Test cases: y, x1, ∆x1, w_quote1, x2, ∆x2, w_quote2 - // Realized dy1 should be greater than dy2 - [ - ( - 1_000_000_000_u64, - 21_000_000_000_000_000_u64, - 21_000_000_000_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_000_u128), - 21_000_000_000_000_000_u64, - 21_000_000_000_u64, - Perquintill::from_rational(1_000_000_000_001_u128, 2_000_000_000_000_u128), - ), - ( - 1_000_000_000_u64, - 21_000_000_000_000_000_u64, - 21_000_000_000_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_001_u128), - 21_000_000_000_000_000_u64, - 21_000_000_000_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_000_u128), - ), - ( - 1_000_000_000_u64, - 21_000_000_000_000_000_u64, - 2_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_000_u128), - 21_000_000_000_000_000_u64, - 1_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_000_u128), - ), - ( - 1_000_000_000_u64, - 21_000_000_000_000_000_u64, - 1_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_000_u128), - 21_000_000_000_000_000_u64, - 1_u64, - Perquintill::from_rational(1_010_000_000_000_u128, 2_000_000_000_000_u128), - ), - ( - 1_000_000_000_u64, - 21_000_000_000_000_000_u64, - 1_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_010_000_000_000_u128), - 21_000_000_000_000_000_u64, - 1_u64, - Perquintill::from_rational(1_000_000_000_000_u128, 2_000_000_000_000_u128), - ), - ] - .into_iter() - .for_each(|(y, x1, dx1, w_quote1, x2, dx2, w_quote2)| { - let bal1 = Balancer::new(w_quote1).unwrap(); - let bal2 = Balancer::new(w_quote2).unwrap(); - - let exp1 = bal1.exp_base_quote(x1, dx1); - let exp2 = bal2.exp_base_quote(x2, dx2); - - let one = U64F64::from_num(1); - let y_fixed = U64F64::from_num(y); - let dy1 = y_fixed * (one - exp1); - let dy2 = y_fixed * (one - exp2); - - assert!(dy1 > dy2); - - let zero = U64F64::from_num(0); - assert!(dy1 != zero); - assert!(dy2 != zero); - }) - } - - /// Test the broad range of w_quote values, usually should be ignored - #[ignore] - #[test] - fn test_exp_quote_broad_range() { - let y = 1_000_000_000_000_u64; - let x = 100_000_000_000_000_u64; - let dx = 10_000_000_u64; - - let mut prev = U64F64::from_num(1_000_000_000); - let mut last_progress = 0.; - let start = 100_000_000_000_u128; - let stop = 900_000_000_000_u128; - for num in (start..=stop).step_by(1000_usize) { - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - let e = bal.exp_base_quote(x, dx); - - let one = U64F64::from_num(1); - let dy = U64F64::from_num(y) * (one - e); - - let progress = (num as f64 - start as f64) / (stop as f64 - start as f64); - if progress - last_progress >= 0.0001 { - // Replace with println for real-time progress - log::debug!("progress = {:?}%", progress * 100.); - log::debug!("dy = {:?}", dy); - last_progress = progress; - } - - assert!(dy != U64F64::from_num(0)); - assert!(dy <= prev); - prev = dy; - } - } - - #[ignore] - #[test] - fn test_exp_quote_fuzzy() { - use rand::rngs::StdRng; - use rand::{Rng, SeedableRng}; - use rayon::prelude::*; - use std::sync::Arc; - use std::sync::atomic::{AtomicUsize, Ordering}; - - const ITERATIONS: usize = 1_000_000_000; - let counter = Arc::new(AtomicUsize::new(0)); - - (0..ITERATIONS) - .into_par_iter() - .for_each(|i| { - // Each iteration gets its own deterministic RNG. - // Seed depends on i, so runs are reproducible. - let mut rng = StdRng::seed_from_u64(42 + i as u64); - let max_supply: u64 = 21_000_000_000_000_000; - let full_range = true; - - let x: u64 = rng.gen_range(1_000..=max_supply); // Alpha reserve - let y: u64 = if full_range { - // TAO reserve (allow huge prices) - rng.gen_range(1_000..=max_supply) - } else { - // TAO reserve (limit prices with 0-1000) - rng.gen_range(1_000..x.saturating_mul(1000).min(max_supply)) - }; - let dx: u64 = if full_range { - // Alhpa sold (allow huge values) - rng.gen_range(1_000..=21_000_000_000_000_000) - } else { - // Alhpa sold (do not sell more than 100% of what's in alpha reserve) - rng.gen_range(1_000..=x) - }; - let w_numerator: u64 = rng.gen_range(ACCURACY / 10..=ACCURACY / 10 * 9); - let w_quote = Perquintill::from_rational(w_numerator, ACCURACY); - - let bal = Balancer::new(w_quote).unwrap(); - let e = bal.exp_base_quote(x, dx); - - let one = U64F64::from_num(1); - let dy = U64F64::from_num(y) * (one - e); - - // Calculate expected in f64 and approx-assert - let w1 = perquintill_to_f64(bal.get_base_weight()); - let w2 = perquintill_to_f64(bal.get_quote_weight()); - let e_expected = (x as f64 / (x as f64 + dx as f64)).powf(w1 / w2); - let dy_expected = y as f64 * (1. - e_expected); - - let actual = dy.to_num::(); - let eps = (dy_expected / 1_000_000.).clamp(1.0, 1000.0); - - assert!( - (actual - dy_expected).abs() <= eps, - "dy mismatch:\n actual: {}\n expected: {}\n eps: {}\nParameters:\n x: {}\n y: {}\n dx: {}\n w_numerator: {}\n", - actual, dy_expected, eps, x, y, dx, w_numerator, - ); - - // Assert that we aren't giving out more than reserve y - assert!(dy <= y, "dy = {},\ny = {}", dy, y,); - - // Print progress - let done = counter.fetch_add(1, Ordering::Relaxed) + 1; - if done % 100_000_000 == 0 { - let progress = done as f64 / ITERATIONS as f64 * 100.0; - // Replace with println for real-time progress - log::debug!("progress = {progress:.4}%"); - } - }); - } - - #[test] - fn test_calculate_quote_delta_in() { - let num = 250_000_000_000_u128; // w1 = 0.75 - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - - let current_price: U64F64 = U64F64::from_num(0.1); - let target_price: U64F64 = U64F64::from_num(0.2); - let tao_reserve: u64 = 1_000_000_000; - - let dy = bal.calculate_quote_delta_in(current_price, target_price, tao_reserve); - - // ∆y = y•[(p'/p)^w1 - 1] - let dy_expected = tao_reserve as f64 - * ((target_price.to_num::() / current_price.to_num::()).powf(0.75) - 1.0); - - assert_eq!(dy, dy_expected as u64,); - } - - #[test] - fn test_calculate_base_delta_in() { - let num = 250_000_000_000_u128; // w2 = 0.25 - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - - let current_price: U64F64 = U64F64::from_num(0.2); - let target_price: U64F64 = U64F64::from_num(0.1); - let alpha_reserve: u64 = 1_000_000_000; - - let dx = bal.calculate_base_delta_in(current_price, target_price, alpha_reserve); - - // ∆x = x•[(p/p')^w2 - 1] - let dx_expected = alpha_reserve as f64 - * ((current_price.to_num::() / target_price.to_num::()).powf(0.25) - 1.0); - - assert_eq!(dx, dx_expected as u64,); - } - - #[test] - fn test_calculate_quote_delta_in_impossible() { - let num = 250_000_000_000_u128; // w1 = 0.75 - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - - // Impossible price (lower) - let current_price: U64F64 = U64F64::from_num(0.1); - let target_price: U64F64 = U64F64::from_num(0.05); - let tao_reserve: u64 = 1_000_000_000; - - let dy = bal.calculate_quote_delta_in(current_price, target_price, tao_reserve); - let dy_expected = 0u64; - - assert_eq!(dy, dy_expected); - } - - #[test] - fn test_calculate_base_delta_in_impossible() { - let num = 250_000_000_000_u128; // w2 = 0.25 - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - - // Impossible price (higher) - let current_price: U64F64 = U64F64::from_num(0.1); - let target_price: U64F64 = U64F64::from_num(0.2); - let alpha_reserve: u64 = 1_000_000_000; - - let dx = bal.calculate_base_delta_in(current_price, target_price, alpha_reserve); - let dx_expected = 0u64; - - assert_eq!(dx, dx_expected); - } - - #[test] - fn test_calculate_delta_in_reverse_swap() { - let num = 500_000_000_000_u128; - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - - let current_price: U64F64 = U64F64::from_num(0.1); - let target_price: U64F64 = U64F64::from_num(0.2); - let tao_reserve: u64 = 1_000_000_000; - - // Here is the simple case of w1 = w2 = 0.5, so alpha = tao / price - let alpha_reserve: u64 = (tao_reserve as f64 / current_price.to_num::()) as u64; - - let dy = bal.calculate_quote_delta_in(current_price, target_price, tao_reserve); - let dx = alpha_reserve as f64 - * (1.0 - - (tao_reserve as f64 / (tao_reserve as f64 + dy as f64)) - .powf(num as f64 / (1_000_000_000_000 - num) as f64)); - - // Verify that buying with dy will in fact bring the price to target_price - let actual_price = bal.calculate_price(alpha_reserve - dx as u64, tao_reserve + dy); - assert_abs_diff_eq!( - actual_price.to_num::(), - target_price.to_num::(), - epsilon = target_price.to_num::() / 1_000_000_000. - ); - } - - #[test] - fn test_mul_round_zero_and_one() { - let v = 1_000_000u128; - - // p = 0 -> always 0 - assert_eq!(Balancer::mul_perquintill_round(Perquintill::zero(), v), 0); - - // p = 1 -> identity - assert_eq!(Balancer::mul_perquintill_round(Perquintill::one(), v), v); - } - - #[test] - fn test_mul_round_half_behaviour() { - // p = 1/2 - let p = Perquintill::from_rational(1u128, 2u128); - - // Check rounding around .5 boundaries - // value * 1/2, rounded to nearest - assert_eq!(Balancer::mul_perquintill_round(p, 0), 0); // 0.0 -> 0 - assert_eq!(Balancer::mul_perquintill_round(p, 1), 1); // 0.5 -> 1 (round up) - assert_eq!(Balancer::mul_perquintill_round(p, 2), 1); // 1.0 -> 1 - assert_eq!(Balancer::mul_perquintill_round(p, 3), 2); // 1.5 -> 2 - assert_eq!(Balancer::mul_perquintill_round(p, 4), 2); // 2.0 -> 2 - assert_eq!(Balancer::mul_perquintill_round(p, 5), 3); // 2.5 -> 3 - assert_eq!(Balancer::mul_perquintill_round(p, 1023), 512); // 511.5 -> 512 - assert_eq!(Balancer::mul_perquintill_round(p, 1025), 513); // 512.5 -> 513 - } - - #[test] - fn test_mul_round_third_behaviour() { - // p = 1/3 - let p = Perquintill::from_rational(1u128, 3u128); - - // value * 1/3, rounded to nearest - assert_eq!(Balancer::mul_perquintill_round(p, 3), 1); // 1.0 -> 1 - assert_eq!(Balancer::mul_perquintill_round(p, 4), 1); // 1.333... -> 1 - assert_eq!(Balancer::mul_perquintill_round(p, 5), 2); // 1.666... -> 2 - assert_eq!(Balancer::mul_perquintill_round(p, 6), 2); // 2.0 -> 2 - } - - #[test] - fn test_mul_round_large_values_simple_rational() { - // p = 7/10 (exact in perquintill: 0.7) - let p = Perquintill::from_rational(7u128, 10u128); - let v: u128 = 1_000_000_000_000_000_000; - - let res = Balancer::mul_perquintill_round(p, v); - - // Expected = round(0.7 * v) with pure integer math: - // round(v * 7 / 10) = (v*7 + 10/2) / 10 - let expected = (v.saturating_mul(7) + 10 / 2) / 10; - - assert_eq!(res, expected); - } - - #[test] - fn test_mul_round_max_value_with_one() { - let v = u128::MAX; - let p = ONE; - - // For p = 1, result must be exactly value, and must not overflow - let res = Balancer::mul_perquintill_round(p, v); - assert_eq!(res, v); - } - - #[test] - fn test_price_with_equal_weights_is_y_over_x() { - // quote = 0.5, base = 0.5 -> w1 / w2 = 1, so price = y/x - let quote = Perquintill::from_rational(1u128, 2u128); - let bal = Balancer::new(quote).unwrap(); - - let x = 2u64; - let y = 5u64; - - let price = bal.calculate_price(x, y); - let price_f = f(price); - - let expected_f = (y as f64) / (x as f64); - assert_abs_diff_eq!(price_f, expected_f, epsilon = 1e-12); - } - - #[test] - fn test_price_scales_with_weight_ratio_two_to_one() { - // Assume base = 1 - quote. - // quote = 1/3 -> base = 2/3, so w1 / w2 = 2. - // Then price = 2 * (y/x). - let quote = Perquintill::from_rational(1u128, 3u128); - let bal = Balancer::new(quote).unwrap(); - - let x = 4u64; - let y = 10u64; - - let price_f = f(bal.calculate_price(x, y)); - let expected_f = 2.0 * (y as f64 / x as f64); - - assert_abs_diff_eq!(price_f, expected_f, epsilon = 1e-10); - } - - #[test] - fn test_price_is_zero_when_y_is_zero() { - // If y = 0, y/x = 0 so price must be 0 regardless of weights (for x > 0). - let quote = Perquintill::from_rational(3u128, 10u128); // 0.3 - let bal = Balancer::new(quote).unwrap(); - - let x = 10u64; - let y = 0u64; - - let price_f = f(bal.calculate_price(x, y)); - assert_abs_diff_eq!(price_f, 0.0, epsilon = 0.0); - } - - #[test] - fn test_price_invariant_when_scaling_x_and_y_with_equal_weights() { - // For equal weights, price(x, y) == price(kx, ky). - let quote = Perquintill::from_rational(1u128, 2u128); // 0.5 - let bal = Balancer::new(quote).unwrap(); - - let x1 = 3u64; - let y1 = 7u64; - let k = 10u64; - let x2 = x1 * k; - let y2 = y1 * k; - - let p1 = f(bal.calculate_price(x1, y1)); - let p2 = f(bal.calculate_price(x2, y2)); - - assert_abs_diff_eq!(p1, p2, epsilon = 1e-12); - } - - #[test] - fn test_price_matches_formula_for_general_quote() { - // General check: price = (w1 / w2) * (y/x), - // where w1 = base_weight, w2 = quote_weight. - // Here we assume get_base_weight = 1 - quote. - let quote = Perquintill::from_rational(2u128, 5u128); // 0.4 - let bal = Balancer::new(quote).unwrap(); - - let x = 9u64; - let y = 25u64; - - let price_f = f(bal.calculate_price(x, y)); - - let base = Perquintill::one() - quote; - let w1 = base.deconstruct() as f64; - let w2 = quote.deconstruct() as f64; - - let expected_f = (w1 / w2) * (y as f64 / x as f64); - assert_abs_diff_eq!(price_f, expected_f, epsilon = 1e-9); - } - - #[test] - fn test_price_high_values_non_equal_weights() { - // Non-equal weights, high x and y (up to 21e15) - let quote = Perquintill::from_rational(3u128, 10u128); // 0.3 - let bal = Balancer::new(quote).unwrap(); - - let x: u64 = 21_000_000_000_000_000; - let y: u64 = 15_000_000_000_000_000; - - let price = bal.calculate_price(x, y); - let price_f = f(price); - - // Expected: (w1 / w2) * (y / x), using Balancer's actual weights - let w1 = bal.get_base_weight().deconstruct() as f64; - let w2 = bal.get_quote_weight().deconstruct() as f64; - let expected_f = (w1 / w2) * (y as f64 / x as f64); - - assert_abs_diff_eq!(price_f, expected_f, epsilon = 1e-9); - } - - // cargo test --package pallet-subtensor-swap --lib -- pallet::balancer::tests::test_exp_scaled --exact --nocapture - #[test] - fn test_exp_scaled() { - [ - // base_weight_numerator, base_weight_denominator, reserve, d_reserve, base_quote - (5_u64, 10_u64, 100000_u64, 100_u64, true, 0.999000999000999), - (1_u64, 4_u64, 500000_u64, 5000_u64, true, 0.970590147927644), - (3_u64, 4_u64, 200000_u64, 2000_u64, false, 0.970590147927644), - ( - 9_u64, - 10_u64, - 13513642_u64, - 1673_u64, - false, - 0.998886481979889, - ), - ( - 773_u64, - 1000_u64, - 7_000_000_000_u64, - 10_000_u64, - true, - 0.999999580484586, - ), - ] - .into_iter() - .map(|v| { - ( - Perquintill::from_rational(v.0, v.1), - v.2, - v.3, - v.4, - U64F64::from_num(v.5), - ) - }) - .for_each(|(quote_weight, reserve, d_reserve, base_quote, expected)| { - let balancer = Balancer::new(quote_weight).unwrap(); - let result = balancer.exp_scaled(reserve, d_reserve as i128, base_quote); - assert_abs_diff_eq!( - result.to_num::(), - expected.to_num::(), - epsilon = 0.000000001 - ); - }); - } - - // cargo test --package pallet-subtensor-swap --lib -- pallet::balancer::tests::test_base_needed_for_quote --exact --nocapture - #[test] - fn test_base_needed_for_quote() { - let num = 250_000_000_000_u128; // w1 = 0.75 - let w_quote = Perquintill::from_rational(num, 1_000_000_000_000_u128); - let bal = Balancer::new(w_quote).unwrap(); - - let tao_reserve: u64 = 1_000_000_000; - let alpha_reserve: u64 = 1_000_000_000; - let tao_delta: u64 = 1_123_432; // typical fee range - - let dx = bal.get_base_needed_for_quote(tao_reserve, alpha_reserve, tao_delta); - - // ∆x = x•[(y/(y+∆y))^(w2/w1) - 1] - let dx_expected = tao_reserve as f64 - * ((tao_reserve as f64 / ((tao_reserve - tao_delta) as f64)).powf(0.25 / 0.75) - 1.0); - - assert_eq!(dx, dx_expected as u64,); - } -} diff --git a/pallets/swap/src/pallet/hooks.rs b/pallets/swap/src/pallet/hooks.rs deleted file mode 100644 index 90989d5f52..0000000000 --- a/pallets/swap/src/pallet/hooks.rs +++ /dev/null @@ -1,30 +0,0 @@ -use frame_support::pallet_macros::pallet_section; - -#[pallet_section] -mod hooks { - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(block_number: BlockNumberFor) -> Weight { - Weight::from_parts(0, 0) - } - - fn on_finalize(_block_number: BlockNumberFor) {} - - fn on_runtime_upgrade() -> Weight { - // --- Migrate storage - let mut weight = Weight::from_parts(0, 0); - - weight = weight - // Cleanup uniswap v3 and migrate to balancer - .saturating_add( - migrations::migrate_swapv3_to_balancer::migrate_swapv3_to_balancer::(), - ); - weight - } - - #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { - Ok(()) - } - } -} diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 54efabb19a..7ebb7ad78e 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -1,136 +1,215 @@ +use core::ops::Neg; + use frame_support::storage::{TransactionOutcome, transactional}; use frame_support::{ensure, pallet_prelude::DispatchError, traits::Get}; use safe_math::*; -use sp_arithmetic::{ - //helpers_128bit, - Perquintill, -}; -use sp_runtime::{DispatchResult, traits::AccountIdConversion}; -use substrate_fixed::types::U64F64; +use sp_arithmetic::helpers_128bit; +use sp_runtime::{DispatchResult, Vec, traits::AccountIdConversion}; +use substrate_fixed::types::{I64F64, U64F64, U96F32}; use subtensor_runtime_common::{ - AlphaCurrency, - // BalanceOps, - Currency, - CurrencyReserve, - NetUid, - SubnetInfo, - TaoCurrency, + AlphaCurrency, BalanceOps, Currency, CurrencyReserve, NetUid, SubnetInfo, TaoCurrency, }; use subtensor_swap_interface::{ DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult, }; use super::pallet::*; -use super::swap_step::{BasicSwapStep, SwapStep}; -use crate::{pallet::Balancer, pallet::balancer::BalancerError}; +use super::swap_step::{BasicSwapStep, SwapStep, SwapStepAction}; +use crate::{ + SqrtPrice, + position::{Position, PositionId}, + tick::{ActiveTickIndexManager, Tick, TickIndex}, +}; + +const MAX_SWAP_ITERATIONS: u16 = 1000; + +#[derive(Debug, PartialEq)] +pub struct UpdateLiquidityResult { + pub tao: TaoCurrency, + pub alpha: AlphaCurrency, + pub fee_tao: TaoCurrency, + pub fee_alpha: AlphaCurrency, + pub removed: bool, + pub tick_low: TickIndex, + pub tick_high: TickIndex, +} + +#[derive(Debug, PartialEq)] +pub struct RemoveLiquidityResult { + pub tao: TaoCurrency, + pub alpha: AlphaCurrency, + pub fee_tao: TaoCurrency, + pub fee_alpha: AlphaCurrency, + pub tick_low: TickIndex, + pub tick_high: TickIndex, + pub liquidity: u64, +} impl Pallet { - pub fn current_price(netuid: NetUid) -> U64F64 { + pub fn current_price(netuid: NetUid) -> U96F32 { match T::SubnetInfo::mechanism(netuid.into()) { 1 => { - let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - if !alpha_reserve.is_zero() { - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let balancer = SwapBalancer::::get(netuid); - balancer.calculate_price(alpha_reserve.into(), tao_reserve.into()) + if SwapV3Initialized::::get(netuid) { + let sqrt_price = AlphaSqrtPrice::::get(netuid); + U96F32::saturating_from_num(sqrt_price.saturating_mul(sqrt_price)) } else { - U64F64::saturating_from_num(0) + let tao_reserve = T::TaoReserve::reserve(netuid.into()); + let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); + if !alpha_reserve.is_zero() { + U96F32::saturating_from_num(tao_reserve) + .saturating_div(U96F32::saturating_from_num(alpha_reserve)) + } else { + U96F32::saturating_from_num(0) + } } } - _ => U64F64::saturating_from_num(1), + _ => U96F32::saturating_from_num(1), } } - // initializes pal-swap (balancer) for a subnet if needed - pub fn maybe_initialize_palswap( - netuid: NetUid, - maybe_price: Option, - ) -> Result<(), Error> { - if PalSwapInitialized::::get(netuid) { + // initializes V3 swap for a subnet if needed + pub fn maybe_initialize_v3(netuid: NetUid) -> Result<(), Error> { + if SwapV3Initialized::::get(netuid) { return Ok(()); } - // Query reserves + // Initialize the v3: + // Reserves are re-purposed, nothing to set, just query values for liquidity and price + // calculation let tao_reserve = T::TaoReserve::reserve(netuid.into()); let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - // Create balancer based on price - let balancer = Balancer::new(if let Some(price) = maybe_price { - // Price is given, calculate weights: - // w_quote = y / (px + y) - let px_high = (price.saturating_to_num::() as u128) - .saturating_mul(u64::from(alpha_reserve) as u128); - let px_low = U64F64::saturating_from_num(alpha_reserve) - .saturating_mul(price.frac()) - .saturating_to_num::(); - let px_plus_y = px_high - .saturating_add(px_low) - .saturating_add(u64::from(tao_reserve) as u128); - - // If price is given and both reserves are zero, the swap doesn't initialize - if px_plus_y == 0u128 { - return Err(Error::::ReservesOutOfBalance); - } - Perquintill::from_rational(u64::from(tao_reserve) as u128, px_plus_y) - } else { - // No price = insert 0.5 into SwapBalancer - Perquintill::from_rational(1_u64, 2_u64) - }) - .map_err(|err| match err { - BalancerError::InvalidValue => Error::::ReservesOutOfBalance, - })?; - SwapBalancer::::insert(netuid, balancer.clone()); + // Set price + let price = U64F64::saturating_from_num(tao_reserve) + .safe_div(U64F64::saturating_from_num(alpha_reserve)); + + let epsilon = U64F64::saturating_from_num(0.000000000001); - PalSwapInitialized::::insert(netuid, true); + let current_sqrt_price = price.checked_sqrt(epsilon).unwrap_or(U64F64::from_num(0)); + AlphaSqrtPrice::::set(netuid, current_sqrt_price); + + // Set current tick + let current_tick = TickIndex::from_sqrt_price_bounded(current_sqrt_price); + CurrentTick::::set(netuid, current_tick); + + // Set initial (protocol owned) liquidity and positions + // Protocol liquidity makes one position from TickIndex::MIN to TickIndex::MAX + // We are using the sp_arithmetic sqrt here, which works for u128 + let liquidity = helpers_128bit::sqrt( + (tao_reserve.to_u64() as u128).saturating_mul(alpha_reserve.to_u64() as u128), + ) as u64; + let protocol_account_id = Self::protocol_account_id(); + + let (position, _, _) = Self::add_liquidity_not_insert( + netuid, + &protocol_account_id, + TickIndex::MIN, + TickIndex::MAX, + liquidity, + )?; + + Positions::::insert(&(netuid, protocol_account_id, position.id), position); Ok(()) } + pub(crate) fn get_proportional_alpha_tao_and_remainders( + sqrt_alpha_price: U64F64, + amount_tao: TaoCurrency, + amount_alpha: AlphaCurrency, + ) -> (TaoCurrency, AlphaCurrency, TaoCurrency, AlphaCurrency) { + let price = sqrt_alpha_price.saturating_mul(sqrt_alpha_price); + let tao_equivalent: u64 = U64F64::saturating_from_num(u64::from(amount_alpha)) + .saturating_mul(price) + .saturating_to_num(); + let amount_tao_u64 = u64::from(amount_tao); + + if tao_equivalent <= amount_tao_u64 { + // Too much or just enough TAO + ( + tao_equivalent.into(), + amount_alpha, + amount_tao.saturating_sub(TaoCurrency::from(tao_equivalent)), + 0.into(), + ) + } else { + // Too much Alpha + let alpha_equivalent: u64 = U64F64::saturating_from_num(u64::from(amount_tao)) + .safe_div(price) + .saturating_to_num(); + ( + amount_tao, + alpha_equivalent.into(), + 0.into(), + u64::from(amount_alpha) + .saturating_sub(alpha_equivalent) + .into(), + ) + } + } + /// Adjusts protocol liquidity with new values of TAO and Alpha reserve - /// Returns actually added Tao and Alpha, which includes fees pub(super) fn adjust_protocol_liquidity( netuid: NetUid, tao_delta: TaoCurrency, alpha_delta: AlphaCurrency, - ) -> (TaoCurrency, AlphaCurrency) { - // Collect fees - let tao_fees = FeesTao::::get(netuid); - let alpha_fees = FeesAlpha::::get(netuid); - FeesTao::::insert(netuid, TaoCurrency::ZERO); - FeesAlpha::::insert(netuid, AlphaCurrency::ZERO); - let actual_tao_delta = tao_delta.saturating_add(tao_fees); - let actual_alpha_delta = alpha_delta.saturating_add(alpha_fees); - - // Get reserves - let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let mut balancer = SwapBalancer::::get(netuid); - - // Update weights and log errors if they go out of range - if balancer - .update_weights_for_added_liquidity( - u64::from(tao_reserve), - u64::from(alpha_reserve), - u64::from(actual_tao_delta), - u64::from(actual_alpha_delta), - ) - .is_err() - { - log::error!( - "Reserves are out of range for emission: netuid = {}, tao = {}, alpha = {}, tao_delta = {}, alpha_delta = {}", - netuid, - tao_reserve, - alpha_reserve, - actual_tao_delta, - actual_alpha_delta - ); - // Return fees back into fee storage and return zeroes - FeesTao::::insert(netuid, tao_fees); - FeesAlpha::::insert(netuid, alpha_fees); - (TaoCurrency::ZERO, AlphaCurrency::ZERO) - } else { - SwapBalancer::::insert(netuid, balancer); - (actual_tao_delta, actual_alpha_delta) + ) { + // Update protocol position with new liquidity + let protocol_account_id = Self::protocol_account_id(); + let mut positions = + Positions::::iter_prefix_values((netuid, protocol_account_id.clone())) + .collect::>(); + + if let Some(position) = positions.get_mut(0) { + // Claim protocol fees and add them to liquidity + let (tao_fees, alpha_fees) = position.collect_fees(); + + // Add fee reservoirs and get proportional amounts + let current_sqrt_price = AlphaSqrtPrice::::get(netuid); + let tao_reservoir = ScrapReservoirTao::::get(netuid); + let alpha_reservoir = ScrapReservoirAlpha::::get(netuid); + let (corrected_tao_delta, corrected_alpha_delta, tao_scrap, alpha_scrap) = + Self::get_proportional_alpha_tao_and_remainders( + current_sqrt_price, + tao_delta + .saturating_add(TaoCurrency::from(tao_fees)) + .saturating_add(tao_reservoir), + alpha_delta + .saturating_add(AlphaCurrency::from(alpha_fees)) + .saturating_add(alpha_reservoir), + ); + + // Update scrap reservoirs + ScrapReservoirTao::::insert(netuid, tao_scrap); + ScrapReservoirAlpha::::insert(netuid, alpha_scrap); + + // Adjust liquidity + let maybe_token_amounts = position.to_token_amounts(current_sqrt_price); + if let Ok((tao, alpha)) = maybe_token_amounts { + // Get updated reserves, calculate liquidity + let new_tao_reserve = tao.saturating_add(corrected_tao_delta.to_u64()); + let new_alpha_reserve = alpha.saturating_add(corrected_alpha_delta.to_u64()); + let new_liquidity = helpers_128bit::sqrt( + (new_tao_reserve as u128).saturating_mul(new_alpha_reserve as u128), + ) as u64; + let liquidity_delta = new_liquidity.saturating_sub(position.liquidity); + + // Update current liquidity + CurrentLiquidity::::mutate(netuid, |current_liquidity| { + *current_liquidity = current_liquidity.saturating_add(liquidity_delta); + }); + + // Update protocol position + position.liquidity = new_liquidity; + Positions::::insert( + (netuid, protocol_account_id, position.id), + position.clone(), + ); + + // Update position ticks + Self::add_liquidity_at_index(netuid, position.tick_low, liquidity_delta, false); + Self::add_liquidity_at_index(netuid, position.tick_high, liquidity_delta, true); + } } } @@ -161,7 +240,7 @@ impl Pallet { pub(crate) fn do_swap( netuid: NetUid, order: Order, - limit_price: U64F64, + limit_sqrt_price: SqrtPrice, drop_fees: bool, simulate: bool, ) -> Result, DispatchError> @@ -172,7 +251,7 @@ impl Pallet { transactional::with_transaction(|| { let reserve = Order::ReserveOut::reserve(netuid.into()); - let result = Self::swap_inner::(netuid, order, limit_price, drop_fees) + let result = Self::swap_inner::(netuid, order, limit_sqrt_price, drop_fees) .map_err(Into::into); if simulate || result.is_err() { @@ -198,7 +277,7 @@ impl Pallet { fn swap_inner( netuid: NetUid, order: Order, - limit_price: U64F64, + limit_sqrt_price: SqrtPrice, drop_fees: bool, ) -> Result, Error> where @@ -210,38 +289,70 @@ impl Pallet { Error::::ReservesTooLow ); - Self::maybe_initialize_palswap(netuid, None)?; + Self::maybe_initialize_v3(netuid)?; // Because user specifies the limit price, check that it is in fact beoynd the current one ensure!( - order.is_beyond_price_limit(Self::current_price(netuid), limit_price), + order.is_beyond_price_limit(AlphaSqrtPrice::::get(netuid), limit_sqrt_price), Error::::PriceLimitExceeded ); + let mut amount_remaining = order.amount(); + let mut amount_paid_out = Order::PaidOut::ZERO; + let mut iteration_counter: u16 = 0; + let mut in_acc = Order::PaidIn::ZERO; + let mut fee_acc = Order::PaidIn::ZERO; + log::trace!("======== Start Swap ========"); - let amount_to_swap = order.amount(); - log::trace!("Amount to swap: {amount_to_swap}"); + log::trace!("Amount Remaining: {amount_remaining}"); - // Create and execute a swap step - let mut swap_step = BasicSwapStep::::new( - netuid, - amount_to_swap, - limit_price, - drop_fees, - ); + // Swap one tick at a time until we reach one of the stop conditions + while !amount_remaining.is_zero() { + log::trace!("\nIteration: {iteration_counter}"); + log::trace!( + "\tCurrent Liquidity: {}", + CurrentLiquidity::::get(netuid) + ); + + // Create and execute a swap step + let mut swap_step = BasicSwapStep::::new( + netuid, + amount_remaining, + limit_sqrt_price, + drop_fees, + ); + + let swap_result = swap_step.execute()?; + + in_acc = in_acc.saturating_add(swap_result.delta_in); + fee_acc = fee_acc.saturating_add(swap_result.fee_paid); + amount_remaining = amount_remaining.saturating_sub(swap_result.amount_to_take); + amount_paid_out = amount_paid_out.saturating_add(swap_result.delta_out); - let swap_result = swap_step.execute()?; + if swap_step.action() == SwapStepAction::Stop { + amount_remaining = Order::PaidIn::ZERO; + } + + // The swap step didn't exchange anything + if swap_result.amount_to_take.is_zero() { + amount_remaining = Order::PaidIn::ZERO; + } + + iteration_counter = iteration_counter.saturating_add(1); + + ensure!( + iteration_counter <= MAX_SWAP_ITERATIONS, + Error::::TooManySwapSteps + ); + } - log::trace!("Delta out: {}", swap_result.delta_out); - log::trace!("Fees: {}", swap_result.fee_paid); - log::trace!("Fees for block author: {}", swap_result.fee_to_block_author); + log::trace!("\nAmount Paid Out: {amount_paid_out}"); log::trace!("======== End Swap ========"); Ok(SwapResult { - amount_paid_in: swap_result.delta_in, - amount_paid_out: swap_result.delta_out, - fee_paid: swap_result.fee_paid, - fee_to_block_author: swap_result.fee_to_block_author, + amount_paid_in: in_acc, + amount_paid_out, + fee_paid: fee_acc, }) } @@ -270,12 +381,425 @@ impl Pallet { } } - pub(crate) fn min_price_inner() -> C { - u64::from(1_000_u64).into() + pub fn find_closest_lower_active_tick(netuid: NetUid, index: TickIndex) -> Option { + ActiveTickIndexManager::::find_closest_lower(netuid, index) + .and_then(|ti| Ticks::::get(netuid, ti)) } - pub(crate) fn max_price_inner() -> C { - u64::from(1_000_000_000_000_000_u64).into() + pub fn find_closest_higher_active_tick(netuid: NetUid, index: TickIndex) -> Option { + ActiveTickIndexManager::::find_closest_higher(netuid, index) + .and_then(|ti| Ticks::::get(netuid, ti)) + } + + /// Here we subtract minimum safe liquidity from current liquidity to stay in the safe range + pub(crate) fn current_liquidity_safe(netuid: NetUid) -> U64F64 { + U64F64::saturating_from_num( + CurrentLiquidity::::get(netuid).saturating_sub(T::MinimumLiquidity::get()), + ) + } + + /// Adds liquidity to the specified price range. + /// + /// This function allows an account to provide liquidity to a given range of price ticks. The + /// amount of liquidity to be added can be determined using + /// [`get_tao_based_liquidity`] and [`get_alpha_based_liquidity`], which compute the required + /// liquidity based on TAO and Alpha balances for the current price tick. + /// + /// ### Behavior: + /// - If the `protocol` flag is **not set** (`false`), the function will attempt to + /// **withdraw balances** from the account using `state_ops.withdraw_balances()`. + /// - If the `protocol` flag is **set** (`true`), the liquidity is added without modifying balances. + /// - If swap V3 was not initialized before, updates the value in storage. + /// + /// ### Parameters: + /// - `coldkey_account_id`: A reference to the account coldkey that is providing liquidity. + /// - `hotkey_account_id`: A reference to the account hotkey that is providing liquidity. + /// - `tick_low`: The lower bound of the price tick range. + /// - `tick_high`: The upper bound of the price tick range. + /// - `liquidity`: The amount of liquidity to be added. + /// + /// ### Returns: + /// - `Ok((u64, u64))`: (tao, alpha) amounts at new position + /// - `Err(SwapError)`: If the operation fails due to insufficient balance, invalid tick range, + /// or other swap-related errors. + /// + /// ### Errors: + /// - [`SwapError::InsufficientBalance`] if the account does not have enough balance. + /// - [`SwapError::InvalidTickRange`] if `tick_low` is greater than or equal to `tick_high`. + /// - Other [`SwapError`] variants as applicable. + pub fn do_add_liquidity( + netuid: NetUid, + coldkey_account_id: &T::AccountId, + hotkey_account_id: &T::AccountId, + tick_low: TickIndex, + tick_high: TickIndex, + liquidity: u64, + ) -> Result<(PositionId, u64, u64), Error> { + ensure!( + EnabledUserLiquidity::::get(netuid), + Error::::UserLiquidityDisabled + ); + + let (position, tao, alpha) = Self::add_liquidity_not_insert( + netuid, + coldkey_account_id, + tick_low, + tick_high, + liquidity, + )?; + let position_id = position.id; + + ensure!( + T::BalanceOps::tao_balance(coldkey_account_id) >= TaoCurrency::from(tao) + && T::BalanceOps::alpha_balance( + netuid.into(), + coldkey_account_id, + hotkey_account_id + ) >= AlphaCurrency::from(alpha), + Error::::InsufficientBalance + ); + + // Small delta is not allowed + ensure!( + liquidity >= T::MinimumLiquidity::get(), + Error::::InvalidLiquidityValue + ); + + Positions::::insert(&(netuid, coldkey_account_id, position.id), position); + + Ok((position_id, tao, alpha)) + } + + // add liquidity without inserting position into storage (used privately for v3 intiialization). + // unlike Self::add_liquidity it also doesn't perform account's balance check. + // + // the public interface is [`Self::add_liquidity`] + fn add_liquidity_not_insert( + netuid: NetUid, + coldkey_account_id: &T::AccountId, + tick_low: TickIndex, + tick_high: TickIndex, + liquidity: u64, + ) -> Result<(Position, u64, u64), Error> { + ensure!( + Self::count_positions(netuid, coldkey_account_id) < T::MaxPositions::get() as usize, + Error::::MaxPositionsExceeded + ); + + // Ensure that tick_high is actually higher than tick_low + ensure!(tick_high > tick_low, Error::::InvalidTickRange); + + // Add liquidity at tick + Self::add_liquidity_at_index(netuid, tick_low, liquidity, false); + Self::add_liquidity_at_index(netuid, tick_high, liquidity, true); + + // Update current tick liquidity + let current_tick_index = TickIndex::current_bounded::(netuid); + Self::clamp_sqrt_price(netuid, current_tick_index); + + Self::update_liquidity_if_needed(netuid, tick_low, tick_high, liquidity as i128); + + // New position + let position_id = PositionId::new::(); + let position = Position::new(position_id, netuid, tick_low, tick_high, liquidity); + + let current_price_sqrt = AlphaSqrtPrice::::get(netuid); + let (tao, alpha) = position.to_token_amounts(current_price_sqrt)?; + + SwapV3Initialized::::set(netuid, true); + + Ok((position, tao, alpha)) + } + + /// Remove liquidity and credit balances back to (coldkey_account_id, hotkey_account_id) stake. + /// Removing is allowed even when user liquidity is enabled. + /// + /// Account ID and Position ID identify position in the storage map + pub fn do_remove_liquidity( + netuid: NetUid, + coldkey_account_id: &T::AccountId, + position_id: PositionId, + ) -> Result> { + let Some(mut position) = Positions::::get((netuid, coldkey_account_id, position_id)) + else { + return Err(Error::::LiquidityNotFound); + }; + + // Collect fees and get tao and alpha amounts + let (fee_tao, fee_alpha) = position.collect_fees(); + let current_price = AlphaSqrtPrice::::get(netuid); + let (tao, alpha) = position.to_token_amounts(current_price)?; + + // Update liquidity at position ticks + Self::remove_liquidity_at_index(netuid, position.tick_low, position.liquidity, false); + Self::remove_liquidity_at_index(netuid, position.tick_high, position.liquidity, true); + + // Update current tick liquidity + Self::update_liquidity_if_needed( + netuid, + position.tick_low, + position.tick_high, + (position.liquidity as i128).neg(), + ); + + // Remove user position + Positions::::remove((netuid, coldkey_account_id, position_id)); + + Ok(RemoveLiquidityResult { + tao: tao.into(), + alpha: alpha.into(), + fee_tao: fee_tao.into(), + fee_alpha: fee_alpha.into(), + tick_low: position.tick_low, + tick_high: position.tick_high, + liquidity: position.liquidity, + }) + } + + pub fn do_modify_position( + netuid: NetUid, + coldkey_account_id: &T::AccountId, + hotkey_account_id: &T::AccountId, + position_id: PositionId, + liquidity_delta: i64, + ) -> Result> { + ensure!( + EnabledUserLiquidity::::get(netuid), + Error::::UserLiquidityDisabled + ); + + // Find the position + let Some(mut position) = Positions::::get((netuid, coldkey_account_id, position_id)) + else { + return Err(Error::::LiquidityNotFound); + }; + + // Small delta is not allowed + ensure!( + liquidity_delta.abs() >= T::MinimumLiquidity::get() as i64, + Error::::InvalidLiquidityValue + ); + let mut delta_liquidity_abs = liquidity_delta.unsigned_abs(); + + // Determine the effective price for token calculations + let current_price_sqrt = AlphaSqrtPrice::::get(netuid); + let sqrt_pa: SqrtPrice = position + .tick_low + .try_to_sqrt_price() + .map_err(|_| Error::::InvalidTickRange)?; + let sqrt_pb: SqrtPrice = position + .tick_high + .try_to_sqrt_price() + .map_err(|_| Error::::InvalidTickRange)?; + let sqrt_price_box = if current_price_sqrt < sqrt_pa { + sqrt_pa + } else if current_price_sqrt > sqrt_pb { + sqrt_pb + } else { + // Update current liquidity if price is in range + let new_liquidity_curr = if liquidity_delta > 0 { + CurrentLiquidity::::get(netuid).saturating_add(delta_liquidity_abs) + } else { + CurrentLiquidity::::get(netuid).saturating_sub(delta_liquidity_abs) + }; + CurrentLiquidity::::set(netuid, new_liquidity_curr); + current_price_sqrt + }; + + // Calculate token amounts for the liquidity change + let mul = SqrtPrice::from_num(1) + .safe_div(sqrt_price_box) + .saturating_sub(SqrtPrice::from_num(1).safe_div(sqrt_pb)); + let alpha = SqrtPrice::saturating_from_num(delta_liquidity_abs).saturating_mul(mul); + let tao = SqrtPrice::saturating_from_num(delta_liquidity_abs) + .saturating_mul(sqrt_price_box.saturating_sub(sqrt_pa)); + + // Validate delta + if liquidity_delta > 0 { + // Check that user has enough balances + ensure!( + T::BalanceOps::tao_balance(coldkey_account_id) + >= TaoCurrency::from(tao.saturating_to_num::()) + && T::BalanceOps::alpha_balance(netuid, coldkey_account_id, hotkey_account_id) + >= AlphaCurrency::from(alpha.saturating_to_num::()), + Error::::InsufficientBalance + ); + } else { + // Check that position has enough liquidity + ensure!( + position.liquidity >= delta_liquidity_abs, + Error::::InsufficientLiquidity + ); + } + + // Collect fees + let (fee_tao, fee_alpha) = position.collect_fees(); + + // If delta brings the position liquidity below MinimumLiquidity, eliminate position and + // withdraw full amounts + let mut remove = false; + if (liquidity_delta < 0) + && (position.liquidity.saturating_sub(delta_liquidity_abs) < T::MinimumLiquidity::get()) + { + delta_liquidity_abs = position.liquidity; + remove = true; + } + + // Adjust liquidity at the ticks based on the delta sign + if liquidity_delta > 0 { + // Add liquidity at tick + Self::add_liquidity_at_index(netuid, position.tick_low, delta_liquidity_abs, false); + Self::add_liquidity_at_index(netuid, position.tick_high, delta_liquidity_abs, true); + + // Add liquidity to user position + position.liquidity = position.liquidity.saturating_add(delta_liquidity_abs); + } else { + // Remove liquidity at tick + Self::remove_liquidity_at_index(netuid, position.tick_low, delta_liquidity_abs, false); + Self::remove_liquidity_at_index(netuid, position.tick_high, delta_liquidity_abs, true); + + // Remove liquidity from user position + position.liquidity = position.liquidity.saturating_sub(delta_liquidity_abs); + } + + // Update or, in case if full liquidity is removed, remove the position + if remove { + Positions::::remove((netuid, coldkey_account_id, position_id)); + } else { + Positions::::insert(&(netuid, coldkey_account_id, position.id), position.clone()); + } + + Ok(UpdateLiquidityResult { + tao: tao.saturating_to_num::().into(), + alpha: alpha.saturating_to_num::().into(), + fee_tao: fee_tao.into(), + fee_alpha: fee_alpha.into(), + removed: remove, + tick_low: position.tick_low, + tick_high: position.tick_high, + }) + } + + /// Adds or updates liquidity at a specific tick index for a subnet + /// + /// # Arguments + /// * `netuid` - The subnet ID + /// * `tick_index` - The tick index to add liquidity to + /// * `liquidity` - The amount of liquidity to add + fn add_liquidity_at_index(netuid: NetUid, tick_index: TickIndex, liquidity: u64, upper: bool) { + // Convert liquidity to signed value, negating it for upper bounds + let net_liquidity_change = if upper { + (liquidity as i128).neg() + } else { + liquidity as i128 + }; + + Ticks::::mutate(netuid, tick_index, |maybe_tick| match maybe_tick { + Some(tick) => { + tick.liquidity_net = tick.liquidity_net.saturating_add(net_liquidity_change); + tick.liquidity_gross = tick.liquidity_gross.saturating_add(liquidity); + } + None => { + let current_tick = TickIndex::current_bounded::(netuid); + + let (fees_out_tao, fees_out_alpha) = if tick_index > current_tick { + ( + I64F64::saturating_from_num(FeeGlobalTao::::get(netuid)), + I64F64::saturating_from_num(FeeGlobalAlpha::::get(netuid)), + ) + } else { + ( + I64F64::saturating_from_num(0), + I64F64::saturating_from_num(0), + ) + }; + *maybe_tick = Some(Tick { + liquidity_net: net_liquidity_change, + liquidity_gross: liquidity, + fees_out_tao, + fees_out_alpha, + }); + } + }); + + // Update active ticks + ActiveTickIndexManager::::insert(netuid, tick_index); + } + + /// Remove liquidity at tick index. + fn remove_liquidity_at_index( + netuid: NetUid, + tick_index: TickIndex, + liquidity: u64, + upper: bool, + ) { + // Calculate net liquidity addition + let net_reduction = if upper { + (liquidity as i128).neg() + } else { + liquidity as i128 + }; + + Ticks::::mutate_exists(netuid, tick_index, |maybe_tick| { + if let Some(tick) = maybe_tick { + tick.liquidity_net = tick.liquidity_net.saturating_sub(net_reduction); + tick.liquidity_gross = tick.liquidity_gross.saturating_sub(liquidity); + + // If no liquidity is left at the tick, remove it + if tick.liquidity_gross == 0 { + *maybe_tick = None; + + // Update active ticks: Final liquidity is zero, remove this tick from active. + ActiveTickIndexManager::::remove(netuid, tick_index); + } + } + }); + } + + /// Updates the current liquidity for a subnet if the current tick index is within the specified + /// range + /// + /// This function handles both increasing and decreasing liquidity based on the sign of the + /// liquidity parameter. It uses i128 to safely handle values up to u64::MAX in both positive + /// and negative directions. + fn update_liquidity_if_needed( + netuid: NetUid, + tick_low: TickIndex, + tick_high: TickIndex, + liquidity: i128, + ) { + let current_tick_index = TickIndex::current_bounded::(netuid); + if (tick_low <= current_tick_index) && (current_tick_index < tick_high) { + CurrentLiquidity::::mutate(netuid, |current_liquidity| { + let is_neg = liquidity.is_negative(); + let liquidity = liquidity.abs().min(u64::MAX as i128) as u64; + if is_neg { + *current_liquidity = current_liquidity.saturating_sub(liquidity); + } else { + *current_liquidity = current_liquidity.saturating_add(liquidity); + } + }); + } + } + + /// Clamps the subnet's sqrt price when tick index is outside of valid bounds + fn clamp_sqrt_price(netuid: NetUid, tick_index: TickIndex) { + if tick_index >= TickIndex::MAX || tick_index <= TickIndex::MIN { + let corrected_price = tick_index.as_sqrt_price_bounded(); + AlphaSqrtPrice::::set(netuid, corrected_price); + } + } + + /// Returns the number of positions for an account in a specific subnet + /// + /// # Arguments + /// * `netuid` - The subnet ID + /// * `account_id` - The account ID + /// + /// # Returns + /// The number of positions that the account has in the specified subnet + pub(super) fn count_positions(netuid: NetUid, account_id: &T::AccountId) -> usize { + Positions::::iter_prefix_values((netuid, account_id.clone())).count() } /// Returns the protocol account ID @@ -286,22 +810,207 @@ impl Pallet { T::ProtocolId::get().into_account_truncating() } + pub(crate) fn min_price_inner() -> C { + TickIndex::min_sqrt_price() + .saturating_mul(TickIndex::min_sqrt_price()) + .saturating_mul(SqrtPrice::saturating_from_num(1_000_000_000)) + .saturating_to_num::() + .into() + } + + pub(crate) fn max_price_inner() -> C { + TickIndex::max_sqrt_price() + .saturating_mul(TickIndex::max_sqrt_price()) + .saturating_mul(SqrtPrice::saturating_from_num(1_000_000_000)) + .saturating_round() + .saturating_to_num::() + .into() + } + + /// Dissolve all LPs and clean state. + pub fn do_dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult { + if SwapV3Initialized::::get(netuid) { + // 1) Snapshot only *non‑protocol* positions: (owner, position_id). + struct CloseItem { + owner: A, + pos_id: PositionId, + } + let protocol_account = Self::protocol_account_id(); + + let mut to_close: sp_std::vec::Vec> = sp_std::vec::Vec::new(); + for ((owner, pos_id), _pos) in Positions::::iter_prefix((netuid,)) { + if owner != protocol_account { + to_close.push(CloseItem { owner, pos_id }); + } + } + + if to_close.is_empty() { + log::debug!( + "dissolve_all_lp: no user positions; netuid={netuid:?}, protocol liquidity untouched" + ); + return Ok(()); + } + + let mut user_refunded_tao = TaoCurrency::ZERO; + let mut user_staked_alpha = AlphaCurrency::ZERO; + + let trust: Vec = T::SubnetInfo::get_validator_trust(netuid.into()); + let permit: Vec = T::SubnetInfo::get_validator_permit(netuid.into()); + + // Helper: pick target validator uid, only among permitted validators, by highest trust. + let pick_target_uid = |trust: &Vec, permit: &Vec| -> Option { + let mut best_uid: Option = None; + let mut best_trust: u16 = 0; + for (i, (&t, &p)) in trust.iter().zip(permit.iter()).enumerate() { + if p && (best_uid.is_none() || t > best_trust) { + best_uid = Some(i); + best_trust = t; + } + } + best_uid.map(|i| i as u16) + }; + + for CloseItem { owner, pos_id } in to_close.into_iter() { + match Self::do_remove_liquidity(netuid, &owner, pos_id) { + Ok(rm) => { + // α withdrawn from the pool = principal + accrued fees + let alpha_total_from_pool: AlphaCurrency = + rm.alpha.saturating_add(rm.fee_alpha); + + // ---------------- USER: refund τ and convert α → stake ---------------- + + // 1) Refund τ principal directly. + let tao_total_from_pool: TaoCurrency = rm.tao.saturating_add(rm.fee_tao); + if tao_total_from_pool > TaoCurrency::ZERO { + T::BalanceOps::increase_balance(&owner, tao_total_from_pool); + user_refunded_tao = + user_refunded_tao.saturating_add(tao_total_from_pool); + T::TaoReserve::decrease_provided(netuid, tao_total_from_pool); + } + + // 2) Stake ALL withdrawn α (principal + fees) to the best permitted validator. + if alpha_total_from_pool > AlphaCurrency::ZERO { + if let Some(target_uid) = pick_target_uid(&trust, &permit) { + let validator_hotkey: T::AccountId = + T::SubnetInfo::hotkey_of_uid(netuid.into(), target_uid).ok_or( + sp_runtime::DispatchError::Other( + "validator_hotkey_missing", + ), + )?; + + // Stake α from LP owner (coldkey) to chosen validator (hotkey). + T::BalanceOps::increase_stake( + &owner, + &validator_hotkey, + netuid, + alpha_total_from_pool, + )?; + + user_staked_alpha = + user_staked_alpha.saturating_add(alpha_total_from_pool); + + log::debug!( + "dissolve_all_lp: user dissolved & staked α: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, α_staked={alpha_total_from_pool:?}, target_uid={target_uid}" + ); + } else { + // No permitted validators; burn to avoid balance drift. + log::debug!( + "dissolve_all_lp: no permitted validators; α burned: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, α_total={alpha_total_from_pool:?}" + ); + } + + T::AlphaReserve::decrease_provided(netuid, alpha_total_from_pool); + } + } + Err(e) => { + log::debug!( + "dissolve_all_lp: force-close failed: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, err={e:?}" + ); + continue; + } + } + } + + log::debug!( + "dissolve_all_liquidity_providers (users-only): netuid={netuid:?}, users_refunded_total_τ={user_refunded_tao:?}, users_staked_total_α={user_staked_alpha:?}; protocol liquidity untouched" + ); + + return Ok(()); + } + + log::debug!( + "dissolve_all_liquidity_providers: netuid={netuid:?}, mode=V2-or-nonV3, leaving all liquidity/state intact" + ); + + Ok(()) + } + /// Clear **protocol-owned** liquidity and wipe all swap state for `netuid`. pub fn do_clear_protocol_liquidity(netuid: NetUid) -> DispatchResult { - // let protocol_account = Self::protocol_account_id(); + let protocol_account = Self::protocol_account_id(); - // 1) Force-close protocol liquidity, burning proceeds. - let burned_tao = T::TaoReserve::reserve(netuid.into()); - let burned_alpha = T::AlphaReserve::reserve(netuid.into()); + // 1) Force-close only protocol positions, burning proceeds. + let mut burned_tao = TaoCurrency::ZERO; + let mut burned_alpha = AlphaCurrency::ZERO; - T::TaoReserve::decrease_provided(netuid.into(), burned_tao); - T::AlphaReserve::decrease_provided(netuid.into(), burned_alpha); + // Collect protocol position IDs first to avoid mutating while iterating. + let protocol_pos_ids: sp_std::vec::Vec = Positions::::iter_prefix((netuid,)) + .filter_map(|((owner, pos_id), _)| { + if owner == protocol_account { + Some(pos_id) + } else { + None + } + }) + .collect(); + + for pos_id in protocol_pos_ids { + match Self::do_remove_liquidity(netuid, &protocol_account, pos_id) { + Ok(rm) => { + let alpha_total_from_pool: AlphaCurrency = + rm.alpha.saturating_add(rm.fee_alpha); + let tao_total_from_pool: TaoCurrency = rm.tao.saturating_add(rm.fee_tao); + + if tao_total_from_pool > TaoCurrency::ZERO { + burned_tao = burned_tao.saturating_add(tao_total_from_pool); + } + if alpha_total_from_pool > AlphaCurrency::ZERO { + burned_alpha = burned_alpha.saturating_add(alpha_total_from_pool); + } + + log::debug!( + "clear_protocol_liquidity: burned protocol pos: netuid={netuid:?}, pos_id={pos_id:?}, τ={tao_total_from_pool:?}, α_total={alpha_total_from_pool:?}" + ); + } + Err(e) => { + log::debug!( + "clear_protocol_liquidity: force-close failed: netuid={netuid:?}, pos_id={pos_id:?}, err={e:?}" + ); + continue; + } + } + } - FeesTao::::remove(netuid); - FeesAlpha::::remove(netuid); - PalSwapInitialized::::remove(netuid); + // 2) Clear active tick index entries, then all swap state (idempotent even if empty/non‑V3). + let active_ticks: sp_std::vec::Vec = + Ticks::::iter_prefix(netuid).map(|(ti, _)| ti).collect(); + for ti in active_ticks { + ActiveTickIndexManager::::remove(netuid, ti); + } + + let _ = Positions::::clear_prefix((netuid,), u32::MAX, None); + let _ = Ticks::::clear_prefix(netuid, u32::MAX, None); + + FeeGlobalTao::::remove(netuid); + FeeGlobalAlpha::::remove(netuid); + CurrentLiquidity::::remove(netuid); + CurrentTick::::remove(netuid); + AlphaSqrtPrice::::remove(netuid); + SwapV3Initialized::::remove(netuid); + + let _ = TickIndexBitmapWords::::clear_prefix((netuid,), u32::MAX, None); FeeRate::::remove(netuid); - SwapBalancer::::remove(netuid); + EnabledUserLiquidity::::remove(netuid); log::debug!( "clear_protocol_liquidity: netuid={netuid:?}, protocol_burned: τ={burned_tao:?}, α={burned_alpha:?}; state cleared" @@ -337,13 +1046,15 @@ where drop_fees: bool, should_rollback: bool, ) -> Result, DispatchError> { - let limit_price = U64F64::saturating_from_num(price_limit.to_u64()) - .safe_div(U64F64::saturating_from_num(1_000_000_000_u64)); + let limit_sqrt_price = SqrtPrice::saturating_from_num(price_limit.to_u64()) + .safe_div(SqrtPrice::saturating_from_num(1_000_000_000)) + .checked_sqrt(SqrtPrice::saturating_from_num(0.0000000001)) + .ok_or(Error::::PriceLimitExceeded)?; Self::do_swap::( NetUid::from(netuid), order, - limit_price, + limit_sqrt_price, drop_fees, should_rollback, ) @@ -400,10 +1111,28 @@ impl SwapHandler for Pallet { Self::calculate_fee_amount(netuid, amount, false) } - fn current_alpha_price(netuid: NetUid) -> U64F64 { + fn current_alpha_price(netuid: NetUid) -> U96F32 { Self::current_price(netuid.into()) } + fn get_protocol_tao(netuid: NetUid) -> TaoCurrency { + let protocol_account_id = Self::protocol_account_id(); + let mut positions = + Positions::::iter_prefix_values((netuid, protocol_account_id.clone())) + .collect::>(); + + if let Some(position) = positions.get_mut(0) { + let current_sqrt_price = AlphaSqrtPrice::::get(netuid); + // Adjust liquidity + let maybe_token_amounts = position.to_token_amounts(current_sqrt_price); + if let Ok((tao, _)) = maybe_token_amounts { + return tao.into(); + } + } + + TaoCurrency::ZERO + } + fn min_price() -> C { Self::min_price_inner() } @@ -416,14 +1145,20 @@ impl SwapHandler for Pallet { netuid: NetUid, tao_delta: TaoCurrency, alpha_delta: AlphaCurrency, - ) -> (TaoCurrency, AlphaCurrency) { - Self::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta) + ) { + Self::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta); } + fn is_user_liquidity_enabled(netuid: NetUid) -> bool { + EnabledUserLiquidity::::get(netuid) + } + fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult { + Self::do_dissolve_all_liquidity_providers(netuid) + } + fn toggle_user_liquidity(netuid: NetUid, enabled: bool) { + EnabledUserLiquidity::::insert(netuid, enabled) + } fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult { Self::do_clear_protocol_liquidity(netuid) } - fn init_swap(netuid: NetUid, maybe_price: Option) { - Self::maybe_initialize_palswap(netuid, maybe_price).unwrap_or_default(); - } } diff --git a/pallets/swap/src/pallet/migrations/migrate_swapv3_to_balancer.rs b/pallets/swap/src/pallet/migrations/migrate_swapv3_to_balancer.rs deleted file mode 100644 index 147849e5a6..0000000000 --- a/pallets/swap/src/pallet/migrations/migrate_swapv3_to_balancer.rs +++ /dev/null @@ -1,81 +0,0 @@ -use super::*; -use crate::HasMigrationRun; -use frame_support::{storage_alias, traits::Get, weights::Weight}; -use scale_info::prelude::string::String; -use substrate_fixed::types::U64F64; - -pub mod deprecated_swap_maps { - use super::*; - - #[storage_alias] - pub type AlphaSqrtPrice = - StorageMap, Twox64Concat, NetUid, U64F64, ValueQuery>; - - /// TAO reservoir for scraps of protocol claimed fees. - #[storage_alias] - pub type ScrapReservoirTao = - StorageMap, Twox64Concat, NetUid, TaoCurrency, ValueQuery>; - - /// Alpha reservoir for scraps of protocol claimed fees. - #[storage_alias] - pub type ScrapReservoirAlpha = - StorageMap, Twox64Concat, NetUid, AlphaCurrency, ValueQuery>; -} - -pub fn migrate_swapv3_to_balancer() -> Weight { - let migration_name = BoundedVec::truncate_from(b"migrate_swapv3_to_balancer".to_vec()); - let mut weight = T::DbWeight::get().reads(1); - - if HasMigrationRun::::get(&migration_name) { - log::info!( - "Migration '{:?}' has already run. Skipping.", - String::from_utf8_lossy(&migration_name) - ); - return weight; - } - - log::info!( - "Running migration '{}'", - String::from_utf8_lossy(&migration_name), - ); - - // ------------------------------ - // Step 1: Initialize swaps with price before price removal - // ------------------------------ - for (netuid, price_sqrt) in deprecated_swap_maps::AlphaSqrtPrice::::iter() { - let price = price_sqrt.saturating_mul(price_sqrt); - crate::Pallet::::maybe_initialize_palswap(netuid, Some(price)).unwrap_or_default(); - } - - // ------------------------------ - // Step 2: Clear Map entries - // ------------------------------ - remove_prefix::("Swap", "AlphaSqrtPrice", &mut weight); - remove_prefix::("Swap", "CurrentTick", &mut weight); - remove_prefix::("Swap", "EnabledUserLiquidity", &mut weight); - remove_prefix::("Swap", "FeeGlobalTao", &mut weight); - remove_prefix::("Swap", "FeeGlobalAlpha", &mut weight); - remove_prefix::("Swap", "LastPositionId", &mut weight); - // Scrap reservoirs can be just cleaned because they are already included in reserves - remove_prefix::("Swap", "ScrapReservoirTao", &mut weight); - remove_prefix::("Swap", "ScrapReservoirAlpha", &mut weight); - remove_prefix::("Swap", "Ticks", &mut weight); - remove_prefix::("Swap", "TickIndexBitmapWords", &mut weight); - remove_prefix::("Swap", "SwapV3Initialized", &mut weight); - remove_prefix::("Swap", "CurrentLiquidity", &mut weight); - remove_prefix::("Swap", "Positions", &mut weight); - - // ------------------------------ - // Step 3: Mark Migration as Completed - // ------------------------------ - - HasMigrationRun::::insert(&migration_name, true); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); - - log::info!( - "Migration '{:?}' completed successfully.", - String::from_utf8_lossy(&migration_name) - ); - - weight -} diff --git a/pallets/swap/src/pallet/migrations/mod.rs b/pallets/swap/src/pallet/migrations/mod.rs deleted file mode 100644 index d34626f05e..0000000000 --- a/pallets/swap/src/pallet/migrations/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -use super::*; -use frame_support::pallet_prelude::Weight; -use sp_io::KillStorageResult; -use sp_io::hashing::twox_128; -use sp_io::storage::clear_prefix; -use sp_std::vec::Vec; - -pub mod migrate_swapv3_to_balancer; - -pub(crate) fn remove_prefix(module: &str, old_map: &str, weight: &mut Weight) { - let mut prefix = Vec::new(); - prefix.extend_from_slice(&twox_128(module.as_bytes())); - prefix.extend_from_slice(&twox_128(old_map.as_bytes())); - - let removal_results = clear_prefix(&prefix, Some(u32::MAX)); - let removed_entries_count = match removal_results { - KillStorageResult::AllRemoved(removed) => removed as u64, - KillStorageResult::SomeRemaining(removed) => { - log::info!("Failed To Remove Some Items During migration"); - removed as u64 - } - }; - - *weight = (*weight).saturating_add(T::DbWeight::get().writes(removed_entries_count)); -} diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 9fc4aca769..3a168cf753 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -1,33 +1,32 @@ use core::num::NonZeroU64; +use core::ops::Neg; use frame_support::{PalletId, pallet_prelude::*, traits::Get}; use frame_system::pallet_prelude::*; -use sp_arithmetic::Perbill; +use substrate_fixed::types::U64F64; use subtensor_runtime_common::{ - AlphaCurrency, BalanceOps, CurrencyReserve, NetUid, SubnetInfo, TaoCurrency, + AlphaCurrency, BalanceOps, Currency, CurrencyReserve, NetUid, SubnetInfo, TaoCurrency, +}; + +use crate::{ + position::{Position, PositionId}, + tick::{LayerLevel, Tick, TickIndex}, + weights::WeightInfo, }; -use crate::{pallet::balancer::Balancer, weights::WeightInfo}; pub use pallet::*; -use subtensor_macros::freeze_struct; -mod balancer; -mod hooks; mod impls; -pub mod migrations; mod swap_step; #[cfg(test)] mod tests; -// Define a maximum length for the migration key -type MigrationKeyMaxLen = ConstU32<128>; - #[allow(clippy::module_inception)] #[frame_support::pallet] #[allow(clippy::expect_used)] mod pallet { use super::*; - use frame_system::ensure_root; + use frame_system::{ensure_root, ensure_signed}; #[pallet::pallet] pub struct Pallet(_); @@ -57,6 +56,10 @@ mod pallet { #[pallet::constant] type MaxFeeRate: Get; + /// The maximum number of positions a user can have + #[pallet::constant] + type MaxPositions: Get; + /// Minimum liquidity that is safe for rounding and integer math. #[pallet::constant] type MinimumLiquidity: Get; @@ -86,41 +89,164 @@ mod pallet { #[pallet::storage] pub type FeeRate = StorageMap<_, Twox64Concat, NetUid, u16, ValueQuery, DefaultFeeRate>; - //////////////////////////////////////////////////// - // Balancer (PalSwap) maps and variables + // Global accrued fees in tao per subnet + #[pallet::storage] + pub type FeeGlobalTao = StorageMap<_, Twox64Concat, NetUid, U64F64, ValueQuery>; - /// Default reserve weight - #[pallet::type_value] - pub fn DefaultBalancer() -> Balancer { - Balancer::default() - } - /// u64-normalized reserve weight + // Global accrued fees in alpha per subnet + #[pallet::storage] + pub type FeeGlobalAlpha = StorageMap<_, Twox64Concat, NetUid, U64F64, ValueQuery>; + + /// Storage for all ticks, using subnet ID as the primary key and tick index as the secondary key #[pallet::storage] - pub type SwapBalancer = - StorageMap<_, Twox64Concat, NetUid, Balancer, ValueQuery, DefaultBalancer>; + pub type Ticks = StorageDoubleMap<_, Twox64Concat, NetUid, Twox64Concat, TickIndex, Tick>; - /// Storage to determine whether balancer swap was initialized for a specific subnet. + /// Storage to determine whether swap V3 was initialized for a specific subnet. #[pallet::storage] - pub type PalSwapInitialized = StorageMap<_, Twox64Concat, NetUid, bool, ValueQuery>; + pub type SwapV3Initialized = StorageMap<_, Twox64Concat, NetUid, bool, ValueQuery>; - /// Total fees in TAO per subnet due to be paid to users / protocol + /// Storage for the square root price of Alpha token for each subnet. + #[pallet::storage] + pub type AlphaSqrtPrice = StorageMap<_, Twox64Concat, NetUid, U64F64, ValueQuery>; + + /// Storage for the current price tick. + #[pallet::storage] + pub type CurrentTick = StorageMap<_, Twox64Concat, NetUid, TickIndex, ValueQuery>; + + /// Storage for the current liquidity amount for each subnet. + #[pallet::storage] + pub type CurrentLiquidity = StorageMap<_, Twox64Concat, NetUid, u64, ValueQuery>; + + /// Indicates whether a subnet has been switched to V3 swap from V2. + /// If `true`, the subnet is permanently on V3 swap mode allowing add/remove liquidity + /// operations. Once set to `true` for a subnet, it cannot be changed back to `false`. + #[pallet::storage] + pub type EnabledUserLiquidity = StorageMap<_, Twox64Concat, NetUid, bool, ValueQuery>; + + /// Storage for user positions, using subnet ID and account ID as keys + /// The value is a bounded vector of Position structs with details about the liquidity positions + #[pallet::storage] + pub type Positions = StorageNMap< + _, + ( + NMapKey, // Subnet ID + NMapKey, // Account ID + NMapKey, // Position ID + ), + Position, + OptionQuery, + >; + + /// Position ID counter. #[pallet::storage] - pub type FeesTao = StorageMap<_, Twox64Concat, NetUid, TaoCurrency, ValueQuery>; + pub type LastPositionId = StorageValue<_, u128, ValueQuery>; - /// Total fees in Alpha per subnet due to be paid to users / protocol + /// Tick index bitmap words storage #[pallet::storage] - pub type FeesAlpha = StorageMap<_, Twox64Concat, NetUid, AlphaCurrency, ValueQuery>; + pub type TickIndexBitmapWords = StorageNMap< + _, + ( + NMapKey, // Subnet ID + NMapKey, // Layer level + NMapKey, // word index + ), + u128, + ValueQuery, + >; + + /// TAO reservoir for scraps of protocol claimed fees. + #[pallet::storage] + pub type ScrapReservoirTao = StorageMap<_, Twox64Concat, NetUid, TaoCurrency, ValueQuery>; - /// --- Storage for migration run status + /// Alpha reservoir for scraps of protocol claimed fees. #[pallet::storage] - pub type HasMigrationRun = - StorageMap<_, Identity, BoundedVec, bool, ValueQuery>; + pub type ScrapReservoirAlpha = + StorageMap<_, Twox64Concat, NetUid, AlphaCurrency, ValueQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Event emitted when the fee rate has been updated for a subnet FeeRateSet { netuid: NetUid, rate: u16 }, + + /// Event emitted when user liquidity operations are enabled for a subnet. + /// First enable even indicates a switch from V2 to V3 swap. + UserLiquidityToggled { netuid: NetUid, enable: bool }, + + /// Event emitted when a liquidity position is added to a subnet's liquidity pool. + LiquidityAdded { + /// The coldkey account that owns the position + coldkey: T::AccountId, + /// The hotkey account where Alpha comes from + hotkey: T::AccountId, + /// The subnet identifier + netuid: NetUid, + /// Unique identifier for the liquidity position + position_id: PositionId, + /// The amount of liquidity added to the position + liquidity: u64, + /// The amount of TAO tokens committed to the position + tao: TaoCurrency, + /// The amount of Alpha tokens committed to the position + alpha: AlphaCurrency, + /// the lower tick + tick_low: TickIndex, + /// the upper tick + tick_high: TickIndex, + }, + + /// Event emitted when a liquidity position is removed from a subnet's liquidity pool. + LiquidityRemoved { + /// The coldkey account that owns the position + coldkey: T::AccountId, + /// The hotkey account where Alpha goes to + hotkey: T::AccountId, + /// The subnet identifier + netuid: NetUid, + /// Unique identifier for the liquidity position + position_id: PositionId, + /// The amount of liquidity removed from the position + liquidity: u64, + /// The amount of TAO tokens returned to the user + tao: TaoCurrency, + /// The amount of Alpha tokens returned to the user + alpha: AlphaCurrency, + /// The amount of TAO fees earned from the position + fee_tao: TaoCurrency, + /// The amount of Alpha fees earned from the position + fee_alpha: AlphaCurrency, + /// the lower tick + tick_low: TickIndex, + /// the upper tick + tick_high: TickIndex, + }, + + /// Event emitted when a liquidity position is modified in a subnet's liquidity pool. + /// Modifying causes the fees to be claimed. + LiquidityModified { + /// The coldkey account that owns the position + coldkey: T::AccountId, + /// The hotkey account where Alpha comes from or goes to + hotkey: T::AccountId, + /// The subnet identifier + netuid: NetUid, + /// Unique identifier for the liquidity position + position_id: PositionId, + /// The amount of liquidity added to or removed from the position + liquidity: i64, + /// The amount of TAO tokens returned to the user + tao: i64, + /// The amount of Alpha tokens returned to the user + alpha: i64, + /// The amount of TAO fees earned from the position + fee_tao: TaoCurrency, + /// The amount of Alpha fees earned from the position + fee_alpha: AlphaCurrency, + /// the lower tick + tick_low: TickIndex, + /// the upper tick + tick_high: TickIndex, + }, } #[pallet::error] @@ -141,9 +267,18 @@ mod pallet { /// The caller does not have enough balance for the operation. InsufficientBalance, + /// Attempted to remove liquidity that does not exist. + LiquidityNotFound, + /// The provided tick range is invalid. InvalidTickRange, + /// Maximum user positions exceeded + MaxPositionsExceeded, + + /// Too many swap steps + TooManySwapSteps, + /// Provided liquidity parameter is invalid (likely too small) InvalidLiquidityValue, @@ -153,14 +288,11 @@ mod pallet { /// The subnet does not exist. MechanismDoesNotExist, + /// User liquidity operations are disabled for this subnet + UserLiquidityDisabled, + /// The subnet does not have subtoken enabled SubtokenDisabled, - - /// Swap reserves are too imbalanced - ReservesOutOfBalance, - - /// The extrinsic is deprecated - Deprecated, } #[pallet::call] @@ -191,103 +323,315 @@ mod pallet { Ok(()) } - /// DEPRECATED + /// Enable user liquidity operations for a specific subnet. This switches the + /// subnet from V2 to V3 swap mode. Thereafter, adding new user liquidity can be disabled + /// by toggling this flag to false, but the swap mode will remain V3 because of existing + /// user liquidity until all users withdraw their liquidity. + /// + /// Only sudo or subnet owner can enable user liquidity. + /// Only sudo can disable user liquidity. #[pallet::call_index(4)] - #[pallet::weight(Weight::from_parts(15_000_000, 0))] - #[deprecated(note = "Deprecated, user liquidity is permanently disabled")] + #[pallet::weight(::WeightInfo::toggle_user_liquidity())] pub fn toggle_user_liquidity( - _origin: OriginFor, - _netuid: NetUid, - _enable: bool, + origin: OriginFor, + netuid: NetUid, + enable: bool, ) -> DispatchResult { - Err(Error::::Deprecated.into()) + if ensure_root(origin.clone()).is_err() { + let account_id: T::AccountId = ensure_signed(origin)?; + // Only enabling is allowed to subnet owner + ensure!( + T::SubnetInfo::is_owner(&account_id, netuid.into()) && enable, + DispatchError::BadOrigin + ); + } + + ensure!( + T::SubnetInfo::exists(netuid.into()), + Error::::MechanismDoesNotExist + ); + + // EnabledUserLiquidity::::insert(netuid, enable); + + // Self::deposit_event(Event::UserLiquidityToggled { netuid, enable }); + + Ok(()) } - /// DEPRECATED + /// Add liquidity to a specific price range for a subnet. + /// + /// Parameters: + /// - origin: The origin of the transaction + /// - netuid: Subnet ID + /// - tick_low: Lower bound of the price range + /// - tick_high: Upper bound of the price range + /// - liquidity: Amount of liquidity to add + /// + /// Emits `Event::LiquidityAdded` on success #[pallet::call_index(1)] - #[pallet::weight(Weight::from_parts(15_000_000, 0))] - #[deprecated(note = "Deprecated, user liquidity is permanently disabled")] + #[pallet::weight(::WeightInfo::add_liquidity())] pub fn add_liquidity( - _origin: OriginFor, + origin: OriginFor, _hotkey: T::AccountId, _netuid: NetUid, _tick_low: TickIndex, _tick_high: TickIndex, _liquidity: u64, ) -> DispatchResult { - Err(Error::::Deprecated.into()) + ensure_signed(origin)?; + + // Extrinsic should have no effect. This fix may have to be reverted later, + // so leaving the code in for now. + + // // Ensure that the subnet exists. + // ensure!( + // T::SubnetInfo::exists(netuid.into()), + // Error::::MechanismDoesNotExist + // ); + + // ensure!( + // T::SubnetInfo::is_subtoken_enabled(netuid.into()), + // Error::::SubtokenDisabled + // ); + + // let (position_id, tao, alpha) = Self::do_add_liquidity( + // netuid.into(), + // &coldkey, + // &hotkey, + // tick_low, + // tick_high, + // liquidity, + // )?; + // let alpha = AlphaCurrency::from(alpha); + // let tao = TaoCurrency::from(tao); + + // // Remove TAO and Alpha balances or fail transaction if they can't be removed exactly + // let tao_provided = T::BalanceOps::decrease_balance(&coldkey, tao)?; + // ensure!(tao_provided == tao, Error::::InsufficientBalance); + + // let alpha_provided = + // T::BalanceOps::decrease_stake(&coldkey, &hotkey, netuid.into(), alpha)?; + // ensure!(alpha_provided == alpha, Error::::InsufficientBalance); + + // // Add provided liquidity to user-provided reserves + // T::TaoReserve::increase_provided(netuid.into(), tao_provided); + // T::AlphaReserve::increase_provided(netuid.into(), alpha_provided); + + // // Emit an event + // Self::deposit_event(Event::LiquidityAdded { + // coldkey, + // hotkey, + // netuid, + // position_id, + // liquidity, + // tao, + // alpha, + // tick_low, + // tick_high, + // }); + + // Ok(()) + + Err(Error::::UserLiquidityDisabled.into()) } - /// DEPRECATED + /// Remove liquidity from a specific position. + /// + /// Parameters: + /// - origin: The origin of the transaction + /// - netuid: Subnet ID + /// - position_id: ID of the position to remove + /// + /// Emits `Event::LiquidityRemoved` on success #[pallet::call_index(2)] - #[pallet::weight(Weight::from_parts(15_000_000, 0))] - #[deprecated(note = "Deprecated, user liquidity is permanently disabled")] + #[pallet::weight(::WeightInfo::remove_liquidity())] pub fn remove_liquidity( - _origin: OriginFor, - _hotkey: T::AccountId, - _netuid: NetUid, - _position_id: PositionId, + origin: OriginFor, + hotkey: T::AccountId, + netuid: NetUid, + position_id: PositionId, ) -> DispatchResult { - Err(Error::::Deprecated.into()) + let coldkey = ensure_signed(origin)?; + + // Ensure that the subnet exists. + ensure!( + T::SubnetInfo::exists(netuid.into()), + Error::::MechanismDoesNotExist + ); + + // Remove liquidity + let result = Self::do_remove_liquidity(netuid, &coldkey, position_id)?; + + // Credit the returned tao and alpha to the account + T::BalanceOps::increase_balance(&coldkey, result.tao.saturating_add(result.fee_tao)); + T::BalanceOps::increase_stake( + &coldkey, + &hotkey, + netuid.into(), + result.alpha.saturating_add(result.fee_alpha), + )?; + + // Remove withdrawn liquidity from user-provided reserves + T::TaoReserve::decrease_provided(netuid.into(), result.tao); + T::AlphaReserve::decrease_provided(netuid.into(), result.alpha); + + // Emit an event + Self::deposit_event(Event::LiquidityRemoved { + coldkey, + hotkey, + netuid: netuid.into(), + position_id, + liquidity: result.liquidity, + tao: result.tao, + alpha: result.alpha, + fee_tao: result.fee_tao, + fee_alpha: result.fee_alpha, + tick_low: result.tick_low.into(), + tick_high: result.tick_high.into(), + }); + + Ok(()) } - /// DEPRECATED + /// Modify a liquidity position. + /// + /// Parameters: + /// - origin: The origin of the transaction + /// - netuid: Subnet ID + /// - position_id: ID of the position to remove + /// - liquidity_delta: Liquidity to add (if positive) or remove (if negative) + /// + /// Emits `Event::LiquidityRemoved` on success #[pallet::call_index(3)] - #[pallet::weight(Weight::from_parts(15_000_000, 0))] - #[deprecated(note = "Deprecated, user liquidity is permanently disabled")] + #[pallet::weight(::WeightInfo::modify_position())] pub fn modify_position( - _origin: OriginFor, - _hotkey: T::AccountId, - _netuid: NetUid, - _position_id: PositionId, - _liquidity_delta: i64, + origin: OriginFor, + hotkey: T::AccountId, + netuid: NetUid, + position_id: PositionId, + liquidity_delta: i64, ) -> DispatchResult { - Err(Error::::Deprecated.into()) + let coldkey = ensure_signed(origin)?; + + // Ensure that the subnet exists. + ensure!( + T::SubnetInfo::exists(netuid.into()), + Error::::MechanismDoesNotExist + ); + + ensure!( + T::SubnetInfo::is_subtoken_enabled(netuid.into()), + Error::::SubtokenDisabled + ); + + // Add or remove liquidity + let result = + Self::do_modify_position(netuid, &coldkey, &hotkey, position_id, liquidity_delta)?; + + if liquidity_delta > 0 { + // Remove TAO and Alpha balances or fail transaction if they can't be removed exactly + let tao_provided = T::BalanceOps::decrease_balance(&coldkey, result.tao)?; + ensure!(tao_provided == result.tao, Error::::InsufficientBalance); + + let alpha_provided = + T::BalanceOps::decrease_stake(&coldkey, &hotkey, netuid.into(), result.alpha)?; + ensure!( + alpha_provided == result.alpha, + Error::::InsufficientBalance + ); + + // Emit an event + Self::deposit_event(Event::LiquidityModified { + coldkey: coldkey.clone(), + hotkey: hotkey.clone(), + netuid, + position_id, + liquidity: liquidity_delta, + tao: result.tao.to_u64() as i64, + alpha: result.alpha.to_u64() as i64, + fee_tao: result.fee_tao, + fee_alpha: result.fee_alpha, + tick_low: result.tick_low, + tick_high: result.tick_high, + }); + } else { + // Credit the returned tao and alpha to the account + T::BalanceOps::increase_balance(&coldkey, result.tao); + T::BalanceOps::increase_stake(&coldkey, &hotkey, netuid.into(), result.alpha)?; + + // Emit an event + if result.removed { + Self::deposit_event(Event::LiquidityRemoved { + coldkey: coldkey.clone(), + hotkey: hotkey.clone(), + netuid, + position_id, + liquidity: liquidity_delta.unsigned_abs(), + tao: result.tao, + alpha: result.alpha, + fee_tao: result.fee_tao, + fee_alpha: result.fee_alpha, + tick_low: result.tick_low, + tick_high: result.tick_high, + }); + } else { + Self::deposit_event(Event::LiquidityModified { + coldkey: coldkey.clone(), + hotkey: hotkey.clone(), + netuid, + position_id, + liquidity: liquidity_delta, + tao: (result.tao.to_u64() as i64).neg(), + alpha: (result.alpha.to_u64() as i64).neg(), + fee_tao: result.fee_tao, + fee_alpha: result.fee_alpha, + tick_low: result.tick_low, + tick_high: result.tick_high, + }); + } + } + + // Credit accrued fees to user account (no matter if liquidity is added or removed) + if result.fee_tao > TaoCurrency::ZERO { + T::BalanceOps::increase_balance(&coldkey, result.fee_tao); + } + if !result.fee_alpha.is_zero() { + T::BalanceOps::increase_stake( + &coldkey, + &hotkey.clone(), + netuid.into(), + result.fee_alpha, + )?; + } + + Ok(()) } - /// DEPRECATED + /// Disable user liquidity in all subnets. + /// + /// Emits `Event::UserLiquidityToggled` on success #[pallet::call_index(5)] - #[pallet::weight(Weight::from_parts(15_000_000, 0))] - #[deprecated(note = "Deprecated, user liquidity is permanently disabled")] - pub fn disable_lp(_origin: OriginFor) -> DispatchResult { - Err(Error::::Deprecated.into()) + #[pallet::weight(::WeightInfo::modify_position())] + pub fn disable_lp(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + + for netuid in 1..=128 { + let netuid = NetUid::from(netuid as u16); + if EnabledUserLiquidity::::get(netuid) { + EnabledUserLiquidity::::insert(netuid, false); + Self::deposit_event(Event::UserLiquidityToggled { + netuid, + enable: false, + }); + } + + // Remove provided liquidity unconditionally because the network may have + // user liquidity previously disabled + // Ignore result to avoid early stopping + let _ = Self::do_dissolve_all_liquidity_providers(netuid); + } + + Ok(()) } } } - -/// Struct representing a tick index, DEPRECATED -#[freeze_struct("7c280c2b3bbbb33e")] -#[derive( - Debug, - Default, - Clone, - Copy, - Decode, - Encode, - DecodeWithMemTracking, - TypeInfo, - MaxEncodedLen, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, -)] -pub struct TickIndex(i32); - -/// Struct representing a liquidity position ID, DEPRECATED -#[freeze_struct("e695cd6455c3f0cb")] -#[derive( - Clone, - Copy, - Decode, - DecodeWithMemTracking, - Default, - Encode, - Eq, - MaxEncodedLen, - PartialEq, - RuntimeDebug, - TypeInfo, -)] -pub struct PositionId(u128); diff --git a/pallets/swap/src/pallet/swap_step.rs b/pallets/swap/src/pallet/swap_step.rs index a161238300..4cae4cb987 100644 --- a/pallets/swap/src/pallet/swap_step.rs +++ b/pallets/swap/src/pallet/swap_step.rs @@ -1,12 +1,14 @@ use core::marker::PhantomData; -use frame_support::ensure; use safe_math::*; -use sp_core::Get; -use substrate_fixed::types::U64F64; -use subtensor_runtime_common::{AlphaCurrency, Currency, CurrencyReserve, NetUid, TaoCurrency}; +use substrate_fixed::types::{I64F64, U64F64}; +use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, TaoCurrency}; use super::pallet::*; +use crate::{ + SqrtPrice, + tick::{ActiveTickIndexManager, TickIndex}, +}; /// A struct representing a single swap step with all its parameters and state pub(crate) struct BasicSwapStep @@ -18,16 +20,22 @@ where // Input parameters netuid: NetUid, drop_fees: bool, - requested_delta_in: PaidIn, - limit_price: U64F64, - // Intermediate calculations - target_price: U64F64, - current_price: U64F64, + // Computed values + current_liquidity: U64F64, + possible_delta_in: PaidIn, + + // Ticks and prices (current, limit, edge, target) + target_sqrt_price: SqrtPrice, + limit_sqrt_price: SqrtPrice, + current_sqrt_price: SqrtPrice, + edge_sqrt_price: SqrtPrice, + edge_tick: TickIndex, // Result values + action: SwapStepAction, delta_in: PaidIn, - final_price: U64F64, + final_price: SqrtPrice, fee: PaidIn, _phantom: PhantomData<(T, PaidIn, PaidOut)>, @@ -44,25 +52,36 @@ where pub(crate) fn new( netuid: NetUid, amount_remaining: PaidIn, - limit_price: U64F64, + limit_sqrt_price: SqrtPrice, drop_fees: bool, ) -> Self { + // Calculate prices and ticks + let current_tick = CurrentTick::::get(netuid); + let current_sqrt_price = AlphaSqrtPrice::::get(netuid); + let edge_tick = Self::tick_edge(netuid, current_tick); + let edge_sqrt_price = edge_tick.as_sqrt_price_bounded(); + let fee = Pallet::::calculate_fee_amount(netuid, amount_remaining, drop_fees); - let requested_delta_in = amount_remaining.saturating_sub(fee); + let possible_delta_in = amount_remaining.saturating_sub(fee); - // Target and current prices - let target_price = Self::price_target(netuid, requested_delta_in); - let current_price = Pallet::::current_price(netuid); + // Target price and quantities + let current_liquidity = U64F64::saturating_from_num(CurrentLiquidity::::get(netuid)); + let target_sqrt_price = + Self::sqrt_price_target(current_liquidity, current_sqrt_price, possible_delta_in); Self { netuid, drop_fees, - requested_delta_in, - limit_price, - target_price, - current_price, + target_sqrt_price, + limit_sqrt_price, + current_sqrt_price, + edge_sqrt_price, + edge_tick, + possible_delta_in, + current_liquidity, + action: SwapStepAction::Stop, delta_in: PaidIn::ZERO, - final_price: target_price, + final_price: target_sqrt_price, fee, _phantom: PhantomData, } @@ -79,25 +98,64 @@ where let mut recalculate_fee = false; // Calculate the stopping price: The price at which we either reach the limit price, - // or exchange the full amount. - if Self::price_is_closer(&self.target_price, &self.limit_price) { - // Case 1. target_quantity is the lowest, execute in full - self.final_price = self.target_price; - self.delta_in = self.requested_delta_in; - } else { + // exchange the full amount, or reach the edge price. + if Self::price_is_closer(&self.target_sqrt_price, &self.limit_sqrt_price) + && Self::price_is_closer(&self.target_sqrt_price, &self.edge_sqrt_price) + { + // Case 1. target_quantity is the lowest + // The trade completely happens within one tick, no tick crossing happens. + self.action = SwapStepAction::Stop; + self.final_price = self.target_sqrt_price; + self.delta_in = self.possible_delta_in; + } else if Self::price_is_closer(&self.limit_sqrt_price, &self.target_sqrt_price) + && Self::price_is_closer(&self.limit_sqrt_price, &self.edge_sqrt_price) + { // Case 2. lim_quantity is the lowest - self.final_price = self.limit_price; - self.delta_in = Self::delta_in(self.netuid, self.current_price, self.limit_price); + // The trade also completely happens within one tick, no tick crossing happens. + self.action = SwapStepAction::Stop; + self.final_price = self.limit_sqrt_price; + self.delta_in = Self::delta_in( + self.current_liquidity, + self.current_sqrt_price, + self.limit_sqrt_price, + ); + recalculate_fee = true; + } else { + // Case 3. edge_quantity is the lowest + // Tick crossing is likely + self.action = SwapStepAction::Crossing; + self.delta_in = Self::delta_in( + self.current_liquidity, + self.current_sqrt_price, + self.edge_sqrt_price, + ); + self.final_price = self.edge_sqrt_price; recalculate_fee = true; } - log::trace!("\tCurrent Price : {}", self.current_price); - log::trace!("\tTarget Price : {}", self.target_price); - log::trace!("\tLimit Price : {}", self.limit_price); + log::trace!("\tAction : {:?}", self.action); + log::trace!( + "\tCurrent Price : {}", + self.current_sqrt_price + .saturating_mul(self.current_sqrt_price) + ); + log::trace!( + "\tTarget Price : {}", + self.target_sqrt_price + .saturating_mul(self.target_sqrt_price) + ); + log::trace!( + "\tLimit Price : {}", + self.limit_sqrt_price.saturating_mul(self.limit_sqrt_price) + ); + log::trace!( + "\tEdge Price : {}", + self.edge_sqrt_price.saturating_mul(self.edge_sqrt_price) + ); log::trace!("\tDelta In : {}", self.delta_in); // Because on step creation we calculate fee off the total amount, we might need to - // recalculate it in case if we hit the limit price. + // recalculate it in case if we hit the limit price or the edge price. if recalculate_fee { let u16_max = U64F64::saturating_from_num(u16::MAX); let fee_rate = if self.drop_fees { @@ -111,13 +169,23 @@ where .saturating_to_num::() .into(); } + + // Now correct the action if we stopped exactly at the edge no matter what was the case + // above. Because order type buy moves the price up and tick semi-open interval doesn't + // include its right point, we cross on buys and stop on sells. + let natural_reason_stop_price = + if Self::price_is_closer(&self.limit_sqrt_price, &self.target_sqrt_price) { + self.limit_sqrt_price + } else { + self.target_sqrt_price + }; + if natural_reason_stop_price == self.edge_sqrt_price { + self.action = Self::action_on_edge_sqrt_price(); + } } /// Process a single step of a swap fn process_swap(&self) -> Result, Error> { - // Convert amounts, actual swap happens here - let delta_out = Self::convert_deltas(self.netuid, self.delta_in); - log::trace!("\tDelta Out : {delta_out}"); let mut fee_to_block_author = 0.into(); if self.delta_in > 0.into() { ensure!(delta_out > 0.into(), Error::::ReservesTooLow); @@ -130,112 +198,316 @@ where // ``` let fee_split = DefaultFeeSplit::get(); let lp_fee = fee_split.mul_floor(self.fee.to_u64()).into(); - Self::add_fees(self.netuid, lp_fee); + + // Hold the reserve portion of fees + if !lp_fee.is_zero() { + Self::add_fees( + self.netuid, + Pallet::::current_liquidity_safe(self.netuid), + lp_fee, + ); + } + fee_to_block_author = self.fee.saturating_sub(lp_fee); } + let delta_out = Self::convert_deltas(self.netuid, self.delta_in); + log::trace!("\tDelta Out : {delta_out}"); + + if self.action == SwapStepAction::Crossing { + let mut tick = Ticks::::get(self.netuid, self.edge_tick).unwrap_or_default(); + tick.fees_out_tao = I64F64::saturating_from_num(FeeGlobalTao::::get(self.netuid)) + .saturating_sub(tick.fees_out_tao); + tick.fees_out_alpha = + I64F64::saturating_from_num(FeeGlobalAlpha::::get(self.netuid)) + .saturating_sub(tick.fees_out_alpha); + Self::update_liquidity_at_crossing(self.netuid)?; + Ticks::::insert(self.netuid, self.edge_tick, tick); + } + + // Update current price + AlphaSqrtPrice::::set(self.netuid, self.final_price); + + // Update current tick + let new_current_tick = TickIndex::from_sqrt_price_bounded(self.final_price); + CurrentTick::::set(self.netuid, new_current_tick); + Ok(SwapStepResult { + amount_to_take: self.delta_in.saturating_add(self.fee), fee_paid: self.fee, delta_in: self.delta_in, delta_out, fee_to_block_author, }) } + + pub(crate) fn action(&self) -> SwapStepAction { + self.action + } } impl SwapStep for BasicSwapStep { - fn delta_in(netuid: NetUid, price_curr: U64F64, price_target: U64F64) -> TaoCurrency { - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let balancer = SwapBalancer::::get(netuid); - TaoCurrency::from(balancer.calculate_quote_delta_in( - price_curr, - price_target, - tao_reserve.into(), - )) + fn delta_in( + liquidity_curr: U64F64, + sqrt_price_curr: SqrtPrice, + sqrt_price_target: SqrtPrice, + ) -> TaoCurrency { + liquidity_curr + .saturating_mul(sqrt_price_target.saturating_sub(sqrt_price_curr)) + .saturating_to_num::() + .into() } - fn price_target(netuid: NetUid, delta_in: TaoCurrency) -> U64F64 { - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - let balancer = SwapBalancer::::get(netuid); - let dy = delta_in; - let dx = Self::convert_deltas(netuid, dy); - balancer.calculate_price( - u64::from(alpha_reserve.saturating_sub(dx)), - u64::from(tao_reserve.saturating_add(dy)), + fn tick_edge(netuid: NetUid, current_tick: TickIndex) -> TickIndex { + ActiveTickIndexManager::::find_closest_higher( + netuid, + current_tick.next().unwrap_or(TickIndex::MAX), ) + .unwrap_or(TickIndex::MAX) + } + + fn sqrt_price_target( + liquidity_curr: U64F64, + sqrt_price_curr: SqrtPrice, + delta_in: TaoCurrency, + ) -> SqrtPrice { + let delta_fixed = U64F64::saturating_from_num(delta_in); + + // No liquidity means that price should go to the limit + if liquidity_curr == 0 { + return SqrtPrice::saturating_from_num( + Pallet::::max_price_inner::().to_u64(), + ); + } + + delta_fixed + .safe_div(liquidity_curr) + .saturating_add(sqrt_price_curr) } - fn price_is_closer(price1: &U64F64, price2: &U64F64) -> bool { - price1 <= price2 + fn price_is_closer(sq_price1: &SqrtPrice, sq_price2: &SqrtPrice) -> bool { + sq_price1 <= sq_price2 } - fn add_fees(netuid: NetUid, fee: TaoCurrency) { - FeesTao::::mutate(netuid, |total| *total = total.saturating_add(fee)) + fn action_on_edge_sqrt_price() -> SwapStepAction { + SwapStepAction::Crossing + } + + fn add_fees(netuid: NetUid, current_liquidity: U64F64, fee: TaoCurrency) { + if current_liquidity == 0 { + return; + } + + let fee_fixed = U64F64::saturating_from_num(fee.to_u64()); + + FeeGlobalTao::::mutate(netuid, |value| { + *value = value.saturating_add(fee_fixed.safe_div(current_liquidity)) + }); } fn convert_deltas(netuid: NetUid, delta_in: TaoCurrency) -> AlphaCurrency { - let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let balancer = SwapBalancer::::get(netuid); - let e = balancer.exp_quote_base(tao_reserve.into(), delta_in.into()); - let one = U64F64::from_num(1); - let alpha_reserve_fixed = U64F64::from_num(alpha_reserve); - AlphaCurrency::from( - alpha_reserve_fixed - .saturating_mul(one.saturating_sub(e)) - .saturating_to_num::(), - ) + // Skip conversion if delta_in is zero + if delta_in.is_zero() { + return AlphaCurrency::ZERO; + } + + let liquidity_curr = SqrtPrice::saturating_from_num(CurrentLiquidity::::get(netuid)); + let sqrt_price_curr = AlphaSqrtPrice::::get(netuid); + let delta_fixed = SqrtPrice::saturating_from_num(delta_in.to_u64()); + + // Calculate result based on order type with proper fixed-point math + // Using safe math operations throughout to prevent overflows + let result = { + // (liquidity_curr * sqrt_price_curr + delta_fixed) * sqrt_price_curr; + let a = liquidity_curr + .saturating_mul(sqrt_price_curr) + .saturating_add(delta_fixed) + .saturating_mul(sqrt_price_curr); + // liquidity_curr / a; + let b = liquidity_curr.safe_div(a); + // b * delta_fixed; + b.saturating_mul(delta_fixed) + }; + + result.saturating_to_num::().into() + } + + fn update_liquidity_at_crossing(netuid: NetUid) -> Result<(), Error> { + let mut liquidity_curr = CurrentLiquidity::::get(netuid); + let current_tick_index = TickIndex::current_bounded::(netuid); + + // Find the appropriate tick based on order type + let tick = { + // Self::find_closest_higher_active_tick(netuid, current_tick_index), + let upper_tick = ActiveTickIndexManager::::find_closest_higher( + netuid, + current_tick_index.next().unwrap_or(TickIndex::MAX), + ) + .unwrap_or(TickIndex::MAX); + Ticks::::get(netuid, upper_tick) + } + .ok_or(Error::::InsufficientLiquidity)?; + + let liquidity_update_abs_u64 = tick.liquidity_net_as_u64(); + + // Update liquidity based on the sign of liquidity_net and the order type + liquidity_curr = if tick.liquidity_net >= 0 { + liquidity_curr.saturating_add(liquidity_update_abs_u64) + } else { + liquidity_curr.saturating_sub(liquidity_update_abs_u64) + }; + + CurrentLiquidity::::set(netuid, liquidity_curr); + + Ok(()) } } impl SwapStep for BasicSwapStep { - fn delta_in(netuid: NetUid, price_curr: U64F64, price_target: U64F64) -> AlphaCurrency { - let alpha_reserve = T::AlphaReserve::reserve(netuid); - let balancer = SwapBalancer::::get(netuid); - AlphaCurrency::from(balancer.calculate_base_delta_in( - price_curr, - price_target, - alpha_reserve.into(), - )) + fn delta_in( + liquidity_curr: U64F64, + sqrt_price_curr: SqrtPrice, + sqrt_price_target: SqrtPrice, + ) -> AlphaCurrency { + let one = U64F64::saturating_from_num(1); + + liquidity_curr + .saturating_mul( + one.safe_div(sqrt_price_target.into()) + .saturating_sub(one.safe_div(sqrt_price_curr)), + ) + .saturating_to_num::() + .into() + } + + fn tick_edge(netuid: NetUid, current_tick: TickIndex) -> TickIndex { + let current_price: SqrtPrice = AlphaSqrtPrice::::get(netuid); + let current_tick_price = current_tick.as_sqrt_price_bounded(); + let is_active = ActiveTickIndexManager::::tick_is_active(netuid, current_tick); + + if is_active && current_price > current_tick_price { + return ActiveTickIndexManager::::find_closest_lower(netuid, current_tick) + .unwrap_or(TickIndex::MIN); + } + + ActiveTickIndexManager::::find_closest_lower( + netuid, + current_tick.prev().unwrap_or(TickIndex::MIN), + ) + .unwrap_or(TickIndex::MIN) } - fn price_target(netuid: NetUid, delta_in: AlphaCurrency) -> U64F64 { - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - let balancer = SwapBalancer::::get(netuid); - let dx = delta_in; - let dy = Self::convert_deltas(netuid, dx); - balancer.calculate_price( - u64::from(alpha_reserve.saturating_add(dx)), - u64::from(tao_reserve.saturating_sub(dy)), + fn sqrt_price_target( + liquidity_curr: U64F64, + sqrt_price_curr: SqrtPrice, + delta_in: AlphaCurrency, + ) -> SqrtPrice { + let delta_fixed = U64F64::saturating_from_num(delta_in); + let one = U64F64::saturating_from_num(1); + + // No liquidity means that price should go to the limit + if liquidity_curr == 0 { + return SqrtPrice::saturating_from_num( + Pallet::::min_price_inner::().to_u64(), + ); + } + + one.safe_div( + delta_fixed + .safe_div(liquidity_curr) + .saturating_add(one.safe_div(sqrt_price_curr)), ) } - fn price_is_closer(price1: &U64F64, price2: &U64F64) -> bool { - price1 >= price2 + fn price_is_closer(sq_price1: &SqrtPrice, sq_price2: &SqrtPrice) -> bool { + sq_price1 >= sq_price2 + } + + fn action_on_edge_sqrt_price() -> SwapStepAction { + SwapStepAction::Stop } - fn add_fees(netuid: NetUid, fee: AlphaCurrency) { - FeesAlpha::::mutate(netuid, |total| *total = total.saturating_add(fee)) + fn add_fees(netuid: NetUid, current_liquidity: U64F64, fee: AlphaCurrency) { + if current_liquidity == 0 { + return; + } + + let fee_fixed = U64F64::saturating_from_num(fee.to_u64()); + + FeeGlobalAlpha::::mutate(netuid, |value| { + *value = value.saturating_add(fee_fixed.safe_div(current_liquidity)) + }); } fn convert_deltas(netuid: NetUid, delta_in: AlphaCurrency) -> TaoCurrency { - let alpha_reserve = T::AlphaReserve::reserve(netuid.into()); - let tao_reserve = T::TaoReserve::reserve(netuid.into()); - let balancer = SwapBalancer::::get(netuid); - let e = balancer.exp_base_quote(alpha_reserve.into(), delta_in.into()); - let one = U64F64::from_num(1); - let tao_reserve_fixed = U64F64::from_num(u64::from(tao_reserve)); - TaoCurrency::from( - tao_reserve_fixed - .saturating_mul(one.saturating_sub(e)) - .saturating_to_num::(), - ) + // Skip conversion if delta_in is zero + if delta_in.is_zero() { + return TaoCurrency::ZERO; + } + + let liquidity_curr = SqrtPrice::saturating_from_num(CurrentLiquidity::::get(netuid)); + let sqrt_price_curr = AlphaSqrtPrice::::get(netuid); + let delta_fixed = SqrtPrice::saturating_from_num(delta_in.to_u64()); + + // Calculate result based on order type with proper fixed-point math + // Using safe math operations throughout to prevent overflows + let result = { + // liquidity_curr / (liquidity_curr / sqrt_price_curr + delta_fixed); + let denom = liquidity_curr + .safe_div(sqrt_price_curr) + .saturating_add(delta_fixed); + let a = liquidity_curr.safe_div(denom); + // a * sqrt_price_curr; + let b = a.saturating_mul(sqrt_price_curr); + + // delta_fixed * b; + delta_fixed.saturating_mul(b) + }; + + result.saturating_to_num::().into() + } + + fn update_liquidity_at_crossing(netuid: NetUid) -> Result<(), Error> { + let mut liquidity_curr = CurrentLiquidity::::get(netuid); + let current_tick_index = TickIndex::current_bounded::(netuid); + + // Find the appropriate tick based on order type + let tick = { + // Self::find_closest_lower_active_tick(netuid, current_tick_index) + let current_price = AlphaSqrtPrice::::get(netuid); + let current_tick_price = current_tick_index.as_sqrt_price_bounded(); + let is_active = ActiveTickIndexManager::::tick_is_active(netuid, current_tick_index); + + let lower_tick = if is_active && current_price > current_tick_price { + ActiveTickIndexManager::::find_closest_lower(netuid, current_tick_index) + .unwrap_or(TickIndex::MIN) + } else { + ActiveTickIndexManager::::find_closest_lower( + netuid, + current_tick_index.prev().unwrap_or(TickIndex::MIN), + ) + .unwrap_or(TickIndex::MIN) + }; + Ticks::::get(netuid, lower_tick) + } + .ok_or(Error::::InsufficientLiquidity)?; + + let liquidity_update_abs_u64 = tick.liquidity_net_as_u64(); + + // Update liquidity based on the sign of liquidity_net and the order type + liquidity_curr = if tick.liquidity_net >= 0 { + liquidity_curr.saturating_sub(liquidity_update_abs_u64) + } else { + liquidity_curr.saturating_add(liquidity_update_abs_u64) + }; + + CurrentLiquidity::::set(netuid, liquidity_curr); + + Ok(()) } } @@ -246,25 +518,49 @@ where PaidOut: Currency, { /// Get the input amount needed to reach the target price - fn delta_in(netuid: NetUid, price_curr: U64F64, price_target: U64F64) -> PaidIn; + fn delta_in( + liquidity_curr: U64F64, + sqrt_price_curr: SqrtPrice, + sqrt_price_target: SqrtPrice, + ) -> PaidIn; - /// Get the target price based on the input amount - fn price_target(netuid: NetUid, delta_in: PaidIn) -> U64F64; + /// Get the tick at the current tick edge. + /// + /// If anything is wrong with tick math and it returns Err, we just abort the deal, i.e. return + /// the edge that is impossible to execute + fn tick_edge(netuid: NetUid, current_tick: TickIndex) -> TickIndex; - /// Returns True if price1 is closer to the current price than price2 + /// Get the target square root price based on the input amount + /// + /// This is the price that would be reached if + /// - There are no liquidity positions other than protocol liquidity + /// - Full delta_in amount is executed + fn sqrt_price_target( + liquidity_curr: U64F64, + sqrt_price_curr: SqrtPrice, + delta_in: PaidIn, + ) -> SqrtPrice; + + /// Returns True if sq_price1 is closer to the current price than sq_price2 /// in terms of order direction. - /// For buying: price1 <= price2 - /// For selling: price1 >= price2 - fn price_is_closer(price1: &U64F64, price2: &U64F64) -> bool; + /// For buying: sq_price1 <= sq_price2 + /// For selling: sq_price1 >= sq_price2 + fn price_is_closer(sq_price1: &SqrtPrice, sq_price2: &SqrtPrice) -> bool; + + /// Get swap step action on the edge sqrt price. + fn action_on_edge_sqrt_price() -> SwapStepAction; /// Add fees to the global fee counters - fn add_fees(netuid: NetUid, fee: PaidIn); + fn add_fees(netuid: NetUid, current_liquidity: U64F64, fee: PaidIn); /// Convert input amount (delta_in) to output amount (delta_out) /// - /// This is the core method of the swap that tells how much output token is given for an - /// amount of input token + /// This is the core method of uniswap V3 that tells how much output token is given for an + /// amount of input token within one price tick. fn convert_deltas(netuid: NetUid, delta_in: PaidIn) -> PaidOut; + + /// Update liquidity when crossing a tick + fn update_liquidity_at_crossing(netuid: NetUid) -> Result<(), Error>; } #[derive(Debug, PartialEq)] @@ -273,8 +569,15 @@ where PaidIn: Currency, PaidOut: Currency, { + pub(crate) amount_to_take: PaidIn, pub(crate) fee_paid: PaidIn, pub(crate) delta_in: PaidIn, pub(crate) delta_out: PaidOut, pub(crate) fee_to_block_author: PaidIn, } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum SwapStepAction { + Crossing, + Stop, +} diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 912c89bbe8..cd18e665cd 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -6,30 +6,76 @@ )] use approx::assert_abs_diff_eq; -use frame_support::{assert_noop, assert_ok}; -use sp_arithmetic::Perquintill; +use frame_support::{assert_err, assert_noop, assert_ok}; +use sp_arithmetic::helpers_128bit; use sp_runtime::DispatchError; -use substrate_fixed::types::U64F64; -use subtensor_runtime_common::{Currency, NetUid}; +use substrate_fixed::types::U96F32; +use subtensor_runtime_common::NetUid; use subtensor_swap_interface::Order as OrderT; use super::*; -use crate::mock::*; use crate::pallet::swap_step::*; +use crate::{SqrtPrice, mock::*}; + +// this function is used to convert price (NON-SQRT price!) to TickIndex. it's only utility for +// testing, all the implementation logic is based on sqrt prices +fn price_to_tick(price: f64) -> TickIndex { + let price_sqrt: SqrtPrice = SqrtPrice::from_num(price.sqrt()); + // Handle potential errors in the conversion + match TickIndex::try_from_sqrt_price(price_sqrt) { + Ok(mut tick) => { + // Ensure the tick is within bounds + if tick > TickIndex::MAX { + tick = TickIndex::MAX; + } else if tick < TickIndex::MIN { + tick = TickIndex::MIN; + } + tick + } + // Default to a reasonable value when conversion fails + Err(_) => { + if price > 1.0 { + TickIndex::MAX + } else { + TickIndex::MIN + } + } + } +} + +fn get_ticked_prices_around_current_price() -> (f64, f64) { + // Get current price, ticks around it, and prices on the tick edges for test cases + let netuid = NetUid::from(1); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + let current_tick = CurrentTick::::get(netuid); -// Run all tests: -// cargo test --package pallet-subtensor-swap --lib -- pallet::tests --nocapture + // Low and high prices that match to a lower and higher tick that doesn't contain the current price + let current_price_low_sqrt = current_tick.as_sqrt_price_bounded(); + let current_price_high_sqrt = current_tick.next().unwrap().as_sqrt_price_bounded(); + let current_price_low = U96F32::from_num(current_price_low_sqrt * current_price_low_sqrt); + let current_price_high = U96F32::from_num(current_price_high_sqrt * current_price_high_sqrt); -#[allow(dead_code)] -fn get_min_price() -> U64F64 { - U64F64::from_num(Pallet::::min_price_inner::()) - / U64F64::from_num(1_000_000_000) + ( + current_price_low.to_num::(), + current_price_high.to_num::() + 0.000000001, + ) } -#[allow(dead_code)] -fn get_max_price() -> U64F64 { - U64F64::from_num(Pallet::::max_price_inner::()) - / U64F64::from_num(1_000_000_000) +// this function is used to convert tick index NON-SQRT (!) price. it's only utility for +// testing, all the implementation logic is based on sqrt prices +fn tick_to_price(tick: TickIndex) -> f64 { + // Handle errors gracefully + match tick.try_to_sqrt_price() { + Ok(price_sqrt) => (price_sqrt * price_sqrt).to_num::(), + Err(_) => { + // Return a sensible default based on whether the tick is above or below the valid range + if tick > TickIndex::MAX { + tick_to_price(TickIndex::MAX) // Use the max valid tick price + } else { + tick_to_price(TickIndex::MIN) // Use the min valid tick price + } + } + } } mod dispatchables { @@ -60,405 +106,641 @@ mod dispatchables { }); } - fn perquintill_to_f64(p: Perquintill) -> f64 { - let parts = p.deconstruct() as f64; - parts / 1_000_000_000_000_000_000_f64 - } + // #[test] + // fn test_toggle_user_liquidity() { + // new_test_ext().execute_with(|| { + // let netuid = NetUid::from(101); + + // assert!(!EnabledUserLiquidity::::get(netuid)); + + // assert_ok!(Swap::toggle_user_liquidity( + // RuntimeOrigin::root(), + // netuid.into(), + // true + // )); + + // assert!(EnabledUserLiquidity::::get(netuid)); + + // assert_noop!( + // Swap::toggle_user_liquidity(RuntimeOrigin::signed(666), netuid.into(), true), + // DispatchError::BadOrigin + // ); + + // assert_ok!(Swap::toggle_user_liquidity( + // RuntimeOrigin::signed(1), + // netuid.into(), + // true + // )); + + // assert_noop!( + // Swap::toggle_user_liquidity( + // RuntimeOrigin::root(), + // NON_EXISTENT_NETUID.into(), + // true + // ), + // Error::::MechanismDoesNotExist + // ); + // }); + // } +} - /// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::dispatchables::test_adjust_protocol_liquidity_happy --exact --nocapture - #[test] - fn test_adjust_protocol_liquidity_happy() { - // test case: tao_delta, alpha_delta - [ - (0_u64, 0_u64), - (0_u64, 1_u64), - (1_u64, 0_u64), - (1_u64, 1_u64), - (0_u64, 10_u64), - (10_u64, 0_u64), - (10_u64, 10_u64), - (0_u64, 100_u64), - (100_u64, 0_u64), - (100_u64, 100_u64), - (0_u64, 1_000_u64), - (1_000_u64, 0_u64), - (1_000_u64, 1_000_u64), - (1_000_000_u64, 0_u64), - (0_u64, 1_000_000_u64), - (1_000_000_u64, 1_000_000_u64), - (1_000_000_000_u64, 0_u64), - (0_u64, 1_000_000_000_u64), - (1_000_000_000_u64, 1_000_000_000_u64), - (1_000_000_000_000_u64, 0_u64), - (0_u64, 1_000_000_000_000_u64), - (1_000_000_000_000_u64, 1_000_000_000_000_u64), - (1_u64, 2_u64), - (2_u64, 1_u64), - (10_u64, 20_u64), - (20_u64, 10_u64), - (100_u64, 200_u64), - (200_u64, 100_u64), - (1_000_u64, 2_000_u64), - (2_000_u64, 1_000_u64), - (1_000_000_u64, 2_000_000_u64), - (2_000_000_u64, 1_000_000_u64), - (1_000_000_000_u64, 2_000_000_000_u64), - (2_000_000_000_u64, 1_000_000_000_u64), - (1_000_000_000_000_u64, 2_000_000_000_000_u64), - (2_000_000_000_000_u64, 1_000_000_000_000_u64), - (1_234_567_u64, 2_432_765_u64), - (1_234_567_u64, 2_432_765_890_u64), - ] - .into_iter() - .for_each(|(tao_delta, alpha_delta)| { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); +#[test] +fn test_swap_initialization() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); - let tao_delta = TaoCurrency::from(tao_delta); - let alpha_delta = AlphaCurrency::from(alpha_delta); + // Get reserves from the mock provider + let tao = TaoReserve::reserve(netuid.into()); + let alpha = AlphaReserve::reserve(netuid.into()); - // Initialize reserves and price - let tao = TaoCurrency::from(1_000_000_000_000_u64); - let alpha = AlphaCurrency::from(4_000_000_000_000_u64); - TaoReserve::set_mock_reserve(netuid, tao); - AlphaReserve::set_mock_reserve(netuid, alpha); - let price_before = Swap::current_price(netuid); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - // Adjust reserves - Swap::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta); - TaoReserve::set_mock_reserve(netuid, tao + tao_delta); - AlphaReserve::set_mock_reserve(netuid, alpha + alpha_delta); + assert!(SwapV3Initialized::::get(netuid)); - // Check that price didn't change - let price_after = Swap::current_price(netuid); - assert_abs_diff_eq!( - price_before.to_num::(), - price_after.to_num::(), - epsilon = price_before.to_num::() / 1_000_000_000_000. - ); + // Verify current price is set + let sqrt_price = AlphaSqrtPrice::::get(netuid); + let expected_sqrt_price = U64F64::from_num(0.5_f64); + assert_abs_diff_eq!( + sqrt_price.to_num::(), + expected_sqrt_price.to_num::(), + epsilon = 0.000000001 + ); - // Check that reserve weight was properly updated - let new_tao = u64::from(tao + tao_delta) as f64; - let new_alpha = u64::from(alpha + alpha_delta) as f64; - let expected_quote_weight = - new_tao / (new_alpha * price_before.to_num::() + new_tao); - let expected_quote_weight_delta = expected_quote_weight - 0.5; - let res_weights = SwapBalancer::::get(netuid); - let actual_quote_weight_delta = - perquintill_to_f64(res_weights.get_quote_weight()) - 0.5; - let eps = expected_quote_weight / 1_000_000_000_000.; - assert_abs_diff_eq!( - expected_quote_weight_delta, - actual_quote_weight_delta, - epsilon = eps - ); - }); - }); - } + // Verify that current tick is set + let current_tick = CurrentTick::::get(netuid); + let expected_current_tick = TickIndex::from_sqrt_price_bounded(expected_sqrt_price); + assert_eq!(current_tick, expected_current_tick); + + // Calculate expected liquidity + let expected_liquidity = + helpers_128bit::sqrt((tao.to_u64() as u128).saturating_mul(alpha.to_u64() as u128)) + as u64; + + // Get the protocol account + let protocol_account_id = Pallet::::protocol_account_id(); + + // Verify position created for protocol account + let positions = Positions::::iter_prefix_values((netuid, protocol_account_id)) + .collect::>(); + assert_eq!(positions.len(), 1); + + let position = &positions[0]; + assert_eq!(position.liquidity, expected_liquidity); + assert_eq!(position.tick_low, TickIndex::MIN); + assert_eq!(position.tick_high, TickIndex::MAX); + assert_eq!(position.fees_tao, 0); + assert_eq!(position.fees_alpha, 0); + + // Verify ticks were created + let tick_low = Ticks::::get(netuid, TickIndex::MIN).unwrap(); + let tick_high = Ticks::::get(netuid, TickIndex::MAX).unwrap(); + + // Check liquidity values + assert_eq!(tick_low.liquidity_net, expected_liquidity as i128); + assert_eq!(tick_low.liquidity_gross, expected_liquidity); + assert_eq!(tick_high.liquidity_net, -(expected_liquidity as i128)); + assert_eq!(tick_high.liquidity_gross, expected_liquidity); + + // Verify current liquidity is set + assert_eq!(CurrentLiquidity::::get(netuid), expected_liquidity); + }); +} - /// This test case verifies that small gradual injections (like emissions in every block) - /// in the worst case - /// - Do not cause price to change - /// - Result in the same weight change as one large injection - /// - /// This is a long test that only tests validity of weights math. Run again if changing - /// Balancer::update_weights_for_added_liquidity - /// - /// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::dispatchables::test_adjust_protocol_liquidity_deltas --exact --nocapture - #[ignore] - #[test] - fn test_adjust_protocol_liquidity_deltas() { - // The number of times (blocks) over which gradual injections will be made - // One year price drift due to precision is under 1e-6 - const ITERATIONS: u64 = 2_700_000; - const PRICE_PRECISION: f64 = 0.000_001; - const PREC_LARGE_DELTA: f64 = 0.001; - const WEIGHT_PRECISION: f64 = 0.000_000_000_000_000_001; - - let initial_tao_reserve = TaoCurrency::from(1_000_000_000_000_000_u64); - let initial_alpha_reserve = AlphaCurrency::from(10_000_000_000_000_000_u64); - - // test case: tao_delta, alpha_delta, price_precision +// Test adding liquidity on top of the existing protocol liquidity +#[test] +fn test_add_liquidity_basic() { + new_test_ext().execute_with(|| { + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let max_tick = price_to_tick(max_price); + assert_eq!(max_tick, TickIndex::MAX); + + assert_ok!(Pallet::::maybe_initialize_v3(NetUid::from(1))); + let current_price = Pallet::::current_price(NetUid::from(1)).to_num::(); + let (current_price_low, current_price_high) = get_ticked_prices_around_current_price(); + + // As a user add liquidity with all possible corner cases + // - Initial price is 0.25 + // - liquidity is expressed in RAO units + // Test case is (price_low, price_high, liquidity, tao, alpha) [ - (0_u64, 0_u64, PRICE_PRECISION), - (0_u64, 1_u64, PRICE_PRECISION), - (1_u64, 0_u64, PRICE_PRECISION), - (1_u64, 1_u64, PRICE_PRECISION), - (0_u64, 10_u64, PRICE_PRECISION), - (10_u64, 0_u64, PRICE_PRECISION), - (10_u64, 10_u64, PRICE_PRECISION), - (0_u64, 100_u64, PRICE_PRECISION), - (100_u64, 0_u64, PRICE_PRECISION), - (100_u64, 100_u64, PRICE_PRECISION), - (0_u64, 987_u64, PRICE_PRECISION), - (987_u64, 0_u64, PRICE_PRECISION), - (876_u64, 987_u64, PRICE_PRECISION), - (0_u64, 1_000_u64, PRICE_PRECISION), - (1_000_u64, 0_u64, PRICE_PRECISION), - (1_000_u64, 1_000_u64, PRICE_PRECISION), - (0_u64, 1_234_u64, PRICE_PRECISION), - (1_234_u64, 0_u64, PRICE_PRECISION), - (1_234_u64, 4_321_u64, PRICE_PRECISION), - (1_234_000_u64, 4_321_000_u64, PREC_LARGE_DELTA), - (1_234_u64, 4_321_000_u64, PREC_LARGE_DELTA), + // Repeat the protocol liquidity at maximum range: Expect all the same values + ( + min_price, + max_price, + 2_000_000_000_u64, + 1_000_000_000_u64, + 4_000_000_000_u64, + ), + // Repeat the protocol liquidity at current to max range: Expect the same alpha + ( + current_price_high, + max_price, + 2_000_000_000_u64, + 0, + 4_000_000_000, + ), + // Repeat the protocol liquidity at min to current range: Expect all the same tao + ( + min_price, + current_price_low, + 2_000_000_000_u64, + 1_000_000_000, + 0, + ), + // Half to double price - just some sane wothdraw amounts + (0.125, 0.5, 2_000_000_000_u64, 293_000_000, 1_171_000_000), + // Both below price - tao is non-zero, alpha is zero + (0.12, 0.13, 2_000_000_000_u64, 28_270_000, 0), + // Both above price - tao is zero, alpha is non-zero + (0.3, 0.4, 2_000_000_000_u64, 0, 489_200_000), ] .into_iter() - .for_each(|(tao_delta, alpha_delta, price_precision)| { - new_test_ext().execute_with(|| { - let netuid1 = NetUid::from(1); - - let tao_delta = TaoCurrency::from(tao_delta); - let alpha_delta = AlphaCurrency::from(alpha_delta); - - // Initialize realistically large reserves - let mut tao = initial_tao_reserve; - let mut alpha = initial_alpha_reserve; - TaoReserve::set_mock_reserve(netuid1, tao); - AlphaReserve::set_mock_reserve(netuid1, alpha); - let price_before = Swap::current_price(netuid1); - - // Adjust reserves gradually - for _ in 0..ITERATIONS { - Swap::adjust_protocol_liquidity(netuid1, tao_delta, alpha_delta); - tao += tao_delta; - alpha += alpha_delta; - TaoReserve::set_mock_reserve(netuid1, tao); - AlphaReserve::set_mock_reserve(netuid1, alpha); - } + .enumerate() + .map(|(n, v)| (NetUid::from(n as u16 + 1), v.0, v.1, v.2, v.3, v.4)) + .for_each( + |(netuid, price_low, price_high, liquidity, expected_tao, expected_alpha)| { + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Calculate ticks (assuming tick math is tested separately) + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + + // Get tick infos and liquidity before adding (to account for protocol liquidity) + let tick_low_info_before = Ticks::::get(netuid, tick_low).unwrap_or_default(); + let tick_high_info_before = + Ticks::::get(netuid, tick_high).unwrap_or_default(); + let liquidity_before = CurrentLiquidity::::get(netuid); + + // Add liquidity + let (position_id, tao, alpha) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + ) + .unwrap(); + + assert_abs_diff_eq!(tao, expected_tao, epsilon = tao / 1000); + assert_abs_diff_eq!(alpha, expected_alpha, epsilon = alpha / 1000); + + // Check that low and high ticks appear in the state and are properly updated + let tick_low_info = Ticks::::get(netuid, tick_low).unwrap(); + let tick_high_info = Ticks::::get(netuid, tick_high).unwrap(); + let expected_liquidity_net_low = liquidity as i128; + let expected_liquidity_gross_low = liquidity; + let expected_liquidity_net_high = -(liquidity as i128); + let expected_liquidity_gross_high = liquidity; + + assert_eq!( + tick_low_info.liquidity_net - tick_low_info_before.liquidity_net, + expected_liquidity_net_low, + ); + assert_eq!( + tick_low_info.liquidity_gross - tick_low_info_before.liquidity_gross, + expected_liquidity_gross_low, + ); + assert_eq!( + tick_high_info.liquidity_net - tick_high_info_before.liquidity_net, + expected_liquidity_net_high, + ); + assert_eq!( + tick_high_info.liquidity_gross - tick_high_info_before.liquidity_gross, + expected_liquidity_gross_high, + ); - // Check that price didn't change - let price_after = Swap::current_price(netuid1); - assert_abs_diff_eq!( - price_before.to_num::(), - price_after.to_num::(), - epsilon = price_precision + // Liquidity position at correct ticks + assert_eq!( + Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), + 1 ); - ///////////////////////// + let position = + Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID, position_id)).unwrap(); + assert_eq!(position.liquidity, liquidity); + assert_eq!(position.tick_low, tick_low); + assert_eq!(position.tick_high, tick_high); + assert_eq!(position.fees_alpha, 0); + assert_eq!(position.fees_tao, 0); + + // Current liquidity is updated only when price range includes the current price + let expected_liquidity = + if (price_high > current_price) && (price_low <= current_price) { + liquidity_before + liquidity + } else { + liquidity_before + }; + + assert_eq!(CurrentLiquidity::::get(netuid), expected_liquidity) + }, + ); + }); +} - // Now do one-time big injection with another netuid and compare weights +#[test] +fn test_add_liquidity_max_limit_enforced() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let liquidity = 2_000_000_000_u64; + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - let netuid2 = NetUid::from(2); + let limit = MaxPositions::get() as usize; - // Initialize same large reserves - TaoReserve::set_mock_reserve(netuid2, initial_tao_reserve); - AlphaReserve::set_mock_reserve(netuid2, initial_alpha_reserve); + for _ in 0..limit { + Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + TickIndex::MIN, + TickIndex::MAX, + liquidity, + ) + .unwrap(); + } - // Adjust reserves by one large amount at once - let tao_delta_once = TaoCurrency::from(ITERATIONS * u64::from(tao_delta)); - let alpha_delta_once = AlphaCurrency::from(ITERATIONS * u64::from(alpha_delta)); - Swap::adjust_protocol_liquidity(netuid2, tao_delta_once, alpha_delta_once); - TaoReserve::set_mock_reserve(netuid2, initial_tao_reserve + tao_delta_once); - AlphaReserve::set_mock_reserve(netuid2, initial_alpha_reserve + alpha_delta_once); + let test_result = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + TickIndex::MIN, + TickIndex::MAX, + liquidity, + ); - // Compare reserve weights for netuid 1 and 2 - let res_weights1 = SwapBalancer::::get(netuid1); - let res_weights2 = SwapBalancer::::get(netuid2); - let actual_quote_weight1 = perquintill_to_f64(res_weights1.get_quote_weight()); - let actual_quote_weight2 = perquintill_to_f64(res_weights2.get_quote_weight()); - assert_abs_diff_eq!( - actual_quote_weight1, - actual_quote_weight2, - epsilon = WEIGHT_PRECISION - ); - }); - }); - } + assert_err!(test_result, Error::::MaxPositionsExceeded); + }); +} - /// Should work ok when initial alpha is zero - /// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::dispatchables::test_adjust_protocol_liquidity_zero_alpha --exact --nocapture - #[test] - fn test_adjust_protocol_liquidity_zero_alpha() { - // test case: tao_delta, alpha_delta +#[test] +fn test_add_liquidity_out_of_bounds() { + new_test_ext().execute_with(|| { [ - (0_u64, 0_u64), - (0_u64, 1_u64), - (1_u64, 0_u64), - (1_u64, 1_u64), - (0_u64, 10_u64), - (10_u64, 0_u64), - (10_u64, 10_u64), - (0_u64, 100_u64), - (100_u64, 0_u64), - (100_u64, 100_u64), - (0_u64, 1_000_u64), - (1_000_u64, 0_u64), - (1_000_u64, 1_000_u64), - (1_000_000_u64, 0_u64), - (0_u64, 1_000_000_u64), - (1_000_000_u64, 1_000_000_u64), - (1_000_000_000_u64, 0_u64), - (0_u64, 1_000_000_000_u64), - (1_000_000_000_u64, 1_000_000_000_u64), - (1_000_000_000_000_u64, 0_u64), - (0_u64, 1_000_000_000_000_u64), - (1_000_000_000_000_u64, 1_000_000_000_000_u64), - (1_u64, 2_u64), - (2_u64, 1_u64), - (10_u64, 20_u64), - (20_u64, 10_u64), - (100_u64, 200_u64), - (200_u64, 100_u64), - (1_000_u64, 2_000_u64), - (2_000_u64, 1_000_u64), - (1_000_000_u64, 2_000_000_u64), - (2_000_000_u64, 1_000_000_u64), - (1_000_000_000_u64, 2_000_000_000_u64), - (2_000_000_000_u64, 1_000_000_000_u64), - (1_000_000_000_000_u64, 2_000_000_000_000_u64), - (2_000_000_000_000_u64, 1_000_000_000_000_u64), - (1_234_567_u64, 2_432_765_u64), - (1_234_567_u64, 2_432_765_890_u64), + // For our tests, we'll construct TickIndex values that are intentionally + // outside the valid range for testing purposes only + ( + TickIndex::new_unchecked(TickIndex::MIN.get() - 1), + TickIndex::MAX, + 1_000_000_000_u64, + ), + ( + TickIndex::MIN, + TickIndex::new_unchecked(TickIndex::MAX.get() + 1), + 1_000_000_000_u64, + ), + ( + TickIndex::new_unchecked(TickIndex::MIN.get() - 1), + TickIndex::new_unchecked(TickIndex::MAX.get() + 1), + 1_000_000_000_u64, + ), + ( + TickIndex::new_unchecked(TickIndex::MIN.get() - 100), + TickIndex::new_unchecked(TickIndex::MAX.get() + 100), + 1_000_000_000_u64, + ), + // Inverted ticks: high < low + ( + TickIndex::new_unchecked(-900), + TickIndex::new_unchecked(-1000), + 1_000_000_000_u64, + ), + // Equal ticks: high == low + ( + TickIndex::new_unchecked(-10_000), + TickIndex::new_unchecked(-10_000), + 1_000_000_000_u64, + ), ] .into_iter() - .for_each(|(tao_delta, alpha_delta)| { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - - let tao_delta = TaoCurrency::from(tao_delta); - let alpha_delta = AlphaCurrency::from(alpha_delta); - - // Initialize reserves and price - // broken state: Zero price because of zero alpha reserve - let tao = TaoCurrency::from(1_000_000_000_000_u64); - let alpha = AlphaCurrency::from(0_u64); - TaoReserve::set_mock_reserve(netuid, tao); - AlphaReserve::set_mock_reserve(netuid, alpha); - let price_before = Swap::current_price(netuid); - assert_eq!(price_before, U64F64::from_num(0)); - let new_tao = u64::from(tao + tao_delta) as f64; - let new_alpha = u64::from(alpha + alpha_delta) as f64; - - // Adjust reserves - Swap::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta); - TaoReserve::set_mock_reserve(netuid, tao + tao_delta); - AlphaReserve::set_mock_reserve(netuid, alpha + alpha_delta); - - let res_weights = SwapBalancer::::get(netuid); - let actual_quote_weight = perquintill_to_f64(res_weights.get_quote_weight()); - - // Check that price didn't change - let price_after = Swap::current_price(netuid); - if new_alpha == 0. { - // If the pool state is still broken (∆x = 0), no change - assert_eq!(actual_quote_weight, 0.5); - assert_eq!(price_after, U64F64::from_num(0)); - } else { - // Price got fixed - let expected_price = new_tao / new_alpha; - assert_abs_diff_eq!( - expected_price, - price_after.to_num::(), - epsilon = price_before.to_num::() / 1_000_000_000_000. - ); - assert_eq!(actual_quote_weight, 0.5); - } - }); + .enumerate() + .map(|(n, v)| (NetUid::from(n as u16 + 1), v.0, v.1, v.2)) + .for_each(|(netuid, tick_low, tick_high, liquidity)| { + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Add liquidity + assert_err!( + Swap::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity + ), + Error::::InvalidTickRange, + ); }); - } + }); +} - /// Collects the fees and adds them to protocol liquidity - /// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::dispatchables::test_adjust_protocol_liquidity_collects_fees --exact --nocapture - #[test] - fn test_adjust_protocol_liquidity_collects_fees() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); +#[test] +fn test_add_liquidity_over_balance() { + new_test_ext().execute_with(|| { + let coldkey_account_id = 3; + let hotkey_account_id = 1002; - let tao_delta = TaoCurrency::ZERO; - let alpha_delta = AlphaCurrency::ZERO; - - // Initialize reserves and price - // 0.1 price - let tao = TaoCurrency::from(1_000_000_000_u64); - let alpha = AlphaCurrency::from(10_000_000_000_u64); - TaoReserve::set_mock_reserve(netuid, tao); - AlphaReserve::set_mock_reserve(netuid, alpha); - - // Insert fees - let tao_fees = TaoCurrency::from(1_000); - let alpha_fees = AlphaCurrency::from(1_000); - FeesTao::::insert(netuid, tao_fees); - FeesAlpha::::insert(netuid, alpha_fees); - - // Adjust reserves - let (actual_tao_delta, actual_alpha_delta) = - Swap::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta); - TaoReserve::set_mock_reserve(netuid, tao + tao_delta); - AlphaReserve::set_mock_reserve(netuid, alpha + alpha_delta); - - // Check that returned reserve deltas are correct (include fees) - assert_eq!(actual_tao_delta, tao_fees); - assert_eq!(actual_alpha_delta, alpha_fees); - - // Check that fees got reset - assert_eq!(FeesTao::::get(netuid), TaoCurrency::ZERO); - assert_eq!(FeesAlpha::::get(netuid), AlphaCurrency::ZERO); + [ + // Lower than price (not enough tao) + (0.1, 0.2, 100_000_000_000_u64), + // Higher than price (not enough alpha) + (0.3, 0.4, 100_000_000_000_u64), + // Around the price (not enough both) + (0.1, 0.4, 100_000_000_000_u64), + ] + .into_iter() + .enumerate() + .map(|(n, v)| (NetUid::from(n as u16 + 1), v.0, v.1, v.2)) + .for_each(|(netuid, price_low, price_high, liquidity)| { + // Calculate ticks + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Add liquidity + assert_err!( + Pallet::::do_add_liquidity( + netuid, + &coldkey_account_id, + &hotkey_account_id, + tick_low, + tick_high, + liquidity + ), + Error::::InsufficientBalance, + ); }); - } + }); } +// cargo test --package pallet-subtensor-swap --lib -- pallet::impls::tests::test_remove_liquidity_basic --exact --show-output #[test] -fn test_swap_initialization() { +fn test_remove_liquidity_basic() { new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let max_tick = price_to_tick(max_price); + assert_eq!(max_tick, TickIndex::MAX); - // Setup reserves - let tao = TaoCurrency::from(1_000_000_000u64); - let alpha = AlphaCurrency::from(4_000_000_000u64); - TaoReserve::set_mock_reserve(netuid, tao); - AlphaReserve::set_mock_reserve(netuid, alpha); + let (current_price_low, current_price_high) = get_ticked_prices_around_current_price(); - assert_ok!(Pallet::::maybe_initialize_palswap(netuid, None)); - assert!(PalSwapInitialized::::get(netuid)); + // As a user add liquidity with all possible corner cases + // - Initial price is 0.25 + // - liquidity is expressed in RAO units + // Test case is (price_low, price_high, liquidity, tao, alpha) + [ + // Repeat the protocol liquidity at maximum range: Expect all the same values + ( + min_price, + max_price, + 2_000_000_000_u64, + 1_000_000_000_u64, + 4_000_000_000_u64, + ), + // Repeat the protocol liquidity at current to max range: Expect the same alpha + ( + current_price_high, + max_price, + 2_000_000_000_u64, + 0, + 4_000_000_000, + ), + // Repeat the protocol liquidity at min to current range: Expect all the same tao + ( + min_price, + current_price_low, + 2_000_000_000_u64, + 1_000_000_000, + 0, + ), + // Half to double price - just some sane wothdraw amounts + (0.125, 0.5, 2_000_000_000_u64, 293_000_000, 1_171_000_000), + // Both below price - tao is non-zero, alpha is zero + (0.12, 0.13, 2_000_000_000_u64, 28_270_000, 0), + // Both above price - tao is zero, alpha is non-zero + (0.3, 0.4, 2_000_000_000_u64, 0, 489_200_000), + ] + .into_iter() + .enumerate() + .map(|(n, v)| (NetUid::from(n as u16 + 1), v.0, v.1, v.2, v.3, v.4)) + .for_each(|(netuid, price_low, price_high, liquidity, tao, alpha)| { + // Calculate ticks (assuming tick math is tested separately) + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + let liquidity_before = CurrentLiquidity::::get(netuid); + + // Add liquidity + let (position_id, _, _) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + ) + .unwrap(); - // Verify current price is set - let price = Pallet::::current_price(netuid); - let expected_price = U64F64::from_num(0.25_f64); - assert_abs_diff_eq!( - price.to_num::(), - expected_price.to_num::(), - epsilon = 0.000000001 - ); + // Remove liquidity + let remove_result = + Pallet::::do_remove_liquidity(netuid, &OK_COLDKEY_ACCOUNT_ID, position_id) + .unwrap(); + assert_abs_diff_eq!(remove_result.tao.to_u64(), tao, epsilon = tao / 1000); + assert_abs_diff_eq!( + u64::from(remove_result.alpha), + alpha, + epsilon = alpha / 1000 + ); + assert_eq!(remove_result.fee_tao, TaoCurrency::ZERO); + assert_eq!(remove_result.fee_alpha, AlphaCurrency::ZERO); - // Verify that swap reserve weight is initialized - let reserve_weight = SwapBalancer::::get(netuid); - assert_eq!( - reserve_weight.get_quote_weight(), - Perquintill::from_rational(1_u64, 2_u64), - ); + // Liquidity position is removed + assert_eq!( + Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), + 0 + ); + assert!(Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID, position_id)).is_none()); + + // Current liquidity is updated (back where it was) + assert_eq!(CurrentLiquidity::::get(netuid), liquidity_before); + }); }); } #[test] -fn test_swap_initialization_with_price() { +fn test_remove_liquidity_nonexisting_position() { new_test_ext().execute_with(|| { + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let max_tick = price_to_tick(max_price); + assert_eq!(max_tick.get(), TickIndex::MAX.get()); + + let liquidity = 2_000_000_000_u64; let netuid = NetUid::from(1); - // Setup reserves, tao / alpha = 0.25 - let tao = TaoCurrency::from(1_000_000_000u64); - let alpha = AlphaCurrency::from(4_000_000_000u64); - TaoReserve::set_mock_reserve(netuid, tao); - AlphaReserve::set_mock_reserve(netuid, alpha); + // Calculate ticks (assuming tick math is tested separately) + let tick_low = price_to_tick(min_price); + let tick_high = price_to_tick(max_price); - // Initialize with 0.2 price - assert_ok!(Pallet::::maybe_initialize_palswap( + // Setup swap + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Add liquidity + assert_ok!(Pallet::::do_add_liquidity( netuid, - Some(U64F64::from(1u16) / U64F64::from(5u16)) + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, )); - assert!(PalSwapInitialized::::get(netuid)); - // Verify current price is set to 0.2 - let price = Pallet::::current_price(netuid); - let expected_price = U64F64::from_num(0.2_f64); - assert_abs_diff_eq!( - price.to_num::(), - expected_price.to_num::(), - epsilon = 0.000000001 + assert!(Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID) > 0); + + // Remove liquidity + assert_err!( + Pallet::::do_remove_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + PositionId::new::() + ), + Error::::LiquidityNotFound, ); }); } -// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_swap_basic --exact --nocapture +// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_modify_position_basic --exact --show-output +#[test] +fn test_modify_position_basic() { + new_test_ext().execute_with(|| { + let max_price = tick_to_price(TickIndex::MAX); + let max_tick = price_to_tick(max_price); + let limit_price = 1000.0_f64; + assert_eq!(max_tick, TickIndex::MAX); + let (current_price_low, _current_price_high) = get_ticked_prices_around_current_price(); + + // As a user add liquidity with all possible corner cases + // - Initial price is 0.25 + // - liquidity is expressed in RAO units + // Test case is (price_low, price_high, liquidity, tao, alpha) + [ + // Repeat the protocol liquidity at current to max range: Expect the same alpha + ( + current_price_low, + max_price, + 2_000_000_000_u64, + 4_000_000_000, + ), + ] + .into_iter() + .enumerate() + .map(|(n, v)| (NetUid::from(n as u16 + 1), v.0, v.1, v.2, v.3)) + .for_each(|(netuid, price_low, price_high, liquidity, alpha)| { + // Calculate ticks (assuming tick math is tested separately) + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Add liquidity + let (position_id, _, _) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + ) + .unwrap(); + + // Get tick infos before the swap/update + let tick_low_info_before = Ticks::::get(netuid, tick_low).unwrap(); + let tick_high_info_before = Ticks::::get(netuid, tick_high).unwrap(); + + // Swap to create fees on the position + let sqrt_limit_price = SqrtPrice::from_num((limit_price).sqrt()); + let order = GetAlphaForTao::with_amount(liquidity / 10); + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); + + // Modify liquidity (also causes claiming of fees) + let liquidity_before = CurrentLiquidity::::get(netuid); + let modify_result = Pallet::::do_modify_position( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + position_id, + -((liquidity / 10) as i64), + ) + .unwrap(); + assert_abs_diff_eq!( + u64::from(modify_result.alpha), + alpha / 10, + epsilon = alpha / 1000 + ); + assert!(modify_result.fee_tao > TaoCurrency::ZERO); + assert_eq!(modify_result.fee_alpha, AlphaCurrency::ZERO); + + // Liquidity position is reduced + assert_eq!( + Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), + 1 + ); + + // Current liquidity is reduced with modify_position + assert!(CurrentLiquidity::::get(netuid) < liquidity_before); + + // Position liquidity is reduced + let position = + Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID, position_id)).unwrap(); + assert_eq!(position.liquidity, liquidity * 9 / 10); + assert_eq!(position.tick_low, tick_low); + assert_eq!(position.tick_high, tick_high); + + // Tick liquidity is updated properly for low and high position ticks + let tick_low_info_after = Ticks::::get(netuid, tick_low).unwrap(); + let tick_high_info_after = Ticks::::get(netuid, tick_high).unwrap(); + + assert_eq!( + tick_low_info_before.liquidity_net - (liquidity / 10) as i128, + tick_low_info_after.liquidity_net, + ); + assert_eq!( + tick_low_info_before.liquidity_gross - (liquidity / 10), + tick_low_info_after.liquidity_gross, + ); + assert_eq!( + tick_high_info_before.liquidity_net + (liquidity / 10) as i128, + tick_high_info_after.liquidity_net, + ); + assert_eq!( + tick_high_info_before.liquidity_gross - (liquidity / 10), + tick_high_info_after.liquidity_gross, + ); + + // Modify liquidity again (ensure fees aren't double-collected) + let modify_result = Pallet::::do_modify_position( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + position_id, + -((liquidity / 100) as i64), + ) + .unwrap(); + + assert_abs_diff_eq!( + u64::from(modify_result.alpha), + alpha / 100, + epsilon = alpha / 1000 + ); + assert_eq!(modify_result.fee_tao, TaoCurrency::ZERO); + assert_eq!(modify_result.fee_alpha, AlphaCurrency::ZERO); + }); + }); +} + +// cargo test --package pallet-subtensor-swap --lib -- pallet::impls::tests::test_swap_basic --exact --show-output #[test] fn test_swap_basic() { new_test_ext().execute_with(|| { @@ -466,284 +748,858 @@ fn test_swap_basic() { netuid: NetUid, order: Order, limit_price: f64, + output_amount: u64, price_should_grow: bool, ) where Order: OrderT, + Order::PaidIn: GlobalFeeInfo, BasicSwapStep: SwapStep, { - let swap_amount = order.amount().to_u64(); + // Consumed liquidity ticks + let tick_low = TickIndex::MIN; + let tick_high = TickIndex::MAX; + let liquidity = order.amount().to_u64(); // Setup swap - // Price is 0.25 - let initial_tao_reserve = TaoCurrency::from(1_000_000_000_u64); - let initial_alpha_reserve = AlphaCurrency::from(4_000_000_000_u64); - TaoReserve::set_mock_reserve(netuid, initial_tao_reserve); - AlphaReserve::set_mock_reserve(netuid, initial_alpha_reserve); - assert_ok!(Pallet::::maybe_initialize_palswap(netuid, None)); - - // Get current price - let current_price_before = Pallet::::current_price(netuid); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - // Get reserves - let tao_reserve = TaoReserve::reserve(netuid.into()).to_u64(); - let alpha_reserve = AlphaReserve::reserve(netuid.into()).to_u64(); + // Get tick infos before the swap + let tick_low_info_before = Ticks::::get(netuid, tick_low).unwrap_or_default(); + let tick_high_info_before = Ticks::::get(netuid, tick_high).unwrap_or_default(); + let liquidity_before = CurrentLiquidity::::get(netuid); - // Expected fee amount - let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; - let expected_fee = (swap_amount as f64 * fee_rate) as u64; - - // Calculate expected output amount using f64 math - // This is a simple case when w1 = w2 = 0.5, so there's no - // exponentiation needed - let x = alpha_reserve as f64; - let y = tao_reserve as f64; - let expected_output_amount = if price_should_grow { - x * (1.0 - y / (y + (swap_amount - expected_fee) as f64)) - } else { - y * (1.0 - x / (x + (swap_amount - expected_fee) as f64)) - }; + // Get current price + let current_price = Pallet::::current_price(netuid); // Swap - let limit_price_fixed = U64F64::from_num(limit_price); + let sqrt_limit_price = SqrtPrice::from_num((limit_price).sqrt()); let swap_result = - Pallet::::do_swap(netuid, order.clone(), limit_price_fixed, false, false) + Pallet::::do_swap(netuid, order.clone(), sqrt_limit_price, false, false) .unwrap(); assert_abs_diff_eq!( swap_result.amount_paid_out.to_u64(), - expected_output_amount as u64, - epsilon = 1 + output_amount, + epsilon = output_amount / 100 ); assert_abs_diff_eq!( swap_result.paid_in_reserve_delta() as u64, - (swap_amount - expected_fee), - epsilon = 1 + liquidity, + epsilon = liquidity / 10 ); assert_abs_diff_eq!( swap_result.paid_out_reserve_delta() as i64, - -(expected_output_amount as i64), - epsilon = 1 + -(output_amount as i64), + epsilon = output_amount as i64 / 10 ); - // Update reserves (because it happens outside of do_swap in stake_utils) - if price_should_grow { - TaoReserve::set_mock_reserve( - netuid, - TaoCurrency::from( - (u64::from(initial_tao_reserve) as i128 - + swap_result.paid_in_reserve_delta()) as u64, - ), - ); - AlphaReserve::set_mock_reserve( - netuid, - AlphaCurrency::from( - (u64::from(initial_alpha_reserve) as i128 - + swap_result.paid_out_reserve_delta()) as u64, - ), - ); - } else { - TaoReserve::set_mock_reserve( - netuid, - TaoCurrency::from( - (u64::from(initial_tao_reserve) as i128 - + swap_result.paid_out_reserve_delta()) as u64, - ), - ); - AlphaReserve::set_mock_reserve( - netuid, - AlphaCurrency::from( - (u64::from(initial_alpha_reserve) as i128 - + swap_result.paid_in_reserve_delta()) as u64, - ), - ); - } + // Check that low and high ticks' fees were updated properly, and liquidity values were not updated + let tick_low_info = Ticks::::get(netuid, tick_low).unwrap(); + let tick_high_info = Ticks::::get(netuid, tick_high).unwrap(); + let expected_liquidity_net_low = tick_low_info_before.liquidity_net; + let expected_liquidity_gross_low = tick_low_info_before.liquidity_gross; + let expected_liquidity_net_high = tick_high_info_before.liquidity_net; + let expected_liquidity_gross_high = tick_high_info_before.liquidity_gross; + assert_eq!(tick_low_info.liquidity_net, expected_liquidity_net_low,); + assert_eq!(tick_low_info.liquidity_gross, expected_liquidity_gross_low,); + assert_eq!(tick_high_info.liquidity_net, expected_liquidity_net_high,); + assert_eq!( + tick_high_info.liquidity_gross, + expected_liquidity_gross_high, + ); + + // Expected fee amount + let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; + let expected_fee = (liquidity as f64 * fee_rate) as u64; + + // Global fees should be updated + let actual_global_fee = (order.amount().global_fee(netuid).to_num::() + * (liquidity_before as f64)) as u64; + + assert!((swap_result.fee_paid.to_u64() as i64 - expected_fee as i64).abs() <= 1); + assert!((actual_global_fee as i64 - expected_fee as i64).abs() <= 1); + + // Tick fees should be updated + + // Liquidity position should not be updated + let protocol_id = Pallet::::protocol_account_id(); + let positions = + Positions::::iter_prefix_values((netuid, protocol_id)).collect::>(); + let position = positions.first().unwrap(); - // Assert that price movement is in correct direction - let current_price_after = Pallet::::current_price(netuid); assert_eq!( - current_price_after >= current_price_before, - price_should_grow + position.liquidity, + helpers_128bit::sqrt( + TaoReserve::reserve(netuid.into()).to_u64() as u128 + * AlphaReserve::reserve(netuid.into()).to_u64() as u128 + ) as u64 ); + assert_eq!(position.tick_low, tick_low); + assert_eq!(position.tick_high, tick_high); + assert_eq!(position.fees_alpha, 0); + assert_eq!(position.fees_tao, 0); + + // Current liquidity is not updated + assert_eq!(CurrentLiquidity::::get(netuid), liquidity_before); + + // Assert that price movement is in correct direction + let sqrt_current_price_after = AlphaSqrtPrice::::get(netuid); + let current_price_after = Pallet::::current_price(netuid); + assert_eq!(current_price_after >= current_price, price_should_grow); + + // Assert that current tick is updated + let current_tick = CurrentTick::::get(netuid); + let expected_current_tick = + TickIndex::from_sqrt_price_bounded(sqrt_current_price_after); + assert_eq!(current_tick, expected_current_tick); } // Current price is 0.25 // Test case is (order_type, liquidity, limit_price, output_amount) - perform_test(1.into(), GetAlphaForTao::with_amount(1_000), 1000.0, true); - perform_test(1.into(), GetAlphaForTao::with_amount(2_000), 1000.0, true); - perform_test(1.into(), GetAlphaForTao::with_amount(123_456), 1000.0, true); - perform_test(2.into(), GetTaoForAlpha::with_amount(1_000), 0.0001, false); - perform_test(2.into(), GetTaoForAlpha::with_amount(2_000), 0.0001, false); + perform_test( + 1.into(), + GetAlphaForTao::with_amount(1_000), + 1000.0, + 3990, + true, + ); perform_test( 2.into(), - GetTaoForAlpha::with_amount(123_456), + GetTaoForAlpha::with_amount(1_000), 0.0001, + 250, false, ); perform_test( 3.into(), - GetAlphaForTao::with_amount(1_000_000_000), - 1000.0, - true, - ); - perform_test( - 3.into(), - GetAlphaForTao::with_amount(10_000_000_000), + GetAlphaForTao::with_amount(500_000_000), 1000.0, + 2_000_000_000, true, ); }); } -// cargo test --package pallet-subtensor-swap --lib -- pallet::impls::tests::test_swap_precision_edge_case --exact --show-output +// In this test the swap starts and ends within one (large liquidity) position +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_swap_single_position --exact --show-output #[test] -fn test_swap_precision_edge_case() { - // Test case: tao_reserve, alpha_reserve, swap_amount - [ - (1_000_u64, 1_000_u64, 999_500_u64), - (1_000_000_u64, 1_000_000_u64, 999_500_000_u64), - ] - .into_iter() - .for_each(|(tao_reserve, alpha_reserve, swap_amount)| { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - let order = GetTaoForAlpha::with_amount(swap_amount); - - // Very low reserves - TaoReserve::set_mock_reserve(netuid, TaoCurrency::from(tao_reserve)); - AlphaReserve::set_mock_reserve(netuid, AlphaCurrency::from(alpha_reserve)); +fn test_swap_single_position() { + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let max_tick = price_to_tick(max_price); + let netuid = NetUid::from(1); + assert_eq!(max_tick, TickIndex::MAX); + + let mut current_price_low = 0_f64; + let mut current_price_high = 0_f64; + let mut current_price = 0_f64; + new_test_ext().execute_with(|| { + let (low, high) = get_ticked_prices_around_current_price(); + current_price_low = low; + current_price_high = high; + current_price = Pallet::::current_price(netuid).to_num::(); + }); - // Minimum possible limit price - let limit_price: U64F64 = get_min_price(); - println!("limit_price = {:?}", limit_price); + macro_rules! perform_test { + ($order_t:ident, + $price_low_offset:expr, + $price_high_offset:expr, + $position_liquidity:expr, + $liquidity_fraction:expr, + $limit_price:expr, + $price_should_grow:expr + ) => { + new_test_ext().execute_with(|| { + let price_low_offset = $price_low_offset; + let price_high_offset = $price_high_offset; + let position_liquidity = $position_liquidity; + let order_liquidity_fraction = $liquidity_fraction; + let limit_price = $limit_price; + let price_should_grow = $price_should_grow; + + ////////////////////////////////////////////// + // Initialize pool and add the user position + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + let tao_reserve = TaoReserve::reserve(netuid.into()).to_u64(); + let alpha_reserve = AlphaReserve::reserve(netuid.into()).to_u64(); + let protocol_liquidity = (tao_reserve as f64 * alpha_reserve as f64).sqrt(); + + // Add liquidity + let current_price = Pallet::::current_price(netuid).to_num::(); + let sqrt_current_price = AlphaSqrtPrice::::get(netuid).to_num::(); + + let price_low = price_low_offset + current_price; + let price_high = price_high_offset + current_price; + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + let (_position_id, _tao, _alpha) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + position_liquidity, + ) + .unwrap(); + + // Liquidity position at correct ticks + assert_eq!( + Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), + 1 + ); - // Swap - let swap_result = - Pallet::::do_swap(netuid, order, limit_price, false, true).unwrap(); + // Get tick infos before the swap + let tick_low_info_before = Ticks::::get(netuid, tick_low).unwrap_or_default(); + let tick_high_info_before = + Ticks::::get(netuid, tick_high).unwrap_or_default(); + let liquidity_before = CurrentLiquidity::::get(netuid); + assert_abs_diff_eq!( + liquidity_before as f64, + protocol_liquidity + position_liquidity as f64, + epsilon = liquidity_before as f64 / 1000. + ); - assert!(swap_result.amount_paid_out > TaoCurrency::ZERO); - }); - }); -} + ////////////////////////////////////////////// + // Swap -#[test] -fn test_convert_deltas() { - new_test_ext().execute_with(|| { - for (tao, alpha, w_quote, delta_in) in [ - (1500, 1000, 0.5, 1), - (1500, 1000, 0.5, 10000), - (1500, 1000, 0.5, 1000000), - (1500, 1000, 0.5, u64::MAX), - (1, 1000000, 0.5, 1), - (1, 1000000, 0.5, 10000), - (1, 1000000, 0.5, 1000000), - (1, 1000000, 0.5, u64::MAX), - (1000000, 1, 0.5, 1), - (1000000, 1, 0.5, 10000), - (1000000, 1, 0.5, 1000000), - (1000000, 1, 0.5, u64::MAX), - (1500, 1000, 0.50000001, 1), - (1500, 1000, 0.50000001, 10000), - (1500, 1000, 0.50000001, 1000000), - (1500, 1000, 0.50000001, u64::MAX), - (1, 1000000, 0.50000001, 1), - (1, 1000000, 0.50000001, 10000), - (1, 1000000, 0.50000001, 1000000), - (1, 1000000, 0.50000001, u64::MAX), - (1000000, 1, 0.50000001, 1), - (1000000, 1, 0.50000001, 10000), - (1000000, 1, 0.50000001, 1000000), - (1000000, 1, 0.50000001, u64::MAX), - (1500, 1000, 0.49999999, 1), - (1500, 1000, 0.49999999, 10000), - (1500, 1000, 0.49999999, 1000000), - (1500, 1000, 0.49999999, u64::MAX), - (1, 1000000, 0.49999999, 1), - (1, 1000000, 0.49999999, 10000), - (1, 1000000, 0.49999999, 1000000), - (1, 1000000, 0.49999999, u64::MAX), - (1000000, 1, 0.49999999, 1), - (1000000, 1, 0.49999999, 10000), - (1000000, 1, 0.49999999, 1000000), - (1000000, 1, 0.49999999, u64::MAX), - // Low quote weight - (1500, 1000, 0.1, 1), - (1500, 1000, 0.1, 10000), - (1500, 1000, 0.1, 1000000), - (1500, 1000, 0.1, u64::MAX), - (1, 1000000, 0.1, 1), - (1, 1000000, 0.1, 10000), - (1, 1000000, 0.1, 1000000), - (1, 1000000, 0.1, u64::MAX), - (1000000, 1, 0.1, 1), - (1000000, 1, 0.1, 10000), - (1000000, 1, 0.1, 1000000), - (1000000, 1, 0.1, u64::MAX), - // High quote weight - (1500, 1000, 0.9, 1), - (1500, 1000, 0.9, 10000), - (1500, 1000, 0.9, 1000000), - (1500, 1000, 0.9, u64::MAX), - (1, 1000000, 0.9, 1), - (1, 1000000, 0.9, 10000), - (1, 1000000, 0.9, 1000000), - (1, 1000000, 0.9, u64::MAX), - (1000000, 1, 0.9, 1), - (1000000, 1, 0.9, 10000), - (1000000, 1, 0.9, 1000000), - (1000000, 1, 0.9, u64::MAX), - ] { - // Initialize reserves and weights - let netuid = NetUid::from(1); - TaoReserve::set_mock_reserve(netuid, TaoCurrency::from(tao)); - AlphaReserve::set_mock_reserve(netuid, AlphaCurrency::from(alpha)); - assert_ok!(Pallet::::maybe_initialize_palswap(netuid, None)); - - let w_accuracy = 1_000_000_000_f64; - let w_quote_pt = - Perquintill::from_rational((w_quote * w_accuracy) as u128, w_accuracy as u128); - let bal = Balancer::new(w_quote_pt).unwrap(); - SwapBalancer::::insert(netuid, bal); - - // Calculate expected swap results (buy and sell) using f64 math - let y = tao as f64; - let x = alpha as f64; - let d = delta_in as f64; - let w1_div_w2 = (1. - w_quote) / w_quote; - let w2_div_w1 = w_quote / (1. - w_quote); - let expected_sell = y * (1. - (x / (x + d)).powf(w1_div_w2)); - let expected_buy = x * (1. - (y / (y + d)).powf(w2_div_w1)); + // Calculate the expected output amount for the cornercase of one step + let order_liquidity = order_liquidity_fraction * position_liquidity as f64; - assert_abs_diff_eq!( - u64::from( - BasicSwapStep::::convert_deltas( - netuid, - delta_in.into() - ) - ), - expected_sell as u64, - epsilon = 2u64 - ); - assert_abs_diff_eq!( - u64::from( - BasicSwapStep::::convert_deltas( - netuid, - delta_in.into() - ) - ), - expected_buy as u64, - epsilon = 2u64 - ); - } - }); -} + let output_amount = >::approx_expected_swap_output( + sqrt_current_price, + liquidity_before as f64, + order_liquidity, + ); -#[test] -fn test_rollback_works() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); + // Do the swap + let sqrt_limit_price = SqrtPrice::from_num((limit_price).sqrt()); + let order = $order_t::with_amount(order_liquidity as u64); + let swap_result = + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); + assert_abs_diff_eq!( + swap_result.amount_paid_out.to_u64() as f64, + output_amount, + epsilon = output_amount / 10. + ); - assert_eq!( + if order_liquidity_fraction <= 0.001 { + assert_abs_diff_eq!( + swap_result.paid_in_reserve_delta() as i64, + order_liquidity as i64, + epsilon = order_liquidity as i64 / 10 + ); + assert_abs_diff_eq!( + swap_result.paid_out_reserve_delta() as i64, + -(output_amount as i64), + epsilon = output_amount as i64 / 10 + ); + } + + // Assert that price movement is in correct direction + let current_price_after = Pallet::::current_price(netuid); + assert_eq!(price_should_grow, current_price_after > current_price); + + // Assert that for small amounts price stays within the user position + if (order_liquidity_fraction <= 0.001) + && (price_low_offset > 0.0001) + && (price_high_offset > 0.0001) + { + assert!(current_price_after <= price_high); + assert!(current_price_after >= price_low); + } + + // Check that low and high ticks' fees were updated properly + let tick_low_info = Ticks::::get(netuid, tick_low).unwrap(); + let tick_high_info = Ticks::::get(netuid, tick_high).unwrap(); + let expected_liquidity_net_low = tick_low_info_before.liquidity_net; + let expected_liquidity_gross_low = tick_low_info_before.liquidity_gross; + let expected_liquidity_net_high = tick_high_info_before.liquidity_net; + let expected_liquidity_gross_high = tick_high_info_before.liquidity_gross; + assert_eq!(tick_low_info.liquidity_net, expected_liquidity_net_low,); + assert_eq!(tick_low_info.liquidity_gross, expected_liquidity_gross_low,); + assert_eq!(tick_high_info.liquidity_net, expected_liquidity_net_high,); + assert_eq!( + tick_high_info.liquidity_gross, + expected_liquidity_gross_high, + ); + + // Expected fee amount + let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; + let expected_fee = (order_liquidity - order_liquidity / (1.0 + fee_rate)) as u64; + + // // Global fees should be updated + let actual_global_fee = ($order_t::with_amount(0) + .amount() + .global_fee(netuid) + .to_num::() + * (liquidity_before as f64)) as u64; + + assert_abs_diff_eq!( + swap_result.fee_paid.to_u64(), + expected_fee, + epsilon = expected_fee / 10 + ); + assert_abs_diff_eq!(actual_global_fee, expected_fee, epsilon = expected_fee / 10); + + // Tick fees should be updated + + // Liquidity position should not be updated + let positions = + Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .collect::>(); + let position = positions.first().unwrap(); + + assert_eq!(position.liquidity, position_liquidity,); + assert_eq!(position.tick_low, tick_low); + assert_eq!(position.tick_high, tick_high); + assert_eq!(position.fees_alpha, 0); + assert_eq!(position.fees_tao, 0); + }); + }; + } + + // Current price is 0.25 + // The test case is based on the current price and position prices are defined as a price + // offset from the current price + // Outer part of test case is Position: (price_low_offset, price_high_offset, liquidity) + [ + // Very localized position at the current price + (-0.1, 0.1, 500_000_000_000_u64), + // Repeat the protocol liquidity at maximum range + ( + min_price - current_price, + max_price - current_price, + 2_000_000_000_u64, + ), + // Repeat the protocol liquidity at current to max range + ( + current_price_high - current_price, + max_price - current_price, + 2_000_000_000_u64, + ), + // Repeat the protocol liquidity at min to current range + ( + min_price - current_price, + current_price_low - current_price, + 2_000_000_000_u64, + ), + // Half to double price + (-0.125, 0.25, 2_000_000_000_u64), + // A few other price ranges and liquidity volumes + (-0.1, 0.1, 2_000_000_000_u64), + (-0.1, 0.1, 10_000_000_000_u64), + (-0.1, 0.1, 100_000_000_000_u64), + (-0.01, 0.01, 100_000_000_000_u64), + (-0.001, 0.001, 100_000_000_000_u64), + ] + .into_iter() + .for_each( + |(price_low_offset, price_high_offset, position_liquidity)| { + // Inner part of test case is Order: (order_type, order_liquidity, limit_price) + // order_liquidity is represented as a fraction of position_liquidity + for liquidity_fraction in [0.0001, 0.001, 0.01, 0.1, 0.2, 0.5] { + perform_test!( + GetAlphaForTao, + price_low_offset, + price_high_offset, + position_liquidity, + liquidity_fraction, + 1000.0_f64, + true + ); + perform_test!( + GetTaoForAlpha, + price_low_offset, + price_high_offset, + position_liquidity, + liquidity_fraction, + 0.0001_f64, + false + ); + } + }, + ); +} + +// This test is a sanity check for swap and multiple positions +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor-swap --lib -- pallet::impls::tests::test_swap_multiple_positions --exact --show-output --nocapture +#[test] +fn test_swap_multiple_positions() { + new_test_ext().execute_with(|| { + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let max_tick = price_to_tick(max_price); + let netuid = NetUid::from(1); + assert_eq!(max_tick, TickIndex::MAX); + + ////////////////////////////////////////////// + // Initialize pool and add the user position + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Add liquidity + let current_price = Pallet::::current_price(netuid).to_num::(); + + // Current price is 0.25 + // All positions below are placed at once + [ + // Very localized position at the current price + (-0.1, 0.1, 500_000_000_000_u64), + // Repeat the protocol liquidity at maximum range + ( + min_price - current_price, + max_price - current_price, + 2_000_000_000_u64, + ), + // Repeat the protocol liquidity at current to max range + (0.0, max_price - current_price, 2_000_000_000_u64), + // Repeat the protocol liquidity at min to current range + (min_price - current_price, 0.0, 2_000_000_000_u64), + // Half to double price + (-0.125, 0.25, 2_000_000_000_u64), + // A few other price ranges and liquidity volumes + (-0.1, 0.1, 2_000_000_000_u64), + (-0.1, 0.1, 10_000_000_000_u64), + (-0.1, 0.1, 100_000_000_000_u64), + (-0.01, 0.01, 100_000_000_000_u64), + (-0.001, 0.001, 100_000_000_000_u64), + // A few (overlapping) positions up the range + (0.01, 0.02, 100_000_000_000_u64), + (0.02, 0.03, 100_000_000_000_u64), + (0.03, 0.04, 100_000_000_000_u64), + (0.03, 0.05, 100_000_000_000_u64), + // A few (overlapping) positions down the range + (-0.02, -0.01, 100_000_000_000_u64), + (-0.03, -0.02, 100_000_000_000_u64), + (-0.04, -0.03, 100_000_000_000_u64), + (-0.05, -0.03, 100_000_000_000_u64), + ] + .into_iter() + .for_each( + |(price_low_offset, price_high_offset, position_liquidity)| { + let price_low = price_low_offset + current_price; + let price_high = price_high_offset + current_price; + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + let (_position_id, _tao, _alpha) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + position_liquidity, + ) + .unwrap(); + }, + ); + + macro_rules! perform_test { + ($order_t:ident, $order_liquidity:expr, $limit_price:expr, $should_price_grow:expr) => { + ////////////////////////////////////////////// + // Swap + let order_liquidity = $order_liquidity; + let limit_price = $limit_price; + let should_price_grow = $should_price_grow; + + let sqrt_current_price = AlphaSqrtPrice::::get(netuid); + let current_price = (sqrt_current_price * sqrt_current_price).to_num::(); + let liquidity_before = CurrentLiquidity::::get(netuid); + let output_amount = >::approx_expected_swap_output( + sqrt_current_price.to_num(), + liquidity_before as f64, + order_liquidity as f64, + ); + + // Do the swap + let sqrt_limit_price = SqrtPrice::from_num((limit_price).sqrt()); + let order = $order_t::with_amount(order_liquidity); + let swap_result = + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); + assert_abs_diff_eq!( + swap_result.amount_paid_out.to_u64() as f64, + output_amount, + epsilon = output_amount / 10. + ); + + let tao_reserve = TaoReserve::reserve(netuid.into()).to_u64(); + let alpha_reserve = AlphaReserve::reserve(netuid.into()).to_u64(); + let output_amount = output_amount as u64; + + assert!(output_amount > 0); + + if alpha_reserve > order_liquidity && tao_reserve > order_liquidity { + assert_abs_diff_eq!( + swap_result.paid_in_reserve_delta() as i64, + order_liquidity as i64, + epsilon = order_liquidity as i64 / 100 + ); + assert_abs_diff_eq!( + swap_result.paid_out_reserve_delta() as i64, + -(output_amount as i64), + epsilon = output_amount as i64 / 100 + ); + } + + // Assert that price movement is in correct direction + let sqrt_current_price_after = AlphaSqrtPrice::::get(netuid); + let current_price_after = + (sqrt_current_price_after * sqrt_current_price_after).to_num::(); + assert_eq!(should_price_grow, current_price_after > current_price); + }; + } + + // All these orders are executed without swap reset + for order_liquidity in [ + (100_000_u64), + (1_000_000), + (10_000_000), + (100_000_000), + (200_000_000), + (500_000_000), + (1_000_000_000), + (10_000_000_000), + ] { + perform_test!(GetAlphaForTao, order_liquidity, 1000.0_f64, true); + perform_test!(GetTaoForAlpha, order_liquidity, 0.0001_f64, false); + } + + // Current price shouldn't be much different from the original + let sqrt_current_price_after = AlphaSqrtPrice::::get(netuid); + let current_price_after = + (sqrt_current_price_after * sqrt_current_price_after).to_num::(); + assert_abs_diff_eq!( + current_price, + current_price_after, + epsilon = current_price / 10. + ) + }); +} + +// cargo test --package pallet-subtensor-swap --lib -- pallet::impls::tests::test_swap_precision_edge_case --exact --show-output +#[test] +fn test_swap_precision_edge_case() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(123); // 123 is netuid with low edge case liquidity + let order = GetTaoForAlpha::with_amount(1_000_000_000_000_000_000); + let tick_low = TickIndex::MIN; + + let sqrt_limit_price: SqrtPrice = tick_low.try_to_sqrt_price().unwrap(); + + // Setup swap + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Swap + let swap_result = + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, true).unwrap(); + + assert!(swap_result.amount_paid_out > TaoCurrency::ZERO); + }); +} + +// cargo test --package pallet-subtensor-swap --lib -- pallet::impls::tests::test_price_tick_price_roundtrip --exact --show-output +#[test] +fn test_price_tick_price_roundtrip() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + // Setup swap + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + let current_price = SqrtPrice::from_num(0.500_000_512_192_122_7); + let tick = TickIndex::try_from_sqrt_price(current_price).unwrap(); + + let round_trip_price = TickIndex::try_to_sqrt_price(&tick).unwrap(); + assert!(round_trip_price <= current_price); + + let roundtrip_tick = TickIndex::try_from_sqrt_price(round_trip_price).unwrap(); + assert!(tick == roundtrip_tick); + }); +} + +#[test] +fn test_convert_deltas() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + for (sqrt_price, delta_in, expected_buy, expected_sell) in [ + (SqrtPrice::from_num(1.5), 1, 0, 2), + (SqrtPrice::from_num(1.5), 10000, 4444, 22500), + (SqrtPrice::from_num(1.5), 1000000, 444444, 2250000), + ( + SqrtPrice::from_num(1.5), + u64::MAX, + 2000000000000, + 3000000000000, + ), + ( + TickIndex::MIN.as_sqrt_price_bounded(), + 1, + 18406523739291577836, + 465, + ), + (TickIndex::MIN.as_sqrt_price_bounded(), 10000, u64::MAX, 465), + ( + TickIndex::MIN.as_sqrt_price_bounded(), + 1000000, + u64::MAX, + 465, + ), + ( + TickIndex::MIN.as_sqrt_price_bounded(), + u64::MAX, + u64::MAX, + 464, + ), + ( + TickIndex::MAX.as_sqrt_price_bounded(), + 1, + 0, + 18406523745214495085, + ), + (TickIndex::MAX.as_sqrt_price_bounded(), 10000, 0, u64::MAX), + (TickIndex::MAX.as_sqrt_price_bounded(), 1000000, 0, u64::MAX), + ( + TickIndex::MAX.as_sqrt_price_bounded(), + u64::MAX, + 2000000000000, + u64::MAX, + ), + ] { + { + AlphaSqrtPrice::::insert(netuid, sqrt_price); + + assert_abs_diff_eq!( + BasicSwapStep::::convert_deltas( + netuid, + delta_in.into() + ), + expected_sell.into(), + epsilon = 2.into() + ); + assert_abs_diff_eq!( + BasicSwapStep::::convert_deltas( + netuid, + delta_in.into() + ), + expected_buy.into(), + epsilon = 2.into() + ); + } + } + }); +} + +// #[test] +// fn test_user_liquidity_disabled() { +// new_test_ext().execute_with(|| { +// // Use a netuid above 100 since our mock enables liquidity for 0-100 +// let netuid = NetUid::from(101); +// let tick_low = TickIndex::new_unchecked(-1000); +// let tick_high = TickIndex::new_unchecked(1000); +// let position_id = PositionId::from(1); +// let liquidity = 1_000_000_000; +// let liquidity_delta = 500_000_000; + +// assert!(!EnabledUserLiquidity::::get(netuid)); + +// assert_noop!( +// Swap::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity +// ), +// Error::::UserLiquidityDisabled +// ); + +// assert_noop!( +// Swap::do_remove_liquidity(netuid, &OK_COLDKEY_ACCOUNT_ID, position_id), +// Error::::LiquidityNotFound +// ); + +// assert_noop!( +// Swap::modify_position( +// RuntimeOrigin::signed(OK_COLDKEY_ACCOUNT_ID), +// OK_HOTKEY_ACCOUNT_ID, +// netuid, +// position_id, +// liquidity_delta +// ), +// Error::::UserLiquidityDisabled +// ); + +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid, +// true +// )); + +// let position_id = Swap::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity, +// ) +// .unwrap() +// .0; + +// assert_ok!(Swap::do_modify_position( +// netuid.into(), +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// position_id, +// liquidity_delta, +// )); + +// assert_ok!(Swap::do_remove_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// position_id, +// )); +// }); +// } + +/// Test correctness of swap fees: +/// - Fees are distribued to (concentrated) liquidity providers +/// +#[test] +fn test_swap_fee_correctness() { + new_test_ext().execute_with(|| { + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let netuid = NetUid::from(1); + + // Provide very spread liquidity at the range from min to max that matches protocol liquidity + let liquidity = 2_000_000_000_000_u64; // 1x of protocol liquidity + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Calculate ticks + let tick_low = price_to_tick(min_price); + let tick_high = price_to_tick(max_price); + + // Add user liquidity + let (position_id, _tao, _alpha) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + ) + .unwrap(); + + // Swap buy and swap sell + Pallet::::do_swap( + netuid, + GetAlphaForTao::with_amount(liquidity / 10), + u64::MAX.into(), + false, + false, + ) + .unwrap(); + Pallet::::do_swap( + netuid, + GetTaoForAlpha::with_amount(liquidity / 10), + 0_u64.into(), + false, + false, + ) + .unwrap(); + + // Get user position + let mut position = + Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID, position_id)).unwrap(); + assert_eq!(position.liquidity, liquidity); + assert_eq!(position.tick_low, tick_low); + assert_eq!(position.tick_high, tick_high); + + // Check that 50% of fees were credited to the position + let fee_rate = FeeRate::::get(NetUid::from(netuid)) as f64 / u16::MAX as f64; + let (actual_fee_tao, actual_fee_alpha) = position.collect_fees(); + let expected_fee = (fee_rate * (liquidity / 10) as f64 * 0.5) as u64; + + assert_abs_diff_eq!(actual_fee_tao, expected_fee, epsilon = 1,); + assert_abs_diff_eq!(actual_fee_alpha, expected_fee, epsilon = 1,); + }); +} + +#[test] +fn test_current_liquidity_updates() { + let netuid = NetUid::from(1); + let liquidity = 1_000_000_000; + + // Get current price + let (current_price, current_price_low, current_price_high) = + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + let sqrt_current_price = AlphaSqrtPrice::::get(netuid); + let current_price = (sqrt_current_price * sqrt_current_price).to_num::(); + let (current_price_low, current_price_high) = get_ticked_prices_around_current_price(); + (current_price, current_price_low, current_price_high) + }); + + // Test case: (price_low, price_high, expect_to_update) + [ + // Current price is out of position range (lower), no current lq update + (current_price * 2., current_price * 3., false), + // Current price is out of position range (higher), no current lq update + (current_price / 3., current_price / 2., false), + // Current price is just below position range, no current lq update + (current_price_high, current_price * 3., false), + // Position lower edge is just below the current price, current lq updates + (current_price_low, current_price * 3., true), + // Current price is exactly at lower edge of position range, current lq updates + (current_price, current_price * 3., true), + // Current price is exactly at higher edge of position range, no current lq update + (current_price / 2., current_price, false), + ] + .into_iter() + .for_each(|(price_low, price_high, expect_to_update)| { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Calculate ticks (assuming tick math is tested separately) + let tick_low = price_to_tick(price_low); + let tick_high = price_to_tick(price_high); + let liquidity_before = CurrentLiquidity::::get(netuid); + + // Add liquidity + assert_ok!(Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + )); + + // Current liquidity is updated only when price range includes the current price + let expected_liquidity = if (price_high > current_price) && (price_low <= current_price) + { + assert!(expect_to_update); + liquidity_before + liquidity + } else { + assert!(!expect_to_update); + liquidity_before + }; + + assert_eq!(CurrentLiquidity::::get(netuid), expected_liquidity) + }); + }); +} + +#[test] +fn test_rollback_works() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + assert_eq!( Pallet::::do_swap( netuid, GetAlphaForTao::with_amount(1_000_000), @@ -764,7 +1620,80 @@ fn test_rollback_works() { }) } -#[allow(dead_code)] +/// Test correctness of swap fees: +/// - New LP is not eligible to previously accrued fees +/// +/// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_new_lp_doesnt_get_old_fees --exact --show-output +#[test] +fn test_new_lp_doesnt_get_old_fees() { + new_test_ext().execute_with(|| { + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let netuid = NetUid::from(1); + + // Provide very spread liquidity at the range from min to max that matches protocol liquidity + let liquidity = 2_000_000_000_000_u64; // 1x of protocol liquidity + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Calculate ticks + let tick_low = price_to_tick(min_price); + let tick_high = price_to_tick(max_price); + + // Add user liquidity + Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + ) + .unwrap(); + + // Swap buy and swap sell + Pallet::::do_swap( + netuid, + GetAlphaForTao::with_amount(liquidity / 10), + u64::MAX.into(), + false, + false, + ) + .unwrap(); + Pallet::::do_swap( + netuid, + GetTaoForAlpha::with_amount(liquidity / 10), + 0_u64.into(), + false, + false, + ) + .unwrap(); + + // Add liquidity from a different user to a new tick + let (position_id_2, _tao, _alpha) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID_2, + &OK_HOTKEY_ACCOUNT_ID_2, + tick_low.next().unwrap(), + tick_high.prev().unwrap(), + liquidity, + ) + .unwrap(); + + // Get user position + let mut position = + Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID_2, position_id_2)).unwrap(); + assert_eq!(position.liquidity, liquidity); + assert_eq!(position.tick_low, tick_low.next().unwrap()); + assert_eq!(position.tick_high, tick_high.prev().unwrap()); + + // Check that collected fees are 0 + let (actual_fee_tao, actual_fee_alpha) = position.collect_fees(); + assert_abs_diff_eq!(actual_fee_tao, 0, epsilon = 1); + assert_abs_diff_eq!(actual_fee_alpha, 0, epsilon = 1); + }); +} + fn bbox(t: U64F64, a: U64F64, b: U64F64) -> U64F64 { if t < a { a @@ -775,40 +1704,955 @@ fn bbox(t: U64F64, a: U64F64, b: U64F64) -> U64F64 { } } -#[allow(dead_code)] fn print_current_price(netuid: NetUid) { - let current_price = Pallet::::current_price(netuid); + let current_sqrt_price = AlphaSqrtPrice::::get(netuid).to_num::(); + let current_price = current_sqrt_price * current_sqrt_price; log::trace!("Current price: {current_price:.6}"); } -/// Simple palswap path: PalSwap is initialized. -/// Function must still clear any residual storages and succeed. +/// RUST_LOG=pallet_subtensor_swap=trace cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_wrapping_fees --exact --show-output --nocapture #[test] -fn test_liquidate_pal_simple_ok_and_clears() { +fn test_wrapping_fees() { new_test_ext().execute_with(|| { - let netuid = NetUid::from(202); + let netuid = NetUid::from(WRAPPING_FEES_NETUID); + let position_1_low_price = 0.20; + let position_1_high_price = 0.255; + let position_2_low_price = 0.255; + let position_2_high_price = 0.257; + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID_RICH, + &OK_COLDKEY_ACCOUNT_ID_RICH, + price_to_tick(position_1_low_price), + price_to_tick(position_1_high_price), + 1_000_000_000_u64, + ) + .unwrap(); - // Insert map values - FeeRate::::insert(netuid, 1_000); - FeesTao::::insert(netuid, TaoCurrency::from(1_000)); - FeesAlpha::::insert(netuid, AlphaCurrency::from(1_000)); - PalSwapInitialized::::insert(netuid, true); - let w_quote_pt = Perquintill::from_rational(1u128, 2u128); - let bal = Balancer::new(w_quote_pt).unwrap(); - SwapBalancer::::insert(netuid, bal); + print_current_price(netuid); - // Sanity: PalSwap is not initialized - assert!(PalSwapInitialized::::get(netuid)); + let order = GetTaoForAlpha::with_amount(800_000_000); + let sqrt_limit_price = SqrtPrice::from_num(0.000001); + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); - // ACT + let order = GetAlphaForTao::with_amount(1_850_000_000); + let sqrt_limit_price = SqrtPrice::from_num(1_000_000.0); + + print_current_price(netuid); + + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); + + print_current_price(netuid); + + let add_liquidity_result = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID_RICH, + &OK_COLDKEY_ACCOUNT_ID_RICH, + price_to_tick(position_2_low_price), + price_to_tick(position_2_high_price), + 1_000_000_000_u64, + ) + .unwrap(); + + let order = GetTaoForAlpha::with_amount(1_800_000_000); + let sqrt_limit_price = SqrtPrice::from_num(0.000001); + + let initial_sqrt_price = AlphaSqrtPrice::::get(netuid); + Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); + let final_sqrt_price = AlphaSqrtPrice::::get(netuid); + + print_current_price(netuid); + + let mut position = + Positions::::get((netuid, &OK_COLDKEY_ACCOUNT_ID_RICH, add_liquidity_result.0)) + .unwrap(); + + let initial_box_price = bbox( + initial_sqrt_price, + position.tick_low.try_to_sqrt_price().unwrap(), + position.tick_high.try_to_sqrt_price().unwrap(), + ); + + let final_box_price = bbox( + final_sqrt_price, + position.tick_low.try_to_sqrt_price().unwrap(), + position.tick_high.try_to_sqrt_price().unwrap(), + ); + + let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; + + log::trace!("fee_rate: {fee_rate:.6}"); + log::trace!("position.liquidity: {}", position.liquidity); + log::trace!( + "initial_box_price: {:.6}", + initial_box_price.to_num::() + ); + log::trace!("final_box_price: {:.6}", final_box_price.to_num::()); + + let expected_fee_tao = ((fee_rate / (1.0 - fee_rate)) + * (position.liquidity as f64) + * (final_box_price.to_num::() - initial_box_price.to_num::())) + as u64; + + let expected_fee_alpha = ((fee_rate / (1.0 - fee_rate)) + * (position.liquidity as f64) + * ((1.0 / final_box_price.to_num::()) - (1.0 / initial_box_price.to_num::()))) + as u64; + + log::trace!("Expected ALPHA fee: {:.6}", expected_fee_alpha as f64); + + let (fee_tao, fee_alpha) = position.collect_fees(); + + log::trace!("Collected fees: TAO: {fee_tao}, ALPHA: {fee_alpha}"); + + assert_abs_diff_eq!(fee_tao, expected_fee_tao, epsilon = 1); + assert_abs_diff_eq!(fee_alpha, expected_fee_alpha, epsilon = 1); + }); +} + +/// Test that price moves less with provided liquidity +/// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_less_price_movement --exact --show-output +#[test] +fn test_less_price_movement() { + let netuid = NetUid::from(1); + let mut last_end_price = U96F32::from_num(0); + let initial_stake_liquidity = 1_000_000_000; + let swapped_liquidity = 1_000_000; + + // Test case is (order_type, provided_liquidity) + // Testing algorithm: + // - Stake initial_stake_liquidity + // - Provide liquidity if iteration provides lq + // - Buy or sell + // - Save end price if iteration doesn't provide lq + macro_rules! perform_test { + ($order_t:ident, $provided_liquidity:expr, $limit_price:expr, $should_price_shrink:expr) => { + let provided_liquidity = $provided_liquidity; + let should_price_shrink = $should_price_shrink; + let limit_price = $limit_price; + new_test_ext().execute_with(|| { + // Setup swap + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Buy Alpha + assert_ok!(Pallet::::do_swap( + netuid, + GetAlphaForTao::with_amount(initial_stake_liquidity), + SqrtPrice::from_num(10_000_000_000_u64), + false, + false + )); + + // Get current price + let start_price = Pallet::::current_price(netuid); + + // Add liquidity if this test iteration provides + if provided_liquidity > 0 { + let tick_low = price_to_tick(start_price.to_num::() * 0.5); + let tick_high = price_to_tick(start_price.to_num::() * 1.5); + assert_ok!(Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + provided_liquidity, + )); + } + + // Swap + let sqrt_limit_price = SqrtPrice::from_num(limit_price); + assert_ok!(Pallet::::do_swap( + netuid, + $order_t::with_amount(swapped_liquidity), + sqrt_limit_price, + false, + false + )); + + let end_price = Pallet::::current_price(netuid); + + // Save end price if iteration doesn't provide or compare with previous end price if + // it does + if provided_liquidity > 0 { + assert_eq!(should_price_shrink, end_price < last_end_price); + } else { + last_end_price = end_price; + } + }); + }; + } + + for provided_liquidity in [0, 1_000_000_000_000_u64] { + perform_test!(GetAlphaForTao, provided_liquidity, 1000.0_f64, true); + } + for provided_liquidity in [0, 1_000_000_000_000_u64] { + perform_test!(GetTaoForAlpha, provided_liquidity, 0.001_f64, false); + } +} + +// TODO: Revise when user liquidity is available +// #[test] +// fn test_swap_subtoken_disabled() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(SUBTOKEN_DISABLED_NETUID); // Use a netuid not used elsewhere +// let price_low = 0.1; +// let price_high = 0.2; +// let tick_low = price_to_tick(price_low); +// let tick_high = price_to_tick(price_high); +// let liquidity = 1_000_000_u64; + +// assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + +// assert_noop!( +// Pallet::::add_liquidity( +// RuntimeOrigin::signed(OK_COLDKEY_ACCOUNT_ID), +// OK_HOTKEY_ACCOUNT_ID, +// netuid, +// tick_low, +// tick_high, +// liquidity, +// ), +// Error::::SubtokenDisabled +// ); + +// assert_noop!( +// Pallet::::modify_position( +// RuntimeOrigin::signed(OK_COLDKEY_ACCOUNT_ID), +// OK_HOTKEY_ACCOUNT_ID, +// netuid, +// PositionId::from(0), +// liquidity as i64, +// ), +// Error::::SubtokenDisabled +// ); +// }); +// } + +#[test] +fn test_liquidate_v3_removes_positions_ticks_and_state() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + // Initialize V3 (creates protocol position, ticks, price, liquidity) + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + assert!(SwapV3Initialized::::get(netuid)); + + // Enable user LP + assert_ok!(Swap::toggle_user_liquidity( + RuntimeOrigin::root(), + netuid.into(), + true + )); + + // Add a user position across the full range to ensure ticks/bitmap are populated. + let min_price = tick_to_price(TickIndex::MIN); + let max_price = tick_to_price(TickIndex::MAX); + let tick_low = price_to_tick(min_price); + let tick_high = price_to_tick(max_price); + let liquidity = 2_000_000_000_u64; + + let (_pos_id, _tao, _alpha) = Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + liquidity, + ) + .expect("add liquidity"); + + // Accrue some global fees so we can verify fee storage is cleared later. + let sqrt_limit_price = SqrtPrice::from_num(1_000_000.0); + assert_ok!(Pallet::::do_swap( + netuid, + GetAlphaForTao::with_amount(1_000_000), + sqrt_limit_price, + false, + false + )); + + // Sanity: protocol & user positions exist, ticks exist, liquidity > 0 + let protocol_id = Pallet::::protocol_account_id(); + let prot_positions = + Positions::::iter_prefix_values((netuid, protocol_id)).collect::>(); + assert!(!prot_positions.is_empty()); + + let user_positions = Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .collect::>(); + assert_eq!(user_positions.len(), 1); + + assert!(Ticks::::get(netuid, TickIndex::MIN).is_some()); + assert!(Ticks::::get(netuid, TickIndex::MAX).is_some()); + assert!(CurrentLiquidity::::get(netuid) > 0); + + let had_bitmap_words = TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_some(); + assert!(had_bitmap_words); + + // ACT: users-only liquidation then protocol clear + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + // ASSERT: positions cleared (both user and protocol) + assert_eq!( + Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), + 0 + ); + let prot_positions_after = + Positions::::iter_prefix_values((netuid, protocol_id)).collect::>(); + assert!(prot_positions_after.is_empty()); + let user_positions_after = + Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .collect::>(); + assert!(user_positions_after.is_empty()); + + // ASSERT: ticks cleared + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!(Ticks::::get(netuid, TickIndex::MIN).is_none()); + assert!(Ticks::::get(netuid, TickIndex::MAX).is_none()); + + // ASSERT: fee globals cleared + assert!(!FeeGlobalTao::::contains_key(netuid)); + assert!(!FeeGlobalAlpha::::contains_key(netuid)); + + // ASSERT: price/tick/liquidity flags cleared + assert!(!AlphaSqrtPrice::::contains_key(netuid)); + assert!(!CurrentTick::::contains_key(netuid)); + assert!(!CurrentLiquidity::::contains_key(netuid)); + assert!(!SwapV3Initialized::::contains_key(netuid)); + + // ASSERT: active tick bitmap cleared + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none() + ); + + // ASSERT: knobs removed on dereg + assert!(!FeeRate::::contains_key(netuid)); + assert!(!EnabledUserLiquidity::::contains_key(netuid)); + }); +} + +// V3 path with user liquidity disabled at teardown: +// must still remove positions and clear state (after protocol clear). +// #[test] +// fn test_liquidate_v3_with_user_liquidity_disabled() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(101); + +// assert_ok!(Pallet::::maybe_initialize_v3(netuid)); +// assert!(SwapV3Initialized::::get(netuid)); + +// // Enable temporarily to add a user position +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid.into(), +// true +// )); + +// let min_price = tick_to_price(TickIndex::MIN); +// let max_price = tick_to_price(TickIndex::MAX); +// let tick_low = price_to_tick(min_price); +// let tick_high = price_to_tick(max_price); +// let liquidity = 1_000_000_000_u64; + +// let (_pos_id, _tao, _alpha) = Pallet::::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity, +// ) +// .expect("add liquidity"); + +// // Disable user LP *before* liquidation; removal must ignore this flag. +// assert_ok!(Swap::toggle_user_liquidity( +// RuntimeOrigin::root(), +// netuid.into(), +// false +// )); + +// // Users-only dissolve, then clear protocol liquidity/state. +// assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); +// assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + +// // ASSERT: positions & ticks gone, state reset +// assert_eq!( +// Pallet::::count_positions(netuid, &OK_COLDKEY_ACCOUNT_ID), +// 0 +// ); +// assert!( +// Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) +// .next() +// .is_none() +// ); +// assert!(Ticks::::iter_prefix(netuid).next().is_none()); +// assert!( +// TickIndexBitmapWords::::iter_prefix((netuid,)) +// .next() +// .is_none() +// ); +// assert!(!SwapV3Initialized::::contains_key(netuid)); +// assert!(!AlphaSqrtPrice::::contains_key(netuid)); +// assert!(!CurrentTick::::contains_key(netuid)); +// assert!(!CurrentLiquidity::::contains_key(netuid)); +// assert!(!FeeGlobalTao::::contains_key(netuid)); +// assert!(!FeeGlobalAlpha::::contains_key(netuid)); + +// // `EnabledUserLiquidity` is removed by protocol clear stage. +// assert!(!EnabledUserLiquidity::::contains_key(netuid)); +// }); +// } + +/// Non‑V3 path: V3 not initialized (no positions); function must still clear any residual storages and succeed. +#[test] +fn test_liquidate_non_v3_uninitialized_ok_and_clears() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(202); + + // Sanity: V3 is not initialized + assert!(!SwapV3Initialized::::get(netuid)); + assert!( + Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .next() + .is_none() + ); + + // ACT + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // ASSERT: Defensive clears leave no residues and do not panic + assert!( + Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .next() + .is_none() + ); + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none() + ); + // All single-key maps should not have the key after liquidation + assert!(!FeeGlobalTao::::contains_key(netuid)); + assert!(!FeeGlobalAlpha::::contains_key(netuid)); + assert!(!CurrentLiquidity::::contains_key(netuid)); + assert!(!CurrentTick::::contains_key(netuid)); + assert!(!AlphaSqrtPrice::::contains_key(netuid)); + assert!(!SwapV3Initialized::::contains_key(netuid)); + assert!(!FeeRate::::contains_key(netuid)); + assert!(!EnabledUserLiquidity::::contains_key(netuid)); + }); +} + +#[test] +fn test_liquidate_idempotent() { + // V3 flavor + new_test_ext().execute_with(|| { + let netuid = NetUid::from(7); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Add a small user position + assert_ok!(Swap::toggle_user_liquidity( + RuntimeOrigin::root(), + netuid.into(), + true + )); + let tick_low = price_to_tick(0.2); + let tick_high = price_to_tick(0.3); + assert_ok!(Pallet::::do_add_liquidity( + netuid, + &OK_COLDKEY_ACCOUNT_ID, + &OK_HOTKEY_ACCOUNT_ID, + tick_low, + tick_high, + 123_456_789 + )); + + // Users-only liquidations are idempotent. + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // Now clear protocol liquidity/state—also idempotent. + assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + + // State remains empty + assert!( + Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .next() + .is_none() + ); + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none() + ); + assert!(!SwapV3Initialized::::contains_key(netuid)); + }); + + // Non‑V3 flavor + new_test_ext().execute_with(|| { + let netuid = NetUid::from(8); + + // Never initialize V3; both calls no-op and succeed. + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + assert!( + Positions::::iter_prefix_values((netuid, OK_COLDKEY_ACCOUNT_ID)) + .next() + .is_none() + ); + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none() + ); + assert!(!SwapV3Initialized::::contains_key(netuid)); + }); +} + +#[test] +fn liquidate_v3_refunds_user_funds_and_clears_state() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + // Enable V3 path & initialize price/ticks (also creates a protocol position). + assert_ok!(Pallet::::toggle_user_liquidity( + RuntimeOrigin::root(), + netuid, + true + )); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Use distinct cold/hot to demonstrate alpha refund/stake accounting. + let cold = OK_COLDKEY_ACCOUNT_ID; + let hot = OK_HOTKEY_ACCOUNT_ID; + + // Tight in‑range band around current tick. + let ct = CurrentTick::::get(netuid); + let tick_low = ct.saturating_sub(10); + let tick_high = ct.saturating_add(10); + let liquidity: u64 = 1_000_000; + + // Snapshot balances BEFORE. + let tao_before = ::BalanceOps::tao_balance(&cold); + let alpha_before_hot = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot); + let alpha_before_owner = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let alpha_before_total = alpha_before_hot + alpha_before_owner; + + // Create the user position (storage & v3 state only; no balances moved yet). + let (_pos_id, need_tao, need_alpha) = + Pallet::::do_add_liquidity(netuid, &cold, &hot, tick_low, tick_high, liquidity) + .expect("add liquidity"); + + // Mirror extrinsic bookkeeping: withdraw funds & bump provided‑reserve counters. + let tao_taken = ::BalanceOps::decrease_balance(&cold, need_tao.into()) + .expect("decrease TAO"); + let alpha_taken = ::BalanceOps::decrease_stake( + &cold, + &hot, + netuid.into(), + need_alpha.into(), + ) + .expect("decrease ALPHA"); + TaoReserve::increase_provided(netuid.into(), tao_taken); + AlphaReserve::increase_provided(netuid.into(), alpha_taken); + + // Users‑only liquidation. + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // Expect balances restored to BEFORE snapshots (no swaps ran -> zero fees). + let tao_after = ::BalanceOps::tao_balance(&cold); + assert_eq!(tao_after, tao_before, "TAO principal must be refunded"); + + // ALPHA totals conserved to owner (distribution may differ). + let alpha_after_hot = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot); + let alpha_after_owner = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let alpha_after_total = alpha_after_hot + alpha_after_owner; + assert_eq!( + alpha_after_total, alpha_before_total, + "ALPHA principal must be refunded/staked for the account (check totals)" + ); + + // Clear protocol liquidity and V3 state now. + assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + + // User position(s) are gone and all V3 state cleared. + assert_eq!(Pallet::::count_positions(netuid, &cold), 0); + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!(!SwapV3Initialized::::contains_key(netuid)); + }); +} + +#[test] +fn refund_alpha_single_provider_exact() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(11); + let cold = OK_COLDKEY_ACCOUNT_ID; + let hot = OK_HOTKEY_ACCOUNT_ID; + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // --- Create an alpha‑only position (range entirely above current tick → TAO = 0, ALPHA > 0). + let ct = CurrentTick::::get(netuid); + let tick_low = ct.next().expect("current tick should not be MAX in tests"); + let tick_high = TickIndex::MAX; + + let liquidity = 1_000_000_u64; + let (_pos_id, tao_needed, alpha_needed) = + Pallet::::do_add_liquidity(netuid, &cold, &hot, tick_low, tick_high, liquidity) + .expect("add alpha-only liquidity"); + assert_eq!(tao_needed, 0, "alpha-only position must not require TAO"); + assert!(alpha_needed > 0, "alpha-only position must require ALPHA"); + + // --- Snapshot BEFORE we withdraw funds (baseline for conservation). + let alpha_before_hot = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot); + let alpha_before_owner = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let alpha_before_total = alpha_before_hot + alpha_before_owner; + + // --- Mimic extrinsic bookkeeping: withdraw α and record provided reserve. + let alpha_taken = ::BalanceOps::decrease_stake( + &cold, + &hot, + netuid.into(), + alpha_needed.into(), + ) + .expect("decrease ALPHA"); + AlphaReserve::increase_provided(netuid.into(), alpha_taken); + + // --- Act: users‑only dissolve. + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // --- Assert: total α conserved to owner (may be staked to validator). + let alpha_after_hot = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot); + let alpha_after_owner = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let alpha_after_total = alpha_after_hot + alpha_after_owner; + assert_eq!( + alpha_after_total, alpha_before_total, + "ALPHA principal must be conserved to the account" + ); + + // Clear protocol liquidity and V3 state now. + assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + + // --- State is cleared. + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert_eq!(Pallet::::count_positions(netuid, &cold), 0); + assert!(!SwapV3Initialized::::contains_key(netuid)); + }); +} + +#[test] +fn refund_alpha_multiple_providers_proportional_to_principal() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(12); + let c1 = OK_COLDKEY_ACCOUNT_ID; + let h1 = OK_HOTKEY_ACCOUNT_ID; + let c2 = OK_COLDKEY_ACCOUNT_ID_2; + let h2 = OK_HOTKEY_ACCOUNT_ID_2; + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Use the same "above current tick" trick for alpha‑only positions. + let ct = CurrentTick::::get(netuid); + let tick_low = ct.next().expect("current tick should not be MAX in tests"); + let tick_high = TickIndex::MAX; + + // Provider #1 (smaller α) + let liq1 = 700_000_u64; + let (_p1, t1, a1) = + Pallet::::do_add_liquidity(netuid, &c1, &h1, tick_low, tick_high, liq1) + .expect("add alpha-only liquidity #1"); + assert_eq!(t1, 0); + assert!(a1 > 0); + + // Provider #2 (larger α) + let liq2 = 2_100_000_u64; + let (_p2, t2, a2) = + Pallet::::do_add_liquidity(netuid, &c2, &h2, tick_low, tick_high, liq2) + .expect("add alpha-only liquidity #2"); + assert_eq!(t2, 0); + assert!(a2 > 0); + + // Baselines BEFORE withdrawing + let a1_before_hot = ::BalanceOps::alpha_balance(netuid.into(), &c1, &h1); + let a1_before_owner = ::BalanceOps::alpha_balance(netuid.into(), &c1, &c1); + let a1_before = a1_before_hot + a1_before_owner; + + let a2_before_hot = ::BalanceOps::alpha_balance(netuid.into(), &c2, &h2); + let a2_before_owner = ::BalanceOps::alpha_balance(netuid.into(), &c2, &c2); + let a2_before = a2_before_hot + a2_before_owner; + + // Withdraw α and account reserves for each provider. + let a1_taken = + ::BalanceOps::decrease_stake(&c1, &h1, netuid.into(), a1.into()) + .expect("decrease α #1"); + AlphaReserve::increase_provided(netuid.into(), a1_taken); + + let a2_taken = + ::BalanceOps::decrease_stake(&c2, &h2, netuid.into(), a2.into()) + .expect("decrease α #2"); + AlphaReserve::increase_provided(netuid.into(), a2_taken); + + // Act + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // Each owner is restored to their exact baseline. + let a1_after_hot = ::BalanceOps::alpha_balance(netuid.into(), &c1, &h1); + let a1_after_owner = ::BalanceOps::alpha_balance(netuid.into(), &c1, &c1); + let a1_after = a1_after_hot + a1_after_owner; + assert_eq!( + a1_after, a1_before, + "owner #1 must receive their α principal back" + ); + + let a2_after_hot = ::BalanceOps::alpha_balance(netuid.into(), &c2, &h2); + let a2_after_owner = ::BalanceOps::alpha_balance(netuid.into(), &c2, &c2); + let a2_after = a2_after_hot + a2_after_owner; + assert_eq!( + a2_after, a2_before, + "owner #2 must receive their α principal back" + ); + }); +} + +#[test] +fn refund_alpha_same_cold_multiple_hotkeys_conserved_to_owner() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(13); + let cold = OK_COLDKEY_ACCOUNT_ID; + let hot1 = OK_HOTKEY_ACCOUNT_ID; + let hot2 = OK_HOTKEY_ACCOUNT_ID_2; + + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + + // Two alpha‑only positions on different hotkeys of the same owner. + let ct = CurrentTick::::get(netuid); + let tick_low = ct.next().expect("current tick should not be MAX in tests"); + let tick_high = TickIndex::MAX; + + let (_p1, _t1, a1) = + Pallet::::do_add_liquidity(netuid, &cold, &hot1, tick_low, tick_high, 900_000) + .expect("add alpha-only pos (hot1)"); + let (_p2, _t2, a2) = + Pallet::::do_add_liquidity(netuid, &cold, &hot2, tick_low, tick_high, 1_500_000) + .expect("add alpha-only pos (hot2)"); + assert!(a1 > 0 && a2 > 0); + + // Baseline BEFORE: sum over (cold,hot1) + (cold,hot2) + (cold,cold). + let before_hot1 = ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot1); + let before_hot2 = ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot2); + let before_owner = ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let before_total = before_hot1 + before_hot2 + before_owner; + + // Withdraw α from both hotkeys; track provided‑reserve. + let t1 = + ::BalanceOps::decrease_stake(&cold, &hot1, netuid.into(), a1.into()) + .expect("decr α #hot1"); + AlphaReserve::increase_provided(netuid.into(), t1); + + let t2 = + ::BalanceOps::decrease_stake(&cold, &hot2, netuid.into(), a2.into()) + .expect("decr α #hot2"); + AlphaReserve::increase_provided(netuid.into(), t2); + + // Act + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // The total α "owned" by the coldkey is conserved (credit may land on (cold,cold)). + let after_hot1 = ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot1); + let after_hot2 = ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot2); + let after_owner = ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let after_total = after_hot1 + after_hot2 + after_owner; + + assert_eq!( + after_total, before_total, + "owner’s α must be conserved across hot ledgers + (owner,owner)" + ); + }); +} + +#[test] +fn test_dissolve_v3_green_path_refund_tao_stake_alpha_and_clear_state() { + new_test_ext().execute_with(|| { + // --- Setup --- + let netuid = NetUid::from(42); + let cold = OK_COLDKEY_ACCOUNT_ID; + let hot = OK_HOTKEY_ACCOUNT_ID; + + assert_ok!(Swap::toggle_user_liquidity( + RuntimeOrigin::root(), + netuid.into(), + true + )); + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); + assert!(SwapV3Initialized::::get(netuid)); + + // Tight in‑range band so BOTH τ and α are required. + let ct = CurrentTick::::get(netuid); + let tick_low = ct.saturating_sub(10); + let tick_high = ct.saturating_add(10); + let liquidity: u64 = 1_250_000; + + // Add liquidity and capture required τ/α. + let (_pos_id, tao_needed, alpha_needed) = + Pallet::::do_add_liquidity(netuid, &cold, &hot, tick_low, tick_high, liquidity) + .expect("add in-range liquidity"); + assert!(tao_needed > 0, "in-range pos must require TAO"); + assert!(alpha_needed > 0, "in-range pos must require ALPHA"); + + // Determine the permitted validator with the highest trust (green path). + let trust = ::SubnetInfo::get_validator_trust(netuid.into()); + let permit = ::SubnetInfo::get_validator_permit(netuid.into()); + assert_eq!(trust.len(), permit.len(), "trust/permit must align"); + let target_uid: u16 = trust + .iter() + .zip(permit.iter()) + .enumerate() + .filter(|(_, (_t, p))| **p) + .max_by_key(|(_, (t, _))| *t) + .map(|(i, _)| i as u16) + .expect("at least one permitted validator"); + let validator_hotkey: ::AccountId = + ::SubnetInfo::hotkey_of_uid(netuid.into(), target_uid) + .expect("uid -> hotkey mapping must exist"); + + // --- Snapshot BEFORE we withdraw τ/α to fund the position --- + let tao_before = ::BalanceOps::tao_balance(&cold); + + let alpha_before_hot = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot); + let alpha_before_owner = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let alpha_before_val = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &validator_hotkey); + + let alpha_before_total = if validator_hotkey == hot { + alpha_before_hot + alpha_before_owner + } else { + alpha_before_hot + alpha_before_owner + alpha_before_val + }; + + // --- Mirror extrinsic bookkeeping: withdraw τ & α; bump provided reserves --- + let tao_taken = ::BalanceOps::decrease_balance(&cold, tao_needed.into()) + .expect("decrease TAO"); + let alpha_taken = ::BalanceOps::decrease_stake( + &cold, + &hot, + netuid.into(), + alpha_needed.into(), + ) + .expect("decrease ALPHA"); + + TaoReserve::increase_provided(netuid.into(), tao_taken); + AlphaReserve::increase_provided(netuid.into(), alpha_taken); + + // --- Act: dissolve (GREEN PATH: permitted validators exist) --- + assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); + + // --- Assert: τ principal refunded to user --- + let tao_after = ::BalanceOps::tao_balance(&cold); + assert_eq!(tao_after, tao_before, "TAO principal must be refunded"); + + // --- α ledger assertions --- + let alpha_after_hot = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &hot); + let alpha_after_owner = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &cold); + let alpha_after_val = + ::BalanceOps::alpha_balance(netuid.into(), &cold, &validator_hotkey); + + // Owner ledger must be unchanged in the green path. + assert_eq!( + alpha_after_owner, alpha_before_owner, + "Owner α ledger must be unchanged (staked to validator, not refunded)" + ); + + if validator_hotkey == hot { + assert_eq!( + alpha_after_hot, alpha_before_hot, + "When validator == hotkey, user's hot ledger must net back to its original balance" + ); + let alpha_after_total = alpha_after_hot + alpha_after_owner; + assert_eq!( + alpha_after_total, alpha_before_total, + "Total α for the coldkey must be conserved (validator==hotkey)" + ); + } else { + assert!( + alpha_before_hot >= alpha_after_hot, + "hot ledger should not increase" + ); + assert!( + alpha_after_val >= alpha_before_val, + "validator ledger should not decrease" + ); + + let hot_loss = alpha_before_hot - alpha_after_hot; + let val_gain = alpha_after_val - alpha_before_val; + assert_eq!( + val_gain, hot_loss, + "α that left the user's hot ledger must equal α credited to the validator ledger" + ); + + let alpha_after_total = alpha_after_hot + alpha_after_owner + alpha_after_val; + assert_eq!( + alpha_after_total, alpha_before_total, + "Total α for the coldkey must be conserved" + ); + } + + // Now clear protocol liquidity & state and assert full reset. + assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + + let protocol_id = Pallet::::protocol_account_id(); + assert_eq!(Pallet::::count_positions(netuid, &cold), 0); + let prot_positions_after = + Positions::::iter_prefix_values((netuid, protocol_id)).collect::>(); + assert!( + prot_positions_after.is_empty(), + "protocol positions must be removed" + ); + + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!(Ticks::::get(netuid, TickIndex::MIN).is_none()); + assert!(Ticks::::get(netuid, TickIndex::MAX).is_none()); + assert!(!CurrentLiquidity::::contains_key(netuid)); + assert!(!CurrentTick::::contains_key(netuid)); + assert!(!AlphaSqrtPrice::::contains_key(netuid)); + assert!(!SwapV3Initialized::::contains_key(netuid)); + + assert!(!FeeGlobalTao::::contains_key(netuid)); + assert!(!FeeGlobalAlpha::::contains_key(netuid)); + + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none(), + "active tick bitmap words must be cleared" + ); + assert!(!FeeRate::::contains_key(netuid)); - assert!(!FeesTao::::contains_key(netuid)); - assert!(!FeesAlpha::::contains_key(netuid)); - assert!(!PalSwapInitialized::::contains_key(netuid)); - assert!(!SwapBalancer::::contains_key(netuid)); + assert!(!EnabledUserLiquidity::::contains_key(netuid)); }); } @@ -816,36 +2660,84 @@ fn test_liquidate_pal_simple_ok_and_clears() { fn test_clear_protocol_liquidity_green_path() { new_test_ext().execute_with(|| { // --- Arrange --- - let netuid = NetUid::from(1); + let netuid = NetUid::from(55); - // Initialize swap state - assert_ok!(Pallet::::maybe_initialize_palswap(netuid, None)); + // Ensure the "user liquidity enabled" flag exists so we can verify it's removed later. + assert_ok!(Pallet::::toggle_user_liquidity( + RuntimeOrigin::root(), + netuid, + true + )); + + // Initialize V3 state; this should set price/tick flags and create a protocol position. + assert_ok!(Pallet::::maybe_initialize_v3(netuid)); assert!( - PalSwapInitialized::::get(netuid), - "Swap must be initialized" + SwapV3Initialized::::get(netuid), + "V3 must be initialized" + ); + + // Sanity: protocol positions exist before clearing. + let protocol_id = Pallet::::protocol_account_id(); + let prot_positions_before = + Positions::::iter_prefix_values((netuid, protocol_id)).collect::>(); + assert!( + !prot_positions_before.is_empty(), + "protocol positions should exist after V3 init" ); // --- Act --- // Green path: just clear protocol liquidity and wipe all V3 state. assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + // --- Assert: all protocol positions removed --- + let prot_positions_after = + Positions::::iter_prefix_values((netuid, protocol_id)).collect::>(); + assert!( + prot_positions_after.is_empty(), + "protocol positions must be removed by do_clear_protocol_liquidity" + ); + + // --- Assert: V3 data wiped (idempotent even if some maps were empty) --- + // Ticks / active tick bitmap + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none(), + "active tick bitmap words must be cleared" + ); + // Fee globals - assert!(!FeesTao::::contains_key(netuid)); - assert!(!FeesAlpha::::contains_key(netuid)); + assert!(!FeeGlobalTao::::contains_key(netuid)); + assert!(!FeeGlobalAlpha::::contains_key(netuid)); - // Flags - assert!(!PalSwapInitialized::::contains_key(netuid)); + // Price / tick / liquidity / flags + assert!(!AlphaSqrtPrice::::contains_key(netuid)); + assert!(!CurrentTick::::contains_key(netuid)); + assert!(!CurrentLiquidity::::contains_key(netuid)); + assert!(!SwapV3Initialized::::contains_key(netuid)); // Knobs removed assert!(!FeeRate::::contains_key(netuid)); + assert!(!EnabledUserLiquidity::::contains_key(netuid)); // --- And it's idempotent --- assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); - assert!(!PalSwapInitialized::::contains_key(netuid)); + assert!( + Positions::::iter_prefix_values((netuid, protocol_id)) + .next() + .is_none() + ); + assert!(Ticks::::iter_prefix(netuid).next().is_none()); + assert!( + TickIndexBitmapWords::::iter_prefix((netuid,)) + .next() + .is_none() + ); + assert!(!SwapV3Initialized::::contains_key(netuid)); }); } -#[allow(dead_code)] fn as_tuple( (t_used, a_used, t_rem, a_rem): (TaoCurrency, AlphaCurrency, TaoCurrency, AlphaCurrency), ) -> (u64, u64, u64, u64) { @@ -857,43 +2749,160 @@ fn as_tuple( ) } -// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_migrate_swapv3_to_balancer --exact --nocapture #[test] -fn test_migrate_swapv3_to_balancer() { - use crate::migrations::migrate_swapv3_to_balancer::deprecated_swap_maps; - use substrate_fixed::types::U64F64; +fn proportional_when_price_is_one_and_tao_is_plenty() { + // sqrt_price = 1.0 => price = 1.0 + let sqrt = U64F64::from_num(1u64); + let amount_tao: TaoCurrency = 10u64.into(); + let amount_alpha: AlphaCurrency = 3u64.into(); + + // alpha * price = 3 * 1 = 3 <= amount_tao(10) + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (3, 3, 7, 0)); +} - new_test_ext().execute_with(|| { - let migration = - crate::migrations::migrate_swapv3_to_balancer::migrate_swapv3_to_balancer::; - let netuid = NetUid::from(1); +#[test] +fn proportional_when_price_is_one_and_alpha_is_excess() { + // sqrt_price = 1.0 => price = 1.0 + let sqrt = U64F64::from_num(1u64); + let amount_tao: TaoCurrency = 5u64.into(); + let amount_alpha: AlphaCurrency = 10u64.into(); + + // tao is limiting: alpha_equiv = floor(5 / 1) = 5 + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (5, 5, 0, 5)); +} - // Insert deprecated maps values - deprecated_swap_maps::AlphaSqrtPrice::::insert(netuid, U64F64::from_num(1.23)); - deprecated_swap_maps::ScrapReservoirTao::::insert(netuid, TaoCurrency::from(9876)); - deprecated_swap_maps::ScrapReservoirAlpha::::insert( - netuid, - AlphaCurrency::from(9876), - ); +#[test] +fn proportional_with_higher_price_and_alpha_limiting() { + // Choose sqrt_price = 2.0 => price = 4.0 (since implementation squares it) + let sqrt = U64F64::from_num(2u64); + let amount_tao: TaoCurrency = 85u64.into(); + let amount_alpha: AlphaCurrency = 20u64.into(); + + // tao_equivalent = alpha * price = 20 * 4 = 80 < 85 => alpha limits tao + // remainders: tao 5, alpha 0 + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (80, 20, 5, 0)); +} - // Insert reserves that do not match the 1.23 price - TaoReserve::set_mock_reserve(netuid, TaoCurrency::from(1_000_000_000)); - AlphaReserve::set_mock_reserve(netuid, AlphaCurrency::from(4_000_000_000)); +#[test] +fn proportional_with_higher_price_and_tao_limiting() { + // Choose sqrt_price = 2.0 => price = 4.0 (since implementation squares it) + let sqrt = U64F64::from_num(2u64); + let amount_tao: TaoCurrency = 50u64.into(); + let amount_alpha: AlphaCurrency = 20u64.into(); + + // tao_equivalent = alpha * price = 20 * 4 = 80 > 50 => tao limits alpha + // alpha_equivalent = floor(50 / 4) = 12 + // remainders: tao 0, alpha 20 - 12 = 8 + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (50, 12, 0, 8)); +} - // Run migration - migration(); +#[test] +fn zero_price_uses_no_tao_and_all_alpha() { + // sqrt_price = 0 => price = 0 + let sqrt = U64F64::from_num(0u64); + let amount_tao: TaoCurrency = 42u64.into(); + let amount_alpha: AlphaCurrency = 17u64.into(); + + // tao_equivalent = 17 * 0 = 0 <= 42 + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (0, 17, 42, 0)); +} - // Test that values are removed from state - assert!(!deprecated_swap_maps::AlphaSqrtPrice::::contains_key( - netuid - )); - assert!(!deprecated_swap_maps::ScrapReservoirAlpha::::contains_key(netuid)); +#[test] +fn rounding_down_behavior_when_dividing_by_price() { + // sqrt_price = 2.0 => price = 4.0 + let sqrt = U64F64::from_num(2u64); + let amount_tao: TaoCurrency = 13u64.into(); + let amount_alpha: AlphaCurrency = 100u64.into(); + + // tao is limiting; alpha_equiv = floor(13 / 4) = 3 + // remainders: tao 0, alpha 100 - 3 = 97 + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (13, 3, 0, 97)); +} - // Test that subnet price is still 1.23^2 - assert_abs_diff_eq!( - Swap::current_price(netuid).to_num::(), - 1.23 * 1.23, - epsilon = 0.1 +#[test] +fn exact_fit_when_tao_matches_alpha_times_price() { + // sqrt_price = 1.0 => price = 1.0 + let sqrt = U64F64::from_num(1u64); + let amount_tao: TaoCurrency = 9u64.into(); + let amount_alpha: AlphaCurrency = 9u64.into(); + + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, amount_tao, amount_alpha); + assert_eq!(as_tuple(out), (9, 9, 0, 0)); +} + +#[test] +fn handles_zero_balances() { + let sqrt = U64F64::from_num(1u64); + + // Zero TAO, some alpha + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, 0u64.into(), 7u64.into()); + // tao limits; alpha_equiv = floor(0 / 1) = 0 + assert_eq!(as_tuple(out), (0, 0, 0, 7)); + + // Some TAO, zero alpha + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, 7u64.into(), 0u64.into()); + // tao_equiv = 0 * 1 = 0 <= 7 + assert_eq!(as_tuple(out), (0, 0, 7, 0)); + + // Both zero + let out = + Pallet::::get_proportional_alpha_tao_and_remainders(sqrt, 0u64.into(), 0u64.into()); + assert_eq!(as_tuple(out), (0, 0, 0, 0)); +} + +#[test] +fn adjust_protocol_liquidity_uses_and_sets_scrap_reservoirs() { + new_test_ext().execute_with(|| { + // --- Arrange + let netuid: NetUid = 1u16.into(); + // Price = 1.0 (since sqrt_price^2 = 1), so proportional match is 1:1 + AlphaSqrtPrice::::insert(netuid, U64F64::saturating_from_num(1u64)); + + // Start with some non-zero scrap reservoirs + ScrapReservoirTao::::insert(netuid, TaoCurrency::from(7u64)); + ScrapReservoirAlpha::::insert(netuid, AlphaCurrency::from(5u64)); + + // Create a minimal protocol position so the function’s body executes. + let protocol = Pallet::::protocol_account_id(); + let position = Position::new( + PositionId::from(0), + netuid, + TickIndex::MIN, + TickIndex::MAX, + 0, + ); + // Ensure collect_fees() returns (0,0) via zeroed fees in `position` (default). + Positions::::insert((netuid, protocol, position.id), position.clone()); + + // --- Act + // No external deltas or fees; only reservoirs should be considered. + // With price=1, the exact proportional pair uses 5 alpha and 5 tao, + // leaving tao scrap = 7 - 5 = 2, alpha scrap = 5 - 5 = 0. + Pallet::::adjust_protocol_liquidity(netuid, 0u64.into(), 0u64.into()); + + // --- Assert: reservoirs were READ (used in proportional calc) and then SET (updated) + assert_eq!( + ScrapReservoirTao::::get(netuid), + TaoCurrency::from(2u64) + ); + assert_eq!( + ScrapReservoirAlpha::::get(netuid), + AlphaCurrency::from(0u64) ); }); } diff --git a/pallets/swap/src/position.rs b/pallets/swap/src/position.rs new file mode 100644 index 0000000000..5a57928a93 --- /dev/null +++ b/pallets/swap/src/position.rs @@ -0,0 +1,198 @@ +use core::marker::PhantomData; + +use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; +use frame_support::pallet_prelude::*; +use safe_math::*; +use substrate_fixed::types::{I64F64, U64F64}; +use subtensor_macros::freeze_struct; +use subtensor_runtime_common::NetUid; + +use crate::SqrtPrice; +use crate::pallet::{Config, Error, FeeGlobalAlpha, FeeGlobalTao, LastPositionId}; +use crate::tick::TickIndex; + +/// Position designates one liquidity position. +/// +/// Alpha price is expressed in rao units per one 10^9 unit. For example, +/// price 1_000_000 is equal to 0.001 TAO per Alpha. +#[freeze_struct("27a1bf8c59480f0")] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen, Default)] +#[scale_info(skip_type_params(T))] +pub struct Position { + /// Unique ID of the position + pub id: PositionId, + /// Network identifier + pub netuid: NetUid, + /// Tick index for lower boundary of price + pub tick_low: TickIndex, + /// Tick index for higher boundary of price + pub tick_high: TickIndex, + /// Position liquidity + pub liquidity: u64, + /// Fees accrued by the position in quote currency (TAO) relative to global fees + pub fees_tao: I64F64, + /// Fees accrued by the position in base currency (Alpha) relative to global fees + pub fees_alpha: I64F64, + /// Phantom marker for generic Config type + pub _phantom: PhantomData, +} + +impl Position { + pub fn new( + id: PositionId, + netuid: NetUid, + tick_low: TickIndex, + tick_high: TickIndex, + liquidity: u64, + ) -> Self { + let mut position = Position { + id, + netuid, + tick_low, + tick_high, + liquidity, + fees_tao: I64F64::saturating_from_num(0), + fees_alpha: I64F64::saturating_from_num(0), + _phantom: PhantomData, + }; + + position.fees_tao = position.fees_in_range(true); + position.fees_alpha = position.fees_in_range(false); + + position + } + + /// Converts position to token amounts + /// + /// returns tuple of (TAO, Alpha) + /// + /// Pseudocode: + /// if self.sqrt_price_curr < sqrt_pa: + /// tao = 0 + /// alpha = L * (1 / sqrt_pa - 1 / sqrt_pb) + /// elif self.sqrt_price_curr > sqrt_pb: + /// tao = L * (sqrt_pb - sqrt_pa) + /// alpha = 0 + /// else: + /// tao = L * (self.sqrt_price_curr - sqrt_pa) + /// alpha = L * (1 / self.sqrt_price_curr - 1 / sqrt_pb) + /// + pub fn to_token_amounts(&self, sqrt_price_curr: SqrtPrice) -> Result<(u64, u64), Error> { + let one = U64F64::saturating_from_num(1); + + let sqrt_price_low = self + .tick_low + .try_to_sqrt_price() + .map_err(|_| Error::::InvalidTickRange)?; + let sqrt_price_high = self + .tick_high + .try_to_sqrt_price() + .map_err(|_| Error::::InvalidTickRange)?; + let liquidity_fixed = U64F64::saturating_from_num(self.liquidity); + + Ok(if sqrt_price_curr < sqrt_price_low { + ( + 0, + liquidity_fixed + .saturating_mul( + one.safe_div(sqrt_price_low) + .saturating_sub(one.safe_div(sqrt_price_high)), + ) + .saturating_to_num::(), + ) + } else if sqrt_price_curr > sqrt_price_high { + ( + liquidity_fixed + .saturating_mul(sqrt_price_high.saturating_sub(sqrt_price_low)) + .saturating_to_num::(), + 0, + ) + } else { + ( + liquidity_fixed + .saturating_mul(sqrt_price_curr.saturating_sub(sqrt_price_low)) + .saturating_to_num::(), + liquidity_fixed + .saturating_mul( + one.safe_div(sqrt_price_curr) + .saturating_sub(one.safe_div(sqrt_price_high)), + ) + .saturating_to_num::(), + ) + }) + } + + /// Collect fees for a position + /// Updates the position + pub fn collect_fees(&mut self) -> (u64, u64) { + let fee_tao_agg = self.fees_in_range(true); + let fee_alpha_agg = self.fees_in_range(false); + + let mut fee_tao = fee_tao_agg.saturating_sub(self.fees_tao); + let mut fee_alpha = fee_alpha_agg.saturating_sub(self.fees_alpha); + + self.fees_tao = fee_tao_agg; + self.fees_alpha = fee_alpha_agg; + + let liquidity_frac = I64F64::saturating_from_num(self.liquidity); + + fee_tao = liquidity_frac.saturating_mul(fee_tao); + fee_alpha = liquidity_frac.saturating_mul(fee_alpha); + + ( + fee_tao.saturating_to_num::(), + fee_alpha.saturating_to_num::(), + ) + } + + /// Get fees in a position's range + /// + /// If quote flag is true, Tao is returned, otherwise alpha. + fn fees_in_range(&self, quote: bool) -> I64F64 { + if quote { + I64F64::saturating_from_num(FeeGlobalTao::::get(self.netuid)) + } else { + I64F64::saturating_from_num(FeeGlobalAlpha::::get(self.netuid)) + } + .saturating_sub(self.tick_low.fees_below::(self.netuid, quote)) + .saturating_sub(self.tick_high.fees_above::(self.netuid, quote)) + } +} + +#[freeze_struct("8501fa251c9d74c")] +#[derive( + Clone, + Copy, + Decode, + DecodeWithMemTracking, + Default, + Encode, + Eq, + MaxEncodedLen, + PartialEq, + RuntimeDebug, + TypeInfo, +)] +pub struct PositionId(u128); + +impl PositionId { + /// Create a new position ID + pub fn new() -> Self { + let new = LastPositionId::::get().saturating_add(1); + LastPositionId::::put(new); + + Self(new) + } +} + +impl From for PositionId { + fn from(value: u128) -> Self { + Self(value) + } +} + +impl From for u128 { + fn from(value: PositionId) -> Self { + value.0 + } +} diff --git a/pallets/swap/src/tick.rs b/pallets/swap/src/tick.rs new file mode 100644 index 0000000000..d3493fde45 --- /dev/null +++ b/pallets/swap/src/tick.rs @@ -0,0 +1,2198 @@ +//! The math is adapted from github.com/0xKitsune/uniswap-v3-math +use core::cmp::Ordering; +use core::convert::TryFrom; +use core::error::Error; +use core::fmt; +use core::hash::Hash; +use core::ops::{Add, AddAssign, BitOr, Deref, Neg, Shl, Shr, Sub, SubAssign}; + +use alloy_primitives::{I256, U256}; +use codec::{Decode, DecodeWithMemTracking, Encode, Error as CodecError, Input, MaxEncodedLen}; +use frame_support::pallet_prelude::*; +use safe_math::*; +use sp_std::vec; +use sp_std::vec::Vec; +use substrate_fixed::types::{I64F64, U64F64}; +use subtensor_macros::freeze_struct; +use subtensor_runtime_common::NetUid; + +use crate::SqrtPrice; +use crate::pallet::{ + Config, CurrentTick, FeeGlobalAlpha, FeeGlobalTao, TickIndexBitmapWords, Ticks, +}; + +const U256_1: U256 = U256::from_limbs([1, 0, 0, 0]); +const U256_2: U256 = U256::from_limbs([2, 0, 0, 0]); +const U256_3: U256 = U256::from_limbs([3, 0, 0, 0]); +const U256_4: U256 = U256::from_limbs([4, 0, 0, 0]); +const U256_5: U256 = U256::from_limbs([5, 0, 0, 0]); +const U256_6: U256 = U256::from_limbs([6, 0, 0, 0]); +const U256_7: U256 = U256::from_limbs([7, 0, 0, 0]); +const U256_8: U256 = U256::from_limbs([8, 0, 0, 0]); +const U256_15: U256 = U256::from_limbs([15, 0, 0, 0]); +const U256_16: U256 = U256::from_limbs([16, 0, 0, 0]); +const U256_32: U256 = U256::from_limbs([32, 0, 0, 0]); +const U256_64: U256 = U256::from_limbs([64, 0, 0, 0]); +const U256_127: U256 = U256::from_limbs([127, 0, 0, 0]); +const U256_128: U256 = U256::from_limbs([128, 0, 0, 0]); +const U256_255: U256 = U256::from_limbs([255, 0, 0, 0]); + +const U256_256: U256 = U256::from_limbs([256, 0, 0, 0]); +const U256_512: U256 = U256::from_limbs([512, 0, 0, 0]); +const U256_1024: U256 = U256::from_limbs([1024, 0, 0, 0]); +const U256_2048: U256 = U256::from_limbs([2048, 0, 0, 0]); +const U256_4096: U256 = U256::from_limbs([4096, 0, 0, 0]); +const U256_8192: U256 = U256::from_limbs([8192, 0, 0, 0]); +const U256_16384: U256 = U256::from_limbs([16384, 0, 0, 0]); +const U256_32768: U256 = U256::from_limbs([32768, 0, 0, 0]); +const U256_65536: U256 = U256::from_limbs([65536, 0, 0, 0]); +const U256_131072: U256 = U256::from_limbs([131072, 0, 0, 0]); +const U256_262144: U256 = U256::from_limbs([262144, 0, 0, 0]); +const U256_524288: U256 = U256::from_limbs([524288, 0, 0, 0]); + +const U256_MAX_TICK: U256 = U256::from_limbs([887272, 0, 0, 0]); + +const MIN_TICK: i32 = -887272; +const MAX_TICK: i32 = -MIN_TICK; + +const MIN_SQRT_RATIO: U256 = U256::from_limbs([4295128739, 0, 0, 0]); +const MAX_SQRT_RATIO: U256 = + U256::from_limbs([6743328256752651558, 17280870778742802505, 4294805859, 0]); + +const SQRT_10001: I256 = I256::from_raw(U256::from_limbs([11745905768312294533, 13863, 0, 0])); +const TICK_LOW: I256 = I256::from_raw(U256::from_limbs([ + 6552757943157144234, + 184476617836266586, + 0, + 0, +])); +const TICK_HIGH: I256 = I256::from_raw(U256::from_limbs([ + 4998474450511881007, + 15793544031827761793, + 0, + 0, +])); + +/// Tick is the price range determined by tick index (not part of this struct, but is the key at +/// which the Tick is stored in state hash maps). Tick struct stores liquidity and fee information. +/// +/// - Net liquidity +/// - Gross liquidity +/// - Fees (above global) in both currencies +#[freeze_struct("ff1bce826e64c4aa")] +#[derive(Debug, Default, Clone, Encode, Decode, TypeInfo, MaxEncodedLen, PartialEq, Eq)] +pub struct Tick { + pub liquidity_net: i128, + pub liquidity_gross: u64, + pub fees_out_tao: I64F64, + pub fees_out_alpha: I64F64, +} + +impl Tick { + pub fn liquidity_net_as_u64(&self) -> u64 { + self.liquidity_net.abs().min(u64::MAX as i128) as u64 + } +} + +/// Struct representing a tick index +#[freeze_struct("13c1f887258657f2")] +#[derive( + Debug, + Default, + Clone, + Copy, + Encode, + DecodeWithMemTracking, + TypeInfo, + MaxEncodedLen, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, +)] +pub struct TickIndex(i32); + +impl Decode for TickIndex { + fn decode(input: &mut I) -> Result { + let raw = i32::decode(input)?; + TickIndex::new(raw).map_err(|_| "TickIndex out of bounds".into()) + } +} + +impl Add for TickIndex { + type Output = Self; + + #[allow(clippy::arithmetic_side_effects)] + fn add(self, rhs: Self) -> Self::Output { + // Note: This assumes the result is within bounds. + // For a safer implementation, consider using checked_add. + Self::new_unchecked(self.get() + rhs.get()) + } +} + +impl Sub for TickIndex { + type Output = Self; + + #[allow(clippy::arithmetic_side_effects)] + fn sub(self, rhs: Self) -> Self::Output { + // Note: This assumes the result is within bounds. + // For a safer implementation, consider using checked_sub. + Self::new_unchecked(self.get() - rhs.get()) + } +} + +impl AddAssign for TickIndex { + #[allow(clippy::arithmetic_side_effects)] + fn add_assign(&mut self, rhs: Self) { + *self = Self::new_unchecked(self.get() + rhs.get()); + } +} + +impl SubAssign for TickIndex { + #[allow(clippy::arithmetic_side_effects)] + fn sub_assign(&mut self, rhs: Self) { + *self = Self::new_unchecked(self.get() - rhs.get()); + } +} + +impl TryFrom for TickIndex { + type Error = TickMathError; + + fn try_from(value: i32) -> Result { + Self::new(value) + } +} + +impl Deref for TickIndex { + type Target = i32; + + fn deref(&self) -> &Self::Target { + // Using get() would create an infinite recursion, so this is one place where we need direct + // field access. This is safe because Self::Target is i32, which is exactly what we're + // storing + &self.0 + } +} + +/// Extension trait to make working with TryFrom more ergonomic +pub trait TryIntoTickIndex { + /// Convert an i32 into a TickIndex, with bounds checking + fn into_tick_index(self) -> Result; +} + +impl TryIntoTickIndex for i32 { + fn into_tick_index(self) -> Result { + TickIndex::try_from(self) + } +} + +impl TickIndex { + /// Minimum value of the tick index + /// The tick_math library uses different bitness, so we have to divide by 2. + /// It's unsafe to change this value to something else. + pub const MIN: Self = Self(MIN_TICK.saturating_div(2)); + + /// Maximum value of the tick index + /// The tick_math library uses different bitness, so we have to divide by 2. + /// It's unsafe to change this value to something else. + pub const MAX: Self = Self(MAX_TICK.saturating_div(2)); + + /// All tick indexes are offset by this value for storage needs + /// so that tick indexes are positive, which simplifies bit logic + const OFFSET: Self = Self(MAX_TICK); + + /// The MIN sqrt price, which is caclculated at Self::MIN + pub fn min_sqrt_price() -> SqrtPrice { + SqrtPrice::saturating_from_num(0.0000000002328350195) + } + + /// The MAX sqrt price, which is calculated at Self::MAX + #[allow(clippy::excessive_precision)] + pub fn max_sqrt_price() -> SqrtPrice { + SqrtPrice::saturating_from_num(4294886577.20989222513899790805) + } + + /// Get fees above a tick + pub fn fees_above(&self, netuid: NetUid, quote: bool) -> I64F64 { + let current_tick = Self::current_bounded::(netuid); + + let tick = Ticks::::get(netuid, *self).unwrap_or_default(); + if *self <= current_tick { + if quote { + I64F64::saturating_from_num(FeeGlobalTao::::get(netuid)) + .saturating_sub(tick.fees_out_tao) + } else { + I64F64::saturating_from_num(FeeGlobalAlpha::::get(netuid)) + .saturating_sub(tick.fees_out_alpha) + } + } else if quote { + tick.fees_out_tao + } else { + tick.fees_out_alpha + } + } + + /// Get fees below a tick + pub fn fees_below(&self, netuid: NetUid, quote: bool) -> I64F64 { + let current_tick = Self::current_bounded::(netuid); + + let tick = Ticks::::get(netuid, *self).unwrap_or_default(); + if *self <= current_tick { + if quote { + tick.fees_out_tao + } else { + tick.fees_out_alpha + } + } else if quote { + I64F64::saturating_from_num(FeeGlobalTao::::get(netuid)) + .saturating_sub(tick.fees_out_tao) + } else { + I64F64::saturating_from_num(FeeGlobalAlpha::::get(netuid)) + .saturating_sub(tick.fees_out_alpha) + } + } + + /// Get the current tick index for a subnet, ensuring it's within valid bounds + pub fn current_bounded(netuid: NetUid) -> Self { + let current_tick = CurrentTick::::get(netuid); + if current_tick > Self::MAX { + Self::MAX + } else if current_tick < Self::MIN { + Self::MIN + } else { + current_tick + } + } + + /// Converts a sqrt price to a tick index, ensuring it's within valid bounds + /// + /// If the price is outside the valid range, this function will return the appropriate boundary + /// tick index (MIN or MAX) instead of an error. + /// + /// # Arguments + /// * `sqrt_price` - The square root price to convert to a tick index + /// + /// # Returns + /// * `TickIndex` - A tick index that is guaranteed to be within valid bounds + pub fn from_sqrt_price_bounded(sqrt_price: SqrtPrice) -> Self { + match Self::try_from_sqrt_price(sqrt_price) { + Ok(index) => index, + Err(_) => { + let max_price = Self::MAX.as_sqrt_price_bounded(); + + if sqrt_price > max_price { + Self::MAX + } else { + Self::MIN + } + } + } + } + + /// Converts a tick index to a sqrt price, ensuring it's within valid bounds + /// + /// Unlike try_to_sqrt_price which returns an error for boundary indices, this function + /// guarantees a valid sqrt price by using fallback values if conversion fails. + /// + /// # Returns + /// * `SqrtPrice` - A sqrt price that is guaranteed to be a valid value + pub fn as_sqrt_price_bounded(&self) -> SqrtPrice { + self.try_to_sqrt_price().unwrap_or_else(|_| { + if *self >= Self::MAX { + Self::max_sqrt_price() + } else { + Self::min_sqrt_price() + } + }) + } + + /// Creates a new TickIndex instance with bounds checking + pub fn new(value: i32) -> Result { + if !(Self::MIN.0..=Self::MAX.0).contains(&value) { + Err(TickMathError::TickOutOfBounds) + } else { + Ok(Self(value)) + } + } + + /// Creates a new TickIndex without bounds checking + /// Use this function with caution, only when you're certain the value is valid + pub fn new_unchecked(value: i32) -> Self { + Self(value) + } + + /// Get the inner value + pub fn get(&self) -> i32 { + self.0 + } + + /// Creates a TickIndex from an offset representation (u32) + /// + /// # Arguments + /// * `offset_index` - An offset index (u32 value) representing a tick index + /// + /// # Returns + /// * `Result` - The corresponding TickIndex if within valid bounds + pub fn from_offset_index(offset_index: u32) -> Result { + // while it's safe, we use saturating math to mute the linter and just in case + let signed_index = ((offset_index as i64).saturating_sub(Self::OFFSET.get() as i64)) as i32; + Self::new(signed_index) + } + + /// Get the next tick index (incrementing by 1) + pub fn next(&self) -> Result { + Self::new(self.0.saturating_add(1)) + } + + /// Get the previous tick index (decrementing by 1) + pub fn prev(&self) -> Result { + Self::new(self.0.saturating_sub(1)) + } + + /// Add a value to this tick index with bounds checking + pub fn checked_add(&self, value: i32) -> Result { + Self::new(self.0.saturating_add(value)) + } + + /// Subtract a value from this tick index with bounds checking + pub fn checked_sub(&self, value: i32) -> Result { + Self::new(self.0.saturating_sub(value)) + } + + /// Add a value to this tick index, saturating at the bounds instead of overflowing + pub fn saturating_add(&self, value: i32) -> Self { + match self.checked_add(value) { + Ok(result) => result, + Err(_) => { + if value > 0 { + Self::MAX + } else { + Self::MIN + } + } + } + } + + /// Subtract a value from this tick index, saturating at the bounds instead of overflowing + pub fn saturating_sub(&self, value: i32) -> Self { + match self.checked_sub(value) { + Ok(result) => result, + Err(_) => { + if value > 0 { + Self::MIN + } else { + Self::MAX + } + } + } + } + + /// Divide the tick index by a value with bounds checking + #[allow(clippy::arithmetic_side_effects)] + pub fn checked_div(&self, value: i32) -> Result { + if value == 0 { + return Err(TickMathError::DivisionByZero); + } + Self::new(self.0.saturating_div(value)) + } + + /// Divide the tick index by a value, saturating at the bounds + pub fn saturating_div(&self, value: i32) -> Self { + if value == 0 { + return Self::MAX; // Return MAX for division by zero + } + match self.checked_div(value) { + Ok(result) => result, + Err(_) => { + if (self.0 < 0 && value > 0) || (self.0 > 0 && value < 0) { + Self::MIN + } else { + Self::MAX + } + } + } + } + + /// Multiply the tick index by a value with bounds checking + pub fn checked_mul(&self, value: i32) -> Result { + // Check for potential overflow + match self.0.checked_mul(value) { + Some(result) => Self::new(result), + None => Err(TickMathError::Overflow), + } + } + + /// Multiply the tick index by a value, saturating at the bounds + pub fn saturating_mul(&self, value: i32) -> Self { + match self.checked_mul(value) { + Ok(result) => result, + Err(_) => { + if (self.0 < 0 && value > 0) || (self.0 > 0 && value < 0) { + Self::MIN + } else { + Self::MAX + } + } + } + } + + /// Converts tick index into SQRT of lower price of this tick In order to find the higher price + /// of this tick, call tick_index_to_sqrt_price(tick_idx + 1) + pub fn try_to_sqrt_price(&self) -> Result { + // because of u256->u128 conversion we have twice less values for min/max ticks + if !(Self::MIN..=Self::MAX).contains(self) { + return Err(TickMathError::TickOutOfBounds); + } + get_sqrt_ratio_at_tick(self.0).and_then(u256_q64_96_to_u64f64) + } + + /// Converts SQRT price to tick index + /// Because the tick is the range of prices [sqrt_lower_price, sqrt_higher_price), the resulting + /// tick index matches the price by the following inequality: + /// sqrt_lower_price <= sqrt_price < sqrt_higher_price + pub fn try_from_sqrt_price(sqrt_price: SqrtPrice) -> Result { + // price in the native Q64.96 integer format + let price_x96 = u64f64_to_u256_q64_96(sqrt_price); + + // first‑pass estimate from the log calculation + let mut tick = get_tick_at_sqrt_ratio(price_x96)?; + + // post‑verification, *both* directions + let price_at_tick = get_sqrt_ratio_at_tick(tick)?; + if price_at_tick > price_x96 { + tick = tick.saturating_sub(1); // estimate was too high + } else { + // it may still be one too low + let price_at_tick_plus = get_sqrt_ratio_at_tick(tick.saturating_add(1))?; + if price_at_tick_plus <= price_x96 { + tick = tick.saturating_add(1); // step up when required + } + } + + tick.into_tick_index() + } +} + +pub struct ActiveTickIndexManager(PhantomData); + +impl ActiveTickIndexManager { + pub fn insert(netuid: NetUid, index: TickIndex) { + // Check the range + if (index < TickIndex::MIN) || (index > TickIndex::MAX) { + return; + } + + // Convert to bitmap representation + let bitmap = TickIndexBitmap::from(index); + + // Update layer words + let mut word0_value = TickIndexBitmapWords::::get(( + netuid, + LayerLevel::Top, + bitmap.word_at(LayerLevel::Top), + )); + let mut word1_value = TickIndexBitmapWords::::get(( + netuid, + LayerLevel::Middle, + bitmap.word_at(LayerLevel::Middle), + )); + let mut word2_value = TickIndexBitmapWords::::get(( + netuid, + LayerLevel::Bottom, + bitmap.word_at(LayerLevel::Bottom), + )); + + // Set bits in each layer + word0_value |= bitmap.bit_mask(LayerLevel::Top); + word1_value |= bitmap.bit_mask(LayerLevel::Middle); + word2_value |= bitmap.bit_mask(LayerLevel::Bottom); + + // Update the storage + TickIndexBitmapWords::::set( + (netuid, LayerLevel::Top, bitmap.word_at(LayerLevel::Top)), + word0_value, + ); + TickIndexBitmapWords::::set( + ( + netuid, + LayerLevel::Middle, + bitmap.word_at(LayerLevel::Middle), + ), + word1_value, + ); + TickIndexBitmapWords::::set( + ( + netuid, + LayerLevel::Bottom, + bitmap.word_at(LayerLevel::Bottom), + ), + word2_value, + ); + } + + pub fn remove(netuid: NetUid, index: TickIndex) { + // Check the range + if (index < TickIndex::MIN) || (index > TickIndex::MAX) { + return; + } + + // Convert to bitmap representation + let bitmap = TickIndexBitmap::from(index); + + // Update layer words + let mut word0_value = TickIndexBitmapWords::::get(( + netuid, + LayerLevel::Top, + bitmap.word_at(LayerLevel::Top), + )); + let mut word1_value = TickIndexBitmapWords::::get(( + netuid, + LayerLevel::Middle, + bitmap.word_at(LayerLevel::Middle), + )); + let mut word2_value = TickIndexBitmapWords::::get(( + netuid, + LayerLevel::Bottom, + bitmap.word_at(LayerLevel::Bottom), + )); + + // Turn the bit off (& !bit) and save as needed + word2_value &= !bitmap.bit_mask(LayerLevel::Bottom); + TickIndexBitmapWords::::set( + ( + netuid, + LayerLevel::Bottom, + bitmap.word_at(LayerLevel::Bottom), + ), + word2_value, + ); + + if word2_value == 0 { + word1_value &= !bitmap.bit_mask(LayerLevel::Middle); + TickIndexBitmapWords::::set( + ( + netuid, + LayerLevel::Middle, + bitmap.word_at(LayerLevel::Middle), + ), + word1_value, + ); + } + + if word1_value == 0 { + word0_value &= !bitmap.bit_mask(LayerLevel::Top); + TickIndexBitmapWords::::set( + (netuid, LayerLevel::Top, bitmap.word_at(LayerLevel::Top)), + word0_value, + ); + } + } + + pub fn find_closest_lower(netuid: NetUid, index: TickIndex) -> Option { + Self::find_closest(netuid, index, true) + } + + pub fn find_closest_higher(netuid: NetUid, index: TickIndex) -> Option { + Self::find_closest(netuid, index, false) + } + + fn find_closest(netuid: NetUid, index: TickIndex, lower: bool) -> Option { + // Check the range + if (index < TickIndex::MIN) || (index > TickIndex::MAX) { + return None; + } + + // Convert to bitmap representation + let bitmap = TickIndexBitmap::from(index); + let mut found = false; + let mut result: u32 = 0; + + // Layer positions from bitmap + let layer0_word = bitmap.word_at(LayerLevel::Top); + let layer0_bit = bitmap.bit_at(LayerLevel::Top); + let layer1_word = bitmap.word_at(LayerLevel::Middle); + let layer1_bit = bitmap.bit_at(LayerLevel::Middle); + let layer2_word = bitmap.word_at(LayerLevel::Bottom); + let layer2_bit = bitmap.bit_at(LayerLevel::Bottom); + + // Find the closest active bits in layer 0, then 1, then 2 + + /////////////// + // Level 0 + let word0 = TickIndexBitmapWords::::get((netuid, LayerLevel::Top, layer0_word)); + let closest_bits_l0 = + TickIndexBitmap::find_closest_active_bit_candidates(word0, layer0_bit, lower); + + for closest_bit_l0 in closest_bits_l0.iter() { + /////////////// + // Level 1 + let word1_index = TickIndexBitmap::layer_to_index(BitmapLayer::new(0, *closest_bit_l0)); + + // Layer 1 words are different, shift the bit to the word edge + let start_from_l1_bit = match word1_index.cmp(&layer1_word) { + Ordering::Less => 127, + Ordering::Greater => 0, + _ => layer1_bit, + }; + let word1_value = + TickIndexBitmapWords::::get((netuid, LayerLevel::Middle, word1_index)); + let closest_bits_l1 = TickIndexBitmap::find_closest_active_bit_candidates( + word1_value, + start_from_l1_bit, + lower, + ); + + for closest_bit_l1 in closest_bits_l1.iter() { + /////////////// + // Level 2 + let word2_index = + TickIndexBitmap::layer_to_index(BitmapLayer::new(word1_index, *closest_bit_l1)); + + // Layer 2 words are different, shift the bit to the word edge + let start_from_l2_bit = match word2_index.cmp(&layer2_word) { + Ordering::Less => 127, + Ordering::Greater => 0, + _ => layer2_bit, + }; + + let word2_value = + TickIndexBitmapWords::::get((netuid, LayerLevel::Bottom, word2_index)); + + let closest_bits_l2 = TickIndexBitmap::find_closest_active_bit_candidates( + word2_value, + start_from_l2_bit, + lower, + ); + + if !closest_bits_l2.is_empty() { + // The active tick is found, restore its full index and return + let offset_found_index = TickIndexBitmap::layer_to_index(BitmapLayer::new( + word2_index, + // it's safe to unwrap, because the len is > 0, but to prevent errors in + // refactoring, we use default fallback here for extra safety + closest_bits_l2.first().copied().unwrap_or_default(), + )); + + if lower { + if (offset_found_index > result) || (!found) { + result = offset_found_index; + found = true; + } + } else if (offset_found_index < result) || (!found) { + result = offset_found_index; + found = true; + } + } + } + } + + if !found { + return None; + } + + // Convert the result offset_index back to a tick index + TickIndex::from_offset_index(result).ok() + } + + pub fn tick_is_active(netuid: NetUid, tick: TickIndex) -> bool { + Self::find_closest_lower(netuid, tick).unwrap_or(TickIndex::MAX) == tick + } +} + +/// Represents the three layers in the Uniswap V3 bitmap structure +#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub enum LayerLevel { + /// Top layer (highest level of the hierarchy) + Top = 0, + /// Middle layer + Middle = 1, + /// Bottom layer (contains the actual ticks) + Bottom = 2, +} + +#[freeze_struct("4015a04919eb5e2e")] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub(crate) struct BitmapLayer { + word: u32, + bit: u32, +} + +impl BitmapLayer { + pub fn new(word: u32, bit: u32) -> Self { + Self { word, bit } + } +} + +/// A bitmap representation of a tick index position across the three-layer structure +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct TickIndexBitmap { + /// The position in layer 0 (top layer) + layer0: BitmapLayer, + /// The position in layer 1 (middle layer) + layer1: BitmapLayer, + /// The position in layer 2 (bottom layer) + layer2: BitmapLayer, +} + +impl TickIndexBitmap { + /// Helper function to convert a bitmap index to a (word, bit) tuple in a bitmap layer using + /// safe methods + /// + /// Note: This function operates on bitmap navigation indices, NOT tick indices. + /// It converts a flat index within the bitmap structure to a (word, bit) position. + fn index_to_layer(index: u32) -> BitmapLayer { + let word = index.safe_div(128); + let bit = index.checked_rem(128).unwrap_or_default(); + BitmapLayer { word, bit } + } + + /// Converts a position (word, bit) within a layer to a word index in the next layer down + /// Note: This returns a bitmap navigation index, NOT a tick index + pub(crate) fn layer_to_index(layer: BitmapLayer) -> u32 { + layer.word.saturating_mul(128).saturating_add(layer.bit) + } + + /// Get the mask for a bit in the specified layer + pub(crate) fn bit_mask(&self, layer: LayerLevel) -> u128 { + match layer { + LayerLevel::Top => 1u128 << self.layer0.bit, + LayerLevel::Middle => 1u128 << self.layer1.bit, + LayerLevel::Bottom => 1u128 << self.layer2.bit, + } + } + + /// Get the word for the specified layer + pub(crate) fn word_at(&self, layer: LayerLevel) -> u32 { + match layer { + LayerLevel::Top => self.layer0.word, + LayerLevel::Middle => self.layer1.word, + LayerLevel::Bottom => self.layer2.word, + } + } + + /// Get the bit for the specified layer + pub(crate) fn bit_at(&self, layer: LayerLevel) -> u32 { + match layer { + LayerLevel::Top => self.layer0.bit, + LayerLevel::Middle => self.layer1.bit, + LayerLevel::Bottom => self.layer2.bit, + } + } + + /// Finds the closest active bit in a bitmap word, and if the active bit exactly matches the + /// requested bit, then it finds the next one as well + /// + /// # Arguments + /// * `word` - The bitmap word to search within + /// * `bit` - The bit position to start searching from + /// * `lower` - If true, search for lower bits (decreasing bit position), if false, search for + /// higher bits (increasing bit position) + /// + /// # Returns + /// * Exact match: Vec with [next_bit, bit] + /// * Non-exact match: Vec with [closest_bit] + /// * No match: Empty Vec + pub(crate) fn find_closest_active_bit_candidates( + word: u128, + bit: u32, + lower: bool, + ) -> Vec { + let mut result = vec![]; + let mut mask: u128 = 1_u128.wrapping_shl(bit); + let mut active_bit: u32 = bit; + + while mask > 0 { + if mask & word != 0 { + result.push(active_bit); + if active_bit != bit { + break; + } + } + + mask = if lower { + active_bit = active_bit.saturating_sub(1); + mask.wrapping_shr(1) + } else { + active_bit = active_bit.saturating_add(1); + mask.wrapping_shl(1) + }; + } + + result + } +} + +impl From for TickIndexBitmap { + fn from(tick_index: TickIndex) -> Self { + // Convert to offset index (internal operation only) + let offset_index = (tick_index.get().saturating_add(TickIndex::OFFSET.get())) as u32; + + // Calculate layer positions + let layer2 = Self::index_to_layer(offset_index); + let layer1 = Self::index_to_layer(layer2.word); + let layer0 = Self::index_to_layer(layer1.word); + + Self { + layer0, + layer1, + layer2, + } + } +} + +#[allow(clippy::arithmetic_side_effects)] +fn get_sqrt_ratio_at_tick(tick: i32) -> Result { + let abs_tick = if tick < 0 { + U256::from(tick.neg()) + } else { + U256::from(tick) + }; + + if abs_tick > U256_MAX_TICK { + return Err(TickMathError::TickOutOfBounds); + } + + let mut ratio = if abs_tick & (U256_1) != U256::ZERO { + U256::from_limbs([12262481743371124737, 18445821805675392311, 0, 0]) + } else { + U256::from_limbs([0, 0, 1, 0]) + }; + + if !(abs_tick & U256_2).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 6459403834229662010, + 18444899583751176498, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_4).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 17226890335427755468, + 18443055278223354162, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_8).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 2032852871939366096, + 18439367220385604838, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_16).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 14545316742740207172, + 18431993317065449817, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_32).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 5129152022828963008, + 18417254355718160513, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_64).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 4894419605888772193, + 18387811781193591352, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_128).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 1280255884321894483, + 18329067761203520168, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_256).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 15924666964335305636, + 18212142134806087854, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_512).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 8010504389359918676, + 17980523815641551639, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_1024).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 10668036004952895731, + 17526086738831147013, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_2048).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 4878133418470705625, + 16651378430235024244, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_4096).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 9537173718739605541, + 15030750278693429944, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_8192).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 9972618978014552549, + 12247334978882834399, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_16384).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 10428997489610666743, + 8131365268884726200, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_32768).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 9305304367709015974, + 3584323654723342297, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_65536).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 14301143598189091785, + 696457651847595233, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_131072).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 7393154844743099908, + 26294789957452057, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_262144).is_zero() { + ratio = (ratio.saturating_mul(U256::from_limbs([ + 2209338891292245656, + 37481735321082, + 0, + 0, + ]))) >> 128 + } + if !(abs_tick & U256_524288).is_zero() { + ratio = + (ratio.saturating_mul(U256::from_limbs([10518117631919034274, 76158723, 0, 0]))) >> 128 + } + + if tick > 0 { + ratio = U256::MAX / ratio; + } + + let shifted: U256 = ratio >> 32; + let ceil = if ratio & U256::from((1u128 << 32) - 1) != U256::ZERO { + shifted.saturating_add(U256_1) + } else { + shifted + }; + Ok(ceil) +} + +#[allow(clippy::arithmetic_side_effects)] +fn get_tick_at_sqrt_ratio(sqrt_price_x_96: U256) -> Result { + if !(sqrt_price_x_96 >= MIN_SQRT_RATIO && sqrt_price_x_96 < MAX_SQRT_RATIO) { + return Err(TickMathError::SqrtPriceOutOfBounds); + } + + let ratio: U256 = sqrt_price_x_96.shl(32); + let mut r = ratio; + let mut msb = U256::ZERO; + + let mut f = if r > U256::from_limbs([18446744073709551615, 18446744073709551615, 0, 0]) { + U256_1.shl(U256_7) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256::from_limbs([18446744073709551615, 0, 0, 0]) { + U256_1.shl(U256_6) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256::from_limbs([4294967295, 0, 0, 0]) { + U256_1.shl(U256_5) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256::from_limbs([65535, 0, 0, 0]) { + U256_1.shl(U256_4) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256_255 { + U256_1.shl(U256_3) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256_15 { + U256_1.shl(U256_2) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256_3 { + U256_1.shl(U256_1) + } else { + U256::ZERO + }; + msb = msb.bitor(f); + r = r.shr(f); + + f = if r > U256_1 { U256_1 } else { U256::ZERO }; + + msb = msb.bitor(f); + + r = if msb >= U256_128 { + ratio.shr(msb.saturating_sub(U256_127)) + } else { + ratio.shl(U256_127.saturating_sub(msb)) + }; + + let mut log_2: I256 = + (I256::from_raw(msb).saturating_sub(I256::from_limbs([128, 0, 0, 0]))).shl(64); + + for i in (51..=63).rev() { + r = r.overflowing_mul(r).0.shr(U256_127); + let f: U256 = r.shr(128); + log_2 = log_2.bitor(I256::from_raw(f.shl(i))); + + r = r.shr(f); + } + + r = r.overflowing_mul(r).0.shr(U256_127); + let f: U256 = r.shr(128); + log_2 = log_2.bitor(I256::from_raw(f.shl(50))); + + let log_sqrt10001 = log_2.wrapping_mul(SQRT_10001); + + let tick_low = (log_sqrt10001.saturating_sub(TICK_LOW) >> 128_u8).low_i32(); + + let tick_high = (log_sqrt10001.saturating_add(TICK_HIGH) >> 128_u8).low_i32(); + + let tick = if tick_low == tick_high { + tick_low + } else if get_sqrt_ratio_at_tick(tick_high)? <= sqrt_price_x_96 { + tick_high + } else { + tick_low + }; + + Ok(tick) +} + +// Convert U64F64 to U256 in Q64.96 format (Uniswap's sqrt price format) +fn u64f64_to_u256_q64_96(value: U64F64) -> U256 { + u64f64_to_u256(value, 96) +} + +/// Convert U64F64 to U256 +/// +/// # Arguments +/// * `value` - The U64F64 value to convert +/// * `target_fractional_bits` - Number of fractional bits in the target U256 format +/// +/// # Returns +/// * `U256` - Converted value +#[allow(clippy::arithmetic_side_effects)] +fn u64f64_to_u256(value: U64F64, target_fractional_bits: u32) -> U256 { + let raw = U256::from(value.to_bits()); + + match target_fractional_bits.cmp(&64) { + Ordering::Less => raw >> (64 - target_fractional_bits), + Ordering::Greater => raw.saturating_shl((target_fractional_bits - 64) as usize), + Ordering::Equal => raw, + } +} + +/// Convert U256 in Q64.96 format (Uniswap's sqrt price format) to U64F64 +fn u256_q64_96_to_u64f64(value: U256) -> Result { + q_to_u64f64(value, 96) +} + +#[allow(clippy::arithmetic_side_effects)] +fn q_to_u64f64(x: U256, frac_bits: u32) -> Result { + let diff = frac_bits.saturating_sub(64) as usize; + + // 1. shift right diff bits + let shifted = if diff != 0 { x >> diff } else { x }; + + // 2. **round up** if we threw away any 1‑bits + let mask = if diff != 0 { + (U256_1.saturating_shl(diff)).saturating_sub(U256_1) + } else { + U256::ZERO + }; + let rounded = if diff != 0 && (x & mask) != U256::ZERO { + shifted.saturating_add(U256_1) + } else { + shifted + }; + + // 3. check that it fits in 128 bits and transmute + if (rounded >> 128) != U256::ZERO { + return Err(TickMathError::Overflow); + } + Ok(U64F64::from_bits(rounded.to::())) +} + +#[derive(Debug, PartialEq, Eq)] +pub enum TickMathError { + TickOutOfBounds, + SqrtPriceOutOfBounds, + ConversionError, + Overflow, + DivisionByZero, +} + +impl fmt::Display for TickMathError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TickOutOfBounds => f.write_str("The given tick is outside of the minimum/maximum values."), + Self::SqrtPriceOutOfBounds =>f.write_str("Second inequality must be < because the price can never reach the price at the max tick"), + Self::ConversionError => f.write_str("Error converting from one number type into another"), + Self::Overflow => f.write_str("Number overflow in arithmetic operation"), + Self::DivisionByZero => f.write_str("Division by zero is not allowed") + } + } +} + +impl Error for TickMathError {} + +#[allow(clippy::unwrap_used)] +#[cfg(test)] +mod tests { + use safe_math::FixedExt; + use std::{ops::Sub, str::FromStr}; + + use super::*; + use crate::mock::*; + + #[test] + fn test_get_sqrt_ratio_at_tick_bounds() { + // the function should return an error if the tick is out of bounds + if let Err(err) = get_sqrt_ratio_at_tick(MIN_TICK - 1) { + assert!(matches!(err, TickMathError::TickOutOfBounds)); + } else { + panic!("get_qrt_ratio_at_tick did not respect lower tick bound") + } + if let Err(err) = get_sqrt_ratio_at_tick(MAX_TICK + 1) { + assert!(matches!(err, TickMathError::TickOutOfBounds)); + } else { + panic!("get_qrt_ratio_at_tick did not respect upper tick bound") + } + } + + #[test] + fn test_get_sqrt_ratio_at_tick_values() { + // test individual values for correct results + assert_eq!( + get_sqrt_ratio_at_tick(MIN_TICK).unwrap(), + U256::from(4295128739u64), + "sqrt ratio at min incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(MIN_TICK + 1).unwrap(), + U256::from(4295343490u64), + "sqrt ratio at min + 1 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(MAX_TICK - 1).unwrap(), + U256::from_str("1461373636630004318706518188784493106690254656249").unwrap(), + "sqrt ratio at max - 1 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(MAX_TICK).unwrap(), + U256::from_str("1461446703485210103287273052203988822378723970342").unwrap(), + "sqrt ratio at max incorrect" + ); + // checking hard coded values against solidity results + assert_eq!( + get_sqrt_ratio_at_tick(50).unwrap(), + U256::from(79426470787362580746886972461u128), + "sqrt ratio at 50 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(100).unwrap(), + U256::from(79625275426524748796330556128u128), + "sqrt ratio at 100 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(250).unwrap(), + U256::from(80224679980005306637834519095u128), + "sqrt ratio at 250 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(500).unwrap(), + U256::from(81233731461783161732293370115u128), + "sqrt ratio at 500 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(1000).unwrap(), + U256::from(83290069058676223003182343270u128), + "sqrt ratio at 1000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(2500).unwrap(), + U256::from(89776708723587163891445672585u128), + "sqrt ratio at 2500 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(3000).unwrap(), + U256::from(92049301871182272007977902845u128), + "sqrt ratio at 3000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(4000).unwrap(), + U256::from(96768528593268422080558758223u128), + "sqrt ratio at 4000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(5000).unwrap(), + U256::from(101729702841318637793976746270u128), + "sqrt ratio at 5000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(50000).unwrap(), + U256::from(965075977353221155028623082916u128), + "sqrt ratio at 50000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(150000).unwrap(), + U256::from(143194173941309278083010301478497u128), + "sqrt ratio at 150000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(250000).unwrap(), + U256::from(21246587762933397357449903968194344u128), + "sqrt ratio at 250000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(500000).unwrap(), + U256::from_str("5697689776495288729098254600827762987878").unwrap(), + "sqrt ratio at 500000 incorrect" + ); + assert_eq!( + get_sqrt_ratio_at_tick(738203).unwrap(), + U256::from_str("847134979253254120489401328389043031315994541").unwrap(), + "sqrt ratio at 738203 incorrect" + ); + } + + #[test] + fn test_get_tick_at_sqrt_ratio() { + //throws for too low + let result = get_tick_at_sqrt_ratio(MIN_SQRT_RATIO.sub(U256_1)); + assert_eq!( + result.unwrap_err().to_string(), + "Second inequality must be < because the price can never reach the price at the max tick" + ); + + //throws for too high + let result = get_tick_at_sqrt_ratio(MAX_SQRT_RATIO); + assert_eq!( + result.unwrap_err().to_string(), + "Second inequality must be < because the price can never reach the price at the max tick" + ); + + //ratio of min tick + let result = get_tick_at_sqrt_ratio(MIN_SQRT_RATIO).unwrap(); + assert_eq!(result, MIN_TICK); + + //ratio of min tick + 1 + let result = get_tick_at_sqrt_ratio(U256::from_str("4295343490").unwrap()).unwrap(); + assert_eq!(result, MIN_TICK + 1); + } + + #[test] + fn test_roundtrip() { + for tick_index in [ + MIN_TICK + 1, // we can't use extremes because of rounding during roundtrip conversion + -1000, + -100, + -10, + -4, + -2, + 0, + 2, + 4, + 10, + 100, + 1000, + MAX_TICK - 1, + ] + .iter() + { + let sqrt_price = get_sqrt_ratio_at_tick(*tick_index).unwrap(); + let round_trip_tick_index = get_tick_at_sqrt_ratio(sqrt_price).unwrap(); + assert_eq!(round_trip_tick_index, *tick_index); + } + } + + #[test] + fn test_u256_to_u64f64_q64_96() { + // Test tick 0 (sqrt price = 1.0 * 2^96) + let tick0_sqrt_price = U256::from(1u128 << 96); + let fixed_price = u256_q64_96_to_u64f64(tick0_sqrt_price).unwrap(); + + // Should be 1.0 in U64F64 + assert_eq!(fixed_price, U64F64::from_num(1.0)); + + // Round trip back to U256 Q64.96 + let back_to_u256 = u64f64_to_u256_q64_96(fixed_price); + assert_eq!(back_to_u256, tick0_sqrt_price); + } + + #[test] + fn test_tick_index_to_sqrt_price() { + let tick_spacing = SqrtPrice::from_num(1.0001); + + // check tick bounds + assert_eq!( + TickIndex(MIN_TICK).try_to_sqrt_price(), + Err(TickMathError::TickOutOfBounds) + ); + + assert_eq!( + TickIndex(MAX_TICK).try_to_sqrt_price(), + Err(TickMathError::TickOutOfBounds), + ); + + assert!( + TickIndex::MAX.try_to_sqrt_price().unwrap().abs_diff( + TickIndex::new_unchecked(TickIndex::MAX.get() + 1).as_sqrt_price_bounded() + ) < SqrtPrice::from_num(1e-6) + ); + + assert!( + TickIndex::MIN.try_to_sqrt_price().unwrap().abs_diff( + TickIndex::new_unchecked(TickIndex::MIN.get() - 1).as_sqrt_price_bounded() + ) < SqrtPrice::from_num(1e-6) + ); + + // At tick index 0, the sqrt price should be 1.0 + let sqrt_price = TickIndex(0).try_to_sqrt_price().unwrap(); + assert_eq!(sqrt_price, SqrtPrice::from_num(1.0)); + + let sqrt_price = TickIndex(2).try_to_sqrt_price().unwrap(); + assert!(sqrt_price.abs_diff(tick_spacing) < SqrtPrice::from_num(1e-10)); + + let sqrt_price = TickIndex(4).try_to_sqrt_price().unwrap(); + // Calculate the expected value: (1 + TICK_SPACING/1e9 + 1.0)^2 + let expected = tick_spacing * tick_spacing; + assert!(sqrt_price.abs_diff(expected) < SqrtPrice::from_num(1e-10)); + + // Test with tick index 10 + let sqrt_price = TickIndex(10).try_to_sqrt_price().unwrap(); + // Calculate the expected value: (1 + TICK_SPACING/1e9 + 1.0)^5 + let expected = tick_spacing.checked_pow(5).unwrap(); + assert!( + sqrt_price.abs_diff(expected) < SqrtPrice::from_num(1e-10), + "diff: {}", + sqrt_price.abs_diff(expected), + ); + } + + #[test] + fn test_sqrt_price_to_tick_index() { + let tick_spacing = SqrtPrice::from_num(1.0001); + let tick_index = TickIndex::try_from_sqrt_price(SqrtPrice::from_num(1.0)).unwrap(); + assert_eq!(tick_index, TickIndex::new_unchecked(0)); + + // Test with sqrt price equal to tick_spacing_tao (should be tick index 2) + let epsilon = SqrtPrice::from_num(0.0000000000000001); + assert!( + TickIndex::new_unchecked(2) + .as_sqrt_price_bounded() + .abs_diff(tick_spacing) + < epsilon + ); + + // Test with sqrt price equal to tick_spacing_tao^2 (should be tick index 4) + let sqrt_price = tick_spacing * tick_spacing; + assert!( + TickIndex::new_unchecked(4) + .as_sqrt_price_bounded() + .abs_diff(sqrt_price) + < epsilon + ); + + // Test with sqrt price equal to tick_spacing_tao^5 (should be tick index 10) + let sqrt_price = tick_spacing.checked_pow(5).unwrap(); + assert!( + TickIndex::new_unchecked(10) + .as_sqrt_price_bounded() + .abs_diff(sqrt_price) + < epsilon + ); + } + + #[test] + fn test_roundtrip_tick_index_sqrt_price() { + for i32_value in [ + TickIndex::MIN.get(), + -1000, + -100, + -10, + -4, + -2, + 0, + 2, + 4, + 10, + 100, + 1000, + TickIndex::MAX.get(), + ] + .into_iter() + { + let tick_index = TickIndex::new_unchecked(i32_value); + let sqrt_price = tick_index.try_to_sqrt_price().unwrap(); + let round_trip_tick_index = TickIndex::try_from_sqrt_price(sqrt_price).unwrap(); + assert_eq!(round_trip_tick_index, tick_index); + } + } + + #[test] + fn test_from_offset_index() { + // Test various tick indices + for i32_value in [ + TickIndex::MIN.get(), + -1000, + -100, + -10, + 0, + 10, + 100, + 1000, + TickIndex::MAX.get(), + ] { + let original_tick = TickIndex::new_unchecked(i32_value); + + // Calculate the offset index (adding OFFSET) + let offset_index = (i32_value + TickIndex::OFFSET.get()) as u32; + + // Convert back from offset index to tick index + let roundtrip_tick = TickIndex::from_offset_index(offset_index).unwrap(); + + // Check that we get the same tick index back + assert_eq!(original_tick, roundtrip_tick); + } + + // Test out of bounds values + let too_large = (TickIndex::MAX.get() + TickIndex::OFFSET.get() + 1) as u32; + assert!(TickIndex::from_offset_index(too_large).is_err()); + } + + #[test] + fn test_tick_price_sanity_check() { + let min_price = TickIndex::MIN.try_to_sqrt_price().unwrap(); + let max_price = TickIndex::MAX.try_to_sqrt_price().unwrap(); + + assert!(min_price > 0.); + assert!(max_price > 0.); + assert!(max_price > min_price); + assert!(min_price < 0.000001); + assert!(max_price > 10.); + + // Roundtrip conversions + let min_price_sqrt = TickIndex::MIN.try_to_sqrt_price().unwrap(); + let min_tick = TickIndex::try_from_sqrt_price(min_price_sqrt).unwrap(); + assert_eq!(min_tick, TickIndex::MIN); + + let max_price_sqrt: SqrtPrice = TickIndex::MAX.try_to_sqrt_price().unwrap(); + let max_tick = TickIndex::try_from_sqrt_price(max_price_sqrt).unwrap(); + assert_eq!(max_tick, TickIndex::MAX); + } + + #[test] + fn test_to_sqrt_price_bounded() { + assert_eq!( + TickIndex::MAX.as_sqrt_price_bounded(), + TickIndex::MAX.try_to_sqrt_price().unwrap() + ); + + assert_eq!( + TickIndex::MIN.as_sqrt_price_bounded(), + TickIndex::MIN.try_to_sqrt_price().unwrap() + ); + } + + mod active_tick_index_manager { + + use super::*; + + #[test] + fn test_tick_search_basic() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + ActiveTickIndexManager::::insert(netuid, TickIndex::MIN); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MIN) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MAX) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MAX.saturating_div(2) + ) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MAX.prev().unwrap() + ) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MIN.next().unwrap() + ) + .unwrap(), + TickIndex::MIN + ); + + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, TickIndex::MIN) + .unwrap(), + TickIndex::MIN + ); + assert!( + ActiveTickIndexManager::::find_closest_higher(netuid, TickIndex::MAX) + .is_none() + ); + assert!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MAX.saturating_div(2) + ) + .is_none() + ); + assert!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MAX.prev().unwrap() + ) + .is_none() + ); + assert!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MIN.next().unwrap() + ) + .is_none() + ); + + ActiveTickIndexManager::::insert(netuid, TickIndex::MAX); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MIN) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MAX) + .unwrap(), + TickIndex::MAX + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MAX.saturating_div(2) + ) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MAX.prev().unwrap() + ) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MIN.next().unwrap() + ) + .unwrap(), + TickIndex::MIN + ); + }); + } + + #[test] + fn test_tick_search_sparse_queries() { + new_test_ext().execute_with(|| { + let active_index = TickIndex::MIN.saturating_add(10); + let netuid = NetUid::from(1); + + ActiveTickIndexManager::::insert(netuid, active_index); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, active_index) + .unwrap(), + active_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MIN.saturating_add(11) + ) + .unwrap(), + active_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MIN.saturating_add(12) + ) + .unwrap(), + active_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MIN), + None + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MIN.saturating_add(9) + ), + None + ); + + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, active_index) + .unwrap(), + active_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MIN.saturating_add(11) + ), + None + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MIN.saturating_add(12) + ), + None + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, TickIndex::MIN) + .unwrap(), + active_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MIN.saturating_add(9) + ) + .unwrap(), + active_index + ); + }); + } + + #[test] + fn test_tick_search_many_lows() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + (0..1000).for_each(|i| { + ActiveTickIndexManager::::insert( + netuid, + TickIndex::MIN.saturating_add(i), + ); + }); + + for i in 0..1000 { + let test_index = TickIndex::MIN.saturating_add(i); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, test_index) + .unwrap(), + test_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, test_index) + .unwrap(), + test_index + ); + } + }); + } + + #[test] + fn test_tick_search_many_sparse() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let count = 1000; + + for i in 0..=count { + ActiveTickIndexManager::::insert( + netuid, + TickIndex::new_unchecked(i * 10), + ); + } + + for i in 1..count { + let tick = TickIndex::new_unchecked(i * 10); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, tick).unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, tick).unwrap(), + tick + ); + for j in 1..=9 { + let before_tick = TickIndex::new_unchecked(i * 10 - j); + let after_tick = TickIndex::new_unchecked(i * 10 + j); + let prev_tick = TickIndex::new_unchecked((i - 1) * 10); + let next_tick = TickIndex::new_unchecked((i + 1) * 10); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, before_tick) + .unwrap(), + prev_tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, after_tick) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + before_tick + ) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, after_tick) + .unwrap(), + next_tick + ); + } + } + }); + } + + #[test] + fn test_tick_search_many_lows_sparse_reversed() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let count = 1000; + + for i in (0..=count).rev() { + ActiveTickIndexManager::::insert( + netuid, + TickIndex::new_unchecked(i * 10), + ); + } + + for i in 1..count { + let tick = TickIndex::new_unchecked(i * 10); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, tick).unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, tick).unwrap(), + tick + ); + for j in 1..=9 { + let before_tick = TickIndex::new_unchecked(i * 10 - j); + let after_tick = TickIndex::new_unchecked(i * 10 + j); + let prev_tick = TickIndex::new_unchecked((i - 1) * 10); + let next_tick = TickIndex::new_unchecked((i + 1) * 10); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, before_tick) + .unwrap(), + prev_tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, after_tick) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + before_tick + ) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, after_tick) + .unwrap(), + next_tick + ); + } + } + }); + } + + #[test] + fn test_tick_search_repeated_insertions() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let count = 1000; + + for _ in 0..10 { + for i in 0..=count { + let tick = TickIndex::new_unchecked(i * 10); + ActiveTickIndexManager::::insert(netuid, tick); + } + + for i in 1..count { + let tick = TickIndex::new_unchecked(i * 10); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, tick) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, tick) + .unwrap(), + tick + ); + for j in 1..=9 { + let before_tick = TickIndex::new_unchecked(i * 10 - j); + let after_tick = TickIndex::new_unchecked(i * 10 + j); + let prev_tick = TickIndex::new_unchecked((i - 1) * 10); + let next_tick = TickIndex::new_unchecked((i + 1) * 10); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + before_tick + ) + .unwrap(), + prev_tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, after_tick + ) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + before_tick + ) + .unwrap(), + tick + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, after_tick + ) + .unwrap(), + next_tick + ); + } + } + } + }); + } + + #[test] + fn test_tick_search_full_range() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let step = 1019; + // Get the full valid tick range by subtracting MIN from MAX + let count = (TickIndex::MAX.get() - TickIndex::MIN.get()) / step; + + for i in 0..=count { + let index = TickIndex::MIN.saturating_add(i * step); + ActiveTickIndexManager::::insert(netuid, index); + } + for i in 1..count { + let index = TickIndex::MIN.saturating_add(i * step); + + let prev_index = TickIndex::new_unchecked(index.get() - step); + let next_minus_one = TickIndex::new_unchecked(index.get() + step - 1); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, prev_index) + .unwrap(), + prev_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, index).unwrap(), + index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, next_minus_one) + .unwrap(), + index + ); + + let mid_next = TickIndex::new_unchecked(index.get() + step / 2); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, mid_next) + .unwrap(), + index + ); + + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, index).unwrap(), + index + ); + + let next_index = TickIndex::new_unchecked(index.get() + step); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, next_index) + .unwrap(), + next_index + ); + + let mid_next = TickIndex::new_unchecked(index.get() + step / 2); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, mid_next) + .unwrap(), + next_index + ); + + let next_minus_1 = TickIndex::new_unchecked(index.get() + step - 1); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, next_minus_1) + .unwrap(), + next_index + ); + for j in 1..=9 { + let before_index = TickIndex::new_unchecked(index.get() - j); + let after_index = TickIndex::new_unchecked(index.get() + j); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + before_index + ) + .unwrap(), + prev_index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, after_index) + .unwrap(), + index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + before_index + ) + .unwrap(), + index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + after_index + ) + .unwrap(), + next_index + ); + } + } + }); + } + + #[test] + fn test_tick_remove_basic() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + + ActiveTickIndexManager::::insert(netuid, TickIndex::MIN); + ActiveTickIndexManager::::insert(netuid, TickIndex::MAX); + ActiveTickIndexManager::::remove(netuid, TickIndex::MAX); + + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MIN) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, TickIndex::MAX) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MAX.saturating_div(2) + ) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MAX.prev().unwrap() + ) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_lower( + netuid, + TickIndex::MIN.next().unwrap() + ) + .unwrap(), + TickIndex::MIN + ); + + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, TickIndex::MIN) + .unwrap(), + TickIndex::MIN + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, TickIndex::MAX), + None + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MAX.saturating_div(2) + ), + None + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MAX.prev().unwrap() + ), + None + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher( + netuid, + TickIndex::MIN.next().unwrap() + ), + None + ); + }); + } + + #[test] + fn test_tick_remove_full_range() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let step = 1019; + // Get the full valid tick range by subtracting MIN from MAX + let count = (TickIndex::MAX.get() - TickIndex::MIN.get()) / step; + let remove_frequency = 5; // Remove every 5th tick + + // Insert ticks + for i in 0..=count { + let index = TickIndex::MIN.saturating_add(i * step); + ActiveTickIndexManager::::insert(netuid, index); + } + + // Remove some ticks + for i in 1..count { + if i % remove_frequency == 0 { + let index = TickIndex::MIN.saturating_add(i * step); + ActiveTickIndexManager::::remove(netuid, index); + } + } + + // Verify + for i in 1..count { + let index = TickIndex::MIN.saturating_add(i * step); + + if i % remove_frequency == 0 { + let lower = + ActiveTickIndexManager::::find_closest_lower(netuid, index); + let higher = + ActiveTickIndexManager::::find_closest_higher(netuid, index); + assert!(lower != Some(index)); + assert!(higher != Some(index)); + } else { + assert_eq!( + ActiveTickIndexManager::::find_closest_lower(netuid, index) + .unwrap(), + index + ); + assert_eq!( + ActiveTickIndexManager::::find_closest_higher(netuid, index) + .unwrap(), + index + ); + } + } + }); + } + } +} diff --git a/pallets/swap/src/weights.rs b/pallets/swap/src/weights.rs index 210bf1dc6d..2bbbb8dbdf 100644 --- a/pallets/swap/src/weights.rs +++ b/pallets/swap/src/weights.rs @@ -15,6 +15,10 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_subtensor_swap. pub trait WeightInfo { fn set_fee_rate() -> Weight; + fn add_liquidity() -> Weight; + fn remove_liquidity() -> Weight; + fn modify_position() -> Weight; + fn toggle_user_liquidity() -> Weight; } /// Default weights for pallet_subtensor_swap. @@ -26,6 +30,34 @@ impl WeightInfo for DefaultWeight { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + + fn add_liquidity() -> Weight { + // Conservative weight estimate for add_liquidity + Weight::from_parts(50_000_000, 0) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + + fn remove_liquidity() -> Weight { + // Conservative weight estimate for remove_liquidity + Weight::from_parts(50_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + + fn modify_position() -> Weight { + // Conservative weight estimate for modify_position + Weight::from_parts(50_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + + fn toggle_user_liquidity() -> Weight { + // Conservative weight estimate: one read and one write + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } // For backwards compatibility and tests @@ -35,4 +67,28 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } + + fn add_liquidity() -> Weight { + Weight::from_parts(50_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + + fn remove_liquidity() -> Weight { + Weight::from_parts(50_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + + fn modify_position() -> Weight { + Weight::from_parts(50_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + + fn toggle_user_liquidity() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } } diff --git a/pallets/transaction-fee/src/lib.rs b/pallets/transaction-fee/src/lib.rs index 21e72e8853..55f44fba95 100644 --- a/pallets/transaction-fee/src/lib.rs +++ b/pallets/transaction-fee/src/lib.rs @@ -30,8 +30,8 @@ use subtensor_swap_interface::SwapHandler; use core::marker::PhantomData; use smallvec::smallvec; use sp_std::vec::Vec; -use substrate_fixed::types::U64F64; -use subtensor_runtime_common::{AuthorshipInfo, Balance, NetUid}; +use substrate_fixed::types::U96F32; +use subtensor_runtime_common::{Balance, Currency, NetUid}; // Tests #[cfg(test)] @@ -153,7 +153,7 @@ where // This is not ideal because it may not pay all fees, but UX is the priority // and this approach still provides spam protection. alpha_vec.iter().any(|(hotkey, netuid)| { - let alpha_balance = U64F64::saturating_from_num( + let alpha_balance = U96F32::saturating_from_num( pallet_subtensor::Pallet::::get_stake_for_hotkey_and_coldkey_on_subnet( hotkey, coldkey, *netuid, ), @@ -176,13 +176,13 @@ where alpha_vec.iter().for_each(|(hotkey, netuid)| { // Divide tao_amount evenly among all alpha entries - let alpha_balance = U64F64::saturating_from_num( + let alpha_balance = U96F32::saturating_from_num( pallet_subtensor::Pallet::::get_stake_for_hotkey_and_coldkey_on_subnet( hotkey, coldkey, *netuid, ), ); let alpha_price = pallet_subtensor_swap::Pallet::::current_alpha_price(*netuid); - let alpha_fee = U64F64::saturating_from_num(tao_per_entry) + let alpha_fee = U96F32::saturating_from_num(tao_per_entry) .checked_div(alpha_price) .unwrap_or(alpha_balance) .min(alpha_balance) diff --git a/pallets/transaction-fee/src/tests/mock.rs b/pallets/transaction-fee/src/tests/mock.rs index e6452a0bcd..e4572bbfea 100644 --- a/pallets/transaction-fee/src/tests/mock.rs +++ b/pallets/transaction-fee/src/tests/mock.rs @@ -401,6 +401,7 @@ impl pallet_balances::Config for Test { parameter_types! { pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap"); pub const SwapMaxFeeRate: u16 = 10000; // 15.26% + pub const SwapMaxPositions: u32 = 100; pub const SwapMinimumLiquidity: u64 = 1_000; pub const SwapMinimumReserve: NonZeroU64 = NonZeroU64::new(1_000_000).unwrap(); } @@ -412,6 +413,7 @@ impl pallet_subtensor_swap::Config for Test { type TaoReserve = pallet_subtensor::TaoCurrencyReserve; type AlphaReserve = pallet_subtensor::AlphaCurrencyReserve; type MaxFeeRate = SwapMaxFeeRate; + type MaxPositions = SwapMaxPositions; type MinimumLiquidity = SwapMinimumLiquidity; type MinimumReserve = SwapMinimumReserve; type WeightInfo = (); diff --git a/pallets/transaction-fee/src/tests/mod.rs b/pallets/transaction-fee/src/tests/mod.rs index 80cfab5fd3..859507b072 100644 --- a/pallets/transaction-fee/src/tests/mod.rs +++ b/pallets/transaction-fee/src/tests/mod.rs @@ -2,11 +2,12 @@ use crate::TransactionSource; use frame_support::assert_ok; use frame_support::dispatch::GetDispatchInfo; +use pallet_subtensor_swap::AlphaSqrtPrice; use sp_runtime::{ traits::{DispatchTransaction, TransactionExtension, TxBaseImplication}, transaction_validity::{InvalidTransaction, TransactionValidityError}, }; -// use substrate_fixed::types::U64F64; +use substrate_fixed::types::U64F64; use subtensor_runtime_common::AlphaCurrency; use mock::*; @@ -443,9 +444,7 @@ fn test_remove_stake_edge_alpha() { assert_ok!(result); // Lower Alpha price to 0.0001 so that there is not enough alpha to cover tx fees - SubnetTAO::::insert(sn.subnets[0].netuid, TaoCurrency::from(1_000_000)); - SubnetAlphaIn::::insert(sn.subnets[0].netuid, AlphaCurrency::from(10_000_000_000)); - + AlphaSqrtPrice::::insert(sn.subnets[0].netuid, U64F64::from_num(0.01)); let result_low_alpha_price = ext.validate( RuntimeOrigin::signed(sn.coldkey).into(), &call.clone(), diff --git a/precompiles/src/alpha.rs b/precompiles/src/alpha.rs index 98737f1269..8dcea0e829 100644 --- a/precompiles/src/alpha.rs +++ b/precompiles/src/alpha.rs @@ -5,7 +5,7 @@ use pallet_evm::{BalanceConverter, PrecompileHandle, SubstrateBalance}; use precompile_utils::EvmResult; use sp_core::U256; use sp_std::vec::Vec; -use substrate_fixed::types::{U64F64, U96F32}; +use substrate_fixed::types::U96F32; use subtensor_runtime_common::{Currency, NetUid}; use subtensor_swap_interface::{Order, SwapHandler}; @@ -37,7 +37,7 @@ where fn get_alpha_price(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { let current_alpha_price = as SwapHandler>::current_alpha_price(netuid.into()); - let price = current_alpha_price.saturating_mul(U64F64::from_num(1_000_000_000)); + let price = current_alpha_price.saturating_mul(U96F32::from_num(1_000_000_000)); let price: SubstrateBalance = price.saturating_to_num::().into(); let price_eth = ::BalanceConverter::into_evm_balance(price) .map(|amount| amount.into_u256()) @@ -194,18 +194,18 @@ where .filter(|(netuid, _)| *netuid != NetUid::ROOT) .collect::>(); - let mut sum_alpha_price: U64F64 = U64F64::from_num(0); + let mut sum_alpha_price: U96F32 = U96F32::from_num(0); for (netuid, _) in netuids { let price = as SwapHandler>::current_alpha_price( netuid.into(), ); - if price < U64F64::from_num(1) { + if price < U96F32::from_num(1) { sum_alpha_price = sum_alpha_price.saturating_add(price); } } - let price = sum_alpha_price.saturating_mul(U64F64::from_num(1_000_000_000)); + let price = sum_alpha_price.saturating_mul(U96F32::from_num(1_000_000_000)); let price: SubstrateBalance = price.saturating_to_num::().into(); let price_eth = ::BalanceConverter::into_evm_balance(price) .map(|amount| amount.into_u256()) diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 95564977cf..623846de12 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -21,7 +21,6 @@ subtensor-custom-rpc-runtime-api.workspace = true smallvec.workspace = true log.workspace = true codec = { workspace = true, features = ["derive"] } -safe-math.workspace = true scale-info = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["alloc"] } pallet-aura = { workspace = true } @@ -200,7 +199,6 @@ std = [ "pallet-preimage/std", "pallet-commitments/std", "precompile-utils/std", - "safe-math/std", "sp-api/std", "sp-block-builder/std", "sp-core/std", diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 460a84e049..b90afd7aa7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -43,10 +43,9 @@ use pallet_subtensor::rpc_info::{ }; use pallet_subtensor::{CommitmentsInterface, ProxyInterface}; use pallet_subtensor_proxy as pallet_proxy; -use pallet_subtensor_swap_runtime_api::{SimSwapResult, SubnetPrice}; +use pallet_subtensor_swap_runtime_api::SimSwapResult; use pallet_subtensor_utility as pallet_utility; use runtime_common::prod_or_fast; -use safe_math::FixedExt; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_consensus_babe::BabeConfiguration; @@ -72,7 +71,6 @@ use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use substrate_fixed::types::U64F64; use subtensor_precompiles::Precompiles; use subtensor_runtime_common::{AlphaCurrency, AuthorshipInfo, TaoCurrency, time::*, *}; use subtensor_swap_interface::{Order, SwapHandler}; @@ -1131,6 +1129,7 @@ impl pallet_subtensor::Config for Runtime { parameter_types! { pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap"); pub const SwapMaxFeeRate: u16 = 10000; // 15.26% + pub const SwapMaxPositions: u32 = 100; pub const SwapMinimumLiquidity: u64 = 1_000; pub const SwapMinimumReserve: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(1_000_000) }; } @@ -1142,6 +1141,7 @@ impl pallet_subtensor_swap::Config for Runtime { type TaoReserve = pallet_subtensor::TaoCurrencyReserve; type AlphaReserve = pallet_subtensor::AlphaCurrencyReserve; type MaxFeeRate = SwapMaxFeeRate; + type MaxPositions = SwapMaxPositions; type MinimumLiquidity = SwapMinimumLiquidity; type MinimumReserve = SwapMinimumReserve; // TODO: set measured weights when the pallet been benchmarked and the type is generated @@ -2486,26 +2486,14 @@ impl_runtime_apis! { impl pallet_subtensor_swap_runtime_api::SwapRuntimeApi for Runtime { fn current_alpha_price(netuid: NetUid) -> u64 { + use substrate_fixed::types::U96F32; + pallet_subtensor_swap::Pallet::::current_price(netuid.into()) - .saturating_mul(U64F64::from_num(1_000_000_000)) + .saturating_mul(U96F32::from_num(1_000_000_000)) .saturating_to_num() } - fn current_alpha_price_all() -> Vec { - pallet_subtensor::Pallet::::get_all_subnet_netuids() - .into_iter() - .map(|netuid| { - SubnetPrice { - netuid, - price: Self::current_alpha_price(netuid), - } - }) - .collect() - } - fn sim_swap_tao_for_alpha(netuid: NetUid, tao: TaoCurrency) -> SimSwapResult { - let price = pallet_subtensor_swap::Pallet::::current_price(netuid.into()); - let no_slippage_alpha = U64F64::saturating_from_num(u64::from(tao)).safe_div(price).saturating_to_num::(); let order = pallet_subtensor::GetAlphaForTao::::with_amount(tao); // fee_to_block_author is included in sr.fee_paid, so it is absent in this calculation pallet_subtensor_swap::Pallet::::sim_swap( @@ -2518,23 +2506,17 @@ impl_runtime_apis! { alpha_amount: 0.into(), tao_fee: 0.into(), alpha_fee: 0.into(), - tao_slippage: 0.into(), - alpha_slippage: 0.into(), }, |sr| SimSwapResult { tao_amount: sr.amount_paid_in.into(), alpha_amount: sr.amount_paid_out.into(), tao_fee: sr.fee_paid.into(), alpha_fee: 0.into(), - tao_slippage: 0.into(), - alpha_slippage: no_slippage_alpha.saturating_sub(sr.amount_paid_out.into()).into(), }, ) } fn sim_swap_alpha_for_tao(netuid: NetUid, alpha: AlphaCurrency) -> SimSwapResult { - let price = pallet_subtensor_swap::Pallet::::current_price(netuid.into()); - let no_slippage_tao = U64F64::saturating_from_num(u64::from(alpha)).saturating_mul(price).saturating_to_num::(); let order = pallet_subtensor::GetTaoForAlpha::::with_amount(alpha); // fee_to_block_author is included in sr.fee_paid, so it is absent in this calculation pallet_subtensor_swap::Pallet::::sim_swap( @@ -2547,16 +2529,12 @@ impl_runtime_apis! { alpha_amount: 0.into(), tao_fee: 0.into(), alpha_fee: 0.into(), - tao_slippage: 0.into(), - alpha_slippage: 0.into(), }, |sr| SimSwapResult { tao_amount: sr.amount_paid_out.into(), alpha_amount: sr.amount_paid_in.into(), tao_fee: 0.into(), alpha_fee: sr.fee_paid.into(), - tao_slippage: no_slippage_tao.saturating_sub(sr.amount_paid_out.into()).into(), - alpha_slippage: 0.into(), }, ) } From 9ef6ba3c8f750e0627bf6f756db9fc894c10df16 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 25 Feb 2026 13:16:03 -0500 Subject: [PATCH 07/43] Cleanup merge --- Cargo.lock | 20 ++ pallets/subtensor/src/tests/mock.rs | 4 +- pallets/subtensor/src/tests/staking.rs | 35 +-- pallets/swap/src/mock.rs | 1 + pallets/swap/src/pallet/impls.rs | 4 + pallets/swap/src/pallet/mod.rs | 1 + pallets/swap/src/pallet/swap_step.rs | 9 +- pallets/swap/src/pallet/tests.rs | 350 ++++++++++++----------- pallets/transaction-fee/src/lib.rs | 2 +- pallets/transaction-fee/src/tests/mod.rs | 2 +- 10 files changed, 232 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2fe04437c..fc7eaf2560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16374,6 +16374,26 @@ dependencies = [ "wide", ] +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" +dependencies = [ + "bstr", + "unicode-segmentation", +] + +[[package]] +name = "similar-asserts" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b441962c817e33508847a22bd82f03a30cff43642dc2fae8b050566121eb9a" +dependencies = [ + "console", + "similar", +] + [[package]] name = "simple-dns" version = "0.9.3" diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index d36875ced1..2435245ad3 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -153,11 +153,13 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +pub const MOCK_BLOCK_BUILDER: u64 = 12345u64; + pub struct MockAuthorshipProvider; impl AuthorshipInfo for MockAuthorshipProvider { fn author() -> Option { - Some(U256::from(12345u64)) + Some(U256::from(MOCK_BLOCK_BUILDER)) } } diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 4bbdc0866a..6a293fa11e 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -4898,8 +4898,6 @@ fn test_swap_fees_tao_correctness() { let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); SubtensorModule::add_balance_to_coldkey_account(&owner_coldkey, owner_balance_before); SubtensorModule::add_balance_to_coldkey_account(&coldkey, user_balance_before); - let fee_rate = pallet_subtensor_swap::FeeRate::::get(NetUid::from(netuid)) as f64 - / u16::MAX as f64; pallet_subtensor_swap::EnabledUserLiquidity::::insert(NetUid::from(netuid), true); // Forse-set alpha in and tao reserve to make price equal 0.25 @@ -4965,14 +4963,15 @@ fn test_swap_fees_tao_correctness() { user_alpha, )); + // TODO: This block is for balancer swap // Cause tao fees to propagate to SubnetTAO - let (claimed_tao_fees, _) = - ::SwapInterface::adjust_protocol_liquidity( - netuid, - 0.into(), - 0.into(), - ); - SubnetTAO::::mutate(netuid, |tao| *tao += claimed_tao_fees); + // let (claimed_tao_fees, _) = + // ::SwapInterface::adjust_protocol_liquidity( + // netuid, + // 0.into(), + // 0.into(), + // ); + // SubnetTAO::::mutate(netuid, |tao| *tao += claimed_tao_fees); // Check ending "total TAO" let owner_balance_after = SubtensorModule::get_coldkey_balance(&owner_coldkey); @@ -5254,6 +5253,10 @@ fn test_update_position_fees() { let alpha_in = AlphaCurrency::from(400_000_000_000); mock::setup_reserves(netuid, tao_reserve, alpha_in); + // Get the block builder balance + let block_builder = U256::from(MOCK_BLOCK_BUILDER); + let block_builder_balance_before = Balances::free_balance(block_builder); + // Get alpha for owner assert_ok!(SubtensorModule::add_stake( RuntimeOrigin::signed(owner_coldkey), @@ -5305,13 +5308,8 @@ fn test_update_position_fees() { user_alpha, )); - // Modify position - fees should be collected and paid to the owner + // Modify position - fees should be collected and paid to the owner (block builder is already paid by now) let owner_tao_before = SubtensorModule::get_coldkey_balance(&owner_coldkey); - let owner_alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( - &owner_hotkey, - &owner_coldkey, - netuid, - ); // Make small modification let delta = @@ -5327,6 +5325,7 @@ fn test_update_position_fees() { )); // Check ending owner TAO and alpha + let block_builder_balance_after_add = Balances::free_balance(block_builder); let owner_tao_after_add = SubtensorModule::get_coldkey_balance(&owner_coldkey); let owner_alpha_after_add = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( &owner_hotkey, @@ -5334,8 +5333,10 @@ fn test_update_position_fees() { netuid, ); - assert!(owner_tao_after_add > owner_tao_before); - assert!(owner_alpha_after_add > owner_alpha_before); // always greater because of claimed fees + assert!( + owner_tao_after_add + block_builder_balance_after_add + > owner_tao_before + block_builder_balance_before + ); // Make small modification again - should not claim more fees assert_ok!(Swap::modify_position( diff --git a/pallets/swap/src/mock.rs b/pallets/swap/src/mock.rs index aacdf90835..29f993ca4a 100644 --- a/pallets/swap/src/mock.rs +++ b/pallets/swap/src/mock.rs @@ -124,6 +124,7 @@ pub type GetAlphaForTao = subtensor_swap_interface::GetAlphaForTao; pub(crate) trait GlobalFeeInfo: Currency { + #[allow(dead_code)] fn global_fee(&self, netuid: NetUid) -> U64F64; } diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 7ebb7ad78e..38830ec688 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -302,6 +302,7 @@ impl Pallet { let mut iteration_counter: u16 = 0; let mut in_acc = Order::PaidIn::ZERO; let mut fee_acc = Order::PaidIn::ZERO; + let mut fee_to_block_author_acc = Order::PaidIn::ZERO; log::trace!("======== Start Swap ========"); log::trace!("Amount Remaining: {amount_remaining}"); @@ -326,6 +327,8 @@ impl Pallet { in_acc = in_acc.saturating_add(swap_result.delta_in); fee_acc = fee_acc.saturating_add(swap_result.fee_paid); + fee_to_block_author_acc = + fee_to_block_author_acc.saturating_add(swap_result.fee_to_block_author); amount_remaining = amount_remaining.saturating_sub(swap_result.amount_to_take); amount_paid_out = amount_paid_out.saturating_add(swap_result.delta_out); @@ -353,6 +356,7 @@ impl Pallet { amount_paid_in: in_acc, amount_paid_out, fee_paid: fee_acc, + fee_to_block_author: fee_to_block_author_acc, }) } diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index 3a168cf753..73f0833d5d 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -3,6 +3,7 @@ use core::ops::Neg; use frame_support::{PalletId, pallet_prelude::*, traits::Get}; use frame_system::pallet_prelude::*; +use sp_arithmetic::Perbill; use substrate_fixed::types::U64F64; use subtensor_runtime_common::{ AlphaCurrency, BalanceOps, Currency, CurrencyReserve, NetUid, SubnetInfo, TaoCurrency, diff --git a/pallets/swap/src/pallet/swap_step.rs b/pallets/swap/src/pallet/swap_step.rs index 4cae4cb987..52215e79b5 100644 --- a/pallets/swap/src/pallet/swap_step.rs +++ b/pallets/swap/src/pallet/swap_step.rs @@ -1,5 +1,6 @@ use core::marker::PhantomData; +use frame_support::{ensure, traits::Get}; use safe_math::*; use substrate_fixed::types::{I64F64, U64F64}; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, TaoCurrency}; @@ -186,6 +187,9 @@ where /// Process a single step of a swap fn process_swap(&self) -> Result, Error> { + let delta_out = Self::convert_deltas(self.netuid, self.delta_in); + log::trace!("\tDelta Out : {delta_out}"); + let mut fee_to_block_author = 0.into(); if self.delta_in > 0.into() { ensure!(delta_out > 0.into(), Error::::ReservesTooLow); @@ -197,7 +201,7 @@ where // fee_to_block_author = self.fee; // ``` let fee_split = DefaultFeeSplit::get(); - let lp_fee = fee_split.mul_floor(self.fee.to_u64()).into(); + let lp_fee: PaidIn = fee_split.mul_floor(self.fee.to_u64()).into(); // Hold the reserve portion of fees if !lp_fee.is_zero() { @@ -211,9 +215,6 @@ where fee_to_block_author = self.fee.saturating_sub(lp_fee); } - let delta_out = Self::convert_deltas(self.netuid, self.delta_in); - log::trace!("\tDelta Out : {delta_out}"); - if self.action == SwapStepAction::Crossing { let mut tick = Ticks::::get(self.netuid, self.edge_tick).unwrap_or_default(); tick.fees_out_tao = I64F64::saturating_from_num(FeeGlobalTao::::get(self.netuid)) diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index cd18e665cd..727e65c95a 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -679,8 +679,10 @@ fn test_modify_position_basic() { alpha / 10, epsilon = alpha / 1000 ); - assert!(modify_result.fee_tao > TaoCurrency::ZERO); - assert_eq!(modify_result.fee_alpha, AlphaCurrency::ZERO); + + // Block author may get all fees + // assert!(modify_result.fee_tao > TaoCurrency::ZERO); + // assert_eq!(modify_result.fee_alpha, AlphaCurrency::ZERO); // Liquidity position is reduced assert_eq!( @@ -814,11 +816,13 @@ fn test_swap_basic() { let expected_fee = (liquidity as f64 * fee_rate) as u64; // Global fees should be updated - let actual_global_fee = (order.amount().global_fee(netuid).to_num::() - * (liquidity_before as f64)) as u64; + // let actual_global_fee = (order.amount().global_fee(netuid).to_num::() + // * (liquidity_before as f64)) as u64; assert!((swap_result.fee_paid.to_u64() as i64 - expected_fee as i64).abs() <= 1); - assert!((actual_global_fee as i64 - expected_fee as i64).abs() <= 1); + + // All fees go to block builder + // assert!((actual_global_fee as i64 - expected_fee as i64).abs() <= 1); // Tick fees should be updated @@ -1024,23 +1028,23 @@ fn test_swap_single_position() { expected_liquidity_gross_high, ); - // Expected fee amount - let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; - let expected_fee = (order_liquidity - order_liquidity / (1.0 + fee_rate)) as u64; + // Expected fee amount - do not test, all fees go to block builder + // let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; + // let expected_fee = (order_liquidity - order_liquidity / (1.0 + fee_rate)) as u64; - // // Global fees should be updated - let actual_global_fee = ($order_t::with_amount(0) - .amount() - .global_fee(netuid) - .to_num::() - * (liquidity_before as f64)) as u64; + // // // Global fees should be updated + // let actual_global_fee = ($order_t::with_amount(0) + // .amount() + // .global_fee(netuid) + // .to_num::() + // * (liquidity_before as f64)) as u64; - assert_abs_diff_eq!( - swap_result.fee_paid.to_u64(), - expected_fee, - epsilon = expected_fee / 10 - ); - assert_abs_diff_eq!(actual_global_fee, expected_fee, epsilon = expected_fee / 10); + // assert_abs_diff_eq!( + // swap_result.fee_paid.to_u64(), + // expected_fee, + // epsilon = expected_fee / 10 + // ); + // assert_abs_diff_eq!(actual_global_fee, expected_fee, epsilon = expected_fee / 10); // Tick fees should be updated @@ -1464,70 +1468,71 @@ fn test_convert_deltas() { // }); // } -/// Test correctness of swap fees: -/// - Fees are distribued to (concentrated) liquidity providers -/// -#[test] -fn test_swap_fee_correctness() { - new_test_ext().execute_with(|| { - let min_price = tick_to_price(TickIndex::MIN); - let max_price = tick_to_price(TickIndex::MAX); - let netuid = NetUid::from(1); - - // Provide very spread liquidity at the range from min to max that matches protocol liquidity - let liquidity = 2_000_000_000_000_u64; // 1x of protocol liquidity - - assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - - // Calculate ticks - let tick_low = price_to_tick(min_price); - let tick_high = price_to_tick(max_price); +// This test is pointless: All fees go to block author +// Test correctness of swap fees: +// - Fees are distribued to (concentrated) liquidity providers +// +// #[test] +// fn test_swap_fee_correctness() { +// new_test_ext().execute_with(|| { +// let min_price = tick_to_price(TickIndex::MIN); +// let max_price = tick_to_price(TickIndex::MAX); +// let netuid = NetUid::from(1); - // Add user liquidity - let (position_id, _tao, _alpha) = Pallet::::do_add_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID, - &OK_HOTKEY_ACCOUNT_ID, - tick_low, - tick_high, - liquidity, - ) - .unwrap(); +// // Provide very spread liquidity at the range from min to max that matches protocol liquidity +// let liquidity = 2_000_000_000_000_u64; // 1x of protocol liquidity - // Swap buy and swap sell - Pallet::::do_swap( - netuid, - GetAlphaForTao::with_amount(liquidity / 10), - u64::MAX.into(), - false, - false, - ) - .unwrap(); - Pallet::::do_swap( - netuid, - GetTaoForAlpha::with_amount(liquidity / 10), - 0_u64.into(), - false, - false, - ) - .unwrap(); +// assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - // Get user position - let mut position = - Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID, position_id)).unwrap(); - assert_eq!(position.liquidity, liquidity); - assert_eq!(position.tick_low, tick_low); - assert_eq!(position.tick_high, tick_high); +// // Calculate ticks +// let tick_low = price_to_tick(min_price); +// let tick_high = price_to_tick(max_price); - // Check that 50% of fees were credited to the position - let fee_rate = FeeRate::::get(NetUid::from(netuid)) as f64 / u16::MAX as f64; - let (actual_fee_tao, actual_fee_alpha) = position.collect_fees(); - let expected_fee = (fee_rate * (liquidity / 10) as f64 * 0.5) as u64; +// // Add user liquidity +// let (position_id, _tao, _alpha) = Pallet::::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID, +// &OK_HOTKEY_ACCOUNT_ID, +// tick_low, +// tick_high, +// liquidity, +// ) +// .unwrap(); - assert_abs_diff_eq!(actual_fee_tao, expected_fee, epsilon = 1,); - assert_abs_diff_eq!(actual_fee_alpha, expected_fee, epsilon = 1,); - }); -} +// // Swap buy and swap sell +// Pallet::::do_swap( +// netuid, +// GetAlphaForTao::with_amount(liquidity / 10), +// u64::MAX.into(), +// false, +// false, +// ) +// .unwrap(); +// Pallet::::do_swap( +// netuid, +// GetTaoForAlpha::with_amount(liquidity / 10), +// 0_u64.into(), +// false, +// false, +// ) +// .unwrap(); + +// // Get user position +// let mut position = +// Positions::::get((netuid, OK_COLDKEY_ACCOUNT_ID, position_id)).unwrap(); +// assert_eq!(position.liquidity, liquidity); +// assert_eq!(position.tick_low, tick_low); +// assert_eq!(position.tick_high, tick_high); + +// // Check that 50% of fees were credited to the position +// let fee_rate = FeeRate::::get(NetUid::from(netuid)) as f64 / u16::MAX as f64; +// let (actual_fee_tao, actual_fee_alpha) = position.collect_fees(); +// let expected_fee = (fee_rate * (liquidity / 10) as f64 * 0.5) as u64; + +// assert_abs_diff_eq!(actual_fee_tao, expected_fee, epsilon = 1,); +// assert_abs_diff_eq!(actual_fee_alpha, expected_fee, epsilon = 1,); +// }); +// } #[test] fn test_current_liquidity_updates() { @@ -1694,123 +1699,124 @@ fn test_new_lp_doesnt_get_old_fees() { }); } -fn bbox(t: U64F64, a: U64F64, b: U64F64) -> U64F64 { - if t < a { - a - } else if t > b { - b - } else { - t - } -} +// fn bbox(t: U64F64, a: U64F64, b: U64F64) -> U64F64 { +// if t < a { +// a +// } else if t > b { +// b +// } else { +// t +// } +// } -fn print_current_price(netuid: NetUid) { - let current_sqrt_price = AlphaSqrtPrice::::get(netuid).to_num::(); - let current_price = current_sqrt_price * current_sqrt_price; - log::trace!("Current price: {current_price:.6}"); -} +// fn print_current_price(netuid: NetUid) { +// let current_sqrt_price = AlphaSqrtPrice::::get(netuid).to_num::(); +// let current_price = current_sqrt_price * current_sqrt_price; +// log::trace!("Current price: {current_price:.6}"); +// } -/// RUST_LOG=pallet_subtensor_swap=trace cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_wrapping_fees --exact --show-output --nocapture -#[test] -fn test_wrapping_fees() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(WRAPPING_FEES_NETUID); - let position_1_low_price = 0.20; - let position_1_high_price = 0.255; - let position_2_low_price = 0.255; - let position_2_high_price = 0.257; - assert_ok!(Pallet::::maybe_initialize_v3(netuid)); +// All fees go to block builder +// RUST_LOG=pallet_subtensor_swap=trace cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_wrapping_fees --exact --show-output --nocapture +// #[test] +// fn test_wrapping_fees() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(WRAPPING_FEES_NETUID); +// let position_1_low_price = 0.20; +// let position_1_high_price = 0.255; +// let position_2_low_price = 0.255; +// let position_2_high_price = 0.257; +// assert_ok!(Pallet::::maybe_initialize_v3(netuid)); - Pallet::::do_add_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID_RICH, - &OK_COLDKEY_ACCOUNT_ID_RICH, - price_to_tick(position_1_low_price), - price_to_tick(position_1_high_price), - 1_000_000_000_u64, - ) - .unwrap(); +// Pallet::::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID_RICH, +// &OK_COLDKEY_ACCOUNT_ID_RICH, +// price_to_tick(position_1_low_price), +// price_to_tick(position_1_high_price), +// 1_000_000_000_u64, +// ) +// .unwrap(); - print_current_price(netuid); +// print_current_price(netuid); - let order = GetTaoForAlpha::with_amount(800_000_000); - let sqrt_limit_price = SqrtPrice::from_num(0.000001); - Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); +// let order = GetTaoForAlpha::with_amount(800_000_000); +// let sqrt_limit_price = SqrtPrice::from_num(0.000001); +// Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); - let order = GetAlphaForTao::with_amount(1_850_000_000); - let sqrt_limit_price = SqrtPrice::from_num(1_000_000.0); +// let order = GetAlphaForTao::with_amount(1_850_000_000); +// let sqrt_limit_price = SqrtPrice::from_num(1_000_000.0); - print_current_price(netuid); +// print_current_price(netuid); - Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); +// Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); - print_current_price(netuid); +// print_current_price(netuid); - let add_liquidity_result = Pallet::::do_add_liquidity( - netuid, - &OK_COLDKEY_ACCOUNT_ID_RICH, - &OK_COLDKEY_ACCOUNT_ID_RICH, - price_to_tick(position_2_low_price), - price_to_tick(position_2_high_price), - 1_000_000_000_u64, - ) - .unwrap(); +// let add_liquidity_result = Pallet::::do_add_liquidity( +// netuid, +// &OK_COLDKEY_ACCOUNT_ID_RICH, +// &OK_COLDKEY_ACCOUNT_ID_RICH, +// price_to_tick(position_2_low_price), +// price_to_tick(position_2_high_price), +// 1_000_000_000_u64, +// ) +// .unwrap(); - let order = GetTaoForAlpha::with_amount(1_800_000_000); - let sqrt_limit_price = SqrtPrice::from_num(0.000001); +// let order = GetTaoForAlpha::with_amount(1_800_000_000); +// let sqrt_limit_price = SqrtPrice::from_num(0.000001); - let initial_sqrt_price = AlphaSqrtPrice::::get(netuid); - Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); - let final_sqrt_price = AlphaSqrtPrice::::get(netuid); +// let initial_sqrt_price = AlphaSqrtPrice::::get(netuid); +// Pallet::::do_swap(netuid, order, sqrt_limit_price, false, false).unwrap(); +// let final_sqrt_price = AlphaSqrtPrice::::get(netuid); - print_current_price(netuid); +// print_current_price(netuid); - let mut position = - Positions::::get((netuid, &OK_COLDKEY_ACCOUNT_ID_RICH, add_liquidity_result.0)) - .unwrap(); +// let mut position = +// Positions::::get((netuid, &OK_COLDKEY_ACCOUNT_ID_RICH, add_liquidity_result.0)) +// .unwrap(); - let initial_box_price = bbox( - initial_sqrt_price, - position.tick_low.try_to_sqrt_price().unwrap(), - position.tick_high.try_to_sqrt_price().unwrap(), - ); +// let initial_box_price = bbox( +// initial_sqrt_price, +// position.tick_low.try_to_sqrt_price().unwrap(), +// position.tick_high.try_to_sqrt_price().unwrap(), +// ); - let final_box_price = bbox( - final_sqrt_price, - position.tick_low.try_to_sqrt_price().unwrap(), - position.tick_high.try_to_sqrt_price().unwrap(), - ); +// let final_box_price = bbox( +// final_sqrt_price, +// position.tick_low.try_to_sqrt_price().unwrap(), +// position.tick_high.try_to_sqrt_price().unwrap(), +// ); - let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; +// let fee_rate = FeeRate::::get(netuid) as f64 / u16::MAX as f64; - log::trace!("fee_rate: {fee_rate:.6}"); - log::trace!("position.liquidity: {}", position.liquidity); - log::trace!( - "initial_box_price: {:.6}", - initial_box_price.to_num::() - ); - log::trace!("final_box_price: {:.6}", final_box_price.to_num::()); +// log::trace!("fee_rate: {fee_rate:.6}"); +// log::trace!("position.liquidity: {}", position.liquidity); +// log::trace!( +// "initial_box_price: {:.6}", +// initial_box_price.to_num::() +// ); +// log::trace!("final_box_price: {:.6}", final_box_price.to_num::()); - let expected_fee_tao = ((fee_rate / (1.0 - fee_rate)) - * (position.liquidity as f64) - * (final_box_price.to_num::() - initial_box_price.to_num::())) - as u64; +// let expected_fee_tao = ((fee_rate / (1.0 - fee_rate)) +// * (position.liquidity as f64) +// * (final_box_price.to_num::() - initial_box_price.to_num::())) +// as u64; - let expected_fee_alpha = ((fee_rate / (1.0 - fee_rate)) - * (position.liquidity as f64) - * ((1.0 / final_box_price.to_num::()) - (1.0 / initial_box_price.to_num::()))) - as u64; +// let expected_fee_alpha = ((fee_rate / (1.0 - fee_rate)) +// * (position.liquidity as f64) +// * ((1.0 / final_box_price.to_num::()) - (1.0 / initial_box_price.to_num::()))) +// as u64; - log::trace!("Expected ALPHA fee: {:.6}", expected_fee_alpha as f64); +// log::trace!("Expected ALPHA fee: {:.6}", expected_fee_alpha as f64); - let (fee_tao, fee_alpha) = position.collect_fees(); +// let (fee_tao, fee_alpha) = position.collect_fees(); - log::trace!("Collected fees: TAO: {fee_tao}, ALPHA: {fee_alpha}"); +// log::trace!("Collected fees: TAO: {fee_tao}, ALPHA: {fee_alpha}"); - assert_abs_diff_eq!(fee_tao, expected_fee_tao, epsilon = 1); - assert_abs_diff_eq!(fee_alpha, expected_fee_alpha, epsilon = 1); - }); -} +// assert_abs_diff_eq!(fee_tao, expected_fee_tao, epsilon = 1); +// assert_abs_diff_eq!(fee_alpha, expected_fee_alpha, epsilon = 1); +// }); +// } /// Test that price moves less with provided liquidity /// cargo test --package pallet-subtensor-swap --lib -- pallet::tests::test_less_price_movement --exact --show-output diff --git a/pallets/transaction-fee/src/lib.rs b/pallets/transaction-fee/src/lib.rs index 55f44fba95..fe1eb43ce8 100644 --- a/pallets/transaction-fee/src/lib.rs +++ b/pallets/transaction-fee/src/lib.rs @@ -31,7 +31,7 @@ use core::marker::PhantomData; use smallvec::smallvec; use sp_std::vec::Vec; use substrate_fixed::types::U96F32; -use subtensor_runtime_common::{Balance, Currency, NetUid}; +use subtensor_runtime_common::{AuthorshipInfo, Balance, NetUid}; // Tests #[cfg(test)] diff --git a/pallets/transaction-fee/src/tests/mod.rs b/pallets/transaction-fee/src/tests/mod.rs index 859507b072..fa501b899f 100644 --- a/pallets/transaction-fee/src/tests/mod.rs +++ b/pallets/transaction-fee/src/tests/mod.rs @@ -1215,7 +1215,7 @@ fn test_recycle_alpha_fees_alpha() { fn test_add_stake_fees_go_to_block_builder() { new_test_ext().execute_with(|| { // Portion of swap fees that should go to the block builder - let block_builder_fee_portion = 3. / 5.; + let block_builder_fee_portion = 1.; // Get the block builder balance let block_builder = U256::from(MOCK_BLOCK_BUILDER); From 969a245579cb54af00f175489553e071a41330ec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 26 Feb 2026 18:24:38 +0000 Subject: [PATCH 08/43] auto-update benchmark weights --- pallets/subtensor/src/macros/dispatches.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 6330e07d1c..902dd5f43a 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1070,8 +1070,8 @@ mod dispatches { /// Only callable by root as it doesn't require an announcement and can be used to swap any coldkey. #[pallet::call_index(71)] #[pallet::weight(Weight::from_parts(161_700_000, 0) - .saturating_add(T::DbWeight::get().reads(16_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)))] + .saturating_add(T::DbWeight::get().reads(17_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)))] pub fn swap_coldkey( origin: OriginFor, old_coldkey: T::AccountId, From 99eabe910e9979bee981de8d7400a0038eebc5f9 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 26 Feb 2026 13:41:30 -0500 Subject: [PATCH 09/43] bump spec to 385 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b90afd7aa7..023e318c7f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -241,7 +241,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 380, + spec_version: 385, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 685049998df7ecff673403c2542d4ec9940517f1 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 26 Feb 2026 13:42:44 -0500 Subject: [PATCH 10/43] commit Cargo.lock changes --- Cargo.lock | 81 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71fe31e5f4..8d579fe469 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4121,6 +4121,16 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "endian-cast" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f7a506e5de77a3db9e56fdbed17fa6f3b8d27ede81545dde96107c3d6a1d2" +dependencies = [ + "generic-array 1.3.5", + "typenum", +] + [[package]] name = "enum-as-inner" version = "0.6.1" @@ -5560,6 +5570,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" +dependencies = [ + "rustversion", + "typenum", +] + [[package]] name = "gethostname" version = "0.2.3" @@ -6921,6 +6941,33 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lencode" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83dc280ed78264020f986b2539e6a44e0720f98f66c99a48a2f52e4a441e99d8" +dependencies = [ + "endian-cast", + "generic-array 1.3.5", + "hashbrown 0.12.3", + "lencode-macros", + "newt-hype", + "ruint", + "zstd-safe 7.2.4", +] + +[[package]] +name = "lencode-macros" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c57df14b9005d1e4e8e56436e922e2c046ad0be55d7cfb062a303714857508" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "libc" version = "0.2.176" @@ -8222,6 +8269,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "newt-hype" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8b7b69b0eafaa88ec8dc9fe7c3860af0a147517e5207cfbd0ecd21cd7cde18" + [[package]] name = "nix" version = "0.26.4" @@ -8654,7 +8707,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.106", @@ -14051,9 +14104,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -14069,9 +14122,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -14315,9 +14368,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rust_decimal" -version = "1.39.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" dependencies = [ "arrayvec 0.7.6", "borsh", @@ -14586,9 +14639,10 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "safe-bigmath" -version = "0.3.0" -source = "git+https://github.com/sam0x17/safe-bigmath#1da0a09c5bcf143fa7c464b431bfaeff5476b080" +version = "0.4.1" +source = "git+https://github.com/sam0x17/safe-bigmath#013c49984910e1c9a23289e8c85e7a856e263a02" dependencies = [ + "lencode", "num-bigint", "num-integer", "num-traits", @@ -21117,6 +21171,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.16+zstd.1.5.7" From 14b813afdf4991df50d1430999ac13f77afd2017 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Tue, 24 Feb 2026 20:07:33 -0300 Subject: [PATCH 11/43] added evm_context to common --- common/Cargo.toml | 2 ++ common/src/evm_context.rs | 47 +++++++++++++++++++++++++++++++++++++++ common/src/lib.rs | 2 ++ 3 files changed, 51 insertions(+) create mode 100644 common/src/evm_context.rs diff --git a/common/Cargo.toml b/common/Cargo.toml index 8b9c010238..732b0cc5b1 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -12,6 +12,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true, features = ["derive"] } +environmental.workspace = true frame-support.workspace = true scale-info.workspace = true serde.workspace = true @@ -31,6 +32,7 @@ approx = ["dep:approx"] fast-runtime = [] std = [ "codec/std", + "environmental/std", "frame-support/std", "scale-info/std", "serde/std", diff --git a/common/src/evm_context.rs b/common/src/evm_context.rs new file mode 100644 index 0000000000..62ae973866 --- /dev/null +++ b/common/src/evm_context.rs @@ -0,0 +1,47 @@ +environmental::environmental!(IN_EVM: bool); + +/// Returns `true` if the current dispatch originated from an EVM precompile. +pub fn is_in_evm() -> bool { + IN_EVM::with(|v| *v).unwrap_or(false) +} + +/// Executes `f` within an EVM context, making `is_in_evm()` return `true` +/// for the duration of the closure. Uses `using_once` so nested calls +/// reuse the already-set value instead of building a stack. +pub fn with_evm_context(f: impl FnOnce() -> R) -> R { + IN_EVM::using_once(&mut true, f) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_in_evm_returns_false_by_default() { + assert!(!is_in_evm()); + } + + #[test] + fn with_evm_context_sets_flag() { + with_evm_context(|| { + assert!(is_in_evm()); + }); + } + + #[test] + fn flag_clears_after_evm_context() { + with_evm_context(|| {}); + assert!(!is_in_evm()); + } + + #[test] + fn nested_evm_context_stays_true() { + with_evm_context(|| { + with_evm_context(|| { + assert!(is_in_evm()); + }); + // Still true after inner context exits thanks to using_once. + assert!(is_in_evm()); + }); + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index f28ec6d878..a63b92779a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -15,8 +15,10 @@ use sp_runtime::{ use subtensor_macros::freeze_struct; pub use currency::*; +pub use evm_context::*; mod currency; +mod evm_context; /// Balance of an account. pub type Balance = u64; From f67ae8464c195ca066196a3ac6abfd664c74f8c4 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Thu, 26 Feb 2026 14:00:39 -0500 Subject: [PATCH 12/43] bump CI From c81103dcfeee6a38d03172df91572235061e9b6b Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 16:20:22 -0300 Subject: [PATCH 13/43] leverage evm_context in precompiles --- precompiles/src/extensions.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/precompiles/src/extensions.rs b/precompiles/src/extensions.rs index 51287a1b88..4a7c418c86 100644 --- a/precompiles/src/extensions.rs +++ b/precompiles/src/extensions.rs @@ -23,6 +23,7 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidityError}, }; use sp_std::vec::Vec; +use subtensor_runtime_common::with_evm_context; pub(crate) trait PrecompileHandleExt: PrecompileHandle { fn caller_account_id(&self) -> R::AccountId @@ -113,7 +114,7 @@ pub(crate) trait PrecompileHandleExt: PrecompileHandle { .prepare(val, &origin, &call, &info, 0) .map_err(extension_error)?; - match call.dispatch(origin) { + match with_evm_context(|| call.dispatch(origin)) { Ok(mut post_info) => { post_info.set_extension_weight(&info); let result: DispatchResult = Ok(()); From a353761b047f87e474e9bac6d5a8b7dbe8a257e2 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 16:21:20 -0300 Subject: [PATCH 14/43] update psdk/frontier to dispatch guard rev --- Cargo.lock | 881 +++++++++++++++++++++++++---------------------------- Cargo.toml | 462 ++++++++-------------------- 2 files changed, 547 insertions(+), 796 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc7eaf2560..cfb96c21d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1056,7 +1056,7 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "assets-common" version = "0.22.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "ethereum-standards", @@ -1435,7 +1435,7 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "binary-merkle-tree" version = "16.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "hash-db", "log", @@ -1704,7 +1704,7 @@ dependencies = [ [[package]] name = "bp-header-chain" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-runtime", "finality-grandpa", @@ -1721,7 +1721,7 @@ dependencies = [ [[package]] name = "bp-messages" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-runtime", @@ -1737,7 +1737,7 @@ dependencies = [ [[package]] name = "bp-parachains" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-polkadot-core", @@ -1754,7 +1754,7 @@ dependencies = [ [[package]] name = "bp-polkadot-core" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-messages", "bp-runtime", @@ -1770,7 +1770,7 @@ dependencies = [ [[package]] name = "bp-relayers" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-messages", @@ -1788,7 +1788,7 @@ dependencies = [ [[package]] name = "bp-runtime" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -1811,7 +1811,7 @@ dependencies = [ [[package]] name = "bp-test-utils" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-parachains", @@ -1831,7 +1831,7 @@ dependencies = [ [[package]] name = "bp-xcm-bridge-hub" version = "0.7.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-messages", "bp-runtime", @@ -1848,7 +1848,7 @@ dependencies = [ [[package]] name = "bp-xcm-bridge-hub-router" version = "0.18.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -1860,7 +1860,7 @@ dependencies = [ [[package]] name = "bridge-hub-common" version = "0.14.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1879,7 +1879,7 @@ dependencies = [ [[package]] name = "bridge-runtime-common" version = "0.22.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-messages", @@ -2722,7 +2722,7 @@ dependencies = [ [[package]] name = "cumulus-client-bootnodes" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -2748,7 +2748,7 @@ dependencies = [ [[package]] name = "cumulus-client-cli" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "clap", "parity-scale-codec", @@ -2765,7 +2765,7 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", @@ -2788,7 +2788,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-aura" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-client-collator", @@ -2835,7 +2835,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-client-pov-recovery", @@ -2867,7 +2867,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-proposer" version = "0.20.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "anyhow", "async-trait", @@ -2882,7 +2882,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-relay-chain" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -2905,7 +2905,7 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-relay-chain-interface", @@ -2932,7 +2932,7 @@ dependencies = [ [[package]] name = "cumulus-client-parachain-inherent" version = "0.18.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -2942,7 +2942,7 @@ dependencies = [ "parity-scale-codec", "sc-client-api", "sc-consensus-babe", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-inherents", "sp-runtime", "sp-state-machine", @@ -2953,7 +2953,7 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -2981,7 +2981,7 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.25.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-channel 1.9.0", "cumulus-client-cli", @@ -3021,7 +3021,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-aura-ext" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-pallet-parachain-system", "frame-support", @@ -3038,7 +3038,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "frame-benchmarking", @@ -3055,7 +3055,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bytes", "cumulus-pallet-parachain-system-proc-macro", @@ -3092,7 +3092,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -3103,7 +3103,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-session-benchmarking" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -3116,7 +3116,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-solo-to-para" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-pallet-parachain-system", "frame-support", @@ -3131,7 +3131,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-weight-reclaim" version = "0.3.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-storage-weight-reclaim", "derive-where", @@ -3150,7 +3150,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm" version = "0.20.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -3165,7 +3165,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "approx", "bounded-collections 0.2.4", @@ -3190,7 +3190,7 @@ dependencies = [ [[package]] name = "cumulus-ping" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-pallet-xcm", "cumulus-primitives-core", @@ -3205,7 +3205,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-aura" version = "0.18.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "sp-api", "sp-consensus-aura", @@ -3214,7 +3214,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.19.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-core-primitives", @@ -3231,7 +3231,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.19.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -3245,7 +3245,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-proof-size-hostfunction" version = "0.13.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "sp-externalities", "sp-runtime-interface", @@ -3255,7 +3255,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-storage-weight-reclaim" version = "12.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "cumulus-primitives-proof-size-hostfunction", @@ -3272,7 +3272,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-utility" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -3289,7 +3289,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.25.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-channel 1.9.0", "async-trait", @@ -3317,7 +3317,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-interface" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -3337,7 +3337,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-minimal-node" version = "0.25.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -3373,7 +3373,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-rpc-interface" version = "0.24.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -3414,7 +3414,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-streams" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-relay-chain-interface", "futures", @@ -3428,7 +3428,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.20.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "parity-scale-codec", @@ -4210,7 +4210,7 @@ dependencies = [ [[package]] name = "ethereum-standards" version = "0.1.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "alloy-core", ] @@ -4427,7 +4427,7 @@ dependencies = [ [[package]] name = "fc-api" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "async-trait", "fp-storage", @@ -4439,7 +4439,7 @@ dependencies = [ [[package]] name = "fc-aura" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fc-rpc", "fp-storage", @@ -4455,7 +4455,7 @@ dependencies = [ [[package]] name = "fc-babe" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fc-rpc", "sc-client-api", @@ -4471,7 +4471,7 @@ dependencies = [ [[package]] name = "fc-consensus" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "async-trait", "fp-consensus", @@ -4487,7 +4487,7 @@ dependencies = [ [[package]] name = "fc-db" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "async-trait", "ethereum", @@ -4517,7 +4517,7 @@ dependencies = [ [[package]] name = "fc-mapping-sync" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fc-db", "fc-storage", @@ -4540,7 +4540,7 @@ dependencies = [ [[package]] name = "fc-rpc" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "ethereum-types", @@ -4591,7 +4591,7 @@ dependencies = [ [[package]] name = "fc-rpc-core" version = "1.1.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "ethereum-types", @@ -4600,13 +4600,13 @@ dependencies = [ "rustc-hex", "serde", "serde_json", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", ] [[package]] name = "fc-storage" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "ethereum-types", @@ -4771,7 +4771,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fork-tree" version = "13.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", ] @@ -4798,7 +4798,7 @@ dependencies = [ [[package]] name = "fp-account" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "hex", "impl-serde", @@ -4816,7 +4816,7 @@ dependencies = [ [[package]] name = "fp-consensus" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "parity-scale-codec", @@ -4827,7 +4827,7 @@ dependencies = [ [[package]] name = "fp-ethereum" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "ethereum-types", @@ -4839,7 +4839,7 @@ dependencies = [ [[package]] name = "fp-evm" version = "3.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "environmental", "evm", @@ -4855,7 +4855,7 @@ dependencies = [ [[package]] name = "fp-rpc" version = "3.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "ethereum-types", @@ -4871,7 +4871,7 @@ dependencies = [ [[package]] name = "fp-self-contained" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "frame-support", "parity-scale-codec", @@ -4883,7 +4883,7 @@ dependencies = [ [[package]] name = "fp-storage" version = "2.0.0" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "parity-scale-codec", "serde", @@ -4898,7 +4898,7 @@ checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" [[package]] name = "frame-benchmarking" version = "41.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-support-procedural", @@ -4922,7 +4922,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "49.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "Inflector", "array-bytes 6.2.3", @@ -4987,7 +4987,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-pallet-pov" version = "31.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -5015,7 +5015,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "16.1.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -5026,7 +5026,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -5043,7 +5043,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "41.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "aquamarine", "frame-support", @@ -5096,7 +5096,7 @@ dependencies = [ [[package]] name = "frame-metadata-hash-extension" version = "0.9.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "const-hex", @@ -5112,7 +5112,7 @@ dependencies = [ [[package]] name = "frame-storage-access-test-runtime" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-pallet-parachain-system", "parity-scale-codec", @@ -5126,7 +5126,7 @@ dependencies = [ [[package]] name = "frame-support" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "aquamarine", "array-bytes 6.2.3", @@ -5167,7 +5167,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "34.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "Inflector", "cfg-expr", @@ -5180,7 +5180,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "syn 2.0.106", ] @@ -5200,7 +5200,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "13.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support-procedural-tools-derive 12.0.0", "proc-macro-crate 3.4.0", @@ -5223,7 +5223,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "12.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro2", "quote", @@ -5233,7 +5233,7 @@ dependencies = [ [[package]] name = "frame-system" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cfg-if", "docify", @@ -5252,7 +5252,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -5266,7 +5266,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "parity-scale-codec", @@ -5276,7 +5276,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.47.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "parity-scale-codec", @@ -7833,7 +7833,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "46.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "log", @@ -7852,7 +7852,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -8335,7 +8335,7 @@ dependencies = [ "pallet-balances", "pallet-base-fee", "pallet-commitments", - "pallet-contracts 40.1.0", + "pallet-contracts", "pallet-crowdloan", "pallet-drand", "pallet-election-provider-multi-phase", @@ -8801,7 +8801,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "frame-benchmarking", @@ -8813,7 +8813,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-io", "sp-runtime", ] @@ -8821,7 +8821,7 @@ dependencies = [ [[package]] name = "pallet-asset-conversion" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8839,7 +8839,7 @@ dependencies = [ [[package]] name = "pallet-asset-conversion-ops" version = "0.9.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8857,7 +8857,7 @@ dependencies = [ [[package]] name = "pallet-asset-conversion-tx-payment" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8872,7 +8872,7 @@ dependencies = [ [[package]] name = "pallet-asset-rate" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8886,7 +8886,7 @@ dependencies = [ [[package]] name = "pallet-asset-rewards" version = "0.3.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8904,7 +8904,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8920,7 +8920,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "43.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "ethereum-standards", "frame-benchmarking", @@ -8938,7 +8938,7 @@ dependencies = [ [[package]] name = "pallet-assets-freezer" version = "0.8.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "pallet-assets", @@ -8950,7 +8950,7 @@ dependencies = [ [[package]] name = "pallet-assets-holder" version = "0.3.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -8965,7 +8965,7 @@ dependencies = [ [[package]] name = "pallet-atomic-swap" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-sdk-frame", @@ -8975,7 +8975,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -8991,7 +8991,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -9006,7 +9006,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -9019,7 +9019,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9042,7 +9042,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "aquamarine", "docify", @@ -9063,7 +9063,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -9079,7 +9079,7 @@ dependencies = [ [[package]] name = "pallet-base-fee" version = "1.0.0" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fp-evm", "frame-support", @@ -9093,7 +9093,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -9112,7 +9112,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "binary-merkle-tree", @@ -9137,7 +9137,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9154,7 +9154,7 @@ dependencies = [ [[package]] name = "pallet-bridge-grandpa" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-runtime", @@ -9173,7 +9173,7 @@ dependencies = [ [[package]] name = "pallet-bridge-messages" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-messages", @@ -9192,7 +9192,7 @@ dependencies = [ [[package]] name = "pallet-bridge-parachains" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-parachains", @@ -9212,7 +9212,7 @@ dependencies = [ [[package]] name = "pallet-bridge-relayers" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-header-chain", "bp-messages", @@ -9235,7 +9235,7 @@ dependencies = [ [[package]] name = "pallet-broker" version = "0.20.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "frame-benchmarking", @@ -9253,7 +9253,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9271,7 +9271,7 @@ dependencies = [ [[package]] name = "pallet-collator-selection" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9290,7 +9290,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -9307,7 +9307,7 @@ dependencies = [ [[package]] name = "pallet-collective-content" version = "0.19.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9345,41 +9345,10 @@ dependencies = [ "w3f-bls 0.1.3", ] -[[package]] -name = "pallet-contracts" -version = "40.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2503-6#598feddb893f5ad3923a62e41a2f179b6e10c30c" -dependencies = [ - "environmental", - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-balances", - "pallet-contracts-proc-macro 23.0.3 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2503-6)", - "pallet-contracts-uapi 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2503-6)", - "parity-scale-codec", - "paste", - "rand 0.8.5", - "rand_pcg", - "scale-info", - "serde", - "smallvec", - "sp-api", - "sp-core", - "sp-io", - "sp-runtime", - "staging-xcm", - "staging-xcm-builder", - "wasm-instrument", - "wasmi 0.32.3", -] - [[package]] name = "pallet-contracts" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "environmental", "frame-benchmarking", @@ -9388,8 +9357,8 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-balances", - "pallet-contracts-proc-macro 23.0.3 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", - "pallet-contracts-uapi 14.0.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "pallet-contracts-proc-macro", + "pallet-contracts-uapi", "parity-scale-codec", "paste", "rand 0.8.5", @@ -9410,14 +9379,14 @@ dependencies = [ [[package]] name = "pallet-contracts-mock-network" version = "18.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", "pallet-assets", "pallet-balances", - "pallet-contracts 41.0.0", - "pallet-contracts-uapi 14.0.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "pallet-contracts", + "pallet-contracts-uapi", "pallet-message-queue", "pallet-timestamp", "pallet-xcm", @@ -9441,17 +9410,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "23.0.3" -source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2503-6#598feddb893f5ad3923a62e41a2f179b6e10c30c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "pallet-contracts-proc-macro" -version = "23.0.3" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro2", "quote", @@ -9461,18 +9420,7 @@ dependencies = [ [[package]] name = "pallet-contracts-uapi" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2503-6#598feddb893f5ad3923a62e41a2f179b6e10c30c" -dependencies = [ - "bitflags 1.3.2", - "parity-scale-codec", - "paste", - "scale-info", -] - -[[package]] -name = "pallet-contracts-uapi" -version = "14.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitflags 1.3.2", "parity-scale-codec", @@ -9483,7 +9431,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "assert_matches", "frame-benchmarking", @@ -9499,7 +9447,7 @@ dependencies = [ [[package]] name = "pallet-core-fellowship" version = "25.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9536,7 +9484,7 @@ dependencies = [ [[package]] name = "pallet-delegated-staking" version = "8.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -9551,7 +9499,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9568,7 +9516,7 @@ dependencies = [ [[package]] name = "pallet-dev-mode" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -9617,7 +9565,7 @@ dependencies = [ [[package]] name = "pallet-dummy-dim" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9635,7 +9583,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-block" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -9656,7 +9604,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -9677,7 +9625,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -9690,7 +9638,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9708,7 +9656,7 @@ dependencies = [ [[package]] name = "pallet-ethereum" version = "4.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "ethereum", "ethereum-types", @@ -9731,7 +9679,7 @@ dependencies = [ [[package]] name = "pallet-evm" version = "6.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "cumulus-primitives-storage-weight-reclaim", "environmental", @@ -9756,7 +9704,7 @@ dependencies = [ [[package]] name = "pallet-evm-chain-id" version = "1.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "frame-support", "frame-system", @@ -9767,7 +9715,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-bn128" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fp-evm", "sp-core", @@ -9777,7 +9725,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-dispatch" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fp-evm", "frame-support", @@ -9789,7 +9737,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fp-evm", "num", @@ -9798,7 +9746,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-sha3fips" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fp-evm", "tiny-keccak", @@ -9807,7 +9755,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-simple" version = "2.0.0-dev" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "fp-evm", "ripemd", @@ -9817,7 +9765,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -9835,7 +9783,7 @@ dependencies = [ [[package]] name = "pallet-glutton" version = "27.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "blake2 0.10.6", "frame-benchmarking", @@ -9853,7 +9801,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9875,7 +9823,7 @@ dependencies = [ [[package]] name = "pallet-hotfix-sufficients" version = "1.0.0" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "frame-benchmarking", "frame-support", @@ -9890,7 +9838,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "enumflags2", "frame-benchmarking", @@ -9906,7 +9854,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9925,7 +9873,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9940,7 +9888,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "29.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-sdk-frame", @@ -9951,7 +9899,7 @@ dependencies = [ [[package]] name = "pallet-lottery" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9964,7 +9912,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -9980,7 +9928,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "44.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "environmental", "frame-benchmarking", @@ -9999,7 +9947,7 @@ dependencies = [ [[package]] name = "pallet-meta-tx" version = "0.3.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -10017,7 +9965,7 @@ dependencies = [ [[package]] name = "pallet-migrations" version = "11.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -10036,7 +9984,7 @@ dependencies = [ [[package]] name = "pallet-mixnet" version = "0.17.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-scale-codec", @@ -10050,7 +9998,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-scale-codec", @@ -10062,7 +10010,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-scale-codec", @@ -10073,7 +10021,7 @@ dependencies = [ [[package]] name = "pallet-nft-fractionalization" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "pallet-assets", @@ -10086,7 +10034,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "35.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "enumflags2", "frame-benchmarking", @@ -10103,7 +10051,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-sdk-frame", @@ -10113,7 +10061,7 @@ dependencies = [ [[package]] name = "pallet-node-authorization" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-scale-codec", @@ -10124,7 +10072,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "39.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10142,7 +10090,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "39.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -10162,7 +10110,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -10172,7 +10120,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10187,7 +10135,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -10210,7 +10158,7 @@ dependencies = [ [[package]] name = "pallet-origin-restriction" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10228,7 +10176,7 @@ dependencies = [ [[package]] name = "pallet-paged-list" version = "0.19.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "parity-scale-codec", @@ -10239,7 +10187,7 @@ dependencies = [ [[package]] name = "pallet-parameters" version = "0.12.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -10256,7 +10204,7 @@ dependencies = [ [[package]] name = "pallet-people" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10274,7 +10222,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10290,7 +10238,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-sdk-frame", @@ -10300,7 +10248,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10318,7 +10266,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-sdk-frame", @@ -10328,7 +10276,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "assert_matches", "frame-benchmarking", @@ -10363,7 +10311,7 @@ dependencies = [ [[package]] name = "pallet-remark" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10378,7 +10326,7 @@ dependencies = [ [[package]] name = "pallet-revive" version = "0.7.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "alloy-core", "derive_more 0.99.20", @@ -10424,7 +10372,7 @@ dependencies = [ [[package]] name = "pallet-revive-fixtures" version = "0.4.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "anyhow", "cargo_metadata", @@ -10438,7 +10386,7 @@ dependencies = [ [[package]] name = "pallet-revive-proc-macro" version = "0.3.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro2", "quote", @@ -10448,7 +10396,7 @@ dependencies = [ [[package]] name = "pallet-revive-uapi" version = "0.5.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitflags 1.3.2", "pallet-revive-proc-macro", @@ -10460,7 +10408,7 @@ dependencies = [ [[package]] name = "pallet-root-offences" version = "38.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10476,7 +10424,7 @@ dependencies = [ [[package]] name = "pallet-root-testing" version = "17.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10489,7 +10437,7 @@ dependencies = [ [[package]] name = "pallet-safe-mode" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "pallet-balances", @@ -10503,7 +10451,7 @@ dependencies = [ [[package]] name = "pallet-salary" version = "26.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "pallet-ranked-collective", @@ -10515,7 +10463,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -10532,7 +10480,7 @@ dependencies = [ [[package]] name = "pallet-scored-pool" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10545,7 +10493,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10566,7 +10514,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10602,7 +10550,7 @@ dependencies = [ [[package]] name = "pallet-skip-feeless-payment" version = "16.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10614,7 +10562,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10631,7 +10579,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -10653,7 +10601,7 @@ dependencies = [ [[package]] name = "pallet-staking-async" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -10676,7 +10624,7 @@ dependencies = [ [[package]] name = "pallet-staking-async-ah-client" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10695,7 +10643,7 @@ dependencies = [ [[package]] name = "pallet-staking-async-rc-client" version = "0.2.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10712,7 +10660,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "12.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -10723,7 +10671,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "sp-arithmetic", @@ -10732,7 +10680,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "27.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "sp-api", @@ -10742,7 +10690,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "46.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10758,7 +10706,7 @@ dependencies = [ [[package]] name = "pallet-statement" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", @@ -10917,7 +10865,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -10932,7 +10880,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -10950,7 +10898,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10968,7 +10916,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -10983,7 +10931,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "44.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -10999,7 +10947,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -11011,7 +10959,7 @@ dependencies = [ [[package]] name = "pallet-transaction-storage" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "frame-benchmarking", @@ -11030,7 +10978,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -11049,7 +10997,7 @@ dependencies = [ [[package]] name = "pallet-tx-pause" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "parity-scale-codec", @@ -11060,7 +11008,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -11074,7 +11022,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -11089,7 +11037,7 @@ dependencies = [ [[package]] name = "pallet-verify-signature" version = "0.4.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -11104,7 +11052,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -11118,7 +11066,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-sdk-frame", @@ -11128,7 +11076,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "20.1.3" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bounded-collections 0.2.4", "frame-benchmarking", @@ -11154,7 +11102,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "21.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-benchmarking", "frame-support", @@ -11171,7 +11119,7 @@ dependencies = [ [[package]] name = "pallet-xcm-bridge-hub" version = "0.17.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-messages", "bp-runtime", @@ -11193,7 +11141,7 @@ dependencies = [ [[package]] name = "pallet-xcm-bridge-hub-router" version = "0.19.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-xcm-bridge-hub-router", "frame-benchmarking", @@ -11213,7 +11161,7 @@ dependencies = [ [[package]] name = "parachains-common" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "cumulus-primitives-utility", @@ -11552,7 +11500,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polkadot-approval-distribution" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "futures-timer", @@ -11570,7 +11518,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "futures-timer", @@ -11585,7 +11533,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fatality", "futures", @@ -11608,7 +11556,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "fatality", @@ -11641,7 +11589,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "25.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "clap", "frame-benchmarking-cli", @@ -11665,7 +11613,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "fatality", @@ -11688,7 +11636,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "18.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -11699,7 +11647,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fatality", "futures", @@ -11721,7 +11669,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -11735,7 +11683,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "24.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "futures-timer", @@ -11748,7 +11696,7 @@ dependencies = [ "sc-network", "sp-application-crypto", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-keystore", "tracing-gum", ] @@ -11756,7 +11704,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "always-assert", "async-trait", @@ -11779,7 +11727,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "parity-scale-codec", @@ -11797,7 +11745,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "bitvec", @@ -11829,7 +11777,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting-parallel" version = "0.7.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -11853,7 +11801,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "futures", @@ -11872,7 +11820,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "fatality", @@ -11893,7 +11841,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "polkadot-node-subsystem", @@ -11908,7 +11856,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -11930,7 +11878,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "polkadot-node-metrics", @@ -11944,7 +11892,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "futures-timer", @@ -11960,7 +11908,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fatality", "futures", @@ -11978,7 +11926,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -11995,7 +11943,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-prospective-parachains" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fatality", "futures", @@ -12009,7 +11957,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "fatality", @@ -12026,7 +11974,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "always-assert", "array-bytes 6.2.3", @@ -12054,7 +12002,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "polkadot-node-subsystem", @@ -12067,7 +12015,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-common" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cpu-time", "futures", @@ -12082,7 +12030,7 @@ dependencies = [ "sc-executor-wasmtime", "seccompiler", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-externalities", "sp-io", "sp-tracing", @@ -12093,7 +12041,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "polkadot-node-metrics", @@ -12108,7 +12056,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bs58", "futures", @@ -12125,7 +12073,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-channel 1.9.0", "async-trait", @@ -12150,7 +12098,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "bounded-vec", @@ -12174,7 +12122,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "polkadot-node-subsystem-types", "polkadot-overseer", @@ -12183,7 +12131,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "derive_more 0.99.20", @@ -12211,7 +12159,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "24.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fatality", "futures", @@ -12242,7 +12190,7 @@ dependencies = [ [[package]] name = "polkadot-omni-node-lib" version = "0.7.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "clap", @@ -12328,7 +12276,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -12348,7 +12296,7 @@ dependencies = [ [[package]] name = "polkadot-parachain-primitives" version = "17.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bounded-collections 0.2.4", "derive_more 0.99.20", @@ -12364,7 +12312,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "19.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "bounded-collections 0.2.4", @@ -12393,7 +12341,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "25.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -12426,7 +12374,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "frame-benchmarking", @@ -12476,7 +12424,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "21.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bs58", "frame-benchmarking", @@ -12488,7 +12436,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "20.0.2" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitflags 1.3.2", "bitvec", @@ -12536,7 +12484,7 @@ dependencies = [ [[package]] name = "polkadot-sdk" version = "2506.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "assets-common", "bridge-hub-common", @@ -12591,7 +12539,7 @@ dependencies = [ "pallet-collator-selection", "pallet-collective", "pallet-collective-content", - "pallet-contracts 41.0.0", + "pallet-contracts", "pallet-contracts-mock-network", "pallet-conviction-voting", "pallet-core-fellowship", @@ -12694,7 +12642,7 @@ dependencies = [ [[package]] name = "polkadot-sdk-frame" version = "0.10.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-benchmarking", @@ -12729,7 +12677,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "25.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "frame-benchmarking", @@ -12837,7 +12785,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitvec", "fatality", @@ -12857,7 +12805,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -13130,7 +13078,7 @@ dependencies = [ [[package]] name = "precompile-utils" version = "0.1.0" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "derive_more 1.0.0", "environmental", @@ -13159,14 +13107,14 @@ dependencies = [ [[package]] name = "precompile-utils-macro" version = "0.1.0" -source = "git+https://github.com/opentensor/frontier?rev=f12a1274f91442a564bb722a2b9547caba487fa0#f12a1274f91442a564bb722a2b9547caba487fa0" +source = "git+https://github.com/opentensor/frontier?rev=b51a81bb3f2a94eabaafcde40eab6a91accf3f36#b51a81bb3f2a94eabaafcde40eab6a91accf3f36" dependencies = [ "case", "num_enum", "prettyplease", "proc-macro2", "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "syn 2.0.106", ] @@ -13348,7 +13296,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "syn 2.0.106", ] @@ -13978,7 +13926,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "24.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "binary-merkle-tree", "bitvec", @@ -14076,7 +14024,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "21.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "polkadot-primitives", @@ -14472,7 +14420,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "32.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "sp-core", @@ -14483,7 +14431,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -14514,7 +14462,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "log", @@ -14535,7 +14483,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.45.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "sp-api", @@ -14550,7 +14498,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "44.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "clap", @@ -14566,7 +14514,7 @@ dependencies = [ "serde_json", "sp-blockchain", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-genesis-builder", "sp-io", "sp-runtime", @@ -14577,7 +14525,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "12.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -14588,7 +14536,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.53.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "chrono", @@ -14630,7 +14578,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fnv", "futures", @@ -14656,7 +14604,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.47.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "hash-db", "kvdb", @@ -14684,7 +14632,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -14707,7 +14655,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -14736,7 +14684,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "fork-tree", @@ -14761,7 +14709,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-slots", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-inherents", "sp-keystore", "sp-runtime", @@ -14772,7 +14720,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "jsonrpsee", @@ -14794,7 +14742,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "30.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -14828,7 +14776,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "30.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "jsonrpsee", @@ -14848,7 +14796,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "fork-tree", "parity-scale-codec", @@ -14861,7 +14809,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.36.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "ahash", "array-bytes 6.2.3", @@ -14895,7 +14843,7 @@ dependencies = [ "sp-consensus", "sp-consensus-grandpa", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-keystore", "sp-runtime", "substrate-prometheus-endpoint", @@ -14905,7 +14853,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.36.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "finality-grandpa", "futures", @@ -14925,7 +14873,7 @@ dependencies = [ [[package]] name = "sc-consensus-manual-seal" version = "0.52.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "assert_matches", "async-trait", @@ -14960,7 +14908,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -14983,7 +14931,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.43.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "parking_lot 0.12.5", @@ -15006,7 +14954,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.39.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "polkavm 0.24.0", "sc-allocator", @@ -15019,7 +14967,7 @@ dependencies = [ [[package]] name = "sc-executor-polkavm" version = "0.36.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "polkavm 0.24.0", @@ -15030,7 +14978,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.39.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "anyhow", "log", @@ -15046,7 +14994,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "console", "futures", @@ -15062,7 +15010,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "36.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "parking_lot 0.12.5", @@ -15076,7 +15024,7 @@ dependencies = [ [[package]] name = "sc-mixnet" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "arrayvec 0.7.6", @@ -15104,7 +15052,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.51.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -15154,7 +15102,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.49.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bitflags 1.3.2", "parity-scale-codec", @@ -15164,7 +15112,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "ahash", "futures", @@ -15183,7 +15131,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -15204,7 +15152,7 @@ dependencies = [ [[package]] name = "sc-network-statement" version = "0.33.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -15224,7 +15172,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "async-channel 1.9.0", @@ -15259,7 +15207,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "futures", @@ -15278,7 +15226,7 @@ dependencies = [ [[package]] name = "sc-network-types" version = "0.17.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bs58", "bytes", @@ -15299,7 +15247,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "46.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bytes", "fnv", @@ -15333,7 +15281,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.20.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -15342,7 +15290,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "46.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "jsonrpsee", @@ -15374,7 +15322,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.50.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -15394,7 +15342,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "dyn-clone", "forwarded-header-value", @@ -15418,7 +15366,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "futures", @@ -15451,13 +15399,13 @@ dependencies = [ [[package]] name = "sc-runtime-utilities" version = "0.3.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "sc-executor", "sc-executor-common", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-state-machine", "sp-wasm-interface", "thiserror 1.0.69", @@ -15466,7 +15414,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.52.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "directories", @@ -15530,7 +15478,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.39.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-scale-codec", @@ -15541,7 +15489,7 @@ dependencies = [ [[package]] name = "sc-statement-store" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-db", @@ -15560,7 +15508,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.25.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "clap", "fs4", @@ -15573,7 +15521,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.51.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -15592,7 +15540,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "43.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "derive_more 0.99.20", "futures", @@ -15605,14 +15553,14 @@ dependencies = [ "serde", "serde_json", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-io", ] [[package]] name = "sc-telemetry" version = "29.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "chrono", "futures", @@ -15631,7 +15579,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "chrono", "console", @@ -15659,7 +15607,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "11.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -15670,7 +15618,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "40.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -15687,7 +15635,7 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-runtime", "sp-tracing", "sp-transaction-pool", @@ -15701,7 +15649,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -15718,7 +15666,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "19.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-channel 1.9.0", "futures", @@ -16436,7 +16384,7 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "slot-range-helper" version = "18.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "enumn", "parity-scale-codec", @@ -16699,7 +16647,7 @@ dependencies = [ [[package]] name = "snowbridge-core" version = "0.14.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bp-relayers", "frame-support", @@ -16783,7 +16731,7 @@ dependencies = [ [[package]] name = "sp-api" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "hash-db", @@ -16805,7 +16753,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "23.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "Inflector", "blake2 0.10.6", @@ -16819,7 +16767,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "41.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -16831,7 +16779,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "27.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "integer-sqrt", @@ -16845,7 +16793,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -16857,7 +16805,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "sp-api", "sp-inherents", @@ -16867,7 +16815,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "futures", "parity-scale-codec", @@ -16886,7 +16834,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.43.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "futures", @@ -16900,7 +16848,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.43.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "parity-scale-codec", @@ -16916,7 +16864,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.43.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "parity-scale-codec", @@ -16934,7 +16882,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "25.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -16942,7 +16890,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-io", "sp-keystore", "sp-mmr-primitives", @@ -16954,7 +16902,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "24.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "finality-grandpa", "log", @@ -16971,7 +16919,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.43.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -16982,7 +16930,7 @@ dependencies = [ [[package]] name = "sp-core" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "ark-vrf", "array-bytes 6.2.3", @@ -17013,7 +16961,7 @@ dependencies = [ "secrecy 0.8.0", "serde", "sha2 0.10.9", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -17030,7 +16978,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.16.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -17064,7 +17012,7 @@ dependencies = [ [[package]] name = "sp-crypto-hashing" version = "0.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "blake2b_simd", "byteorder", @@ -17077,17 +17025,17 @@ dependencies = [ [[package]] name = "sp-crypto-hashing-proc-macro" version = "0.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "syn 2.0.106", ] [[package]] name = "sp-database" version = "10.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "kvdb", "parking_lot 0.12.5", @@ -17096,7 +17044,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "proc-macro2", "quote", @@ -17106,7 +17054,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.30.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "environmental", "parity-scale-codec", @@ -17116,7 +17064,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.18.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -17128,7 +17076,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -17141,7 +17089,7 @@ dependencies = [ [[package]] name = "sp-io" version = "41.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bytes", "docify", @@ -17153,7 +17101,7 @@ dependencies = [ "rustversion", "secp256k1 0.28.2", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-externalities", "sp-keystore", "sp-runtime-interface", @@ -17167,7 +17115,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "sp-core", "sp-runtime", @@ -17177,7 +17125,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.43.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "parking_lot 0.12.5", @@ -17188,7 +17136,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "11.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "thiserror 1.0.69", "zstd 0.12.4", @@ -17197,7 +17145,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.11.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-metadata 23.0.0", "parity-scale-codec", @@ -17207,7 +17155,7 @@ dependencies = [ [[package]] name = "sp-mixnet" version = "0.15.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -17218,7 +17166,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "log", "parity-scale-codec", @@ -17235,7 +17183,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -17248,7 +17196,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "sp-api", "sp-core", @@ -17258,7 +17206,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "13.0.2" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "backtrace", "regex", @@ -17267,7 +17215,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "35.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "rustc-hash 1.1.0", "serde", @@ -17277,7 +17225,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "42.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "binary-merkle-tree", "docify", @@ -17306,7 +17254,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "30.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -17325,7 +17273,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "19.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "Inflector", "expander", @@ -17338,7 +17286,7 @@ dependencies = [ [[package]] name = "sp-session" version = "39.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "scale-info", @@ -17352,7 +17300,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "39.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -17365,7 +17313,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.46.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "hash-db", "log", @@ -17385,7 +17333,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "21.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "aes-gcm", "curve25519-dalek", @@ -17398,7 +17346,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61)", "sp-externalities", "sp-runtime", "sp-runtime-interface", @@ -17409,12 +17357,12 @@ dependencies = [ [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" [[package]] name = "sp-storage" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "impl-serde", "parity-scale-codec", @@ -17426,7 +17374,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "parity-scale-codec", @@ -17438,7 +17386,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "17.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "tracing", @@ -17449,7 +17397,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "sp-api", "sp-runtime", @@ -17458,7 +17406,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "37.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "async-trait", "parity-scale-codec", @@ -17472,7 +17420,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "ahash", "foldhash 0.1.5", @@ -17497,7 +17445,7 @@ dependencies = [ [[package]] name = "sp-version" version = "40.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "impl-serde", "parity-scale-codec", @@ -17514,7 +17462,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "15.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "parity-scale-codec", "proc-macro-warning", @@ -17526,7 +17474,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "22.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -17538,7 +17486,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "32.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "bounded-collections 0.2.4", "parity-scale-codec", @@ -17712,7 +17660,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "staging-chain-spec-builder" version = "12.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "clap", "docify", @@ -17725,7 +17673,7 @@ dependencies = [ [[package]] name = "staging-node-inspect" version = "0.29.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "clap", "parity-scale-codec", @@ -17743,7 +17691,7 @@ dependencies = [ [[package]] name = "staging-parachain-info" version = "0.21.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -17756,7 +17704,7 @@ dependencies = [ [[package]] name = "staging-xcm" version = "17.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "bounded-collections 0.2.4", @@ -17777,7 +17725,7 @@ dependencies = [ [[package]] name = "staging-xcm-builder" version = "21.1.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "environmental", "frame-support", @@ -17801,7 +17749,7 @@ dependencies = [ [[package]] name = "staging-xcm-executor" version = "20.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "environmental", "frame-benchmarking", @@ -17913,7 +17861,7 @@ dependencies = [ [[package]] name = "substrate-bip39" version = "0.6.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "hmac 0.12.1", "pbkdf2", @@ -17938,7 +17886,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "11.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" [[package]] name = "substrate-fixed" @@ -17954,7 +17902,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "45.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "docify", "frame-system-rpc-runtime-api", @@ -17974,7 +17922,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.17.6" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "http-body-util", "hyper 1.7.0", @@ -17988,7 +17936,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "44.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -18015,7 +17963,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "27.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "array-bytes 6.2.3", "build-helper", @@ -18063,7 +18011,7 @@ dependencies = [ "log", "num_enum", "pallet-balances", - "pallet-contracts 40.1.0", + "pallet-contracts", "pallet-crowdloan", "pallet-drand", "pallet-preimage", @@ -18166,6 +18114,7 @@ name = "subtensor-runtime-common" version = "0.1.0" dependencies = [ "approx", + "environmental", "frame-support", "parity-scale-codec", "polkadot-runtime-common", @@ -19045,7 +18994,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "20.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "coarsetime", "polkadot-primitives", @@ -19056,7 +19005,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "5.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "expander", "proc-macro-crate 3.4.0", @@ -20007,7 +19956,7 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "westend-runtime" version = "24.0.1" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "binary-merkle-tree", "bitvec", @@ -20114,7 +20063,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "21.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "polkadot-primitives", @@ -20667,7 +20616,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "11.0.2" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "Inflector", "proc-macro2", @@ -20678,7 +20627,7 @@ dependencies = [ [[package]] name = "xcm-runtime-apis" version = "0.8.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "parity-scale-codec", @@ -20692,7 +20641,7 @@ dependencies = [ [[package]] name = "xcm-simulator" version = "21.0.0" -source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8#a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" +source = "git+https://github.com/opentensor/polkadot-sdk.git?rev=71629fd93b6c12a362a5cfb6331accef9b2b2b61#71629fd93b6c12a362a5cfb6331accef9b2b2b61" dependencies = [ "frame-support", "frame-system", diff --git a/Cargo.toml b/Cargo.toml index efc22431fa..32bcacf4c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,159 +118,160 @@ ahash = { version = "0.8", default-features = false } regex = { version = "1.11.1", default-features = false } ethereum = { version = "0.18.2", default-features = false } num_enum = { version = "0.7.4", default-features = false } +environmental = { version = "1.1.4", default-features = false } -frame = { package = "polkadot-sdk-frame", git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-benchmarking-cli = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-executive = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-metadata-hash-extension = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-system-benchmarking = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -frame-try-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +frame = { package = "polkadot-sdk-frame", git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-benchmarking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-benchmarking-cli = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-executive = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-metadata-hash-extension = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-support = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-system = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-system-benchmarking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-system-rpc-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +frame-try-runtime = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } frame-metadata = { version = "23.0.0", default-features = false } pallet-subtensor-proxy = { path = "pallets/proxy", default-features = false } pallet-subtensor-utility = { path = "pallets/utility", default-features = false } -pallet-babe = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-aura = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-grandpa = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-insecure-randomness-collective-flip = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-multisig = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-preimage = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-safe-mode = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-scheduler = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-sudo = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-timestamp = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-transaction-payment = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-root-testing = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-contracts = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +pallet-babe = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-aura = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-balances = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-grandpa = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-insecure-randomness-collective-flip = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-multisig = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-preimage = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-safe-mode = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-scheduler = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-sudo = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-timestamp = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-transaction-payment = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-transaction-payment-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-root-testing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-contracts = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } # NPoS -frame-election-provider-support = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-authority-discovery = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-authorship = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-bags-list = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-election-provider-multi-phase = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-fast-unstake = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-nomination-pools = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-nomination-pools-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-session = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-staking = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-staking-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-staking-reward-fn = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-staking-reward-curve = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -pallet-offences = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +frame-election-provider-support = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-authority-discovery = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-authorship = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-bags-list = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-election-provider-multi-phase = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-fast-unstake = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-nomination-pools = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-nomination-pools-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-session = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-staking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-staking-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-staking-reward-fn = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-staking-reward-curve = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +pallet-offences = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } -sc-basic-authorship = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-cli = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-client-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-aura = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-babe = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-babe-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-grandpa-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-epochs = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-chain-spec-derive = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-chain-spec = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-slots = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-executor = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-keystore = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-network = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-offchain = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-rpc-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-service = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-telemetry = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-transaction-pool-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-consensus-manual-seal = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sc-network-sync = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +sc-basic-authorship = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-cli = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-client-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-aura = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-babe = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-babe-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-grandpa = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-grandpa-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-epochs = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-chain-spec-derive = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-chain-spec = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-slots = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-executor = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-keystore = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-network = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-offchain = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-rpc-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-service = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-telemetry = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-transaction-pool = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-transaction-pool-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-consensus-manual-seal = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sc-network-sync = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } -sp-api = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-authority-discovery = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-arithmetic = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-block-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-staking = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-consensus = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-consensus-aura = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-consensus-babe = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-consensus-slots = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-npos-elections = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-genesis-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-inherents = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-rpc = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-session = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-storage = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-tracing = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-version = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-weights = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-crypto-hashing = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -sp-application-crypto = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +sp-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-authority-discovery = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-arithmetic = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-block-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-blockchain = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-staking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-consensus = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-consensus-aura = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-consensus-babe = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-consensus-slots = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-npos-elections = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-consensus-grandpa = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-genesis-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-core = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-inherents = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-io = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-keyring = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-offchain = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-runtime = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-session = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-std = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-storage = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-timestamp = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-tracing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-transaction-pool = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-version = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-weights = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-crypto-hashing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +sp-application-crypto = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } -substrate-build-script-utils = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +substrate-build-script-utils = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } substrate-fixed = { git = "https://github.com/encointer/substrate-fixed.git", tag = "v0.6.0", default-features = false } -substrate-frame-rpc-system = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } -substrate-prometheus-endpoint = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +substrate-frame-rpc-system = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +substrate-wasm-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } +substrate-prometheus-endpoint = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } -polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +polkadot-sdk = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } -runtime-common = { package = "polkadot-runtime-common", git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +runtime-common = { package = "polkadot-runtime-common", git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } # Frontier -fp-evm = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fp-rpc = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fp-self-contained = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fp-account = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-storage = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-db = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-consensus = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fp-consensus = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fp-dynamic-fee = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-api = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-rpc = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-rpc-core = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-aura = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-babe = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -fc-mapping-sync = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -precompile-utils = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } +fp-evm = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fp-rpc = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fp-self-contained = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fp-account = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-storage = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-db = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-consensus = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fp-consensus = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fp-dynamic-fee = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-api = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-rpc = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-rpc-core = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-aura = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-babe = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +fc-mapping-sync = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +precompile-utils = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } # Frontier FRAME -pallet-base-fee = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-dynamic-fee = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-ethereum = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm-precompile-dispatch = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm-chain-id = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm-precompile-modexp = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm-precompile-sha3fips = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm-precompile-simple = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-evm-precompile-bn128 = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } -pallet-hotfix-sufficients = { git = "https://github.com/opentensor/frontier", rev = "f12a1274f91442a564bb722a2b9547caba487fa0", default-features = false } +pallet-base-fee = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-dynamic-fee = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-ethereum = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm-precompile-dispatch = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm-chain-id = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm-precompile-modexp = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm-precompile-sha3fips = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm-precompile-simple = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-evm-precompile-bn128 = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } +pallet-hotfix-sufficients = { git = "https://github.com/opentensor/frontier", rev = "b51a81bb3f2a94eabaafcde40eab6a91accf3f36", default-features = false } #DRAND pallet-drand = { path = "pallets/drand", default-features = false } -sp-crypto-ec-utils = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +sp-crypto-ec-utils = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } getrandom = { version = "0.2.15", default-features = false, features = [ "custom", ] } -sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2503-6", default-features = false } +sp-keystore = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "71629fd93b6c12a362a5cfb6331accef9b2b2b61", default-features = false } w3f-bls = { git = "https://github.com/opentensor/bls", branch = "fix-no-std", default-features = false } ark-crypto-primitives = { version = "0.4.0", default-features = false } ark-scale = { version = "0.0.11", default-features = false } @@ -305,203 +306,4 @@ default = [] pow-faucet = [] [patch.crates-io] -w3f-bls = { git = "https://github.com/opentensor/bls", branch = "fix-no-std" } - -# Patches automatically generated with `diener`: -# `diener patch --target https://github.com/paritytech/polkadot-sdk --point-to-git https://github.com/opentensor/polkadot-sdk.git --point-to-git-commit 81fa2c54e94f824eba7dabe9dffd063481cb2d80 --crates-to-patch ../polkadot-sdk --ignore-unused` -# -# Using latest commit from `polkadot-stable2506-2-otf-patches`. -# -# View code changes here: -# -# -# NOTE: The Diener will patch unnecesarry crates while this is waiting to be merged: . -# You may install diener from `liamaharon:ignore-unused-flag` if you like in the meantime. -[patch."https://github.com/paritytech/polkadot-sdk"] -frame-support = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -binary-merkle-tree = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-core = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-crypto-hashing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-crypto-hashing-proc-macro = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-debug-derive = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-externalities = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-storage = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-runtime-interface = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-runtime-interface-proc-macro = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-std = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-tracing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-wasm-interface = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-io = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-keystore = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-state-machine = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-panic-handler = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-trie = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-runtime = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-application-crypto = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-arithmetic = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-weights = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-api-proc-macro = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-metadata-ir = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-version = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-version-proc-macro = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-block-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-block-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-inherents = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-blockchain = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-consensus = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-database = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-client-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -substrate-prometheus-endpoint = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-executor = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-executor-common = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-allocator = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-maybe-compressed-blob = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-executor-polkavm = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-executor-wasmtime = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -substrate-wasm-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-tracing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-tracing-proc-macro = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-executive = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-system = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-try-runtime = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-balances = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-benchmarking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-support-procedural = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-support-procedural-tools = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-support-procedural-tools-derive = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-client-db = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-state-db = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-sdk-frame = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-system-benchmarking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-system-rpc-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-consensus-aura = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-consensus-slots = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-timestamp = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-consensus-grandpa = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-genesis-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-keyring = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-offchain = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-session = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-staking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-transaction-pool = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-sdk = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-primitives-core = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-core-primitives = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-parachain-primitives = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-primitives = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-authority-discovery = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -staging-xcm = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -xcm-procedural = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-primitives-parachain-inherent = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-primitives-proof-size-hostfunction = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-message-queue = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-runtime-parachains = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-authority-discovery = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-session = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-timestamp = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-authorship = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-babe = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-consensus-babe = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-election-provider-support = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-election-provider-solution-type = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-npos-elections = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-offences = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-staking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-bags-list = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-staking-reward-curve = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-broker = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-mmr = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-mmr-primitives = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-runtime-metrics = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -staging-xcm-executor = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-keystore = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -staging-xcm-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-asset-conversion = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-transaction-payment = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-grandpa = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-sudo = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-vesting = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-runtime-common = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-asset-rate = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-election-provider-multi-phase = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-election-provider-support-benchmarking = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-fast-unstake = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-identity = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-staking-reward-fn = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-treasury = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-utility = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-root-testing = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -slot-range-helper = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-primitives-storage-weight-reclaim = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-aura = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-test-relay-sproof-builder = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-chain-spec = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-chain-spec-derive = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network-common = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network-types = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-utils = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-telemetry = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-cli = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-mixnet = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-transaction-pool-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-mixnet = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-service = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-informant = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network-sync = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -fork-tree = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network-light = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network-transactions = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-rpc-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-statement-store = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-transaction-pool = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-rpc-server = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-rpc-spec-v2 = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-sysinfo = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-transaction-storage-proof = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-relay-chain-interface = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-overseer = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -tracing-gum = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -tracing-gum-proc-macro = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-node-metrics = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-node-primitives = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-node-subsystem-types = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-node-network-protocol = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-authority-discovery = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -polkadot-statement-table = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-benchmarking-cli = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -cumulus-client-parachain-inherent = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-runtime-utilities = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -frame-metadata-hash-extension = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-nomination-pools = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-membership = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-multisig = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-nomination-pools-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-preimage = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-proxy = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-scheduler = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-staking-runtime-api = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-offchain = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-babe = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-epochs = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-slots = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-transaction-payment-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-babe-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-network-gossip = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-grandpa = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-grandpa-rpc = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -substrate-frame-rpc-system = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-basic-authorship = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-proposer-metrics = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -substrate-build-script-utils = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-aura = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-insecure-randomness-collective-flip = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -pallet-safe-mode = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sc-consensus-manual-seal = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -sp-crypto-ec-utils = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } -substrate-bip39 = { git = "https://github.com/opentensor/polkadot-sdk.git", rev = "a584a577eeaf31e3f1a65e91b0e0b41f0356f7c8" } +w3f-bls = { git = "https://github.com/opentensor/bls", branch = "fix-no-std" } \ No newline at end of file From 6ec7cf8877182bb0bed74255bd5fb22513bb3606 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 16:21:39 -0300 Subject: [PATCH 15/43] add noop dispatch guard to runtime --- pallets/swap/src/mock.rs | 17 +---------------- runtime/src/lib.rs | 1 + 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/pallets/swap/src/mock.rs b/pallets/swap/src/mock.rs index 29f993ca4a..ac5c7166d4 100644 --- a/pallets/swap/src/mock.rs +++ b/pallets/swap/src/mock.rs @@ -46,11 +46,9 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl system::Config for Test { type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Hash = H256; @@ -59,24 +57,11 @@ impl system::Config for Test { type Lookup = IdentityLookup; type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; - type Version = (); type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; - type OnSetCode = (); type MaxConsumers = ConstU32<16>; type Nonce = u64; type Block = Block; - type RuntimeTask = (); - type SingleBlockMigrations = (); - type MultiBlockMigrator = (); - type PreInherents = (); - type PostInherents = (); - type PostTransactions = (); - type ExtensionsWeightInfo = (); } parameter_types! { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 023e318c7f..6087eafcb5 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -332,6 +332,7 @@ impl frame_system::Config for Runtime { type PostInherents = (); type PostTransactions = (); type ExtensionsWeightInfo = frame_system::SubstrateExtensionsWeight; + type DispatchGuard = (); } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} From 77d858789affa94b50e3c6bc7c01e1bc8fecab2e Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 18:48:02 -0300 Subject: [PATCH 16/43] remove CheckColdkeySwap tx extension --- .../src/extensions/check_coldkey_swap.rs | 384 ------------------ pallets/subtensor/src/extensions/mod.rs | 2 - pallets/subtensor/src/extensions/subtensor.rs | 28 +- 3 files changed, 3 insertions(+), 411 deletions(-) delete mode 100644 pallets/subtensor/src/extensions/check_coldkey_swap.rs diff --git a/pallets/subtensor/src/extensions/check_coldkey_swap.rs b/pallets/subtensor/src/extensions/check_coldkey_swap.rs deleted file mode 100644 index db603f9614..0000000000 --- a/pallets/subtensor/src/extensions/check_coldkey_swap.rs +++ /dev/null @@ -1,384 +0,0 @@ -use crate::{Call, ColdkeySwapAnnouncements, ColdkeySwapDisputes, Config, CustomTransactionError}; -use codec::{Decode, DecodeWithMemTracking, Encode}; -use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; -use frame_support::traits::IsSubType; -use pallet_subtensor_proxy::Call as ProxyCall; -use scale_info::TypeInfo; -use sp_runtime::{ - impl_tx_ext_default, - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, Implication, StaticLookup, - TransactionExtension, ValidateResult, - }, - transaction_validity::TransactionSource, -}; -use sp_std::marker::PhantomData; -use subtensor_macros::freeze_struct; - -type CallOf = ::RuntimeCall; -type OriginOf = ::RuntimeOrigin; -type LookupOf = ::Lookup; - -#[freeze_struct("483277dc74a5aa56")] -#[derive(Default, Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)] -pub struct CheckColdkeySwap(pub PhantomData); - -impl CheckColdkeySwap { - pub fn new() -> Self { - Self(Default::default()) - } -} - -impl sp_std::fmt::Debug for CheckColdkeySwap { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "CheckColdkeySwap") - } -} - -impl - TransactionExtension> for CheckColdkeySwap -where - CallOf: Dispatchable - + IsSubType> - + IsSubType> - + IsSubType>, - OriginOf: AsSystemOriginSigner + Clone, -{ - const IDENTIFIER: &'static str = "CheckColdkeySwap"; - - type Implicit = (); - type Val = (); - type Pre = (); - - fn validate( - &self, - origin: OriginOf, - call: &CallOf, - _info: &DispatchInfoOf>, - _len: usize, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Implication, - _source: TransactionSource, - ) -> ValidateResult> { - // Ensure the transaction is signed, else we just skip the extension. - let Some(who) = origin.as_system_origin_signer() else { - return Ok((Default::default(), (), origin)); - }; - - // Get the real account and origin if we are behind a proxy. - let (who, call) = if let Some( - ProxyCall::proxy { real, call, .. } | ProxyCall::proxy_announced { real, call, .. }, - ) = call.is_sub_type() - { - let real = LookupOf::::lookup(real.clone()) - .map_err(|_| CustomTransactionError::InvalidRealAccount)?; - (real, (*call.clone()).into()) - } else { - (who.clone(), call.clone()) - }; - - if ColdkeySwapAnnouncements::::contains_key(&who) { - if ColdkeySwapDisputes::::contains_key(&who) { - return Err(CustomTransactionError::ColdkeySwapDisputed.into()); - } - - let is_allowed_direct = matches!( - call.is_sub_type(), - Some( - Call::announce_coldkey_swap { .. } - | Call::swap_coldkey_announced { .. } - | Call::dispute_coldkey_swap { .. } - ) - ); - - let is_mev_protected = matches!( - IsSubType::>::is_sub_type(&call), - Some(pallet_shield::Call::submit_encrypted { .. }) - ); - - if !is_allowed_direct && !is_mev_protected { - return Err(CustomTransactionError::ColdkeySwapAnnounced.into()); - } - } - - Ok((Default::default(), (), origin)) - } - - impl_tx_ext_default!(CallOf; weight prepare); -} - -#[cfg(test)] -#[allow(clippy::expect_used, clippy::unwrap_used)] -mod tests { - use super::*; - use crate::{BalancesCall, DefaultMinStake, tests::mock::*}; - use frame_support::testing_prelude::*; - use frame_support::{dispatch::GetDispatchInfo, traits::OriginTrait}; - use frame_system::Call as SystemCall; - use sp_core::U256; - use sp_runtime::{ - BoundedVec, - traits::{AsTransactionAuthorizedOrigin, Hash, TxBaseImplication}, - }; - use subtensor_runtime_common::{Currency, NetUid}; - - type HashingOf = ::Hashing; - - const CALL: RuntimeCall = RuntimeCall::System(SystemCall::remark { remark: vec![] }); - - #[test] - fn skipped_for_non_signed_origins() { - new_test_ext(1).execute_with(|| { - let info = CALL.get_dispatch_info(); - let len = 0_usize; - - let (_, _, origin) = CheckColdkeySwap::::new() - .validate( - None.into(), - &CALL, - &info, - len, - (), - &TxBaseImplication(CALL), - TransactionSource::External, - ) - .unwrap(); - assert!(!origin.is_transaction_authorized()); - - let (_, _, origin) = CheckColdkeySwap::::new() - .validate( - RuntimeOrigin::root().into(), - &CALL, - &info, - len, - (), - &TxBaseImplication(CALL), - TransactionSource::External, - ) - .unwrap(); - assert!(origin.as_system_ref().unwrap().is_root()); - }) - } - - #[test] - fn skipped_if_no_active_swap() { - new_test_ext(1).execute_with(|| { - let who = U256::from(1); - let info = CALL.get_dispatch_info(); - let len = 0_usize; - - let (_, _, origin) = CheckColdkeySwap::::new() - .validate( - RuntimeOrigin::signed(who).into(), - &CALL, - &info, - len, - (), - &TxBaseImplication(CALL), - TransactionSource::External, - ) - .unwrap(); - assert_eq!(origin.as_signer(), Some(&who)); - }) - } - - #[test] - fn validate_calls_correctly() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let stake = DefaultMinStake::::get().to_u64(); - let who = U256::from(1); - let now = System::block_number(); - let another_coldkey = U256::from(3); - let another_coldkey_hash = HashingOf::::hash_of(&another_coldkey); - let new_coldkey = U256::from(42); - let new_coldkey_hash = HashingOf::::hash_of(&new_coldkey); - ColdkeySwapAnnouncements::::insert(who, (now, new_coldkey_hash)); - - let reserve = stake * 10; - setup_reserves(netuid, reserve.into(), reserve.into()); - - // Setup network and neuron - let hotkey = U256::from(2); - add_network(netuid, 1, 0); - register_ok_neuron(netuid, hotkey, who, 0); - - SubtensorModule::add_balance_to_coldkey_account(&who, u64::MAX); - - let forbidden_calls: Vec = vec![ - RuntimeCall::SubtensorModule(SubtensorCall::dissolve_network { - netuid, - coldkey: who, - }), - RuntimeCall::SubtensorModule(SubtensorCall::add_stake { - hotkey, - netuid, - amount_staked: stake.into(), - }), - RuntimeCall::SubtensorModule(SubtensorCall::add_stake_limit { - hotkey, - netuid, - amount_staked: stake.into(), - limit_price: stake.into(), - allow_partial: false, - }), - RuntimeCall::SubtensorModule(SubtensorCall::swap_stake { - hotkey, - origin_netuid: netuid, - destination_netuid: netuid, - alpha_amount: stake.into(), - }), - RuntimeCall::SubtensorModule(SubtensorCall::swap_stake_limit { - hotkey, - origin_netuid: netuid, - destination_netuid: netuid, - alpha_amount: stake.into(), - limit_price: stake.into(), - allow_partial: false, - }), - RuntimeCall::SubtensorModule(SubtensorCall::move_stake { - origin_hotkey: hotkey, - destination_hotkey: hotkey, - origin_netuid: netuid, - destination_netuid: netuid, - alpha_amount: stake.into(), - }), - RuntimeCall::SubtensorModule(SubtensorCall::transfer_stake { - destination_coldkey: new_coldkey, - hotkey, - origin_netuid: netuid, - destination_netuid: netuid, - alpha_amount: stake.into(), - }), - RuntimeCall::SubtensorModule(SubtensorCall::remove_stake { - hotkey, - netuid, - amount_unstaked: (DefaultMinStake::::get().to_u64() * 2).into(), - }), - RuntimeCall::SubtensorModule(SubtensorCall::remove_stake_limit { - hotkey, - netuid, - amount_unstaked: (stake * 2).into(), - limit_price: 123456789.into(), - allow_partial: true, - }), - RuntimeCall::SubtensorModule(SubtensorCall::burned_register { netuid, hotkey }), - RuntimeCall::Balances(BalancesCall::transfer_all { - dest: new_coldkey, - keep_alive: false, - }), - RuntimeCall::Balances(BalancesCall::transfer_keep_alive { - dest: new_coldkey, - value: 100_000_000_000, - }), - RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: new_coldkey, - value: 100_000_000_000, - }), - ]; - - // Forbidden calls through direct origin - for call in &forbidden_calls { - assert_eq!( - ext_validate(who, call.clone()).unwrap_err(), - CustomTransactionError::ColdkeySwapAnnounced.into() - ); - } - - let delegate = U256::from(2); - - // Forbidden calls through proxy - for call in &forbidden_calls { - let proxy_calls = build_proxy_calls(who, delegate, call.clone()); - for proxy_call in proxy_calls { - assert_eq!( - ext_validate(delegate, proxy_call.clone()).unwrap_err(), - CustomTransactionError::ColdkeySwapAnnounced.into() - ); - } - } - - let authorized_calls: Vec = vec![ - RuntimeCall::SubtensorModule(SubtensorCall::announce_coldkey_swap { - new_coldkey_hash: another_coldkey_hash, - }), - RuntimeCall::SubtensorModule(SubtensorCall::swap_coldkey_announced { new_coldkey }), - RuntimeCall::SubtensorModule(SubtensorCall::dispute_coldkey_swap {}), - RuntimeCall::Shield(pallet_shield::Call::submit_encrypted { - commitment: ::Hashing::hash_of(&new_coldkey), - ciphertext: BoundedVec::truncate_from(vec![1, 2, 3, 4]), - }), - ]; - - // Authorized calls through direct origin - for call in &authorized_calls { - let (_, _, origin) = ext_validate(who, call.clone()).unwrap(); - assert_eq!(origin.as_signer(), Some(&who)); - } - - // Authorized calls through proxy - for call in &authorized_calls { - let proxy_calls = build_proxy_calls(who, delegate, call.clone()); - for proxy_call in proxy_calls { - let (_, _, origin) = ext_validate(delegate, proxy_call.clone()).unwrap(); - assert_eq!(origin.as_signer(), Some(&delegate)); - } - } - - ColdkeySwapDisputes::::insert(who, now); - - // All calls should fail when the coldkey swap is disputed - let all_calls = forbidden_calls.iter().chain(authorized_calls.iter()); - - // All calls through direct origin during dispute - for call in all_calls.clone() { - assert_eq!( - ext_validate(who, call.clone()).unwrap_err(), - CustomTransactionError::ColdkeySwapDisputed.into() - ); - } - - // All calls through proxy during dispute - for call in all_calls { - let proxy_calls = build_proxy_calls(who, delegate, call.clone()); - for proxy_call in proxy_calls { - assert_eq!( - ext_validate(delegate, proxy_call.clone()).unwrap_err(), - CustomTransactionError::ColdkeySwapDisputed.into() - ); - } - } - }) - } - - fn build_proxy_calls(who: U256, delegate: U256, call: RuntimeCall) -> Vec { - vec![ - RuntimeCall::Proxy(ProxyCall::proxy { - real: who, - force_proxy_type: None, - call: Box::new(call.clone()), - }), - RuntimeCall::Proxy(ProxyCall::proxy_announced { - delegate, - real: who, - force_proxy_type: None, - call: Box::new(call.clone()), - }), - ] - } - - fn ext_validate(who: U256, call: RuntimeCall) -> ValidateResult<(), RuntimeCall> { - let info = call.get_dispatch_info(); - let len = 0_usize; - - CheckColdkeySwap::::new().validate( - RuntimeOrigin::signed(who).into(), - &call.clone(), - &info, - len, - (), - &TxBaseImplication(call), - TransactionSource::External, - ) - } -} diff --git a/pallets/subtensor/src/extensions/mod.rs b/pallets/subtensor/src/extensions/mod.rs index d77987c583..9171c222be 100644 --- a/pallets/subtensor/src/extensions/mod.rs +++ b/pallets/subtensor/src/extensions/mod.rs @@ -1,5 +1,3 @@ -mod check_coldkey_swap; mod subtensor; -pub use check_coldkey_swap::*; pub use subtensor::*; diff --git a/pallets/subtensor/src/extensions/subtensor.rs b/pallets/subtensor/src/extensions/subtensor.rs index a24a54f3fd..950326c653 100644 --- a/pallets/subtensor/src/extensions/subtensor.rs +++ b/pallets/subtensor/src/extensions/subtensor.rs @@ -1,7 +1,4 @@ -use crate::{ - BalancesCall, Call, CheckColdkeySwap, Config, CustomTransactionError, Error, Pallet, - TransactionType, -}; +use crate::{BalancesCall, Call, Config, CustomTransactionError, Error, Pallet, TransactionType}; use codec::{Decode, DecodeWithMemTracking, Encode}; use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; use frame_support::traits::IsSubType; @@ -90,18 +87,10 @@ where impl TransactionExtension> for SubtensorTransactionExtension where - T: Config - + Send - + Sync - + TypeInfo - + pallet_balances::Config - + pallet_subtensor_proxy::Config - + pallet_shield::Config, + T: Config + Send + Sync + TypeInfo + pallet_balances::Config, CallOf: Dispatchable + IsSubType> - + IsSubType> - + IsSubType> - + IsSubType>, + + IsSubType>, OriginOf: AsSystemOriginSigner + Clone, { const IDENTIFIER: &'static str = "SubtensorTransactionExtension"; @@ -125,17 +114,6 @@ where return Ok((Default::default(), (), origin)); }; - // TODO: move into tx extension pipeline but require node upgrade - CheckColdkeySwap::::new().validate( - origin.clone(), - call, - _info, - _len, - _self_implicit, - _inherited_implication, - _source, - )?; - match call.is_sub_type() { Some(Call::commit_weights { netuid, .. }) => { if Self::check_weights_min_stake(who, *netuid) { From 061c84b30322e7ac34d5728320329cf791e628b4 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 19:23:06 -0300 Subject: [PATCH 17/43] added new errors to the subtensor pallet --- pallets/subtensor/src/macros/errors.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 7d50373f19..1bf36e5dde 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -282,5 +282,9 @@ mod errors { Deprecated, /// "Add stake and burn" exceeded the operation rate limit AddStakeBurnRateLimitExceeded, + /// A coldkey swap has been announced for this account. + ColdkeySwapActive, + /// A coldkey swap for this account is under dispute. + ColdkeySwapDisputed, } } From 0b0c61a7a27d86dfcf875cd320ff1181c52f8747 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 19:23:39 -0300 Subject: [PATCH 18/43] added CheckColdkeySwap dispatch guard and tests --- .../src/guards/check_coldkey_swap.rs | 315 ++++++++++++++++++ pallets/subtensor/src/guards/mod.rs | 3 + pallets/subtensor/src/lib.rs | 2 + pallets/subtensor/src/tests/mock.rs | 1 + 4 files changed, 321 insertions(+) create mode 100644 pallets/subtensor/src/guards/check_coldkey_swap.rs create mode 100644 pallets/subtensor/src/guards/mod.rs diff --git a/pallets/subtensor/src/guards/check_coldkey_swap.rs b/pallets/subtensor/src/guards/check_coldkey_swap.rs new file mode 100644 index 0000000000..1716a9d3c8 --- /dev/null +++ b/pallets/subtensor/src/guards/check_coldkey_swap.rs @@ -0,0 +1,315 @@ +use crate::{Call, ColdkeySwapAnnouncements, ColdkeySwapDisputes, Config, Error}; +use frame_support::dispatch::{DispatchGuard, DispatchInfo, DispatchResultWithPostInfo, PostDispatchInfo}; +use frame_support::traits::{IsSubType, OriginTrait}; +use sp_runtime::traits::Dispatchable; +use sp_std::marker::PhantomData; + +type CallOf = ::RuntimeCall; +type DispatchableOriginOf = as Dispatchable>::RuntimeOrigin; + +/// Dispatch guard that blocks most calls when a coldkey swap is active. +/// +/// When a coldkey swap has been announced for the signing account: +/// - If the swap is disputed, ALL calls are blocked. +/// - Otherwise, only swap-related calls and MEV-protected calls (`submit_encrypted`) +/// are allowed through. +/// +/// Root origin bypasses this guard entirely (handled by `check_dispatch_guard`). +/// Non-signed origins pass through. +/// +/// Because this is a `DispatchGuard` (not a `TransactionExtension`), it fires at every +/// `call.dispatch(origin)` site — including inside the proxy pallet's `do_proxy()`. +/// This means nested proxies of any depth are handled automatically with the real +/// resolved origin. +pub struct CheckColdkeySwap(PhantomData); + +impl DispatchGuard<::RuntimeCall> for CheckColdkeySwap +where + T: Config + pallet_shield::Config, + ::RuntimeCall: + Dispatchable + + IsSubType> + + IsSubType>, + DispatchableOriginOf: + OriginTrait, +{ + fn check( + origin: &DispatchableOriginOf, + call: &CallOf, + ) -> DispatchResultWithPostInfo { + // Only care about signed origins. + // Root is already bypassed by check_dispatch_guard() before we get here. + let Some(who) = origin.as_signer() else { + return Ok(().into()); + }; + + if ColdkeySwapAnnouncements::::contains_key(who) { + if ColdkeySwapDisputes::::contains_key(who) { + return Err(Error::::ColdkeySwapDisputed.into()); + } + + let is_allowed_direct = matches!( + call.is_sub_type(), + Some( + Call::announce_coldkey_swap { .. } + | Call::swap_coldkey_announced { .. } + | Call::dispute_coldkey_swap { .. } + ) + ); + + let is_mev_protected = matches!( + IsSubType::>::is_sub_type(call), + Some(pallet_shield::Call::submit_encrypted { .. }) + ); + + if !is_allowed_direct && !is_mev_protected { + return Err(Error::::ColdkeySwapActive.into()); + } + } + + Ok(().into()) + } +} + +#[cfg(test)] +#[allow(clippy::expect_used, clippy::unwrap_used)] +mod tests { + use crate::{ColdkeySwapAnnouncements, ColdkeySwapDisputes, Error, tests::mock::*}; + use frame_support::{assert_ok, BoundedVec}; + use frame_system::Call as SystemCall; + use pallet_subtensor_proxy::Call as ProxyCall; + use sp_core::U256; + use sp_runtime::traits::{Dispatchable, Hash}; + use subtensor_runtime_common::ProxyType; + + type HashingOf = ::Hashing; + + /// Calls that should be blocked when a coldkey swap is active. + fn forbidden_calls() -> Vec { + vec![ + RuntimeCall::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::SubtensorModule(crate::Call::add_stake { + hotkey: U256::from(1), + netuid: 1u16.into(), + amount_staked: 1_000u64.into(), + }), + RuntimeCall::SubtensorModule(crate::Call::remove_stake { + hotkey: U256::from(1), + netuid: 1u16.into(), + amount_unstaked: 1_000u64.into(), + }), + RuntimeCall::SubtensorModule(crate::Call::set_weights { + netuid: 1u16.into(), + dests: vec![], + weights: vec![], + version_key: 0, + }), + RuntimeCall::SubtensorModule(crate::Call::register_network { + hotkey: U256::from(1), + }), + ] + } + + /// Calls that should be allowed through the guard during an active (undisputed) swap. + fn authorized_calls() -> Vec { + vec![ + RuntimeCall::SubtensorModule(crate::Call::announce_coldkey_swap { + new_coldkey_hash: HashingOf::::hash_of(&U256::from(99)), + }), + RuntimeCall::SubtensorModule(crate::Call::swap_coldkey_announced { + new_coldkey: U256::from(42), + }), + RuntimeCall::SubtensorModule(crate::Call::dispute_coldkey_swap {}), + RuntimeCall::Shield(pallet_shield::Call::submit_encrypted { + commitment: HashingOf::::hash_of(&U256::from(42)), + ciphertext: BoundedVec::truncate_from(vec![1, 2, 3, 4]), + }), + ] + } + + fn setup_swap_announced(who: &U256) { + let now = System::block_number(); + let hash = HashingOf::::hash_of(&U256::from(42)); + ColdkeySwapAnnouncements::::insert(who, (now, hash)); + } + + fn setup_swap_disputed(who: &U256) { + setup_swap_announced(who); + ColdkeySwapDisputes::::insert(who, System::block_number()); + } + + fn remark_call() -> RuntimeCall { + RuntimeCall::System(SystemCall::remark { remark: vec![] }) + } + + #[test] + fn no_active_swap_allows_calls() { + new_test_ext(1).execute_with(|| { + let who = U256::from(1); + assert_ok!(remark_call().dispatch(RuntimeOrigin::signed(who))); + }); + } + + #[test] + fn none_bypasses_guard() { + new_test_ext(1).execute_with(|| { + let who = U256::from(1); + setup_swap_disputed(&who); + + assert_ok!(remark_call().dispatch(RuntimeOrigin::none())); + }); + } + + #[test] + fn root_bypasses_guard() { + new_test_ext(1).execute_with(|| { + let who = U256::from(1); + setup_swap_disputed(&who); + + assert_ok!(remark_call().dispatch(RuntimeOrigin::root())); + }); + } + + #[test] + fn active_swap_blocks_forbidden_calls() { + new_test_ext(1).execute_with(|| { + let who = U256::from(1); + setup_swap_announced(&who); + + for call in forbidden_calls() { + assert_eq!( + call.dispatch(RuntimeOrigin::signed(who)).unwrap_err().error, + Error::::ColdkeySwapActive.into() + ); + } + }); + } + + #[test] + fn active_swap_allows_authorized_calls() { + new_test_ext(1).execute_with(|| { + let who = U256::from(1); + setup_swap_announced(&who); + + for call in authorized_calls() { + if let Err(err) = call.dispatch(RuntimeOrigin::signed(who)) { + assert_ne!( + err.error, + Error::::ColdkeySwapActive.into(), + "Authorized call should not be blocked by the guard" + ); + } + } + }); + } + + #[test] + fn disputed_swap_blocks_all_calls() { + new_test_ext(1).execute_with(|| { + let who = U256::from(1); + setup_swap_disputed(&who); + + // Both forbidden and authorized calls should be blocked during dispute + let all_calls = forbidden_calls() + .into_iter() + .chain(authorized_calls()) + .collect::>(); + + for call in all_calls { + assert_eq!( + call.dispatch(RuntimeOrigin::signed(who)).unwrap_err().error, + Error::::ColdkeySwapDisputed.into() + ); + } + }); + } + + #[test] + fn proxied_forbidden_call_blocked() { + new_test_ext(1).execute_with(|| { + let real = U256::from(1); + let delegate = U256::from(2); + let now = System::block_number(); + let hash = HashingOf::::hash_of(&U256::from(42)); + ColdkeySwapAnnouncements::::insert(real, (now, hash)); + + // Give delegate enough balance for proxy deposit + SubtensorModule::add_balance_to_coldkey_account(&real, 1_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&delegate, 1_000_000_000); + + // Register proxy: delegate can act on behalf of real + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(real), + delegate, + ProxyType::Any, + 0 + )); + + // Dispatch a proxy call as delegate + let proxy_call = RuntimeCall::Proxy(ProxyCall::proxy { + real, + force_proxy_type: None, + call: Box::new(remark_call()), + }); + + // The outer proxy call itself succeeds + assert_ok!(proxy_call.dispatch(RuntimeOrigin::signed(delegate))); + + // The inner call was blocked — check via LastCallResult storage. + assert_eq!( + pallet_subtensor_proxy::LastCallResult::::get(real), + Some(Err(Error::::ColdkeySwapActive.into())) + ); + }); + } + + #[test] + fn nested_proxy_blocked() { + new_test_ext(1).execute_with(|| { + let real = U256::from(1); + let delegate1 = U256::from(2); + let delegate2 = U256::from(3); + let now = System::block_number(); + let hash = HashingOf::::hash_of(&U256::from(42)); + ColdkeySwapAnnouncements::::insert(real, (now, hash)); + + SubtensorModule::add_balance_to_coldkey_account(&real, 1_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&delegate1, 1_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&delegate2, 1_000_000_000); + + // delegate1 can proxy for real, delegate2 can proxy for delegate1 + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(real), + delegate1, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(delegate1), + delegate2, + ProxyType::Any, + 0 + )); + + // Nested: delegate2 -> delegate1 -> proxy(real, remark) + let inner_proxy = RuntimeCall::Proxy(ProxyCall::proxy { + real, + force_proxy_type: None, + call: Box::new(remark_call()), + }); + let outer_proxy = RuntimeCall::Proxy(ProxyCall::proxy { + real: delegate1, + force_proxy_type: None, + call: Box::new(inner_proxy), + }); + + assert_ok!(outer_proxy.dispatch(RuntimeOrigin::signed(delegate2))); + + // The innermost call (remark as real) was blocked. + assert_eq!( + pallet_subtensor_proxy::LastCallResult::::get(real), + Some(Err(Error::::ColdkeySwapActive.into())) + ); + }); + } +} diff --git a/pallets/subtensor/src/guards/mod.rs b/pallets/subtensor/src/guards/mod.rs new file mode 100644 index 0000000000..44fba0c50f --- /dev/null +++ b/pallets/subtensor/src/guards/mod.rs @@ -0,0 +1,3 @@ +mod check_coldkey_swap; + +pub use check_coldkey_swap::*; diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 69645c0419..3688ddc602 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -37,6 +37,7 @@ mod benchmarks; pub mod coinbase; pub mod epoch; pub mod extensions; +pub mod guards; pub mod macros; pub mod migrations; pub mod rpc_info; @@ -48,6 +49,7 @@ use crate::utils::rate_limiting::{Hyperparameter, TransactionType}; use macros::{config, dispatches, errors, events, genesis, hooks}; pub use extensions::*; +pub use guards::*; #[cfg(test)] mod tests; diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 2435245ad3..7af9420ba3 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -146,6 +146,7 @@ impl system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; type Nonce = u64; type Block = Block; + type DispatchGuard = crate::CheckColdkeySwap; } parameter_types! { From a764147f29b1a6bdcd973adc76c39177c1c90866 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 19:24:06 -0300 Subject: [PATCH 19/43] wire CheckColdkeySwap dispatch guard in the runtime --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2ce014bead..b324934caa 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -353,7 +353,7 @@ impl frame_system::Config for Runtime { type PostInherents = (); type PostTransactions = (); type ExtensionsWeightInfo = frame_system::SubstrateExtensionsWeight; - type DispatchGuard = (); + type DispatchGuard = pallet_subtensor::CheckColdkeySwap; } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} From fd4337ae75456b7a013c2874005d3253f06f79c9 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 19:38:40 -0300 Subject: [PATCH 20/43] remove unused errors from tx etc and deprecate old error --- pallets/subtensor/src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 3688ddc602..47726bd6b0 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2487,7 +2487,9 @@ pub mod pallet { #[derive(Debug, PartialEq)] pub enum CustomTransactionError { - ColdkeySwapAnnounced, + /// Deprecated: coldkey swap now uses announcements and check moved to DispatchGuard + #[deprecated] + ColdkeyInSwapSchedule, StakeAmountTooLow, BalanceTooLow, SubnetNotExists, @@ -2509,14 +2511,13 @@ pub enum CustomTransactionError { InputLengthsUnequal, UidNotFound, EvmKeyAssociateRateLimitExceeded, - ColdkeySwapDisputed, - InvalidRealAccount, } impl From for u8 { fn from(variant: CustomTransactionError) -> u8 { match variant { - CustomTransactionError::ColdkeySwapAnnounced => 0, + #[allow(deprecated)] + CustomTransactionError::ColdkeyInSwapSchedule => 0, CustomTransactionError::StakeAmountTooLow => 1, CustomTransactionError::BalanceTooLow => 2, CustomTransactionError::SubnetNotExists => 3, @@ -2538,8 +2539,6 @@ impl From for u8 { CustomTransactionError::InputLengthsUnequal => 18, CustomTransactionError::UidNotFound => 19, CustomTransactionError::EvmKeyAssociateRateLimitExceeded => 20, - CustomTransactionError::ColdkeySwapDisputed => 21, - CustomTransactionError::InvalidRealAccount => 22, } } } From 7b190643c982148c13005064a33aae3e21255e8a Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 19:55:15 -0300 Subject: [PATCH 21/43] cargo fmt --- .../subtensor/src/guards/check_coldkey_swap.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pallets/subtensor/src/guards/check_coldkey_swap.rs b/pallets/subtensor/src/guards/check_coldkey_swap.rs index 1716a9d3c8..903d9abd57 100644 --- a/pallets/subtensor/src/guards/check_coldkey_swap.rs +++ b/pallets/subtensor/src/guards/check_coldkey_swap.rs @@ -1,5 +1,7 @@ use crate::{Call, ColdkeySwapAnnouncements, ColdkeySwapDisputes, Config, Error}; -use frame_support::dispatch::{DispatchGuard, DispatchInfo, DispatchResultWithPostInfo, PostDispatchInfo}; +use frame_support::dispatch::{ + DispatchGuard, DispatchInfo, DispatchResultWithPostInfo, PostDispatchInfo, +}; use frame_support::traits::{IsSubType, OriginTrait}; use sp_runtime::traits::Dispatchable; use sp_std::marker::PhantomData; @@ -26,17 +28,12 @@ pub struct CheckColdkeySwap(PhantomData); impl DispatchGuard<::RuntimeCall> for CheckColdkeySwap where T: Config + pallet_shield::Config, - ::RuntimeCall: - Dispatchable + ::RuntimeCall: Dispatchable + IsSubType> + IsSubType>, - DispatchableOriginOf: - OriginTrait, + DispatchableOriginOf: OriginTrait, { - fn check( - origin: &DispatchableOriginOf, - call: &CallOf, - ) -> DispatchResultWithPostInfo { + fn check(origin: &DispatchableOriginOf, call: &CallOf) -> DispatchResultWithPostInfo { // Only care about signed origins. // Root is already bypassed by check_dispatch_guard() before we get here. let Some(who) = origin.as_signer() else { @@ -75,7 +72,7 @@ where #[allow(clippy::expect_used, clippy::unwrap_used)] mod tests { use crate::{ColdkeySwapAnnouncements, ColdkeySwapDisputes, Error, tests::mock::*}; - use frame_support::{assert_ok, BoundedVec}; + use frame_support::{BoundedVec, assert_ok}; use frame_system::Call as SystemCall; use pallet_subtensor_proxy::Call as ProxyCall; use sp_core::U256; From ae16032f8dae331db90824bf611726057fd2e696 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 20:08:17 -0300 Subject: [PATCH 22/43] fix import --- pallets/swap/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/swap/src/mock.rs b/pallets/swap/src/mock.rs index ac5c7166d4..f71cb656bc 100644 --- a/pallets/swap/src/mock.rs +++ b/pallets/swap/src/mock.rs @@ -2,7 +2,7 @@ use core::num::NonZeroU64; -use frame_support::construct_runtime; +use frame_support::{construct_runtime, derive_impl}; use frame_support::pallet_prelude::*; use frame_support::{ PalletId, parameter_types, From 4a8795f24629abc3b9bda79036945de562043567 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 20:13:14 -0300 Subject: [PATCH 23/43] Error::ColdkeySwapActive to ColdkeySwapAnnounced --- pallets/subtensor/src/guards/check_coldkey_swap.rs | 10 +++++----- pallets/subtensor/src/macros/errors.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/guards/check_coldkey_swap.rs b/pallets/subtensor/src/guards/check_coldkey_swap.rs index 903d9abd57..95a640b9dc 100644 --- a/pallets/subtensor/src/guards/check_coldkey_swap.rs +++ b/pallets/subtensor/src/guards/check_coldkey_swap.rs @@ -60,7 +60,7 @@ where ); if !is_allowed_direct && !is_mev_protected { - return Err(Error::::ColdkeySwapActive.into()); + return Err(Error::::ColdkeySwapAnnounced.into()); } } @@ -176,7 +176,7 @@ mod tests { for call in forbidden_calls() { assert_eq!( call.dispatch(RuntimeOrigin::signed(who)).unwrap_err().error, - Error::::ColdkeySwapActive.into() + Error::::ColdkeySwapAnnounced.into() ); } }); @@ -192,7 +192,7 @@ mod tests { if let Err(err) = call.dispatch(RuntimeOrigin::signed(who)) { assert_ne!( err.error, - Error::::ColdkeySwapActive.into(), + Error::::ColdkeySwapAnnounced.into(), "Authorized call should not be blocked by the guard" ); } @@ -255,7 +255,7 @@ mod tests { // The inner call was blocked — check via LastCallResult storage. assert_eq!( pallet_subtensor_proxy::LastCallResult::::get(real), - Some(Err(Error::::ColdkeySwapActive.into())) + Some(Err(Error::::ColdkeySwapAnnounced.into())) ); }); } @@ -305,7 +305,7 @@ mod tests { // The innermost call (remark as real) was blocked. assert_eq!( pallet_subtensor_proxy::LastCallResult::::get(real), - Some(Err(Error::::ColdkeySwapActive.into())) + Some(Err(Error::::ColdkeySwapAnnounced.into())) ); }); } diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 1bf36e5dde..e6c3aa5e78 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -283,7 +283,7 @@ mod errors { /// "Add stake and burn" exceeded the operation rate limit AddStakeBurnRateLimitExceeded, /// A coldkey swap has been announced for this account. - ColdkeySwapActive, + ColdkeySwapAnnounced, /// A coldkey swap for this account is under dispute. ColdkeySwapDisputed, } From f88e095a7b46c7a22bc4a182e9644dd46594f0ff Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 20:15:23 -0300 Subject: [PATCH 24/43] cargo fmt --- pallets/swap/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/swap/src/mock.rs b/pallets/swap/src/mock.rs index f71cb656bc..bb671e4762 100644 --- a/pallets/swap/src/mock.rs +++ b/pallets/swap/src/mock.rs @@ -2,12 +2,12 @@ use core::num::NonZeroU64; -use frame_support::{construct_runtime, derive_impl}; use frame_support::pallet_prelude::*; use frame_support::{ PalletId, parameter_types, traits::{ConstU32, Everything}, }; +use frame_support::{construct_runtime, derive_impl}; use frame_system::{self as system}; use sp_core::H256; use sp_runtime::{ From f05505dcadca8515110385611b22209748590ee9 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 20:43:59 -0300 Subject: [PATCH 25/43] fix failing test --- runtime/tests/precompiles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/precompiles.rs b/runtime/tests/precompiles.rs index 5565aa8f7f..2e21eac8fd 100644 --- a/runtime/tests/precompiles.rs +++ b/runtime/tests/precompiles.rs @@ -204,7 +204,7 @@ mod balance_transfer { other => panic!("unexpected precompile failure: {other:?}"), }; assert!( - message.contains("transaction extension rejected"), + message.contains("dispatch execution failed: ColdkeySwapAnnounced"), "unexpected precompile failure: {message}" ); From 80bc2ad5abe09517e41cd0adde01b6352ec223ab Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Thu, 26 Feb 2026 20:45:28 -0300 Subject: [PATCH 26/43] fix test --- runtime/tests/precompiles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/precompiles.rs b/runtime/tests/precompiles.rs index 2e21eac8fd..dcd7b3f3b9 100644 --- a/runtime/tests/precompiles.rs +++ b/runtime/tests/precompiles.rs @@ -158,7 +158,7 @@ mod balance_transfer { } #[test] - fn balance_transfer_precompile_respects_subtensor_extension_policy() { + fn balance_transfer_precompile_respects_dispatch_guard_policy() { new_test_ext().execute_with(|| { let precompiles = Precompiles::::new(); let precompile_addr = addr_from_index(BalanceTransferPrecompile::::INDEX); From 8cc84fa2de72dcb70c25adae250c3998ef03d503 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 27 Feb 2026 11:30:53 +0800 Subject: [PATCH 27/43] fix ink contract test --- contract-tests/bittensor/Cargo.toml | 2 - contract-tests/bittensor/lib.rs | 114 +++++++++++++--------------- 2 files changed, 51 insertions(+), 65 deletions(-) diff --git a/contract-tests/bittensor/Cargo.toml b/contract-tests/bittensor/Cargo.toml index ff46eb3696..a322f2f99e 100755 --- a/contract-tests/bittensor/Cargo.toml +++ b/contract-tests/bittensor/Cargo.toml @@ -10,7 +10,6 @@ edition = "2021" ink = { version = "5.1.1", default-features = false } parity-scale-codec = { version = "3.0.0", default-features = false } serde = { version = "1.0.228", default-features = false } -subtensor-runtime-common = { path = "../../common", default-features = false } [dev-dependencies] ink_e2e = { version = "5.1.1" } @@ -23,7 +22,6 @@ std = [ "ink/std", "parity-scale-codec/std", "serde/std", - "subtensor-runtime-common/std", ] ink-as-dependency = [] diff --git a/contract-tests/bittensor/lib.rs b/contract-tests/bittensor/lib.rs index 48e8d18aea..8867d017d8 100755 --- a/contract-tests/bittensor/lib.rs +++ b/contract-tests/bittensor/lib.rs @@ -5,7 +5,6 @@ use parity_scale_codec::Compact; #[derive(Debug, Clone)] pub struct CustomEnvironment; -use subtensor_runtime_common::{AlphaCurrency, NetUid, TaoCurrency}; pub enum FunctionId { GetStakeInfoForHotkeyColdkeyNetuidV1 = 0, AddStakeV1 = 1, @@ -39,15 +38,15 @@ pub trait RuntimeReadWrite { #[ink(function = 1)] fn add_stake( hotkey: ::AccountId, - netuid: NetUid, - amount: AlphaCurrency, + netuid: u16, + amount: u64, ); #[ink(function = 2)] fn remove_stake( hotkey: ::AccountId, - netuid: NetUid, - amount: AlphaCurrency, + netuid: u16, + amount: u64, ); #[ink(function = 3)] @@ -60,66 +59,66 @@ pub trait RuntimeReadWrite { fn move_stake( origin_hotkey: ::AccountId, destination_hotkey: ::AccountId, - origin_netuid: NetUid, - destination_netuid: NetUid, - amount: AlphaCurrency, + origin_netuid: u16, + destination_netuid: u16, + amount: u64, ); #[ink(function = 6)] fn transfer_stake( destination_coldkey: ::AccountId, hotkey: ::AccountId, - origin_netuid: NetUid, - destination_netuid: NetUid, - amount: AlphaCurrency, + origin_netuid: u16, + destination_netuid: u16, + amount: u64, ); #[ink(function = 7)] fn swap_stake( hotkey: ::AccountId, - origin_netuid: NetUid, - destination_netuid: NetUid, - amount: AlphaCurrency, + origin_netuid: u16, + destination_netuid: u16, + amount: u64, ); #[ink(function = 8)] fn add_stake_limit( hotkey: ::AccountId, - netuid: NetUid, - amount: TaoCurrency, - limit_price: TaoCurrency, + netuid: u16, + amount: u64, + limit_price: u64, allow_partial: bool, ); #[ink(function = 9)] fn remove_stake_limit( hotkey: ::AccountId, - netuid: NetUid, - amount: TaoCurrency, - limit_price: TaoCurrency, + netuid: u16, + amount: u64, + limit_price: u64, allow_partial: bool, ); #[ink(function = 10)] fn swap_stake_limit( hotkey: ::AccountId, - origin_netuid: NetUid, - destination_netuid: NetUid, - amount: AlphaCurrency, - limit_price: TaoCurrency, + origin_netuid: u16, + destination_netuid: u16, + amount: u64, + limit_price: u64, allow_partial: bool, ); #[ink(function = 11)] fn remove_stake_full_limit( hotkey: ::AccountId, - netuid: NetUid, - limit_price: TaoCurrency, + netuid: u16, + limit_price: u64, ); #[ink(function = 12)] fn set_coldkey_auto_stake_hotkey( - netuid: NetUid, + netuid: u16, hotkey: ::AccountId, ); @@ -130,7 +129,7 @@ pub trait RuntimeReadWrite { fn remove_proxy(delegate: ::AccountId); #[ink(function = 15)] - fn get_alpha_price(netuid: NetUid) -> u64; + fn get_alpha_price(netuid: u16) -> u64; } #[ink::scale_derive(Encode, Decode, TypeInfo)] @@ -166,11 +165,11 @@ impl ink::env::Environment for CustomEnvironment { pub struct StakeInfo { hotkey: AccountId, coldkey: AccountId, - netuid: Compact, - stake: Compact, + netuid: Compact, + stake: Compact, locked: Compact, - emission: Compact, - tao_emission: Compact, + emission: Compact, + tao_emission: Compact, drain: Compact, is_registered: bool, } @@ -220,7 +219,7 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env() .extension() - .add_stake(hotkey.into(), netuid.into(), amount.into()) + .add_stake(hotkey.into(), netuid, amount) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -233,7 +232,7 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env() .extension() - .remove_stake(hotkey.into(), netuid.into(), amount.into()) + .remove_stake(hotkey.into(), netuid, amount) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -267,9 +266,9 @@ mod bittensor { .move_stake( origin_hotkey.into(), destination_hotkey.into(), - origin_netuid.into(), - destination_netuid.into(), - amount.into(), + origin_netuid, + destination_netuid, + amount, ) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -288,9 +287,9 @@ mod bittensor { .transfer_stake( destination_coldkey.into(), hotkey.into(), - origin_netuid.into(), - destination_netuid.into(), - amount.into(), + origin_netuid, + destination_netuid, + amount, ) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -305,12 +304,7 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env() .extension() - .swap_stake( - hotkey.into(), - origin_netuid.into(), - destination_netuid.into(), - amount.into(), - ) + .swap_stake(hotkey.into(), origin_netuid, destination_netuid, amount) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -325,13 +319,7 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env() .extension() - .add_stake_limit( - hotkey.into(), - netuid.into(), - amount.into(), - limit_price.into(), - allow_partial, - ) + .add_stake_limit(hotkey.into(), netuid, amount, limit_price, allow_partial) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -346,9 +334,9 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env().extension().remove_stake_limit( hotkey.into(), - netuid.into(), - amount.into(), - limit_price.into(), + netuid, + amount, + limit_price, allow_partial, ) } @@ -367,10 +355,10 @@ mod bittensor { .extension() .swap_stake_limit( hotkey.into(), - origin_netuid.into(), - destination_netuid.into(), - amount.into(), - limit_price.into(), + origin_netuid, + destination_netuid, + amount, + limit_price, allow_partial, ) .map_err(|_e| ReadWriteErrorCode::WriteFailed) @@ -385,7 +373,7 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env() .extension() - .remove_stake_full_limit(hotkey.into(), netuid.into(), limit_price.into()) + .remove_stake_full_limit(hotkey.into(), netuid, limit_price) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -397,7 +385,7 @@ mod bittensor { ) -> Result<(), ReadWriteErrorCode> { self.env() .extension() - .set_coldkey_auto_stake_hotkey(netuid.into(), hotkey.into()) + .set_coldkey_auto_stake_hotkey(netuid, hotkey.into()) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } @@ -421,7 +409,7 @@ mod bittensor { pub fn get_alpha_price(&self, netuid: u16) -> Result { self.env() .extension() - .get_alpha_price(netuid.into()) + .get_alpha_price(netuid) .map_err(|_e| ReadWriteErrorCode::ReadFailed) } } From 8dee4c6e2f9326da47e47f540f6f3f26018ba6c8 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 10:46:04 -0300 Subject: [PATCH 28/43] added set_real_pays_fee extrinsic and tests --- pallets/proxy/src/benchmarking.rs | 23 ++++++ pallets/proxy/src/lib.rs | 69 +++++++++++++++++ pallets/proxy/src/tests.rs | 122 ++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/pallets/proxy/src/benchmarking.rs b/pallets/proxy/src/benchmarking.rs index 9a759e1846..9bf21cb951 100644 --- a/pallets/proxy/src/benchmarking.rs +++ b/pallets/proxy/src/benchmarking.rs @@ -491,5 +491,28 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn set_real_pays_fee(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; + let caller: T::AccountId = whitelisted_caller(); + let delegate: T::AccountId = account("target", 0, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), delegate_lookup, true); + + assert!(RealPaysFee::::contains_key(&caller, &delegate)); + assert_last_event::( + Event::RealPaysFeeSet { + real: caller, + delegate, + pays_fee: true, + } + .into(), + ); + + Ok(()) + } + impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/pallets/proxy/src/lib.rs b/pallets/proxy/src/lib.rs index a255f99b48..1fca855327 100644 --- a/pallets/proxy/src/lib.rs +++ b/pallets/proxy/src/lib.rs @@ -674,6 +674,44 @@ pub mod pallet { Pays::Yes.into() }) } + + /// Set whether the real account pays transaction fees for proxy calls made by a + /// specific delegate. + /// + /// The dispatch origin for this call must be _Signed_ and must be the real (delegator) + /// account that has an existing proxy relationship with the delegate. + /// + /// Parameters: + /// - `delegate`: The proxy account for which to set the fee payment preference. + /// - `pays_fee`: If `true`, the real account will pay fees for proxy calls made by + /// this delegate. If `false`, the delegate pays (default behavior). + #[pallet::call_index(11)] + #[pallet::weight(T::WeightInfo::set_real_pays_fee(T::MaxProxies::get()))] + pub fn set_real_pays_fee( + origin: OriginFor, + delegate: AccountIdLookupOf, + pays_fee: bool, + ) -> DispatchResult { + let real = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + + // Verify proxy relationship exists + Self::find_proxy(&real, &delegate, None)?; + + if pays_fee { + RealPaysFee::::insert(&real, &delegate, ()); + } else { + RealPaysFee::::remove(&real, &delegate); + } + + Self::deposit_event(Event::RealPaysFeeSet { + real, + delegate, + pays_fee, + }); + + Ok(()) + } } #[pallet::event] @@ -727,6 +765,12 @@ pub mod pallet { old_deposit: BalanceOf, new_deposit: BalanceOf, }, + /// The real-pays-fee setting was updated for a proxy relationship. + RealPaysFeeSet { + real: T::AccountId, + delegate: T::AccountId, + pays_fee: bool, + }, } #[pallet::error] @@ -796,6 +840,21 @@ pub mod pallet { pub type LastCallResult = StorageMap<_, Twox64Concat, T::AccountId, DispatchResult, OptionQuery>; + /// Tracks which (real, delegate) pairs have opted in to the real account paying + /// transaction fees for proxy calls made by the delegate. + /// Existence of an entry means the real account pays; absence means the delegate pays + /// (default). + #[pallet::storage] + pub type RealPaysFee = StorageDoubleMap< + _, + Twox64Concat, + T::AccountId, // real + Twox64Concat, + T::AccountId, // delegate + (), + OptionQuery, + >; + #[pallet::view_functions] impl Pallet { /// Check if a `RuntimeCall` is allowed for a given `ProxyType`. @@ -951,6 +1010,9 @@ impl Pallet { if !proxies.is_empty() { *x = Some((proxies, new_deposit)) } + // Clean up real-pays-fee flag for this specific proxy relationship + RealPaysFee::::remove(delegator, &delegatee); + Self::deposit_event(Event::::ProxyRemoved { delegator: delegator.clone(), delegatee, @@ -1081,5 +1143,12 @@ impl Pallet { pub fn remove_all_proxy_delegates(delegator: &T::AccountId) { let (_, old_deposit) = Proxies::::take(delegator); T::Currency::unreserve(delegator, old_deposit); + // Clean up all real-pays-fee flags for this delegator + let _ = RealPaysFee::::clear_prefix(delegator, u32::MAX, None); + } + + /// Check if the real account has opted in to paying fees for a specific delegate. + pub fn is_real_pays_fee(real: &T::AccountId, delegate: &T::AccountId) -> bool { + RealPaysFee::::contains_key(real, delegate) } } diff --git a/pallets/proxy/src/tests.rs b/pallets/proxy/src/tests.rs index ea64aef030..5bc5be2415 100644 --- a/pallets/proxy/src/tests.rs +++ b/pallets/proxy/src/tests.rs @@ -1251,3 +1251,125 @@ fn poke_deposit_fails_for_unsigned_origin() { ); }); } + +#[test] +fn set_real_pays_fee_works() { + new_test_ext().execute_with(|| { + // Account 1 adds account 3 as proxy + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + + // Account 1 (real) enables real-pays-fee for delegate 3 + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true)); + assert!(Proxy::is_real_pays_fee(&1, &3)); + System::assert_last_event( + ProxyEvent::RealPaysFeeSet { + real: 1, + delegate: 3, + pays_fee: true, + } + .into(), + ); + + // Disable it + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, false)); + assert!(!Proxy::is_real_pays_fee(&1, &3)); + System::assert_last_event( + ProxyEvent::RealPaysFeeSet { + real: 1, + delegate: 3, + pays_fee: false, + } + .into(), + ); + }); +} + +#[test] +fn set_real_pays_fee_fails_without_proxy() { + new_test_ext().execute_with(|| { + // No proxy relationship between 1 and 3 + assert_noop!( + Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true), + Error::::NotProxy, + ); + }); +} + +#[test] +fn set_real_pays_fee_fails_unsigned() { + new_test_ext().execute_with(|| { + assert_noop!( + Proxy::set_real_pays_fee(RuntimeOrigin::none(), 3, true), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn set_real_pays_fee_fails_root() { + new_test_ext().execute_with(|| { + assert_noop!( + Proxy::set_real_pays_fee(RuntimeOrigin::root(), 3, true), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn real_pays_fee_cleaned_on_remove_proxy() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true)); + assert!(Proxy::is_real_pays_fee(&1, &3)); + + // Remove the proxy + assert_ok!(Proxy::remove_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + + // Flag should be cleaned up + assert!(!Proxy::is_real_pays_fee(&1, &3)); + }); +} + +#[test] +fn real_pays_fee_cleaned_on_remove_proxies() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 2, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 2, true)); + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true)); + assert!(Proxy::is_real_pays_fee(&1, &2)); + assert!(Proxy::is_real_pays_fee(&1, &3)); + + // Remove all proxies + assert_ok!(Proxy::remove_proxies(RuntimeOrigin::signed(1))); + + // Both flags should be cleaned up + assert!(!Proxy::is_real_pays_fee(&1, &2)); + assert!(!Proxy::is_real_pays_fee(&1, &3)); + }); +} From c558c477490deedee222618cb63c113d9e7f69cf Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 11:39:05 -0300 Subject: [PATCH 29/43] updated the ChargeTxPaymentWrapper to handle RealPaysFee for proxies --- runtime/src/transaction_payment_wrapper.rs | 251 +++++++++++++++++---- 1 file changed, 202 insertions(+), 49 deletions(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 96d7f3609b..25b030d1a3 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -3,18 +3,28 @@ use codec::{Decode, DecodeWithMemTracking, Encode}; use frame_election_provider_support::private::sp_arithmetic::traits::SaturatedConversion; use frame_support::dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}; use frame_support::pallet_prelude::TypeInfo; +use frame_support::traits::{IsSubType, IsType}; +use pallet_subtensor_proxy as pallet_proxy; +use pallet_subtensor_utility as pallet_utility; use pallet_transaction_payment::{ChargeTransactionPayment, Config, Pre, Val}; use sp_runtime::DispatchResult; use sp_runtime::traits::{ - DispatchInfoOf, DispatchOriginOf, Dispatchable, Implication, PostDispatchInfoOf, - TransactionExtension, TransactionExtensionMetadata, ValidateResult, + AsSystemOriginSigner, DispatchInfoOf, DispatchOriginOf, Dispatchable, Implication, + PostDispatchInfoOf, StaticLookup, TransactionExtension, TransactionExtensionMetadata, + ValidateResult, }; use sp_runtime::transaction_validity::{ TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, }; +use sp_std::boxed::Box; use sp_std::vec::Vec; use subtensor_macros::freeze_struct; +type RuntimeCallOf = ::RuntimeCall; +type RuntimeOriginOf = ::RuntimeOrigin; +type AccountIdOf = ::AccountId; +type LookupOf = ::Lookup; + #[freeze_struct("5f10cb9db06873c0")] #[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] @@ -41,64 +51,207 @@ impl ChargeTransactionPaymentWrapper { } } -impl TransactionExtension for ChargeTransactionPaymentWrapper +impl ChargeTransactionPaymentWrapper where - T::RuntimeCall: Dispatchable, + RuntimeCallOf: IsSubType> + IsSubType>, + RuntimeOriginOf: AsSystemOriginSigner> + Clone, +{ + /// Extract (real, delegate, inner_call) from a `proxy` or `proxy_announced` call. + /// For `proxy`, `signer` is used as the delegate since it is implicit (the caller). + fn extract_proxy_parts<'a>( + call: &'a RuntimeCallOf, + signer: &AccountIdOf, + ) -> Option<( + AccountIdOf, + AccountIdOf, + &'a Box<::RuntimeCall>, + )> { + match call.is_sub_type()? { + pallet_proxy::Call::proxy { real, call, .. } => { + let real = LookupOf::::lookup(real.clone()).ok()?; + Some((real, signer.clone(), call)) + } + pallet_proxy::Call::proxy_announced { + delegate, + real, + call, + .. + } => { + let real = LookupOf::::lookup(real.clone()).ok()?; + let delegate = LookupOf::::lookup(delegate.clone()).ok()?; + Some((real, delegate, call)) + } + _ => None, + } + } + + /// Determine who should pay the transaction fee for a proxy call. + /// + /// Follows the RealPaysFee chain up to 2 levels deep: + /// - Case 1: `proxy(real=A, call)` → A pays if `RealPaysFee` + /// - Case 2: `proxy(real=B, proxy(real=A, call))` → A pays if both + /// `RealPaysFee` and `RealPaysFee` are set; B pays if only the former. + /// - Case 3: `proxy(real=B, batch([proxy(real=A, ..), ..]))` → A pays if + /// `RealPaysFee`, all batch items are proxy calls with the same real A, + /// and `RealPaysFee` is set; B pays if only the first condition holds. + /// + /// Returns `None` if the signer should pay (no RealPaysFee opt-in). + fn extract_real_fee_payer( + call: &RuntimeCallOf, + origin: &RuntimeOriginOf, + ) -> Option> { + let signer = origin.as_system_origin_signer()?; + let (outer_real, delegate, inner_call) = Self::extract_proxy_parts(call, signer)?; + + // Check if the outer real account has opted in to pay for the delegate. + if !pallet_proxy::Pallet::::is_real_pays_fee(&outer_real, &delegate) { + return None; + } + + // outer_real pays. Try to push the fee deeper into nested proxy structures. + let inner_call: &RuntimeCallOf = (*inner_call).as_ref().into_ref(); + + // Case 2: inner call is another proxy call. + if let Some(inner_payer) = Self::extract_inner_proxy_payer(inner_call, &outer_real) { + return Some(inner_payer); + } + + // Case 3: inner call is a batch of proxy calls with the same real. + if let Some(batch_payer) = Self::extract_batch_proxy_payer(inner_call, &outer_real) { + return Some(batch_payer); + } + + // Case 1: simple proxy, outer_real pays. + Some(outer_real) + } + + /// Check if an inner call is a proxy call where the inner real has opted in to pay. + /// `outer_real` is used as the implicit delegate for `proxy` calls. + fn extract_inner_proxy_payer( + inner_call: &RuntimeCallOf, + outer_real: &AccountIdOf, + ) -> Option> { + let (inner_real, inner_delegate, _call) = + Self::extract_proxy_parts(inner_call, outer_real)?; + + if pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { + Some(inner_real) + } else { + None + } + } + + /// Check if an inner call is a batch where ALL items are proxy calls with the same real + /// account, and that real account has opted in to pay. + /// `outer_real` is used as the implicit delegate for `proxy` calls within the batch. + fn extract_batch_proxy_payer( + inner_call: &RuntimeCallOf, + outer_real: &AccountIdOf, + ) -> Option> { + let calls: &Vec<::RuntimeCall> = + match inner_call.is_sub_type()? { + pallet_utility::Call::batch { calls } + | pallet_utility::Call::batch_all { calls } + | pallet_utility::Call::force_batch { calls } => calls, + _ => return None, + }; + + if calls.is_empty() { + return None; + } + + let mut common_real: Option> = None; + + for call in calls.iter() { + let call_ref: &RuntimeCallOf = call.into_ref(); + let (inner_real, inner_delegate, _) = Self::extract_proxy_parts(call_ref, outer_real)?; + + // All items must share the same real account. + match &common_real { + None => common_real = Some(inner_real.clone()), + Some(existing) if *existing != inner_real => return None, + _ => {} + } + + if !pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { + return None; + } + } + + common_real + } +} + +impl + TransactionExtension> for ChargeTransactionPaymentWrapper +where + RuntimeCallOf: Dispatchable + + IsSubType> + + IsSubType>, + RuntimeOriginOf: AsSystemOriginSigner> + + Clone + + From>>, { const IDENTIFIER: &'static str = "ChargeTransactionPaymentWrapper"; type Implicit = (); type Val = Val; type Pre = Pre; - fn weight(&self, call: &T::RuntimeCall) -> Weight { + fn weight(&self, call: &RuntimeCallOf) -> Weight { self.charge_transaction_payment.weight(call) } fn validate( &self, - origin: DispatchOriginOf, - call: &T::RuntimeCall, - info: &DispatchInfoOf, + origin: DispatchOriginOf>, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, self_implicit: Self::Implicit, inherited_implication: &impl Implication, source: TransactionSource, - ) -> ValidateResult { - let inner_validate = self.charge_transaction_payment.validate( - origin, - call, - info, - len, - self_implicit, - inherited_implication, - source, - ); - - match inner_validate { - Ok((mut valid_transaction, val, origin)) => { - let overridden_priority = { - let base: TransactionPriority = match info.class { - DispatchClass::Normal => NORMAL_DISPATCH_BASE_PRIORITY, - DispatchClass::Mandatory => NORMAL_DISPATCH_BASE_PRIORITY, - DispatchClass::Operational => OPERATIONAL_DISPATCH_PRIORITY, - }; - base.saturated_into::() - }; - - valid_transaction.priority = overridden_priority; - - Ok((valid_transaction, val, origin)) - } - Err(err) => Err(err), - } + ) -> ValidateResult> { + let overridden_priority = { + let base: TransactionPriority = match info.class { + DispatchClass::Normal => NORMAL_DISPATCH_BASE_PRIORITY, + DispatchClass::Mandatory => NORMAL_DISPATCH_BASE_PRIORITY, + DispatchClass::Operational => OPERATIONAL_DISPATCH_PRIORITY, + }; + base.saturated_into::() + }; + + // If a real account opted in to pay fees, create a synthetic origin for fee validation. + // Otherwise, the signer pays as usual. + let fee_origin = if let Some(real) = Self::extract_real_fee_payer(call, &origin) { + frame_system::RawOrigin::Signed(real).into() + } else { + origin.clone() + }; + + let (mut valid_transaction, val, _fee_origin) = + self.charge_transaction_payment.validate( + fee_origin, + call, + info, + len, + self_implicit, + inherited_implication, + source, + )?; + + valid_transaction.priority = overridden_priority; + + // Always return the original origin so the actual signer remains + // the origin for dispatch and all subsequent extensions. + Ok((valid_transaction, val, origin)) } fn prepare( self, val: Self::Val, - origin: &DispatchOriginOf, - call: &T::RuntimeCall, - info: &DispatchInfoOf, + origin: &DispatchOriginOf>, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, ) -> Result { self.charge_transaction_payment @@ -109,8 +262,8 @@ where } fn post_dispatch_details( pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf>, + post_info: &PostDispatchInfoOf>, len: usize, result: &DispatchResult, ) -> Result { @@ -119,8 +272,8 @@ where fn post_dispatch( pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &mut PostDispatchInfoOf, + info: &DispatchInfoOf>, + post_info: &mut PostDispatchInfoOf>, len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { @@ -128,24 +281,24 @@ where } fn bare_validate( - call: &T::RuntimeCall, - info: &DispatchInfoOf, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, ) -> TransactionValidity { ChargeTransactionPayment::::bare_validate(call, info, len) } fn bare_validate_and_prepare( - call: &T::RuntimeCall, - info: &DispatchInfoOf, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, ) -> Result<(), TransactionValidityError> { ChargeTransactionPayment::::bare_validate_and_prepare(call, info, len) } fn bare_post_dispatch( - info: &DispatchInfoOf, - post_info: &mut PostDispatchInfoOf, + info: &DispatchInfoOf>, + post_info: &mut PostDispatchInfoOf>, len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { From abc0baf5071b66efed6e982c7c30d2e1e2b7a402 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 12:40:06 -0300 Subject: [PATCH 30/43] do not handle proxy_announced + memoize storage read --- runtime/src/transaction_payment_wrapper.rs | 39 +++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 25b030d1a3..7f700f92d3 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -56,8 +56,10 @@ where RuntimeCallOf: IsSubType> + IsSubType>, RuntimeOriginOf: AsSystemOriginSigner> + Clone, { - /// Extract (real, delegate, inner_call) from a `proxy` or `proxy_announced` call. - /// For `proxy`, `signer` is used as the delegate since it is implicit (the caller). + /// Extract (real, delegate, inner_call) from a `proxy` call. + /// `signer` is used as the delegate since it is implicit (the caller). + /// `proxy_announced` is intentionally not handled here; fee propagation + /// only applies to `proxy` calls to keep the logic simple. fn extract_proxy_parts<'a>( call: &'a RuntimeCallOf, signer: &AccountIdOf, @@ -71,16 +73,6 @@ where let real = LookupOf::::lookup(real.clone()).ok()?; Some((real, signer.clone(), call)) } - pallet_proxy::Call::proxy_announced { - delegate, - real, - call, - .. - } => { - let real = LookupOf::::lookup(real.clone()).ok()?; - let delegate = LookupOf::::lookup(delegate.clone()).ok()?; - Some((real, delegate, call)) - } _ => None, } } @@ -164,18 +156,27 @@ where for call in calls.iter() { let call_ref: &RuntimeCallOf = call.into_ref(); - let (inner_real, inner_delegate, _) = Self::extract_proxy_parts(call_ref, outer_real)?; + let (inner_real, inner_delegate, _) = + Self::extract_proxy_parts(call_ref, outer_real)?; - // All items must share the same real account. match &common_real { - None => common_real = Some(inner_real.clone()), + None => { + // Check RealPaysFee once on the first item and memoize. For `proxy` + // calls the delegate is always `outer_real`, so a single read covers + // the entire batch; for `proxy_announced` it uses the explicit delegate. + if !pallet_proxy::Pallet::::is_real_pays_fee( + &inner_real, + &inner_delegate, + ) + { + return None; + } + common_real = Some(inner_real); + } + // All items must share the same real account. Some(existing) if *existing != inner_real => return None, _ => {} } - - if !pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { - return None; - } } common_real From cbad8e693322e1d3b6236f800571bdbfd23c80b2 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 12:40:12 -0300 Subject: [PATCH 31/43] added tests --- runtime/tests/transaction_payment_wrapper.rs | 464 +++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 runtime/tests/transaction_payment_wrapper.rs diff --git a/runtime/tests/transaction_payment_wrapper.rs b/runtime/tests/transaction_payment_wrapper.rs new file mode 100644 index 0000000000..99c8254ed8 --- /dev/null +++ b/runtime/tests/transaction_payment_wrapper.rs @@ -0,0 +1,464 @@ +#![allow(clippy::unwrap_used)] + +use frame_support::{ + assert_ok, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, +}; +use node_subtensor_runtime::{ + BuildStorage, Proxy, Runtime, RuntimeCall, RuntimeGenesisConfig, RuntimeOrigin, System, + SystemCall, transaction_payment_wrapper, NORMAL_DISPATCH_BASE_PRIORITY, + OPERATIONAL_DISPATCH_PRIORITY, +}; +use pallet_subtensor_proxy as pallet_proxy; +use pallet_subtensor_utility as pallet_utility; +use pallet_transaction_payment::{ChargeTransactionPayment, Val}; +use sp_runtime::traits::{TransactionExtension, TxBaseImplication}; +use sp_runtime::transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}; +use subtensor_runtime_common::{AccountId, ProxyType}; + +const SIGNER: [u8; 32] = [1_u8; 32]; +const REAL_A: [u8; 32] = [2_u8; 32]; +const REAL_B: [u8; 32] = [3_u8; 32]; +const OTHER: [u8; 32] = [4_u8; 32]; +const BALANCE: u64 = 1_000_000_000_000; + +fn new_test_ext() -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut ext: sp_io::TestExternalities = RuntimeGenesisConfig { + balances: pallet_balances::GenesisConfig { + balances: vec![ + (AccountId::from(SIGNER), BALANCE), + (AccountId::from(REAL_A), BALANCE), + (AccountId::from(REAL_B), BALANCE), + (AccountId::from(OTHER), BALANCE), + ], + dev_accounts: None, + }, + ..Default::default() + } + .build_storage() + .unwrap() + .into(); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +fn signer() -> AccountId { + AccountId::from(SIGNER) +} +fn real_a() -> AccountId { + AccountId::from(REAL_A) +} +fn real_b() -> AccountId { + AccountId::from(REAL_B) +} +fn other() -> AccountId { + AccountId::from(OTHER) +} + +// -- Call builders -- + +fn call_remark() -> RuntimeCall { + RuntimeCall::System(SystemCall::remark { + remark: vec![1, 2, 3], + }) +} + +fn proxy_call(real: AccountId, inner: RuntimeCall) -> RuntimeCall { + RuntimeCall::Proxy(pallet_proxy::Call::proxy { + real: real.into(), + force_proxy_type: None, + call: Box::new(inner), + }) +} + +fn proxy_announced_call(delegate: AccountId, real: AccountId, inner: RuntimeCall) -> RuntimeCall { + RuntimeCall::Proxy(pallet_proxy::Call::proxy_announced { + delegate: delegate.into(), + real: real.into(), + force_proxy_type: None, + call: Box::new(inner), + }) +} + +fn batch_call(calls: Vec) -> RuntimeCall { + RuntimeCall::Utility(pallet_utility::Call::batch { calls }) +} + +fn batch_all_call(calls: Vec) -> RuntimeCall { + RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) +} + +fn force_batch_call(calls: Vec) -> RuntimeCall { + RuntimeCall::Utility(pallet_utility::Call::force_batch { calls }) +} + +// -- Setup helpers -- + +fn add_proxy(real: &AccountId, delegate: &AccountId) { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(real.clone()), + delegate.clone().into(), + ProxyType::Any, + 0, + )); +} + +fn enable_real_pays_fee(real: &AccountId, delegate: &AccountId) { + assert_ok!(Proxy::set_real_pays_fee( + RuntimeOrigin::signed(real.clone()), + delegate.clone().into(), + true, + )); +} + +// -- Validate helpers -- + +fn validate_call( + origin: RuntimeOrigin, + call: &RuntimeCall, +) -> Result<(ValidTransaction, Val), TransactionValidityError> { + validate_call_with_info(origin, call, &call.get_dispatch_info()) +} + +fn validate_call_with_info( + origin: RuntimeOrigin, + call: &RuntimeCall, + info: &DispatchInfo, +) -> Result<(ValidTransaction, Val), TransactionValidityError> { + let ext = transaction_payment_wrapper::ChargeTransactionPaymentWrapper::::new( + ChargeTransactionPayment::from(0u64), + ); + let (valid_tx, val, _origin) = ext.validate( + origin, + call, + info, + 100, + (), + &TxBaseImplication(()), + TransactionSource::External, + )?; + Ok((valid_tx, val)) +} + +/// Extract the fee payer from the validate result. +fn fee_payer(val: &Val) -> AccountId { + match val { + Val::Charge { who, .. } => who.clone(), + _ => panic!("expected Val::Charge"), + } +} + +// ============================================================ +// Case 0: Non-proxy calls +// ============================================================ + +#[test] +fn non_proxy_call_charges_signer() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +// ============================================================ +// Case 1: Simple proxy (1 level) +// ============================================================ + +#[test] +fn simple_proxy_charges_real_when_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &signer()); + enable_real_pays_fee(&real_a(), &signer()); + + let call = proxy_call(real_a(), call_remark()); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn simple_proxy_charges_signer_when_not_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &signer()); + // No enable_real_pays_fee + + let call = proxy_call(real_a(), call_remark()); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +#[test] +fn proxy_announced_always_charges_signer() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + // Fee propagation intentionally ignores proxy_announced; signer always pays. + let call = proxy_announced_call(real_b(), real_a(), call_remark()); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +// ============================================================ +// Case 2: Nested proxy (2 levels) +// ============================================================ + +#[test] +fn nested_proxy_charges_inner_real_when_both_opted_in() { + new_test_ext().execute_with(|| { + // Chain: signer → real_b → real_a + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn nested_proxy_charges_outer_real_when_only_outer_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // No enable_real_pays_fee for A→B + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn nested_proxy_charges_signer_when_neither_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // No enable_real_pays_fee at all + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +#[test] +fn nested_proxy_charges_signer_when_only_inner_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + // No enable_real_pays_fee for B→signer + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + // Outer RealPaysFee not set → signer pays (inner opt-in is irrelevant) + assert_eq!(fee_payer(&val), signer()); + }); +} + +// ============================================================ +// Case 3: Batch of proxy calls +// ============================================================ + +#[test] +fn batch_charges_inner_real_when_all_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn batch_all_charges_inner_real_when_all_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let batch = batch_all_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn force_batch_charges_inner_real_when_all_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let batch = force_batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn batch_charges_outer_real_when_only_outer_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // No enable_real_pays_fee for A→B + + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_mixed_inner_reals() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + add_proxy(&other(), &real_b()); + enable_real_pays_fee(&other(), &real_b()); + + // Different inner reals → can't push deeper + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(other(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_non_proxy_in_batch() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + + // Batch contains a non-proxy call → extract_proxy_parts fails + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + call_remark(), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_empty() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + + let batch = batch_call(vec![]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_inner_real_not_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // real_a has NOT opted in to pay for real_b + + // Even with same real in all batch items, if RealPaysFee not set → outer_real pays + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +// ============================================================ +// Priority override +// ============================================================ + +#[test] +fn priority_override_normal_dispatch() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let (valid_tx, _val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(valid_tx.priority, NORMAL_DISPATCH_BASE_PRIORITY); + }); +} + +#[test] +fn priority_override_operational_dispatch() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let mut info = call.get_dispatch_info(); + info.class = DispatchClass::Operational; + + let (valid_tx, _val) = + validate_call_with_info(RuntimeOrigin::signed(signer()), &call, &info).unwrap(); + assert_eq!(valid_tx.priority, OPERATIONAL_DISPATCH_PRIORITY); + }); +} + +#[test] +fn priority_override_mandatory_dispatch() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let mut info = call.get_dispatch_info(); + info.class = DispatchClass::Mandatory; + + let (valid_tx, _val) = + validate_call_with_info(RuntimeOrigin::signed(signer()), &call, &info).unwrap(); + // Mandatory uses the same base as Normal + assert_eq!(valid_tx.priority, NORMAL_DISPATCH_BASE_PRIORITY); + }); +} + +#[test] +fn priority_override_applies_with_real_pays_fee() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &signer()); + enable_real_pays_fee(&real_a(), &signer()); + + let call = proxy_call(real_a(), call_remark()); + let (valid_tx, _val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + // Priority override should still apply when real pays fee + assert_eq!(valid_tx.priority, NORMAL_DISPATCH_BASE_PRIORITY); + }); +} From 8578ad3ba369a730474db84ed98eeda44f03027a Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 13:58:17 -0300 Subject: [PATCH 32/43] added additional weights to extension --- runtime/src/transaction_payment_wrapper.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 7f700f92d3..a9d6f60b76 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -199,7 +199,11 @@ where type Pre = Pre; fn weight(&self, call: &RuntimeCallOf) -> Weight { - self.charge_transaction_payment.weight(call) + // Account for up to 3 storage reads in the worst-case fee payer resolution + // (outer is_real_pays_fee + inner/batch is_real_pays_fee + margin). + self.charge_transaction_payment + .weight(call) + .saturating_add(T::DbWeight::get().reads(3)) } fn validate( From f22315dc34f96243a1405a6313b2560785709b92 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 13:58:36 -0300 Subject: [PATCH 33/43] cargo fmt --- runtime/src/transaction_payment_wrapper.rs | 28 ++++++++------------ runtime/tests/transaction_payment_wrapper.rs | 15 +++++------ 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index a9d6f60b76..6246af6b9e 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -156,19 +156,14 @@ where for call in calls.iter() { let call_ref: &RuntimeCallOf = call.into_ref(); - let (inner_real, inner_delegate, _) = - Self::extract_proxy_parts(call_ref, outer_real)?; + let (inner_real, inner_delegate, _) = Self::extract_proxy_parts(call_ref, outer_real)?; match &common_real { None => { // Check RealPaysFee once on the first item and memoize. For `proxy` // calls the delegate is always `outer_real`, so a single read covers // the entire batch; for `proxy_announced` it uses the explicit delegate. - if !pallet_proxy::Pallet::::is_real_pays_fee( - &inner_real, - &inner_delegate, - ) - { + if !pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { return None; } common_real = Some(inner_real); @@ -233,16 +228,15 @@ where origin.clone() }; - let (mut valid_transaction, val, _fee_origin) = - self.charge_transaction_payment.validate( - fee_origin, - call, - info, - len, - self_implicit, - inherited_implication, - source, - )?; + let (mut valid_transaction, val, _fee_origin) = self.charge_transaction_payment.validate( + fee_origin, + call, + info, + len, + self_implicit, + inherited_implication, + source, + )?; valid_transaction.priority = overridden_priority; diff --git a/runtime/tests/transaction_payment_wrapper.rs b/runtime/tests/transaction_payment_wrapper.rs index 99c8254ed8..639e8b3576 100644 --- a/runtime/tests/transaction_payment_wrapper.rs +++ b/runtime/tests/transaction_payment_wrapper.rs @@ -5,15 +5,17 @@ use frame_support::{ dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, }; use node_subtensor_runtime::{ - BuildStorage, Proxy, Runtime, RuntimeCall, RuntimeGenesisConfig, RuntimeOrigin, System, - SystemCall, transaction_payment_wrapper, NORMAL_DISPATCH_BASE_PRIORITY, - OPERATIONAL_DISPATCH_PRIORITY, + BuildStorage, NORMAL_DISPATCH_BASE_PRIORITY, OPERATIONAL_DISPATCH_PRIORITY, Proxy, Runtime, + RuntimeCall, RuntimeGenesisConfig, RuntimeOrigin, System, SystemCall, + transaction_payment_wrapper, }; use pallet_subtensor_proxy as pallet_proxy; use pallet_subtensor_utility as pallet_utility; use pallet_transaction_payment::{ChargeTransactionPayment, Val}; use sp_runtime::traits::{TransactionExtension, TxBaseImplication}; -use sp_runtime::transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}; +use sp_runtime::transaction_validity::{ + TransactionSource, TransactionValidityError, ValidTransaction, +}; use subtensor_runtime_common::{AccountId, ProxyType}; const SIGNER: [u8; 32] = [1_u8; 32]; @@ -368,10 +370,7 @@ fn batch_charges_outer_real_when_non_proxy_in_batch() { enable_real_pays_fee(&real_b(), &signer()); // Batch contains a non-proxy call → extract_proxy_parts fails - let batch = batch_call(vec![ - proxy_call(real_a(), call_remark()), - call_remark(), - ]); + let batch = batch_call(vec![proxy_call(real_a(), call_remark()), call_remark()]); let call = proxy_call(real_b(), batch); let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); assert_eq!(fee_payer(&val), real_b()); From 4ec43ec4eb21cd930a2046e5d30177791f4c648e Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 15:18:15 -0300 Subject: [PATCH 34/43] add missing import --- runtime/src/transaction_payment_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 6246af6b9e..7973c44caf 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -3,7 +3,7 @@ use codec::{Decode, DecodeWithMemTracking, Encode}; use frame_election_provider_support::private::sp_arithmetic::traits::SaturatedConversion; use frame_support::dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}; use frame_support::pallet_prelude::TypeInfo; -use frame_support::traits::{IsSubType, IsType}; +use frame_support::traits::{Get, IsSubType, IsType}; use pallet_subtensor_proxy as pallet_proxy; use pallet_subtensor_utility as pallet_utility; use pallet_transaction_payment::{ChargeTransactionPayment, Config, Pre, Val}; From e8436a1b6b6956d2842883183a8505229776676c Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 15:52:23 -0300 Subject: [PATCH 35/43] added pallet proxy to benchmarks --- runtime/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b324934caa..41a00e3f64 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1698,6 +1698,7 @@ mod benches { [pallet_crowdloan, Crowdloan] [pallet_subtensor_swap, Swap] [pallet_shield, MevShield] + [pallet_subtensor_proxy, Proxy] ); } From 57e2796529bced0a54c01cbd5f1162f7995deaa7 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 20:12:27 +0100 Subject: [PATCH 36/43] benchmark the proxy pallet with new extrinsic --- pallets/proxy/src/weights.rs | 529 +++++++++++++++++++---------------- 1 file changed, 290 insertions(+), 239 deletions(-) diff --git a/pallets/proxy/src/weights.rs b/pallets/proxy/src/weights.rs index 6a14c7de2c..d8f463497f 100644 --- a/pallets/proxy/src/weights.rs +++ b/pallets/proxy/src/weights.rs @@ -17,42 +17,40 @@ //! Autogenerated weights for `pallet_proxy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-03-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 49.1.0 +//! DATE: 2026-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `99fc4dfa9c86`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `Ubuntu-2404-noble-amd64-base`, CPU: `AMD Ryzen 9 5950X 16-Core Processor` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` // Executed Command: -// frame-omni-bencher -// v1 +// ./target/production/node-subtensor // benchmark // pallet // --extrinsic=* -// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm -// --pallet=pallet_proxy -// --header=/__w/polkadot-sdk/polkadot-sdk/substrate/HEADER-APACHE2 -// --output=/__w/polkadot-sdk/polkadot-sdk/substrate/frame/proxy/src/weights.rs +// --runtime=target/production/wbuild/node-subtensor-runtime/node_subtensor_runtime.wasm +// --genesis-builder=runtime +// --genesis-builder-preset=benchmark +// --pallet=pallet_subtensor_proxy +// --output=pallets/proxy/src/weights.rs // --wasm-execution=compiled // --steps=50 // --repeat=20 // --heap-pages=4096 -// --template=substrate/.maintain/frame-umbrella-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs // --no-storage-info // --no-min-squares // --no-median-slopes -// --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic,pallet_nomination_pools,pallet_remark,pallet_transaction_storage,pallet_election_provider_multi_block,pallet_election_provider_multi_block::signed,pallet_election_provider_multi_block::unsigned,pallet_election_provider_multi_block::verifier #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -#![allow(dead_code)] -use crate as pallet_proxy; -use frame::weights_prelude::*; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; -/// Weight functions needed for `pallet_proxy`. +/// Weight functions needed for `pallet_subtensor_proxy`. pub trait WeightInfo { fn proxy(p: u32, ) -> Weight; fn proxy_announced(a: u32, p: u32, ) -> Weight; @@ -65,385 +63,438 @@ pub trait WeightInfo { fn create_pure(p: u32, ) -> Weight; fn kill_pure(p: u32, ) -> Weight; fn poke_deposit() -> Weight; + fn set_real_pays_fee(p: u32, ) -> Weight; } -/// Weights for `pallet_proxy` using the Substrate node and recommended hardware. +/// Weights for `pallet_subtensor_proxy` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `339 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_353_000 picoseconds. - Weight::from_parts(25_084_085, 4706) - // Standard Error: 2_569 - .saturating_add(Weight::from_parts(33_574, 0).saturating_mul(p.into())) + // Measured: `625 + p * (37 ±0)` + // Estimated: `4254 + p * (37 ±0)` + // Minimum execution time: 19_346_000 picoseconds. + Weight::from_parts(19_857_012, 4254) + // Standard Error: 1_610 + .saturating_add(Weight::from_parts(42_156, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `666 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 47_196_000 picoseconds. - Weight::from_parts(48_686_812, 5698) - // Standard Error: 3_711 - .saturating_add(Weight::from_parts(171_107, 0).saturating_mul(a.into())) - // Standard Error: 3_834 - .saturating_add(Weight::from_parts(34_523, 0).saturating_mul(p.into())) + // Measured: `882 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615 + a * (68 ±0) + p * (37 ±0)` + // Minimum execution time: 37_952_000 picoseconds. + Weight::from_parts(37_943_137, 8615) + // Standard Error: 994 + .saturating_add(Weight::from_parts(155_667, 0).saturating_mul(a.into())) + // Standard Error: 3_984 + .saturating_add(Weight::from_parts(20_119, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 68).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 29_341_000 picoseconds. - Weight::from_parts(30_320_504, 5698) - // Standard Error: 1_821 - .saturating_add(Weight::from_parts(158_572, 0).saturating_mul(a.into())) - // Standard Error: 1_881 - .saturating_add(Weight::from_parts(8_433, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 18_064_000 picoseconds. + Weight::from_parts(18_046_024, 8615) + // Standard Error: 690 + .saturating_add(Weight::from_parts(130_637, 0).saturating_mul(a.into())) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(27_361, 0).saturating_mul(p.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(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 28_422_000 picoseconds. - Weight::from_parts(29_754_384, 5698) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(176_827, 0).saturating_mul(a.into())) - // Standard Error: 1_901 - .saturating_add(Weight::from_parts(9_607, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 17_964_000 picoseconds. + Weight::from_parts(18_288_524, 8615) + // Standard Error: 953 + .saturating_add(Weight::from_parts(136_907, 0).saturating_mul(a.into())) + // Standard Error: 3_819 + .saturating_add(Weight::from_parts(11_084, 0).saturating_mul(p.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(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `453 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 36_885_000 picoseconds. - Weight::from_parts(38_080_636, 5698) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(157_335, 0).saturating_mul(a.into())) - // Standard Error: 2_730 - .saturating_add(Weight::from_parts(28_872, 0).saturating_mul(p.into())) + // Measured: `308 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615` + // Minimum execution time: 23_855_000 picoseconds. + Weight::from_parts(23_721_196, 8615) + // Standard Error: 813 + .saturating_add(Weight::from_parts(135_522, 0).saturating_mul(a.into())) + // Standard Error: 3_256 + .saturating_add(Weight::from_parts(42_377, 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(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 27_016_000 picoseconds. - Weight::from_parts(28_296_216, 4706) - // Standard Error: 1_643 - .saturating_add(Weight::from_parts(50_271, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_854_000 picoseconds. + Weight::from_parts(18_203_947, 4254) + // Standard Error: 1_051 + .saturating_add(Weight::from_parts(44_781, 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(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 26_955_000 picoseconds. - Weight::from_parts(28_379_566, 4706) - // Standard Error: 1_547 - .saturating_add(Weight::from_parts(45_784, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_815_000 picoseconds. + Weight::from_parts(19_464_499, 4254) + // Standard Error: 1_215 + .saturating_add(Weight::from_parts(44_540, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_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(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 24_656_000 picoseconds. - Weight::from_parts(25_821_878, 4706) - // Standard Error: 2_300 - .saturating_add(Weight::from_parts(33_972, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_245_000 picoseconds. + Weight::from_parts(18_987_977, 4254) + // Standard Error: 1_120 + .saturating_add(Weight::from_parts(18_728, 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(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `4706` - // Minimum execution time: 28_416_000 picoseconds. - Weight::from_parts(29_662_728, 4706) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(29_928, 0).saturating_mul(p.into())) + // Measured: `139` + // Estimated: `4254` + // Minimum execution time: 18_836_000 picoseconds. + Weight::from_parts(19_336_942, 4254) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(17_419, 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(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[0, 30]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 18]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `231 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_505_000 picoseconds. - Weight::from_parts(26_780_627, 4706) - // Standard Error: 1_581 - .saturating_add(Weight::from_parts(33_085, 0).saturating_mul(p.into())) + // Measured: `156 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_853_000 picoseconds. + Weight::from_parts(18_593_111, 4254) + // Standard Error: 990 + .saturating_add(Weight::from_parts(23_569, 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(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `519` - // Estimated: `5698` - // Minimum execution time: 46_733_000 picoseconds. - Weight::from_parts(47_972_000, 5698) + // Measured: `412` + // Estimated: `8615` + // Minimum execution time: 31_739_000 picoseconds. + Weight::from_parts(32_491_000, 8615) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. + fn set_real_pays_fee(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 9_568_000 picoseconds. + Weight::from_parts(10_007_076, 4254) + // Standard Error: 854 + .saturating_add(Weight::from_parts(24_307, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests. impl WeightInfo for () { /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `339 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_353_000 picoseconds. - Weight::from_parts(25_084_085, 4706) - // Standard Error: 2_569 - .saturating_add(Weight::from_parts(33_574, 0).saturating_mul(p.into())) + // Measured: `625 + p * (37 ±0)` + // Estimated: `4254 + p * (37 ±0)` + // Minimum execution time: 19_346_000 picoseconds. + Weight::from_parts(19_857_012, 4254) + // Standard Error: 1_610 + .saturating_add(Weight::from_parts(42_156, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `666 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 47_196_000 picoseconds. - Weight::from_parts(48_686_812, 5698) - // Standard Error: 3_711 - .saturating_add(Weight::from_parts(171_107, 0).saturating_mul(a.into())) - // Standard Error: 3_834 - .saturating_add(Weight::from_parts(34_523, 0).saturating_mul(p.into())) + // Measured: `882 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615 + a * (68 ±0) + p * (37 ±0)` + // Minimum execution time: 37_952_000 picoseconds. + Weight::from_parts(37_943_137, 8615) + // Standard Error: 994 + .saturating_add(Weight::from_parts(155_667, 0).saturating_mul(a.into())) + // Standard Error: 3_984 + .saturating_add(Weight::from_parts(20_119, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 68).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 29_341_000 picoseconds. - Weight::from_parts(30_320_504, 5698) - // Standard Error: 1_821 - .saturating_add(Weight::from_parts(158_572, 0).saturating_mul(a.into())) - // Standard Error: 1_881 - .saturating_add(Weight::from_parts(8_433, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 18_064_000 picoseconds. + Weight::from_parts(18_046_024, 8615) + // Standard Error: 690 + .saturating_add(Weight::from_parts(130_637, 0).saturating_mul(a.into())) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(27_361, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 28_422_000 picoseconds. - Weight::from_parts(29_754_384, 5698) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(176_827, 0).saturating_mul(a.into())) - // Standard Error: 1_901 - .saturating_add(Weight::from_parts(9_607, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 17_964_000 picoseconds. + Weight::from_parts(18_288_524, 8615) + // Standard Error: 953 + .saturating_add(Weight::from_parts(136_907, 0).saturating_mul(a.into())) + // Standard Error: 3_819 + .saturating_add(Weight::from_parts(11_084, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `453 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 36_885_000 picoseconds. - Weight::from_parts(38_080_636, 5698) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(157_335, 0).saturating_mul(a.into())) - // Standard Error: 2_730 - .saturating_add(Weight::from_parts(28_872, 0).saturating_mul(p.into())) + // Measured: `308 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615` + // Minimum execution time: 23_855_000 picoseconds. + Weight::from_parts(23_721_196, 8615) + // Standard Error: 813 + .saturating_add(Weight::from_parts(135_522, 0).saturating_mul(a.into())) + // Standard Error: 3_256 + .saturating_add(Weight::from_parts(42_377, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 27_016_000 picoseconds. - Weight::from_parts(28_296_216, 4706) - // Standard Error: 1_643 - .saturating_add(Weight::from_parts(50_271, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_854_000 picoseconds. + Weight::from_parts(18_203_947, 4254) + // Standard Error: 1_051 + .saturating_add(Weight::from_parts(44_781, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 26_955_000 picoseconds. - Weight::from_parts(28_379_566, 4706) - // Standard Error: 1_547 - .saturating_add(Weight::from_parts(45_784, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_815_000 picoseconds. + Weight::from_parts(19_464_499, 4254) + // Standard Error: 1_215 + .saturating_add(Weight::from_parts(44_540, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 24_656_000 picoseconds. - Weight::from_parts(25_821_878, 4706) - // Standard Error: 2_300 - .saturating_add(Weight::from_parts(33_972, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_245_000 picoseconds. + Weight::from_parts(18_987_977, 4254) + // Standard Error: 1_120 + .saturating_add(Weight::from_parts(18_728, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `4706` - // Minimum execution time: 28_416_000 picoseconds. - Weight::from_parts(29_662_728, 4706) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(29_928, 0).saturating_mul(p.into())) + // Measured: `139` + // Estimated: `4254` + // Minimum execution time: 18_836_000 picoseconds. + Weight::from_parts(19_336_942, 4254) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(17_419, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[0, 30]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 18]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `231 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_505_000 picoseconds. - Weight::from_parts(26_780_627, 4706) - // Standard Error: 1_581 - .saturating_add(Weight::from_parts(33_085, 0).saturating_mul(p.into())) + // Measured: `156 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_853_000 picoseconds. + Weight::from_parts(18_593_111, 4254) + // Standard Error: 990 + .saturating_add(Weight::from_parts(23_569, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `519` - // Estimated: `5698` - // Minimum execution time: 46_733_000 picoseconds. - Weight::from_parts(47_972_000, 5698) + // Measured: `412` + // Estimated: `8615` + // Minimum execution time: 31_739_000 picoseconds. + Weight::from_parts(32_491_000, 8615) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } -} + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. + fn set_real_pays_fee(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 9_568_000 picoseconds. + Weight::from_parts(10_007_076, 4254) + // Standard Error: 854 + .saturating_add(Weight::from_parts(24_307, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} \ No newline at end of file From eb4072cd0385e7cdf33471db20b3937f24d7250d Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 16:19:37 -0300 Subject: [PATCH 37/43] fix missing imports --- Cargo.lock | 2 ++ pallets/proxy/Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index cfb96c21d6..0b2a387c2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10781,6 +10781,8 @@ dependencies = [ name = "pallet-subtensor-proxy" version = "40.1.0" dependencies = [ + "frame-support", + "frame-system", "pallet-balances", "pallet-subtensor-utility", "parity-scale-codec", diff --git a/pallets/proxy/Cargo.toml b/pallets/proxy/Cargo.toml index 3d8da72029..9a7fd5b78e 100644 --- a/pallets/proxy/Cargo.toml +++ b/pallets/proxy/Cargo.toml @@ -19,6 +19,8 @@ codec = { workspace = true, features = ["max-encoded-len"] } frame = { workspace = true, features = ["runtime"] } scale-info = { workspace = true, features = ["derive"] } subtensor-macros.workspace = true +frame-system.workspace = true +frame-support.workspace = true [dev-dependencies] pallet-balances = { default-features = true, workspace = true } From 727243f27648673f1c77a68fe99f3a6ae43ce397 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 16:51:34 -0300 Subject: [PATCH 38/43] fix zepter check --- pallets/proxy/Cargo.toml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pallets/proxy/Cargo.toml b/pallets/proxy/Cargo.toml index 9a7fd5b78e..9331739325 100644 --- a/pallets/proxy/Cargo.toml +++ b/pallets/proxy/Cargo.toml @@ -28,14 +28,24 @@ pallet-subtensor-utility = { default-features = true, workspace = true } [features] default = ["std"] -std = ["codec/std", "frame/std", "scale-info/std"] +std = [ + "codec/std", + "frame/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", +] runtime-benchmarks = [ "frame/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-subtensor-utility/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] try-runtime = [ "frame/try-runtime", "pallet-balances/try-runtime", "pallet-subtensor-utility/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", ] From 2423d5c41b347c70242c0428d1f897523746f4b0 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Fri, 27 Feb 2026 17:01:39 -0500 Subject: [PATCH 39/43] Use mortal era for all transactions --- runtime/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b324934caa..95670892a7 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -164,13 +164,20 @@ impl frame_system::offchain::CreateSignedTransaction ) -> Option { use sp_runtime::traits::StaticLookup; + // Transaction validity period from block hash included in signature + // Has to a power of 2. 256 blocks yields to 3072 s = 51.2 minutes. + let validity_period = 256_u64; + let current_block = frame_system::Pallet::::block_number(); + // Transaction validity era starts at the current block + let era = Era::mortal(validity_period, current_block as u64); + let address = ::Lookup::unlookup(account.clone()); let extra: TransactionExtensions = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(Era::Immortal), + frame_system::CheckEra::::from(era), check_nonce::CheckNonce::::from(nonce).into(), frame_system::CheckWeight::::new(), ChargeTransactionPaymentWrapper::new( From 0c3ad434e8c0d82fb1a8adb20f4fbb4a71a38ff5 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Fri, 27 Feb 2026 17:05:18 -0500 Subject: [PATCH 40/43] Revert "Use mortal era for all transactions" This reverts commit 2423d5c41b347c70242c0428d1f897523746f4b0. --- runtime/src/lib.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 95670892a7..b324934caa 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -164,20 +164,13 @@ impl frame_system::offchain::CreateSignedTransaction ) -> Option { use sp_runtime::traits::StaticLookup; - // Transaction validity period from block hash included in signature - // Has to a power of 2. 256 blocks yields to 3072 s = 51.2 minutes. - let validity_period = 256_u64; - let current_block = frame_system::Pallet::::block_number(); - // Transaction validity era starts at the current block - let era = Era::mortal(validity_period, current_block as u64); - let address = ::Lookup::unlookup(account.clone()); let extra: TransactionExtensions = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(era), + frame_system::CheckEra::::from(Era::Immortal), check_nonce::CheckNonce::::from(nonce).into(), frame_system::CheckWeight::::new(), ChargeTransactionPaymentWrapper::new( From 9d0d787eba1c1079f2032986a51d7be0ad7b7e3a Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Fri, 27 Feb 2026 19:16:58 +0100 Subject: [PATCH 41/43] Fix benchmarks --- pallets/admin-utils/src/benchmarking.rs | 4 +- pallets/admin-utils/src/lib.rs | 2 +- pallets/admin-utils/src/tests/mod.rs | 2 +- pallets/subtensor/src/benchmarks.rs | 123 +++++++++++++++++------- pallets/subtensor/src/lib.rs | 6 +- 5 files changed, 95 insertions(+), 42 deletions(-) diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 9cab4894e9..1a16c1f721 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -18,6 +18,8 @@ use super::*; #[benchmarks] mod benchmarks { use super::*; + #[cfg(test)] + use crate::tests::mock; use subtensor_runtime_common::NetUid; #[benchmark] @@ -651,5 +653,5 @@ mod benchmarks { ); /* sudo_set_min_non_immune_uids() */ } - //impl_benchmark_test_suite!(AdminUtils, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(AdminUtils, mock::new_test_ext(), mock::Test); } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 654f7207b8..532bb50227 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -14,7 +14,7 @@ use sp_runtime::{DispatchResult, RuntimeAppPublic, Vec, traits::Member}; mod benchmarking; #[cfg(test)] -mod tests; +pub(crate) mod tests; #[deny(missing_docs)] #[frame_support::pallet] diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index f87ba31bba..be86489446 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -23,7 +23,7 @@ use crate::Error; use crate::pallet::PrecompileEnable; use mock::*; -mod mock; +pub(crate) mod mock; #[test] fn test_sudo_set_default_take() { diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index b370b6dbe1..b9abd4e3ee 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -26,6 +26,21 @@ use subtensor_runtime_common::{AlphaCurrency, NetUid, TaoCurrency}; mod pallet_benchmarks { use super::*; + fn seed_swap_reserves(netuid: NetUid) { + let tao_reserve = TaoCurrency::from(150_000_000_000); + let alpha_in = AlphaCurrency::from(100_000_000_000); + set_reserves::(netuid, tao_reserve, alpha_in); + } + + fn set_reserves(netuid: NetUid, tao_reserve: TaoCurrency, alpha_in: AlphaCurrency) { + SubnetTAO::::insert(netuid, tao_reserve); + SubnetAlphaIn::::insert(netuid, alpha_in); + } + + fn benchmark_registration_burn() -> TaoCurrency { + TaoCurrency::from(1_000_000) + } + #[benchmark] fn register() { let netuid = NetUid::from(1); @@ -36,6 +51,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_network_pow_registration_allowed(netuid, true); + Subtensor::::set_difficulty(netuid, 1); let block_number: u64 = Subtensor::::get_current_block_as_u64(); let (nonce, work): (u64, Vec) = @@ -66,6 +82,7 @@ mod pallet_benchmarks { Subtensor::::set_max_registrations_per_block(netuid, 4096); Subtensor::::set_target_registrations_per_interval(netuid, 4096); Subtensor::::set_commit_reveal_weights_enabled(netuid, false); + Subtensor::::set_weights_set_rate_limit(netuid, 0); let mut seed: u32 = 1; let mut dests = Vec::new(); @@ -77,7 +94,8 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); seed += 1; - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); + seed_swap_reserves::(netuid); let amount_to_be_staked: u64 = 1_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); @@ -110,7 +128,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); @@ -120,6 +138,7 @@ mod pallet_benchmarks { let total_stake = TaoCurrency::from(1_000_000_000); let amount = TaoCurrency::from(60_000_000); + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&coldkey, total_stake.into()); assert_ok!(Subtensor::::do_burned_registration( RawOrigin::Signed(coldkey.clone()).into(), @@ -154,6 +173,7 @@ mod pallet_benchmarks { let reg_fee = Subtensor::::get_burn(netuid); let deposit = reg_fee.saturating_mul(2.into()); + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&caller, deposit.into()); assert_ok!(Subtensor::::do_burned_registration( @@ -192,6 +212,7 @@ mod pallet_benchmarks { let reg_fee = Subtensor::::get_burn(netuid); let deposit = reg_fee.saturating_mul(2.into()); + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&caller, deposit.into()); assert_ok!(Subtensor::::do_burned_registration( @@ -221,7 +242,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); let amount: u64 = 1_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount); @@ -239,12 +260,18 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); assert_eq!(Subtensor::::get_max_allowed_uids(netuid), 4096); + Subtensor::::init_new_network(NetUid::ROOT, 1); + Subtensor::::set_network_registration_allowed(NetUid::ROOT, true); + Subtensor::::set_network_pow_registration_allowed(NetUid::ROOT, true); + FirstEmissionBlockNumber::::insert(NetUid::ROOT, 1); + SubtokenEnabled::::insert(NetUid::ROOT, true); let amount: u64 = 100_000_000_000_000; + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&coldkey, amount); assert_ok!(Subtensor::::do_burned_registration( @@ -292,6 +319,8 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); Subtensor::::set_network_pow_registration_allowed(netuid, true); + Subtensor::::set_weights_set_rate_limit(netuid, 0); + Subtensor::::set_difficulty(netuid, 1); let block_number: u64 = Subtensor::::get_current_block_as_u64(); let (nonce, work) = Subtensor::::create_work_for_block_number( @@ -330,6 +359,8 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_network_pow_registration_allowed(netuid, true); + Subtensor::::set_weights_set_rate_limit(netuid, 0); + Subtensor::::set_difficulty(netuid, 1); let block_number: u64 = Subtensor::::get_current_block_as_u64(); let (nonce, work) = @@ -356,11 +387,19 @@ mod pallet_benchmarks { salt.clone(), version_key, )); - let _ = Subtensor::::commit_weights( + let commit_block = Subtensor::::get_current_block_as_u64(); + assert_ok!(Subtensor::::commit_weights( RawOrigin::Signed(hotkey.clone()).into(), netuid, commit_hash, - ); + )); + + let (first_reveal_block, _) = Subtensor::::get_reveal_blocks(netuid, commit_block); + let reveal_block: BlockNumberFor = first_reveal_block + .try_into() + .ok() + .expect("can't convert to block number"); + frame_system::Pallet::::set_block_number(reveal_block); #[extrinsic_call] _( @@ -394,6 +433,7 @@ mod pallet_benchmarks { let reg_fee = Subtensor::::get_burn(netuid); let deposit = reg_fee.saturating_mul(2.into()); + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit.into()); assert_ok!(Subtensor::::do_burned_registration( @@ -441,6 +481,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_network_pow_registration_allowed(netuid, true); + Subtensor::::set_difficulty(netuid, 1); let block_number = Subtensor::::get_current_block_as_u64(); let (nonce, work) = @@ -473,6 +514,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_network_pow_registration_allowed(netuid, true); + Subtensor::::set_difficulty(netuid, 1); let block_number = Subtensor::::get_current_block_as_u64(); let (nonce, work) = @@ -535,6 +577,7 @@ mod pallet_benchmarks { Subtensor::::set_network_pow_registration_allowed(netuid, true); Subtensor::::set_commit_reveal_weights_enabled(netuid, true); Subtensor::::set_weights_set_rate_limit(netuid, 0); + Subtensor::::set_difficulty(netuid, 1); let block_number: u64 = Subtensor::::get_current_block_as_u64(); let (nonce, work) = @@ -556,6 +599,7 @@ mod pallet_benchmarks { let mut salts_list = Vec::new(); let mut version_keys = Vec::new(); + let commit_block = Subtensor::::get_current_block_as_u64(); for i in 0..num_commits { let uids = vec![0u16]; let values = vec![i as u16]; @@ -583,6 +627,13 @@ mod pallet_benchmarks { version_keys.push(version_key_i); } + let (first_reveal_block, _) = Subtensor::::get_reveal_blocks(netuid, commit_block); + let reveal_block: BlockNumberFor = first_reveal_block + .try_into() + .ok() + .expect("can't convert to block number"); + frame_system::Pallet::::set_block_number(reveal_block); + #[extrinsic_call] _( RawOrigin::Signed(hotkey.clone()), @@ -604,9 +655,10 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); let amount_to_be_staked = 1_000_000_000; + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); assert_ok!(Subtensor::::do_burned_registration( RawOrigin::Signed(coldkey.clone()).into(), @@ -647,9 +699,10 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); let amount_to_be_staked: u64 = 1_000_000_000; + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); assert_ok!(Subtensor::::do_burned_registration( RawOrigin::Signed(coldkey.clone()).into(), @@ -689,8 +742,9 @@ mod pallet_benchmarks { SubtokenEnabled::::insert(netuid, true); Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); let amount_to_be_staked = 1_000_000; + seed_swap_reserves::(netuid); Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); SubnetOwner::::set(netuid, coldkey.clone()); @@ -722,7 +776,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); @@ -736,8 +790,7 @@ mod pallet_benchmarks { let tao_reserve = TaoCurrency::from(150_000_000_000); let alpha_in = AlphaCurrency::from(100_000_000_000); - SubnetTAO::::insert(netuid, tao_reserve); - SubnetAlphaIn::::insert(netuid, alpha_in); + set_reserves::(netuid, tao_reserve, alpha_in); assert_ok!(Subtensor::::do_burned_registration( RawOrigin::Signed(coldkey.clone()).into(), @@ -777,8 +830,7 @@ mod pallet_benchmarks { origin.clone() )); - SubnetTAO::::insert(netuid, deposit); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(deposit.to_u64())); + set_reserves::(netuid, deposit, AlphaCurrency::from(deposit.to_u64())); TotalStake::::set(deposit); assert_ok!(Subtensor::::add_stake_limit( @@ -827,13 +879,12 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); let limit = TaoCurrency::from(1_000_000_000); let tao_reserve = TaoCurrency::from(150_000_000_000); let alpha_in = AlphaCurrency::from(100_000_000_000); - SubnetTAO::::insert(netuid, tao_reserve); - SubnetAlphaIn::::insert(netuid, alpha_in); + set_reserves::(netuid, tao_reserve, alpha_in); let wallet_bal = 1000000u32.into(); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal); @@ -885,8 +936,7 @@ mod pallet_benchmarks { let tao_reserve = TaoCurrency::from(150_000_000_000); let alpha_in = AlphaCurrency::from(100_000_000_000); - SubnetTAO::::insert(netuid1, tao_reserve); - SubnetAlphaIn::::insert(netuid1, alpha_in); + set_reserves::(netuid1, tao_reserve, alpha_in); SubnetTAO::::insert(netuid2, tao_reserve); Subtensor::::increase_total_stake(1_000_000_000_000.into()); @@ -955,8 +1005,7 @@ mod pallet_benchmarks { hot.clone() )); - SubnetTAO::::insert(netuid, deposit); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(deposit.to_u64())); + set_reserves::(netuid, deposit, AlphaCurrency::from(deposit.to_u64())); TotalStake::::set(deposit); assert_ok!(Subtensor::::add_stake_limit( @@ -1010,10 +1059,8 @@ mod pallet_benchmarks { hot.clone() )); - SubnetTAO::::insert(netuid1, deposit); - SubnetAlphaIn::::insert(netuid1, AlphaCurrency::from(deposit.to_u64())); - SubnetTAO::::insert(netuid2, deposit); - SubnetAlphaIn::::insert(netuid2, AlphaCurrency::from(deposit.to_u64())); + set_reserves::(netuid1, deposit, AlphaCurrency::from(deposit.to_u64())); + set_reserves::(netuid2, deposit, AlphaCurrency::from(deposit.to_u64())); TotalStake::::set(deposit); assert_ok!(Subtensor::::add_stake_limit( @@ -1052,6 +1099,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); Subtensor::::set_network_pow_registration_allowed(netuid, true); SubtokenEnabled::::insert(netuid, true); + Subtensor::::set_weights_set_rate_limit(netuid, 0); let reg_fee = Subtensor::::get_burn(netuid); Subtensor::::add_balance_to_coldkey_account(&hotkey, reg_fee.to_u64().saturating_mul(2)); @@ -1115,9 +1163,11 @@ mod pallet_benchmarks { fn decrease_take() { let coldkey: T::AccountId = whitelisted_caller(); let hotkey: T::AccountId = account("Alice", 0, 1); - let take: u16 = 100; + let min_take = Subtensor::::get_min_delegate_take(); + let take: u16 = min_take; + let current_take = min_take.saturating_add(1); - Delegates::::insert(&hotkey, 200u16); + Delegates::::insert(&hotkey, current_take); Owner::::insert(&hotkey, &coldkey); #[extrinsic_call] @@ -1318,10 +1368,13 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); - SubnetTAO::::insert(netuid, TaoCurrency::from(150_000_000_000)); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(100_000_000_000)); + set_reserves::( + netuid, + TaoCurrency::from(150_000_000_000), + AlphaCurrency::from(100_000_000_000), + ); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 1000000u32.into()); @@ -1366,13 +1419,12 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); let limit = TaoCurrency::from(1_000_000_000); let tao_reserve = TaoCurrency::from(150_000_000_000); let alpha_in = AlphaCurrency::from(100_000_000_000); - SubnetTAO::::insert(netuid, tao_reserve); - SubnetAlphaIn::::insert(netuid, alpha_in); + set_reserves::(netuid, tao_reserve, alpha_in); let wallet_bal = 1000000u32.into(); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal); @@ -1730,7 +1782,7 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + Subtensor::::set_burn(netuid, benchmark_registration_burn()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); @@ -1746,8 +1798,7 @@ mod pallet_benchmarks { let tao_reserve = TaoCurrency::from(150_000_000_000); let alpha_in = AlphaCurrency::from(100_000_000_000); - SubnetTAO::::insert(netuid, tao_reserve); - SubnetAlphaIn::::insert(netuid, alpha_in); + set_reserves::(netuid, tao_reserve, alpha_in); assert_ok!(Subtensor::::do_burned_registration( RawOrigin::Signed(coldkey.clone()).into(), diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 47726bd6b0..c0000d2662 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -52,7 +52,7 @@ pub use extensions::*; pub use guards::*; #[cfg(test)] -mod tests; +pub(crate) mod tests; // apparently this is stabilized since rust 1.36 extern crate alloc; @@ -1227,7 +1227,7 @@ pub mod pallet { /// ================== /// ==== Coinbase ==== /// ================== - /// --- ITEM ( global_block_emission ) + /// --- ITEM ( global_block_emission ) #[pallet::storage] pub type BlockEmission = StorageValue<_, u64, ValueQuery, DefaultBlockEmission>; @@ -1267,7 +1267,7 @@ pub mod pallet { #[pallet::storage] pub type TotalStake = StorageValue<_, TaoCurrency, ValueQuery, DefaultZeroTao>; - /// --- ITEM ( moving_alpha ) -- subnet moving alpha. + /// --- ITEM ( moving_alpha ) -- subnet moving alpha. #[pallet::storage] pub type SubnetMovingAlpha = StorageValue<_, I96F32, ValueQuery, DefaultMovingAlpha>; From 3a5e808dce53500ab50026b0f338c5d7ec5626fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 2 Mar 2026 14:32:02 +0000 Subject: [PATCH 42/43] auto-update benchmark weights --- pallets/subtensor/src/macros/dispatches.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 37e8adadf2..7656985819 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1735,8 +1735,8 @@ mod dispatches { /// #[pallet::call_index(89)] #[pallet::weight((Weight::from_parts(377_400_000, 0) - .saturating_add(T::DbWeight::get().reads(29_u64)) - .saturating_add(T::DbWeight::get().writes(15_u64)), DispatchClass::Normal, Pays::Yes))] + .saturating_add(T::DbWeight::get().reads(28_u64)) + .saturating_add(T::DbWeight::get().writes(14_u64)), DispatchClass::Normal, Pays::Yes))] pub fn remove_stake_limit( origin: OriginFor, hotkey: T::AccountId, @@ -1957,8 +1957,8 @@ mod dispatches { /// Without limit_price it remove all the stake similar to `remove_stake` extrinsic #[pallet::call_index(103)] #[pallet::weight((Weight::from_parts(395_300_000, 10142) - .saturating_add(T::DbWeight::get().reads(29_u64)) - .saturating_add(T::DbWeight::get().writes(15_u64)), DispatchClass::Normal, Pays::Yes))] + .saturating_add(T::DbWeight::get().reads(28_u64)) + .saturating_add(T::DbWeight::get().writes(14_u64)), DispatchClass::Normal, Pays::Yes))] pub fn remove_stake_full_limit( origin: T::RuntimeOrigin, hotkey: T::AccountId, From 6bbda12631a9190bbd7332d213b119dbeb5ec823 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Mon, 2 Mar 2026 15:33:25 +0100 Subject: [PATCH 43/43] Trigger CI