From 8ac6201c59125a46581c738d2a93cf956367df7d Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 9 Dec 2025 09:52:46 +0800 Subject: [PATCH 1/6] all alpha price in Ink --- Cargo.lock | 1 + chain-extensions/Cargo.toml | 2 ++ chain-extensions/src/lib.rs | 28 +++++++++++++-- chain-extensions/src/tests.rs | 42 ++++++++++++++++++++++- chain-extensions/src/types.rs | 1 + contract-tests/bittensor/lib.rs | 12 +++++++ contract-tests/test/wasm.contract.test.ts | 10 ++++++ 7 files changed, 93 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5f4583519..5a21194201 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18047,6 +18047,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "substrate-fixed", "subtensor-runtime-common", "subtensor-swap-interface", ] diff --git a/chain-extensions/Cargo.toml b/chain-extensions/Cargo.toml index ae69b94d4c..9727439e7a 100644 --- a/chain-extensions/Cargo.toml +++ b/chain-extensions/Cargo.toml @@ -34,6 +34,7 @@ pallet-subtensor-proxy.workspace = true pallet-drand.workspace = true subtensor-swap-interface.workspace = true num_enum.workspace = true +substrate-fixed.workspace = true [lints] workspace = true @@ -64,4 +65,5 @@ std = [ "pallet-drand/std", "subtensor-swap-interface/std", "num_enum/std", + "substrate-fixed/std", ] diff --git a/chain-extensions/src/lib.rs b/chain-extensions/src/lib.rs index e53fac765f..eaaee70d27 100644 --- a/chain-extensions/src/lib.rs +++ b/chain-extensions/src/lib.rs @@ -18,7 +18,9 @@ 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::U96F32; use subtensor_runtime_common::{AlphaCurrency, NetUid, ProxyType, TaoCurrency}; +use subtensor_swap_interface::SwapHandler; #[derive(DebugNoBound)] pub struct SubtensorChainExtension(PhantomData); @@ -33,7 +35,8 @@ impl ChainExtension for SubtensorChainExtension where T: pallet_subtensor::Config + pallet_contracts::Config - + pallet_proxy::Config, + + pallet_proxy::Config + + pallet_subtensor_swap::Config, T::AccountId: Clone, <::Lookup as StaticLookup>::Source: From<::AccountId>, { @@ -54,7 +57,8 @@ impl SubtensorChainExtension where T: pallet_subtensor::Config + pallet_contracts::Config - + pallet_proxy::Config, + + pallet_proxy::Config + + pallet_subtensor_swap::Config, T::AccountId: Clone, { fn dispatch(env: &mut Env) -> Result @@ -506,6 +510,26 @@ where } } } + FunctionId::GetAlphaPriceV1 => { + let netuid: NetUid = env + .read_as() + .map_err(|_| DispatchError::Other("Failed to decode input parameters"))?; + + let current_alpha_price = + as SwapHandler>::current_alpha_price( + netuid.into(), + ); + + 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(); + + env.write_output(&encoded_result) + .map_err(|_| DispatchError::Other("Failed to write output"))?; + + Ok(RetVal::Converging(Output::Success as u32)) + } } } } diff --git a/chain-extensions/src/tests.rs b/chain-extensions/src/tests.rs index 378fa084a1..5d4276c3a5 100644 --- a/chain-extensions/src/tests.rs +++ b/chain-extensions/src/tests.rs @@ -2,7 +2,7 @@ use super::{SubtensorChainExtension, SubtensorExtensionEnv, mock}; use crate::types::{FunctionId, Output}; -use codec::Encode; +use codec::{Decode, Encode}; use frame_support::{assert_ok, weights::Weight}; use frame_system::RawOrigin; use pallet_contracts::chain_extension::RetVal; @@ -10,6 +10,7 @@ use pallet_subtensor::DefaultMinStake; use sp_core::Get; use sp_core::U256; use sp_runtime::DispatchError; +use substrate_fixed::types::U96F32; use subtensor_runtime_common::{AlphaCurrency, Currency as CurrencyTrait, NetUid, TaoCurrency}; use subtensor_swap_interface::SwapHandler; @@ -964,3 +965,42 @@ fn unstake_all_success_unstakes_balance() { assert!(post_balance > pre_balance); }); } + +#[test] +fn get_alpha_price_returns_encoded_price() { + mock::new_test_ext(1).execute_with(|| { + let owner_hotkey = U256::from(8001); + let owner_coldkey = U256::from(8002); + let caller = U256::from(8003); + + let netuid = mock::add_dynamic_network(&owner_hotkey, &owner_coldkey); + + // Set up reserves to establish a price + let tao_reserve = TaoCurrency::from(150_000_000_000u64); + let alpha_reserve = AlphaCurrency::from(100_000_000_000u64); + mock::setup_reserves(netuid, tao_reserve, alpha_reserve); + + // Get expected price from swap handler + let expected_price = + as SwapHandler>::current_alpha_price( + netuid.into(), + ); + 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()); + + let ret = SubtensorChainExtension::::dispatch(&mut env).unwrap(); + assert_success(ret); + assert!(env.charged_weight().is_none()); + + // Decode the output + let output_price: u64 = + Decode::decode(&mut &env.output()[..]).expect("Failed to decode output price"); + + assert_eq!( + output_price, expected_price_u64, + "Price should match expected value" + ); + }); +} diff --git a/chain-extensions/src/types.rs b/chain-extensions/src/types.rs index 7c0bfe4202..ee6298ad5b 100644 --- a/chain-extensions/src/types.rs +++ b/chain-extensions/src/types.rs @@ -20,6 +20,7 @@ pub enum FunctionId { SetColdkeyAutoStakeHotkeyV1 = 12, AddProxyV1 = 13, RemoveProxyV1 = 14, + GetAlphaPriceV1 = 15, } #[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug)] diff --git a/contract-tests/bittensor/lib.rs b/contract-tests/bittensor/lib.rs index 03367339ca..48e8d18aea 100755 --- a/contract-tests/bittensor/lib.rs +++ b/contract-tests/bittensor/lib.rs @@ -22,6 +22,7 @@ pub enum FunctionId { SetColdkeyAutoStakeHotkeyV1 = 12, AddProxyV1 = 13, RemoveProxyV1 = 14, + GetAlphaPriceV1 = 15, } #[ink::chain_extension(extension = 0x1000)] @@ -127,6 +128,9 @@ pub trait RuntimeReadWrite { #[ink(function = 14)] fn remove_proxy(delegate: ::AccountId); + + #[ink(function = 15)] + fn get_alpha_price(netuid: NetUid) -> u64; } #[ink::scale_derive(Encode, Decode, TypeInfo)] @@ -412,5 +416,13 @@ mod bittensor { .remove_proxy(delegate.into()) .map_err(|_e| ReadWriteErrorCode::WriteFailed) } + + #[ink(message)] + pub fn get_alpha_price(&self, netuid: u16) -> Result { + self.env() + .extension() + .get_alpha_price(netuid.into()) + .map_err(|_e| ReadWriteErrorCode::ReadFailed) + } } } diff --git a/contract-tests/test/wasm.contract.test.ts b/contract-tests/test/wasm.contract.test.ts index 680a4a56f2..be8771594f 100644 --- a/contract-tests/test/wasm.contract.test.ts +++ b/contract-tests/test/wasm.contract.test.ts @@ -563,4 +563,14 @@ describe("Test wasm contract", () => { assert.ok(proxiesAfterRemove !== undefined) assert.ok(proxiesAfterRemove[0].length === 0) }) + + it("Can get alpha price", async () => { + const message = inkClient.message("get_alpha_price") + const data = message.encode({ + netuid: netuid, + }) + const result = await sendWasmContractExtrinsic(api, coldkey, contractAddress, data) + assert.ok(result !== undefined) + assert.ok(result > BigInt(0)) + }) }); \ No newline at end of file From c974798dc9b05fa565fadb895bb760d120a728d9 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 9 Dec 2025 09:56:19 +0800 Subject: [PATCH 2/6] cargo fix --- chain-extensions/src/tests.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chain-extensions/src/tests.rs b/chain-extensions/src/tests.rs index 5d4276c3a5..094b0987e2 100644 --- a/chain-extensions/src/tests.rs +++ b/chain-extensions/src/tests.rs @@ -995,8 +995,7 @@ fn get_alpha_price_returns_encoded_price() { assert!(env.charged_weight().is_none()); // Decode the output - let output_price: u64 = - Decode::decode(&mut &env.output()[..]).expect("Failed to decode output price"); + let output_price: u64 = Decode::decode(&mut &env.output()[..]).unwrap(); assert_eq!( output_price, expected_price_u64, From 4ed7fa0c63defaece0747075d1773c65392def8b Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 9 Dec 2025 13:26:28 +0800 Subject: [PATCH 3/6] fix ink test --- contract-tests/test/wasm.contract.test.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/contract-tests/test/wasm.contract.test.ts b/contract-tests/test/wasm.contract.test.ts index be8771594f..26d5c87924 100644 --- a/contract-tests/test/wasm.contract.test.ts +++ b/contract-tests/test/wasm.contract.test.ts @@ -569,8 +569,19 @@ describe("Test wasm contract", () => { const data = message.encode({ netuid: netuid, }) - const result = await sendWasmContractExtrinsic(api, coldkey, contractAddress, data) + + const response = await api.apis.ContractsApi.call( + convertPublicKeyToSs58(hotkey.publicKey), + contractAddress, + BigInt(0), + undefined, + undefined, + Binary.fromBytes(data.asBytes()), + ) + + assert.ok(response.result.success) + const result = message.decode(response.result.value).value.value + assert.ok(result !== undefined) - assert.ok(result > BigInt(0)) }) }); \ No newline at end of file From 2a024420212c0b45c7cf87f994e6d897388b7a78 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 9 Dec 2025 13:27:49 +0800 Subject: [PATCH 4/6] fix time count --- contract-tests/run-ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract-tests/run-ci.sh b/contract-tests/run-ci.sh index a5a8c2f52e..10f8c47793 100755 --- a/contract-tests/run-ci.sh +++ b/contract-tests/run-ci.sh @@ -15,7 +15,7 @@ while [ $i -le 2000 ]; do done # port not available exit with error -if [ "$i" -eq 1000 ]; then +if [ "$i" -eq 2000 ]; then exit 1 fi From 237b34468e50b98504e1e07ac499cb96c1c11f08 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 9 Dec 2025 13:39:16 +0800 Subject: [PATCH 5/6] optimize process --- contract-tests/run-ci.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/contract-tests/run-ci.sh b/contract-tests/run-ci.sh index 10f8c47793..0ea0e72297 100755 --- a/contract-tests/run-ci.sh +++ b/contract-tests/run-ci.sh @@ -2,6 +2,16 @@ echo "start run-ci.sh" +cd contract-tests + +cd bittensor + +rustup component add rust-src +cargo install cargo-contract +cargo contract build --release + +cd ../.. + scripts/localnet.sh &>/dev/null & i=1 @@ -28,14 +38,6 @@ fi cd contract-tests -cd bittensor - -rustup component add rust-src -cargo install cargo-contract -cargo contract build --release - -cd .. - # required for papi in get-metadata.sh, but we cannot run yarn before papi as it adds the descriptors to the package.json which won't resolve npm i -g polkadot-api From 3fccecf7086fd9b6ec2d229aaa09048bfe87d8a1 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 9 Dec 2025 13:39:38 +0800 Subject: [PATCH 6/6] bump 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 9d502c925d..35272d9817 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -237,7 +237,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: 360, + spec_version: 361, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,