Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

嵌入式 Balance:池子、金库与与协议资金的边界

本节要回答的问题

  • 为什么 DeFi/游戏金库 几乎总是 Balance 字段 + 模块入口,而不是 send_funds 堆地址
  • coin::take / putinto_balance / from_balance 如何选?
  • 自定义聚合全局 accumulator 各适用于什么信任模型?

前置§15.5§12.11(该节已有 Vault + SUI 的完整示例;本节用泛型 T 复述同一模式,不重复 长代码讲解)。


原理:BalanceUID,适合「账内数」

Balance<T> 只有 store不能单独作为拥有型对象出现在全局对象集里。放在 PoolVaultEscrow 里时:

  • 读写路径完全由你的模块逻辑控制
  • 不占用 用户地址下的 Coin 对象列表
  • TreasuryCap 的 mint/burn 通过 Coin 进出 衔接。

精髓应用内记账 = 嵌入式 Balance协议级地址资金 = §15.7/14.11;二者 不要默认互通


奖池:存入与提取

use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin};

public struct PrizePool<phantom T> has key {
    id: UID,
    pool: Balance<T>,
}

public fun deposit<T>(p: &mut PrizePool<T>, c: Coin<T>) {
    balance::join(&mut p.pool, coin::into_balance(c));
}

public fun withdraw<T>(p: &mut PrizePool<T>, amount: u64, ctx: &mut TxContext): Coin<T> {
    coin::take(&mut p.pool, amount, ctx)
}

初始化pool 通常为 balance::zero()充值 只能来自 Coinmint,不能凭空 join 非零


选型:take/put vs into_balance/from_balance

  • take / put:在 已有 Balance 字段Coin 之间 部分存取UID 始终在 Coin 侧新建/销毁
  • into_balance / from_balance整枚 Coin ↔ 整块 Balance,适合 整单入账/出账

send_funds 的对比

机制控制者典型场景
对象内 Balance你的模块AMM、拍卖托管、游戏仓库
balance::send_funds协议 accumulator 语义需要与 settled_funds_value系统级读数 对齐的结算

常见误区

  1. 在公开函数里 into_balance 后忘记 join:会导致 资源泄漏编译失败(视上下文)。
  2. 把池子 Balance 当用户余额:用户侧应 withdrawCoin 后再展示为「可转资产」。
  3. 混用两种聚合不告知用户:同一地址 既有 Coin 又有 settled 资金 时,产品必须拆分说明

小结

嵌入式 Balance 是应用层资产记账的默认答案全局 accumulator 是协议层结算的补充工具。下一节:上线运维与版本误解