MVX内存令牌分类账模式Skill mvx_vault_pattern

此技能涉及MultiversX区块链平台的内存令牌分类账模式,用于在智能合约中高效管理多步令牌操作的中间余额,避免不必要的存储写入,提升交易性能和原子性。关键词:MultiversX, 内存令牌分类账, 智能合约, 中间余额, 令牌管理, 区块链开发。

智能合约 0 次安装 0 次浏览 更新于 3/21/2026

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 = &current - 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的提款、选择性结算(保留小额余额作为收入)、金额模式枚举(固定/百分比/全部/先前结果)。