name: mvx_vault_pattern description: 用于在单笔交易中跟踪多步操作期间中间余额的内存令牌分类账。
MultiversX 内存令牌分类账
问题
单笔交易中的多步令牌操作需要跟踪中间余额而无需存储写入。
使用时机
- 单笔交易中的多步令牌操作(交换、批处理、原子流程)
- 不适用于单步操作或必须在交易之间持久化的状态
核心模式:双数据结构
使用 ManagedMapEncoded(O(1)查找)+ ManagedVec(用于结算的有序迭代)。
pub struct TokenLedger<M: VMApi> {
balances: ManagedMapEncoded<M, TokenIdentifier<M>, BigUint<M>>,
tokens: ManagedVec<M, TokenIdentifier<M>>,
}
impl<M: VMApi> TokenLedger<M> {
pub fn new() -> Self {
Self { balances: ManagedMapEncoded::new(), tokens: ManagedVec::new() }
}
pub fn from_payments(payments: &PaymentVec<M>) -> Self {
let mut ledger = Self::new();
for payment in payments.iter() {
ledger.deposit(&payment.token_identifier, payment.amount.as_big_uint());
}
ledger
}
pub fn deposit(&mut self, token: &TokenIdentifier<M>, amount: &BigUint<M>) {
if !self.balances.contains(token) {
self.tokens.push(token.clone());
self.balances.put(token, amount);
} else {
let current = self.balances.get(token);
self.balances.put(token, &(current + amount));
}
}
pub fn withdraw(&mut self, token: &TokenIdentifier<M>, amount: &BigUint<M>) -> BigUint<M> {
let current = self.balance_of(token);
require!(current >= *amount, "分类账余额不足");
let new_balance = ¤t - amount;
if new_balance == 0u64 { self.remove_token(token); }
else { self.balances.put(token, &new_balance); }
amount.clone()
}
pub fn withdraw_all(&mut self, token: &TokenIdentifier<M>) -> BigUint<M> {
let amount = self.balance_of(token);
if amount > 0u64 { self.remove_token(token); }
amount
}
pub fn balance_of(&self, token: &TokenIdentifier<M>) -> BigUint<M> {
if !self.balances.contains(token) { return BigUint::zero(); }
self.balances.get(token)
}
pub fn settle_all(&self) -> ManagedVec<M, Payment<M>> {
let mut payments = ManagedVec::new();
for token in self.tokens.iter() {
let amount = self.balances.get(&token);
if amount > 0u64 {
payments.push(Payment::new(token.clone_value(), 0u64, amount));
}
}
payments
}
fn remove_token(&mut self, token: &TokenIdentifier<M>) {
self.balances.remove(token);
for (i, t) in self.tokens.iter().enumerate() {
if t.as_managed_buffer() == token.as_managed_buffer() {
self.tokens.remove(i);
break;
}
}
}
}
反模式
- 使用存储处理临时余额(昂贵、不必要)
- 不清理零余额条目(结算时浪费gas)
- 仅使用ManagedVec而没有映射(O(N)查找)
变体
生产仓库扩展了:结果链式处理、基于PPM的提款、选择性结算(保留小额余额作为收入)、金额模式枚举(固定/百分比/全部/先前结果)。