{"content":{"title":"Sui Move Bucket 稳定币协议合约初探","body":"## 前言\r\n\r\nBucket 协议是SUI上的基于抵押资产的稳定币协议，通过抵押SUI等加密资产，用户可以借出对应的稳定币 **BUCK**\r\n\r\n\r\n## 核心组件\r\nBucket 协议中有不少名字有趣的核心组件，它们有这样的关系图表\r\n\r\n![bucket-protocol.png](https://img.learnblockchain.cn/attachments/2024/08/7ng2NGoU66c7150e5c032.png)\r\n\r\n### Bucket \r\n可以理解为**桶** 是一个容器，它管理着同类抵押资产的所有参与者的信息\r\n\r\nMove定义\r\n```\r\npublic struct Bucket<phantom T0> has store, key {\r\n    id: sui::object::UID,\r\n    min_collateral_ratio: u64,\r\n    recovery_mode_threshold: u64,\r\n    collateral_decimal: u8,\r\n    max_mint_amount: std::option::Option<u64>,\r\n    collateral_vault: sui::balance::Balance<T0>,\r\n    bottle_table: bucket_protocol::bottle::BottleTable,\r\n    surplus_bottle_table: sui::table::Table<address, bucket_protocol::bottle::Bottle>,\r\n    minted_buck_amount: u64,\r\n    base_fee_rate: u64,\r\n    latest_redemption_time: u64,\r\n    total_flash_loan_amount: u64,\r\n}\r\n```\r\n\r\n**T0**：抵押的加密货币的类型，比如 0x2::sui::SUI\r\n**collateral_vault**: 抵押金库，所有同类抵押品的balance总和\r\n**bottle_table**: 抵押参与者的数据结构，该结构有一个核心的字段table 它是***基于抵押率排序的链表***，在后面的redeem操作中会优先处理抵押率较低的bottle来进行基于抵押物实际价值的赎回操作\r\n**surplus_bottle_table**：赎回redeem操作中如果一个bottle被完全赎回销毁了，就会自动创建一个**盈余table**，下一次对该bottle的借贷过程中会尝试从**盈余table**拿回剩下的抵押物\r\n\r\n### Bottle \r\n可以理解为**瓶子** 它代表每个参与者的抵押借贷信息\r\n\r\nMove定义\r\n```\r\npublic struct Bottle has store, key {\r\n    id: UID,\r\n    collateral_amount: u64,\r\n    buck_amount: u64,\r\n    stake_amount: u64,\r\n    reward_coll_snapshot: u128,\r\n    reward_debt_snapshot: u128,\r\n}\r\n```\r\n\r\n**collateral_amount**：抵押品的数量\r\n**buck_amount**：借出来的buck数量\r\n\r\n### Tank \r\n可以理解为 **蓄水池**，它在清算流程中有着重要的作用\r\n当一个用户的bottle因为健康值低于110%被清算的时候，首先会通过Tank里的Buck来偿还清算，然后Tank会收到bottle的打折抵押物\r\n用户也可以通过手动存入buck到tank中得到代币**ContributorToken**，根据持有的**ContributorToken**占比可以获得bottle清算的抵押物作为奖励\r\n\r\n### Well \r\n可以理解为 **福利池**，协议中的各种fee都会在well中进行收集，比如Borrow(抵押借贷), Redeem(赎回), Flash Loan(闪电贷), Liquidation(清算)\r\n\r\n```\r\npublic struct Well<phantom T0> has store, key {\r\n    id: UID,\r\n    shared_pool: Balance<T0>,\r\n    reserve: Balance<T0>,\r\n    staked: Balance<BKT>,\r\n    total_weight: u64,\r\n    current_s: u128,\r\n}\r\n```\r\n\r\n## 核心操作\r\n### borrow\r\n抵押借贷，用户通过存入抵押的加密货币，来借出一定数量的BUCK稳定币\r\n**collateralInput** 就是存入抵押的加密货币的balance值  \r\n**buckMintAmount** 是你期望借出的buck数量 只要满足存入抵押物之后bottle还满足健康条件都能借出来\r\n**insertionPlace** bottle的管理是用了一个基于抵押率排序的LinkedTable，所以这里的插入位置其实是一个建议值，可以减少遍历链表所产生的gas费，不传的话就是从链表的front开始遍历\r\n\r\n```\r\npublic fun borrow<T0>(\r\n    protocol: &mut BucketProtocol,\r\n    oracle: &BucketOracle,\r\n    clock: &Clock,\r\n    collateralInput: Balance<T0>,\r\n    buckMintAmount: u64,\r\n    insertionPlace: Option<address>,\r\n    ctx: &mut TxContext\r\n) : Balance<BUCK> {\r\n}\r\n```\r\n\r\n### repay\r\n偿还操作，用户通过偿还buck来换回它之前存入bottle的抵押加密货币\r\n该操作和下面的redeem有所不同，它只能由用户自己来偿还，同时它是不考虑偿还时候的抵押物的实际价值的，而是根据buck和抵押物的比例来偿还\r\n```\r\npublic fun repay<T0>(\r\n    bucketProtocol: &mut BucketProtocol,\r\n    buckInput: Balance<BUCK>,\r\n    ctx: &TxContext\r\n) : Balance<T0> {\r\n}\r\n```\r\n\r\n### redeem\r\n赎回操作，它是维持BUCK稳定币锚定1美元地板价格的方式\r\n任何持有BUCK的用户都可以通过赎回操作来换取协议里存入的抵押加密货币\r\n赎回的时候，会使用Bucket里的**BottleTable**数据结构，根据抵押率从低到高进行赎回\r\n\r\n```\r\npublic fun redeem<T0>(\r\n    bucketProtocol: &mut BucketProtocol,\r\n    oracle: &BucketOracle,\r\n    clock: &Clock,\r\n    buckInput: Balance<BUCK>,\r\n    insertionPlace: Option<address>\r\n) : Balance<T0> {\r\n}\r\n```\r\n\r\n### liquidate\r\n清算操作，当一个bottle的抵押率低于110%的时候，它就可以被清算\r\nBucket协议清算的时候设计了**Tank缓冲池**来作为偿还BUCK获得抵押物的第一来源\r\n\r\n```\r\npublic fun liquidate_under_normal_mode<T0>(\r\n    bucketProtocol: &mut BucketProtocol, \r\n    oracle: &BucketOracle, \r\n    clock: &Clock, \r\n    targetAddress: address\r\n) : Balance<T0> {\r\n}\r\n```\r\n\r\n### flash loan\r\n闪电贷，在MOVE中通过hot potato模式就可以实现闪电贷\r\n在Bucket协议中，闪电贷的池子来源有两处\r\n\r\n一处是bottle中的抵押物\r\n```\r\npublic fun flash_borrow<T0>(\r\n    bucketProtocol: &mut BucketProtocol, \r\n    amount: u64\r\n) : (Balance<T0>, bucket::FlashReceipt<T0>) {\r\n}\r\n```\r\n```\r\npublic fun flash_repay<T0>(\r\n    bucketProtocol: &mut BucketProtocol, \r\n    repayBalance: Balance<T0>, \r\n    flashReceipt: bucket::FlashReceipt<T0>\r\n) {\r\n}\r\n```\r\n\r\n一处是tank中存入的buck\r\n```\r\npublic fun flash_borrow_buck<T0>(\r\n    bucketProtocol: &mut BucketProtocol, \r\n    amount: u64\r\n) : (Balance<BUCK>, tank::FlashReceipt<BUCK, T0>) {\r\n}\r\n```\r\n```\r\npublic fun flash_repay_buck<T0>(\r\n    bucketProtocol: &mut BucketProtocol, \r\n    repayBalance: Balance<BUCK>, \r\n    flashReceipt: tank::FlashReceipt<BUCK, T0>\r\n) {\r\n}\r\n```\r\n\r\nbucket::FlashReceipt和tank::FlashReceipt分别是实现闪电贷所用的hot potato凭据，拿到凭据后必须在同一个PTB中完成借款资金的归还\r\n\r\n## PSM模块\r\nBuck锚定在1美元，之前的方法是通过鼓励套利者通过borrow/redeem操作来完成的\r\nPSM模块则是提供了另外一种更简单便捷的方法，也即通过维护Buck和USDT/USDC的池子  \r\n\r\n如果BUCK高于1 USDC，用户可以以1:1的价格将USDC兑换成BUCK，然后卖出BUCK获利。\r\n在市场激励的推动下，这给BUCK带来了抛售压力，引导BUCK的价格回到1美元。\r\n\r\n如果BUCK低于1 USDC，用户可以购买BUCK并通过PSM转换为USDC。\r\n这种购买压力对用户来说是有利可图的，通过增加对BUCK的需求，有助于重建BUCK与USDC/USDT的锚定。\r\n\r\nPSM合约模块实现也比较简单,Buck和池子里的USDC/USDT是一比一兑换的\r\n\r\n```\r\npublic struct Reservoir<phantom T0> has store, key {\r\n    id: sui::object::UID,\r\n    conversion_rate: u64,\r\n    charge_fee_rate: u64,\r\n    discharge_fee_rate: u64,\r\n    pool: sui::balance::Balance<T0>,\r\n    buck_minted_amount: u64,\r\n}\r\n```\r\n\r\n```\r\npublic(friend) fun handle_charge<T0>(\r\n    reservoir: &mut Reservoir<T0>,\r\n    chargeBalance: sui::balance::Balance<T0>\r\n) : u64 {\r\n}\r\n```\r\n\r\n```\r\npublic(friend) fun handle_discharge<T0>(\r\n    reservoir: &mut Reservoir<T0>, \r\n    amount: u64\r\n) : sui::balance::Balance<T0> {\r\n}\r\n```\r\n\r\n## 总结\r\n本文通过分析Bucket Move合约，介绍了协议里相关组件和模块，Bucket是一个超额抵押稳定币协议，具有创新的清算和赎回机制\r\n此外，Bucket协议从一开始就设计了不少激励用户的机制，将其协议收入的很大一部分代币化并重新分配给用户。\r\n当然，Bucket协议里还设计了其他机制，比如Recovery Mode，借贷buck时候的复利计算Interest Rate，Tank池子空的时候保底机制redistribution，这些都可以通过下面的参考资料进一步的学习\r\n\r\n## 参考资料\r\n[bucket官方文档](https://docs.bucketprotocol.io/)\r\n[bucket白皮书](https://github.com/Bucket-Protocol/whitepaper)\r\n[bucket SDK](https://github.com/Bucket-Protocol/bucket-protocol-sdk/blob/main/src/client.ts)"},"author":{"user":"https://learnblockchain.cn/people/19525","address":null},"history":"bafkreicsh32626z4nz4chi234w3oqqtoz7fv4fbaztnkm3xo5kfr33ebmy","timestamp":1724324091,"version":1}