Skip to content
Merged
Show file tree
Hide file tree
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
214 changes: 128 additions & 86 deletions common/src/currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,103 +33,101 @@ use subtensor_macros::freeze_struct;
)]
pub struct AlphaCurrency(u64);

impl TypeInfo for AlphaCurrency {
type Identity = <u64 as TypeInfo>::Identity;
fn type_info() -> scale_info::Type {
<u64 as TypeInfo>::type_info()
}
}

impl Display for AlphaCurrency {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}

impl CompactAs for AlphaCurrency {
type As = u64;

fn encode_as(&self) -> &Self::As {
&self.0
}

fn decode_from(v: Self::As) -> Result<Self, CodecError> {
Ok(Self(v))
}
}

impl From<Compact<AlphaCurrency>> for AlphaCurrency {
fn from(c: Compact<AlphaCurrency>) -> Self {
c.0
}
}

impl From<AlphaCurrency> for u64 {
fn from(val: AlphaCurrency) -> Self {
val.0
}
}
#[freeze_struct("4d1bcb31c40c2594")]
#[repr(transparent)]
#[derive(
Deserialize,
Serialize,
Clone,
Copy,
Decode,
DecodeWithMemTracking,
Default,
Encode,
Eq,
Hash,
MaxEncodedLen,
Ord,
PartialEq,
PartialOrd,
RuntimeDebug,
)]
pub struct TaoCurrency(u64);

impl From<u64> for AlphaCurrency {
fn from(value: u64) -> Self {
Self(value)
}
}
// implements traits required by the Currency trait (ToFixed + Into<u64> + From<u64>) and CompactAs,
// TypeInfo and Display. It expects a wrapper structure for u64 (CurrencyT(u64)).
macro_rules! impl_currency_reqs {
($currency_type:ident) => {
impl $currency_type {
pub const fn new(inner: u64) -> Self {
Self(inner)
}
}

impl ToFixed for AlphaCurrency {
fn to_fixed<F: Fixed>(self) -> F {
self.0.to_fixed()
}
impl TypeInfo for $currency_type {
type Identity = <u64 as TypeInfo>::Identity;
fn type_info() -> scale_info::Type {
<u64 as TypeInfo>::type_info()
}
}

fn checked_to_fixed<F: Fixed>(self) -> Option<F> {
self.0.checked_to_fixed()
}
impl Display for $currency_type {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}

fn saturating_to_fixed<F: Fixed>(self) -> F {
self.0.saturating_to_fixed()
}
fn wrapping_to_fixed<F: Fixed>(self) -> F {
self.0.wrapping_to_fixed()
}
impl CompactAs for $currency_type {
type As = u64;

fn overflowing_to_fixed<F: Fixed>(self) -> (F, bool) {
self.0.overflowing_to_fixed()
}
}
fn encode_as(&self) -> &Self::As {
&self.0
}

impl Currency for AlphaCurrency {
const MAX: Self = Self(u64::MAX);
const ZERO: Self = Self(0);
}
fn decode_from(v: Self::As) -> Result<Self, CodecError> {
Ok(Self(v))
}
}

pub trait Currency: ToFixed + Into<u64> + From<u64> + Clone + Copy {
const MAX: Self;
const ZERO: Self;
impl From<Compact<$currency_type>> for $currency_type {
fn from(c: Compact<$currency_type>) -> Self {
c.0
}
}

fn is_zero(&self) -> bool {
Into::<u64>::into(*self) == 0
}
impl From<$currency_type> for u64 {
fn from(val: $currency_type) -> Self {
val.0
}
}

fn to_u64(&self) -> u64 {
(*self).into()
}
impl From<u64> for $currency_type {
fn from(value: u64) -> Self {
Self(value)
}
}

fn saturating_add(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_add(rhv.into()).into()
}
impl ToFixed for $currency_type {
fn to_fixed<F: Fixed>(self) -> F {
self.0.to_fixed()
}

#[allow(clippy::arithmetic_side_effects)]
fn saturating_div(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_div(rhv.into()).into()
}
fn checked_to_fixed<F: Fixed>(self) -> Option<F> {
self.0.checked_to_fixed()
}

fn saturating_sub(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_sub(rhv.into()).into()
}
fn saturating_to_fixed<F: Fixed>(self) -> F {
self.0.saturating_to_fixed()
}
fn wrapping_to_fixed<F: Fixed>(self) -> F {
self.0.wrapping_to_fixed()
}

fn saturating_mul(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_mul(rhv.into()).into()
}
fn overflowing_to_fixed<F: Fixed>(self) -> (F, bool) {
self.0.overflowing_to_fixed()
}
}
};
}

macro_rules! impl_arithmetic_operators {
Expand Down Expand Up @@ -208,8 +206,6 @@ macro_rules! impl_arithmetic_operators {
};
}

impl_arithmetic_operators!(AlphaCurrency);

macro_rules! impl_approx {
($currency_type:ident) => {
#[cfg(feature = "approx")]
Expand All @@ -231,4 +227,50 @@ macro_rules! impl_approx {
};
}

pub trait Currency: ToFixed + Into<u64> + From<u64> + Clone + Copy {
const MAX: Self;
const ZERO: Self;

fn is_zero(&self) -> bool {
Into::<u64>::into(*self) == 0
}

fn to_u64(&self) -> u64 {
(*self).into()
}
Comment on lines +238 to +240
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious what the purpose of this wrapper is, instead of using into

Copy link
Contributor Author

@ales-otf ales-otf Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some cases compiler can not know exact type in compilation time, so you can't use into, and then you should do something like Into::<u64>::into(value) or u64::from(value). here because the function returns u64, compiler knows into which type to convert.


fn saturating_add(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_add(rhv.into()).into()
}

#[allow(clippy::arithmetic_side_effects)]
fn saturating_div(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_div(rhv.into()).into()
}

fn saturating_sub(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_sub(rhv.into()).into()
}

fn saturating_mul(&self, rhv: Self) -> Self {
Into::<u64>::into(*self).saturating_mul(rhv.into()).into()
}
}

impl_arithmetic_operators!(AlphaCurrency);
impl_approx!(AlphaCurrency);
impl_currency_reqs!(AlphaCurrency);

impl_arithmetic_operators!(TaoCurrency);
impl_approx!(TaoCurrency);
impl_currency_reqs!(TaoCurrency);

impl Currency for AlphaCurrency {
const MAX: Self = Self(u64::MAX);
const ZERO: Self = Self(0);
}

impl Currency for TaoCurrency {
const MAX: Self = Self(u64::MAX);
const ZERO: Self = Self(0);
}
15 changes: 9 additions & 6 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,21 @@ impl Default for ProxyType {
}

pub trait SubnetInfo<AccountId> {
fn tao_reserve(netuid: NetUid) -> u64;
fn tao_reserve(netuid: NetUid) -> TaoCurrency;
fn alpha_reserve(netuid: NetUid) -> AlphaCurrency;
fn exists(netuid: NetUid) -> bool;
fn mechanism(netuid: NetUid) -> u16;
fn is_owner(account_id: &AccountId, netuid: NetUid) -> bool;
}

pub trait BalanceOps<AccountId> {
fn tao_balance(account_id: &AccountId) -> u64;
fn tao_balance(account_id: &AccountId) -> TaoCurrency;
fn alpha_balance(netuid: NetUid, coldkey: &AccountId, hotkey: &AccountId) -> AlphaCurrency;
fn increase_balance(coldkey: &AccountId, tao: u64);
fn decrease_balance(coldkey: &AccountId, tao: u64) -> Result<u64, DispatchError>;
fn increase_balance(coldkey: &AccountId, tao: TaoCurrency);
fn decrease_balance(
coldkey: &AccountId,
tao: TaoCurrency,
) -> Result<TaoCurrency, DispatchError>;
fn increase_stake(
coldkey: &AccountId,
hotkey: &AccountId,
Expand All @@ -192,8 +195,8 @@ pub trait BalanceOps<AccountId> {
netuid: NetUid,
alpha: AlphaCurrency,
) -> Result<AlphaCurrency, DispatchError>;
fn increase_provided_tao_reserve(netuid: NetUid, tao: u64);
fn decrease_provided_tao_reserve(netuid: NetUid, tao: u64);
fn increase_provided_tao_reserve(netuid: NetUid, tao: TaoCurrency);
fn decrease_provided_tao_reserve(netuid: NetUid, tao: TaoCurrency);
fn increase_provided_alpha_reserve(netuid: NetUid, alpha: AlphaCurrency);
fn decrease_provided_alpha_reserve(netuid: NetUid, alpha: AlphaCurrency);
}
Expand Down
4 changes: 2 additions & 2 deletions pallets/admin-utils/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ mod benchmarks {
);

#[extrinsic_call]
_(RawOrigin::Root, 1u16.into()/*netuid*/, 10u64/*max_burn*/)/*sudo_set_max_burn*/;
_(RawOrigin::Root, 1u16.into()/*netuid*/, 10.into()/*max_burn*/)/*sudo_set_max_burn*/;
}

#[benchmark]
Expand All @@ -277,7 +277,7 @@ mod benchmarks {
);

#[extrinsic_call]
_(RawOrigin::Root, 1u16.into()/*netuid*/, 10u64/*min_burn*/)/*sudo_set_min_burn*/;
_(RawOrigin::Root, 1u16.into()/*netuid*/, 10.into()/*min_burn*/)/*sudo_set_min_burn*/;
}

#[benchmark]
Expand Down
12 changes: 6 additions & 6 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub mod pallet {
use pallet_subtensor::utils::rate_limiting::TransactionType;
use sp_runtime::BoundedVec;
use substrate_fixed::types::I96F32;
use subtensor_runtime_common::NetUid;
use subtensor_runtime_common::{NetUid, TaoCurrency};

/// The main data structure of the module.
#[pallet::pallet]
Expand Down Expand Up @@ -665,7 +665,7 @@ pub mod pallet {
pub fn sudo_set_min_burn(
origin: OriginFor<T>,
netuid: NetUid,
min_burn: u64,
min_burn: TaoCurrency,
) -> DispatchResult {
ensure_root(origin)?;

Expand All @@ -688,7 +688,7 @@ pub mod pallet {
pub fn sudo_set_max_burn(
origin: OriginFor<T>,
netuid: NetUid,
max_burn: u64,
max_burn: TaoCurrency,
) -> DispatchResult {
ensure_root(origin)?;

Expand Down Expand Up @@ -904,7 +904,7 @@ pub mod pallet {
#[pallet::weight((0, DispatchClass::Operational, Pays::No))]
pub fn sudo_set_total_issuance(
origin: OriginFor<T>,
total_issuance: u64,
total_issuance: TaoCurrency,
) -> DispatchResult {
ensure_root(origin)?;

Expand Down Expand Up @@ -948,7 +948,7 @@ pub mod pallet {
))]
pub fn sudo_set_network_min_lock_cost(
origin: OriginFor<T>,
lock_cost: u64,
lock_cost: TaoCurrency,
) -> DispatchResult {
ensure_root(origin)?;

Expand Down Expand Up @@ -1005,7 +1005,7 @@ pub mod pallet {
pub fn sudo_set_rao_recycled(
origin: OriginFor<T>,
netuid: NetUid,
rao_recycled: u64,
rao_recycled: TaoCurrency,
) -> DispatchResult {
ensure_root(origin)?;
ensure!(
Expand Down
Loading
Loading