substrate3.0中的balances模块

balances模块文档

说明

  • 最新的balances模块对抵押添加了NamedReservableCurrency功能, 可以更加精准的操作抵押金额
  • 新增了一些辅助的traits, 方便不同应用场景的使用
  • balances模块的资产是可变资产, 跟nft有本质的不同, 也就是fungible

重要接口(对外开放)

  1. 转账
    • 代码 `transfer(
      origin: OriginFor<T>,
      dest: <T::Lookup as StaticLookup>::Source,

      [pallet::compact] value: T::Balance,

      )`
    • 参数:
      dest 对方地址
      value 转账金额
    • 逻辑:
      • 默认地址可以废弃掉(死亡)

  2. 设置账户金额
    • 代码 `pub fn set_balance(
      origin: OriginFor<T>,
      who: <T::Lookup as StaticLookup>::Source,

      [pallet::compact] new_free: T::Balance,

      [pallet::compact] new_reserved: T::Balance,

      )`
    • 参数:
      who 目标账户
      new_free 自由账户余额
      new_reserved 保留账户余额
    • 逻辑:
      • root权限
      • 如果new_free + new_reserved < T::ExistentialDeposit::get(),那么两个账户最新余额都是零
      • 账户之前的余额都归零, 以输入的金额作为最新金额

  3. 保持账户存活的转账
    • 代码 `pub fn transfer_keep_alive(
      origin: OriginFor<T>,
      dest: <T::Lookup as StaticLookup>::Source,

      [pallet::compact] value: T::Balance,

      )`
    • 参数:
      dest 对方地址
      value 转账金额
    • 逻辑:
      • 账户剩余的金额必须大于系统的最小存货活金额

  4. 全部转账
    • 代码 pub fn transfer_all( origin: OriginFor<T>, dest: <T::Lookup as StaticLookup>::Source, keep_alive: bool, )
    • 参数:
      dest 对方账户
      keep_alive 是否保持存活
    • 逻辑
      • 如果账户允许死亡, 并且system里面允许这个账户死亡, 那么就直接转出free - frozen剩余的那部分金额, 如果是其他, 则考虑账户存活问题, 剩余的金额不能低于最小存活要求

    Self::reducible_balance 查询账户可转账的金额


几个重要的辅助trait(供其他模块调用)

> 目前其他模块不常用, 只是辅助作用
  1. fungible::Inspect<T::AccountId>
    • 主要作用: 提供查询账户金额的各种接口
    • 主要方法
      • fn total_issuance() 查询链总发行代币
      • minimum_balance() 查询账户最小存活金额
      • fn balance(who: &T::AccountId) 查询账户的总金额: 自由余额 + 保留余额
      • fn reducible_balance(who: &T::AccountId, keep_alive: bool) 查询账户可用的最大金额
      • fn can_deposit(who: &T::AccountId, amount: Self::Balance) 是否可以铸造币子
      • fn can_withdraw( who: &T::AccountId, amount: Self::Balance, ) 是否可以减掉这个金额

  2. fungible::Mutate<T::AccountId>
    • 主要作用:对账户金额进行凭空加减操作(铸币或是销毁)
    • 主要方法:
      • fn mint_into(who: &T::AccountId, amount: Self::Balance) 铸造币子
      • fn burn_from( who: &T::AccountId, amount: Self::Balance, ) 销毁某个账户的币子

  3. fungible::Transfer<T::AccountId>
    • 主要功能: 转账
    • 主要方法
      • fn transfer( source: &T::AccountId, dest: &T::AccountId, amount: T::Balance, keep_alive: bool, ) 转账

  4. fungible::Unbalanced
    • 功能: 暴力设置账户金额或是发行量
    • 主要方法
      • fn set_balance(who: &T::AccountId, amount: Self::Balance) 设置某个账户的金额
      • fn set_total_issuance(amount: Self::Balance) 设置发行总量

      这个方法对于其他模块的开发没有作用
      ***

  5. fungible::InspectHold<T::AccountId>
    • 作用: 查询保留余额与对金额进行抵押判断
    • 方法:
      • fn balance_on_hold(who: &T::AccountId) 查询账户的保留余额
      • fn can_hold(who: &T::AccountId, amount: T::Balance) -> bool 是否可以抵押该金额

  6. fungible::MutateHold<T::AccountId>
    • 作用: 抵押金额相关操作
    • 主要方法
      • fn hold(who: &T::AccountId, amount: Self::Balance) 抵押金额
      • fn release( who: &T::AccountId, amount: Self::Balance, best_effort: bool, ) 有条件的解除抵押
      • fn transfer_held( source: &T::AccountId, dest: &T::AccountId, amount: Self::Balance, best_effort: bool, on_hold: bool, ) 转移抵押金额给某人

极其重要的trait(经常使用)

  1. Currency<T::AccountId>
    • 作用: 资产的普通操作
      • 主要方法
        • total_balance(who: &T::AccountId) -> Self::Balance 查询账户总金额
        • fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool 是否可以惩罚掉这个金额(自由余额的金额要足够, 只扣除自由余额)
        • fn total_issuance() -> Self::Balance 查询账户总发行量
        • fn minimum_balance() -> Self::Balance 查询最低存活金额
        • fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance 减少发行量
        • fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance 增加发行量
        • fn free_balance(who: &T::AccountId) -> Self::Balance 查询账户自由余额
        • fn ensure_can_withdraw( who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, new_balance: T::Balance, ) -> DispatchResult 是否可以扣掉这个金额(不考虑存活)
        • fn transfer( transactor: &T::AccountId, dest: &T::AccountId, value: Self::Balance, existence_requirement: ExistenceRequirement, ) -> DispatchResult 转账
        • fn slash(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) 惩罚账户金额
        • fn deposit_into_existing( who: &T::AccountId, value: Self::Balance, ) -> Result<Self::PositiveImbalance, DispatchError> 给已经存在过的地址铸造币子
        • fn deposit_creating(who: &T::AccountId, value: Self::Balance) -> Self::PositiveImbalance 给账户铸造币子, 不管是否存在(但是铸造的金额必须大于最小存活金额)
        • fn withdraw( who: &T::AccountId, value: Self::Balance, reasons: WithdrawReasons, liveness: ExistenceRequirement, ) 根据某原因扣掉金额(自由余额)
        • fn make_free_balance_be( who: &T::AccountId, value: Self::Balance, ) -> SignedImbalance<Self::Balance, Self::PositiveImbalance> 给某账户设置自由余额

  2. ReservableCurrency<T::AccountId>
    • 作用: 抵押相关操作
    • 方法:
      • fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool 是否可以抵押
      • fn reserved_balance(who: &T::AccountId) -> Self::Balance 查询已经抵押的金额
      • fn reserve(who: &T::AccountId, value: Self::Balance) -> DispatchResult 抵押
      • fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance 解除抵押
      • fn slash_reserved( who: &T::AccountId, value: Self::Balance, ) 惩罚抵押金额(考虑存活)
      • fn repatriate_reserved( slashed: &T::AccountId, beneficiary: &T::AccountId, value: Self::Balance, status: Status, ) 转移抵押金额

  3. NamedReservableCurrency<T::AccountId>
    • 作用:根据模块来进行抵押操作, 跟2中的抵押功能相同, 不过2中是全局操作, 这里是模块,更加精准
    • 方法:
      • fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &T::AccountId) 查询这个模块中的用户抵押金额
      • fn reserve_named( id: &Self::ReserveIdentifier, who: &T::AccountId, value: Self::Balance, ) -> DispatchResult 抵押
      • fn unreserve_named( id: &Self::ReserveIdentifier, who: &T::AccountId, value: Self::Balance, ) -> Self::Balance 解抵押
      • fn slash_reserved_named( id: &Self::ReserveIdentifier, who: &T::AccountId, value: Self::Balance, ) -> (Self::NegativeImbalance, Self::Balance) 惩罚抵押
      • fn repatriate_reserved_named( id: &Self::ReserveIdentifier, slashed: &T::AccountId, beneficiary: &T::AccountId, value: Self::Balance, status: Status, ) -> Result<Self::Balance, DispatchError> 转移抵押金额

  4. LockableCurrency<T::AccountId>
    • 作用: 锁仓相关v操作
    • 方法:
      fn set_lock( id: LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, ) 设置锁仓(id相同的锁用最新的)
    • fn extend_lock( id: LockIdentifier, who: &T::AccountId, amount: T::Balance, reasons: WithdrawReasons, ) 扩展锁 id相同用最大
    • fn remove_lock(id: LockIdentifier, who: &T::AccountId) 删除锁

关于withdraw

在其他方法里, 先判断扣除后剩余的金额

//balances模块里面
fn frozen(&self, reasons: Reasons) -> Balance {
match reasons {
Reasons::All => self.misc_frozen.max(self.fee_frozen),
Reasons::Misc => self.misc_frozen,
Reasons::Fee => self.fee_frozen,
}
}
//balances 模块里面
impl From<WithdrawReasons> for Reasons {
    fn from(r: WithdrawReasons) -> Reasons {
        if r == WithdrawReasons::from(WithdrawReasons::TRANSACTION_PAYMENT) {
            Reasons::Fee
        } else if r.contains(WithdrawReasons::TRANSACTION_PAYMENT) {
            Reasons::All
        } else {
            Reasons::Misc
        }
    }
}
//payment模块里面
fn withdraw_fee(
        who: &T::AccountId,
        _call: &T::Call,
        _info: &DispatchInfoOf<T::Call>,
        fee: Self::Balance,
        tip: Self::Balance,
    ) -> Result<Self::LiquidityInfo, TransactionValidityError> {
        if fee.is_zero() {
            return Ok(None)
        }

        let withdraw_reason = if tip.is_zero() {
            WithdrawReasons::TRANSACTION_PAYMENT
        } else {
            WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP
        };

        match C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive) {
            Ok(imbalance) => Ok(Some(imbalance)),
            Err(_) => Err(InvalidTransaction::Payment.into()),
        }
    }

// balances 模块
fn ensure_can_withdraw(
        who: &T::AccountId,
        amount: T::Balance,
        reasons: WithdrawReasons,
        new_balance: T::Balance,
    ) -> DispatchResult {
        if amount.is_zero() {
            return Ok(())
        }
        let min_balance = Self::account(who).frozen(reasons.into());
        ensure!(new_balance >= min_balance, Error::<T, I>::LiquidityRestrictions);
        Ok(())
    }

通过上面代码的分析我们发现ensure_can_withdraw只与扣掉金额后剩余的自由余额有关; 并且payment模块的扣掉金额原因均与TRANSACTION_PAYMENT有关, 对应的理由是fee或是all, 就是支付的费用是fee或者是misc跟fee之间的最大值。

  • 问题
  1. 账户里面的misc_frozenfee_frozen是怎么来的
// 方法update_locks中的代码
let res = Self::mutate_account(who, |b| {
            b.misc_frozen = Zero::zero();
            b.fee_frozen = Zero::zero();
            for l in locks.iter() {
                if l.reasons == Reasons::All || l.reasons == Reasons::Misc {
                    b.misc_frozen = b.misc_frozen.max(l.amount);
                }
                if l.reasons == Reasons::All || l.reasons == Reasons::Fee {
                    b.fee_frozen = b.fee_frozen.max(l.amount);
                }
            }
        });

根据代码我们可以得出,有TRANSACTION_PAYMENT原因的锁比较特殊外, 绝大部分的锁仓其实是misc_frozen

// 关于原因的enum
bitflags::bitflags! {
    /// Reasons for moving funds out of an account.
    #[derive(Encode, Decode)]
    pub struct WithdrawReasons: u8 {
        /// In order to pay for (system) transaction costs.
        const TRANSACTION_PAYMENT = 0b00000001;
        /// In order to transfer ownership.
        const TRANSFER = 0b00000010;
        /// In order to reserve some funds for a later return or repatriation.
        const RESERVE = 0b00000100;
        /// In order to pay some other (higher-level) fees.
        const FEE = 0b00001000;
        /// In order to tip a validator for transaction inclusion.
        const TIP = 0b00010000;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容