balances模块文档
说明
- 最新的balances模块对抵押添加了
NamedReservableCurrency
功能, 可以更加精准的操作抵押金额 - 新增了一些辅助的traits, 方便不同应用场景的使用
- balances模块的资产是可变资产, 跟nft有本质的不同, 也就是
fungible
重要接口(对外开放)
- 转账
- 代码 `transfer(
origin: OriginFor<T>,
dest: <T::Lookup as StaticLookup>::Source,[pallet::compact] value: T::Balance,
)` - 参数:
dest
对方地址
value
转账金额 - 逻辑:
- 默认地址可以废弃掉(死亡)
- 代码 `transfer(
- 设置账户金额
- 代码 `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()
,那么两个账户最新余额都是零 - 账户之前的余额都归零, 以输入的金额作为最新金额
- 代码 `pub fn set_balance(
- 保持账户存活的转账
- 代码 `pub fn transfer_keep_alive(
origin: OriginFor<T>,
dest: <T::Lookup as StaticLookup>::Source,[pallet::compact] value: T::Balance,
)` - 参数:
dest
对方地址
value
转账金额 - 逻辑:
- 账户剩余的金额必须大于系统的最小存货活金额
- 代码 `pub fn transfer_keep_alive(
- 全部转账
- 代码
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(供其他模块调用)
> 目前其他模块不常用, 只是辅助作用
- 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, )
是否可以减掉这个金额
-
- fungible::Mutate<T::AccountId>
- 主要作用:对账户金额进行凭空加减操作(铸币或是销毁)
- 主要方法:
-
fn mint_into(who: &T::AccountId, amount: Self::Balance)
铸造币子 -
fn burn_from( who: &T::AccountId, amount: Self::Balance, )
销毁某个账户的币子
-
- fungible::Transfer<T::AccountId>
- 主要功能: 转账
- 主要方法
-
fn transfer( source: &T::AccountId, dest: &T::AccountId, amount: T::Balance, keep_alive: bool, )
转账
-
- fungible::Unbalanced
- 功能: 暴力设置账户金额或是发行量
- 主要方法
-
fn set_balance(who: &T::AccountId, amount: Self::Balance)
设置某个账户的金额 -
fn set_total_issuance(amount: Self::Balance)
设置发行总量
这个方法对于其他模块的开发没有作用
*** -
- fungible::InspectHold<T::AccountId>
- 作用: 查询保留余额与对金额进行抵押判断
- 方法:
-
fn balance_on_hold(who: &T::AccountId)
查询账户的保留余额 -
fn can_hold(who: &T::AccountId, amount: T::Balance) -> bool
是否可以抵押该金额
-
- 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(经常使用)
- 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>
给某账户设置自由余额
-
- 主要方法
- 作用: 资产的普通操作
- 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, )
转移抵押金额
-
- 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>
转移抵押金额
-
- 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之间的最大值。
- 问题
- 账户里面的
misc_frozen
与fee_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;
}
}