Skip to content

alpha precompiles #1686

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: devnet-ready
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

546 changes: 324 additions & 222 deletions evm-tests/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion evm-tests/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,8 @@
"mocha": "^11.1.0",
"polkadot-api": "^1.9.5",
"scale-ts": "^1.6.1",
"viem": "2.23.4"
"viem": "2.23.4",
"ws": "^8.18.2"
},
"devDependencies": {
"@types/bun": "^1.1.13",
249 changes: 249 additions & 0 deletions evm-tests/src/contracts/alpha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
export const IALPHA_ADDRESS = "0x0000000000000000000000000000000000000808";

export const IAlphaABI = [
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getMovingAlphaPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getTaoInPool",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaInPool",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaOutPool",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaIssuance",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getTaoWeight",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "tao",
"type": "uint64"
}
],
"name": "simSwapTaoForAlpha",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "alpha",
"type": "uint64"
}
],
"name": "simSwapAlphaForTao",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getSubnetMechanism",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getRootNetuid",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getEMAPriceHalvingBlocks",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getSubnetVolume",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
428 changes: 428 additions & 0 deletions evm-tests/test/alpha.precompile.test.ts

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -113,6 +113,8 @@ pub mod pallet {
Neuron,
/// Enum for UID lookup precompile
UidLookup,
/// Enum for alpha precompile
Alpha,
}

#[pallet::type_value]
3 changes: 2 additions & 1 deletion precompiles/Cargo.toml
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
subtensor-runtime-common = { workspace = true }

substrate-fixed = { workspace = true }
pallet-subtensor = { workspace = true }
pallet-admin-utils = { workspace = true }

@@ -58,5 +58,6 @@ std = [
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"substrate-fixed/std",
"subtensor-runtime-common/std",
]
120 changes: 120 additions & 0 deletions precompiles/src/alpha.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use core::marker::PhantomData;

use pallet_evm::PrecompileHandle;
use precompile_utils::EvmResult;
use sp_core::U256;
use substrate_fixed::types::U96F32;

use crate::PrecompileExt;

pub struct AlphaPrecompile<R>(PhantomData<R>);

impl<R> PrecompileExt<R::AccountId> for AlphaPrecompile<R>
where
R: frame_system::Config + pallet_subtensor::Config,
R::AccountId: From<[u8; 32]>,
{
const INDEX: u64 = 2056;
}

#[precompile_utils::precompile]
impl<R> AlphaPrecompile<R>
where
R: frame_system::Config + pallet_subtensor::Config,
{
#[precompile::public("getAlphaPrice(uint16)")]
#[precompile::view]
fn get_alpha_price(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<U256> {
let price: U96F32 = pallet_subtensor::Pallet::<R>::get_alpha_price(netuid);
Ok(U256::from(price.saturating_to_num::<u64>()))
}

#[precompile::public("getMovingAlphaPrice(uint16)")]
#[precompile::view]
fn get_moving_alpha_price(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<U256> {
let price: U96F32 = pallet_subtensor::Pallet::<R>::get_moving_alpha_price(netuid);
Ok(U256::from(price.saturating_to_num::<u64>()))
}

#[precompile::public("getTaoInPool(uint16)")]
#[precompile::view]
fn get_tao_in_pool(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<u64> {
Ok(pallet_subtensor::SubnetTAO::<R>::get(netuid))
}

#[precompile::public("getAlphaInPool(uint16)")]
#[precompile::view]
fn get_alpha_in_pool(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<u64> {
Ok(pallet_subtensor::SubnetAlphaIn::<R>::get(netuid))
}

#[precompile::public("getAlphaOutPool(uint16)")]
#[precompile::view]
fn get_alpha_out_pool(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<u64> {
Ok(pallet_subtensor::SubnetAlphaOut::<R>::get(netuid))
}

#[precompile::public("getAlphaIssuance(uint16)")]
#[precompile::view]
fn get_alpha_issuance(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<u64> {
Ok(pallet_subtensor::Pallet::<R>::get_alpha_issuance(netuid))
}

#[precompile::public("getTaoWeight()")]
#[precompile::view]
fn get_tao_weight(_handle: &mut impl PrecompileHandle) -> EvmResult<U256> {
let weight: U96F32 = pallet_subtensor::Pallet::<R>::get_tao_weight();
Ok(U256::from(weight.saturating_to_num::<u64>()))
}

#[precompile::public("simSwapTaoForAlpha(uint16,uint64)")]
#[precompile::view]
fn sim_swap_tao_for_alpha(
_handle: &mut impl PrecompileHandle,
netuid: u16,
tao: u64,
) -> EvmResult<U256> {
let alpha_option = pallet_subtensor::Pallet::<R>::sim_swap_tao_for_alpha(netuid, tao);
let result = alpha_option.unwrap_or(0);
Ok(U256::from(result))
}

#[precompile::public("simSwapAlphaForTao(uint16,uint64)")]
#[precompile::view]
fn sim_swap_alpha_for_tao(
_handle: &mut impl PrecompileHandle,
netuid: u16,
alpha: u64,
) -> EvmResult<U256> {
let tao_option = pallet_subtensor::Pallet::<R>::sim_swap_alpha_for_tao(netuid, alpha);
let result = tao_option.unwrap_or(0);
Ok(U256::from(result))
}

#[precompile::public("getSubnetMechanism(uint16)")]
#[precompile::view]
fn get_subnet_mechanism(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<u16> {
Ok(pallet_subtensor::SubnetMechanism::<R>::get(netuid))
}

#[precompile::public("getRootNetuid()")]
#[precompile::view]
fn get_root_netuid(_handle: &mut impl PrecompileHandle) -> EvmResult<u16> {
Ok(pallet_subtensor::Pallet::<R>::get_root_netuid())
}

#[precompile::public("getEMAPriceHalvingBlocks(uint16)")]
#[precompile::view]
fn get_ema_price_halving_blocks(
_handle: &mut impl PrecompileHandle,
netuid: u16,
) -> EvmResult<u64> {
Ok(pallet_subtensor::EMAPriceHalvingBlocks::<R>::get(netuid))
}

#[precompile::public("getSubnetVolume(uint16)")]
#[precompile::view]
fn get_subnet_volume(_handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<U256> {
Ok(U256::from(pallet_subtensor::SubnetVolume::<R>::get(netuid)))
}
}
8 changes: 7 additions & 1 deletion precompiles/src/lib.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ use subtensor_runtime_common::ProxyType;

use pallet_admin_utils::PrecompileEnum;

use crate::alpha::*;
use crate::balance_transfer::*;
use crate::ed25519::*;
use crate::extensions::*;
@@ -33,6 +34,7 @@ use crate::storage_query::*;
use crate::subnet::*;
use crate::uid_lookup::*;

mod alpha;
mod balance_transfer;
mod ed25519;
mod extensions;
@@ -91,7 +93,7 @@ where
Self(Default::default())
}

pub fn used_addresses() -> [H160; 17] {
pub fn used_addresses() -> [H160; 18] {
[
hash(1),
hash(2),
@@ -110,6 +112,7 @@ where
hash(StakingPrecompileV2::<R>::INDEX),
hash(StorageQueryPrecompile::<R>::INDEX),
hash(UidLookupPrecompile::<R>::INDEX),
hash(AlphaPrecompile::<R>::INDEX),
]
}
}
@@ -178,6 +181,9 @@ where
a if a == hash(StorageQueryPrecompile::<R>::INDEX) => {
Some(StorageQueryPrecompile::<R>::execute(handle))
}
a if a == hash(AlphaPrecompile::<R>::INDEX) => {
AlphaPrecompile::<R>::try_execute::<R>(handle, PrecompileEnum::Alpha)
}
_ => None,
}
}
247 changes: 247 additions & 0 deletions precompiles/src/solidity/alpha.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
[
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getMovingAlphaPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getTaoInPool",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaInPool",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaOutPool",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getAlphaIssuance",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getTaoWeight",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "tao",
"type": "uint64"
}
],
"name": "simSwapTaoForAlpha",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "alpha",
"type": "uint64"
}
],
"name": "simSwapAlphaForTao",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getSubnetMechanism",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getRootNetuid",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getEMAPriceHalvingBlocks",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "netuid",
"type": "uint16"
}
],
"name": "getSubnetVolume",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
70 changes: 70 additions & 0 deletions precompiles/src/solidity/alpha.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
pragma solidity ^0.8.0;

address constant IALPHA_ADDRESS = 0x0000000000000000000000000000000000000808;

interface IAlpha {
/// @dev Returns the current alpha price for a subnet.
/// @param netuid The subnet identifier.
/// @return The alpha price in RAO per alpha.
function getAlphaPrice(uint16 netuid) external view returns (uint256);

/// @dev Returns the moving (EMA) alpha price for a subnet.
/// @param netuid The subnet identifier.
/// @return The moving alpha price in RAO per alpha.
function getMovingAlphaPrice(uint16 netuid) external view returns (uint256);

/// @dev Returns the amount of TAO in the pool for a subnet.
/// @param netuid The subnet identifier.
/// @return The TAO amount in the pool.
function getTaoInPool(uint16 netuid) external view returns (uint64);

/// @dev Returns the amount of alpha in the pool for a subnet.
/// @param netuid The subnet identifier.
/// @return The alpha amount in the pool.
function getAlphaInPool(uint16 netuid) external view returns (uint64);

/// @dev Returns the amount of alpha outside the pool for a subnet.
/// @param netuid The subnet identifier.
/// @return The alpha amount outside the pool.
function getAlphaOutPool(uint16 netuid) external view returns (uint64);

/// @dev Returns the total alpha issuance for a subnet.
/// @param netuid The subnet identifier.
/// @return The total alpha issuance.
function getAlphaIssuance(uint16 netuid) external view returns (uint64);

/// @dev Returns the global TAO weight.
/// @return The TAO weight value.
function getTaoWeight() external view returns (uint256);

/// @dev Simulates swapping TAO for alpha.
/// @param netuid The subnet identifier.
/// @param tao The amount of TAO to swap.
/// @return The amount of alpha that would be received.
function simSwapTaoForAlpha(uint16 netuid, uint64 tao) external view returns (uint256);

/// @dev Simulates swapping alpha for TAO.
/// @param netuid The subnet identifier.
/// @param alpha The amount of alpha to swap.
/// @return The amount of TAO that would be received.
function simSwapAlphaForTao(uint16 netuid, uint64 alpha) external view returns (uint256);

/// @dev Returns the mechanism type for a subnet (0 for Stable, 1 for Dynamic).
/// @param netuid The subnet identifier.
/// @return The subnet mechanism type.
function getSubnetMechanism(uint16 netuid) external view returns (uint16);

/// @dev Returns the root subnet unique identifier.
/// @return The root subnet ID.
function getRootNetuid() external view returns (uint16);

/// @dev Returns the EMA price halving blocks parameter for a subnet.
/// @param netuid The subnet identifier.
/// @return The number of blocks for EMA price halving.
function getEMAPriceHalvingBlocks(uint16 netuid) external view returns (uint64);

/// @dev Returns the transaction volume for a subnet.
/// @param netuid The subnet identifier.
/// @return The subnet volume.
function getSubnetVolume(uint16 netuid) external view returns (uint256);
}
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -209,7 +209,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: 274,
spec_version: 275,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,