ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TigerBeetle 货币兑换(Currency Exchange)实战:基于 ledger 与 linked 转账的多币种建模方案

TigerBeetle 货币兑换(Currency Exchange)实战:基于 ledger 与 linked 转账的多币种建模方案 TigerBeetle 货币兑换Currency Exchange实战基于 ledger 与 linked 转账的多币种建模方案【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetleTigerBeetle 以单一借贷转账single debit / single credit为原语通过ledger字段对账户进行资产类型分区不同ledger的账户之间不允许直接转账。本文围绕仓库中的 Currency Exchange Recipe 展开讲解如何用两对不同 ledger 的账户 两条原子链接的转账实现汇率无关的多币种兑换并给出汇率舍入、Spread点差建模等实战细节帮助读者在 TigerBeetle 之上落地可审计、可防套利的外汇业务。为什么需要货币兑换这一层建模很多应用天然涉及多种货币银行可能同时持有多个币种的余额支付平台需要做跨境汇款。TigerBeetle 的数据模型由 Account、Transfer 和 ledger 三类概念组成其中ledger是一个 32 位无符号整数标识符用于把账户划分成互不交易的集合见 Data Modeling: Ledgers。一个逻辑实体若要持有多个币种每个币种必须放在独立的Account中而不同币种对应的账户则需要落在不同的ledger上。之所以不推荐在应用层把多币种统一折算成单一币种是因为汇率是波动的——如果只记录折合后的单一币种余额交易当时的真实汇率信息就会丢失审计与对账将无从谈起。因此 TigerBeetle 的设计选择是ledger直接编码币种或其他资产类型把汇率语义留给应用层去显式建模。补充ledger还可以进一步细分。例如多租户场景下可以为每个客户单独分配一个ledger如果客户同时持有多个币种则该客户会对应多个ledger。ledger在 TigerBeetle 中只作为数字标识存储额外的元数据币种符号、精度等建议放到控制面数据库管理见 system-architecture.md。核心约束不同ledger的账户不能直接转账在 create_transfers 中TigerBeetle 强制校验一条规则转账双方账户的ledger必须一致否则返回accounts_must_have_the_same_ledger转账自身的ledger也必须与两个账户一致否则返回transfer_must_have_the_same_ledger_as_accounts。从源码可以得到直接印证在 src/state_machine.zig 的create_transfer实现中if (dr_account.ledger ! cr_account.ledger) return .accounts_must_have_the_same_ledger; if (t.ledger ! dr_account.ledger) { return .transfer_must_have_the_same_ledger_as_accounts; }ledger字段本身的约束见 Account.ledger 与 Transfer.ledger包括类型为 32 位无符号整数且不能为零。因此跨币种的资金移动无法靠单条转账完成必须拆成多条同ledger内的转账再通过原子链接绑定为一个整体。数据建模四个账户 两条链接转账TigerBeetle 的单条Transfer只能借记一个账户、贷记一个账户且两者必须在同一ledger。要实现货币兑换标准的 Recipe 做法是创建两条原子链接的、分属不同ledger的转账。一个最简单的货币兑换涉及四个账户账户说明ledgerA₁源账户source account即付款方1如 USDA₂目标账户destination account即收款方2如 INRL₁源流动性账户source liquidity account1如 USDL₂目标流动性账户destination liquidity account2如 INR以及两条链接转账转账T₁从源账户A₁转到源流动性账户L₁都在ledger 1上转账T₂从目标流动性账户L₂转到目标账户A₂都在ledger 2上。两条转账的金额按汇率计算各不相同。L₁与L₂都属于同一实体——流动性提供者liquidity provider例如银行或交易所而A₁与A₂既可以属于同一实体也可以分属不同实体视具体业务而定。为什么用两条转账而不是一条关键在于 TigerBeetle 的账本不变量系统要求所有账户的已过账借方总额等于已过账贷方总额见 Account Guarantees。只有同时记录付出去的 USD和收进来的 INR账本才在全局保持平衡且两条记录不可分割——它们通过flags.linked绑定要么同时成功要么同时失败。完整示例USD → INR 汇款假设要从账户A₁以 USD 计价向账户A₂以 INR 计价发送100.00 USD。汇率为1.00 USD 82.42135 INR则100.00 USD 8242.14 INR。在 TigerBeetle 中提交这两条转账LedgerDebit AccountCredit AccountAmountflags.linkedUSDA₁L₁10000trueINRL₂A₂824214false注意两点金额是整数。TigerBeetle 的金额与余额都是无符号 128 位整数详见 Transfer.amount分数金额需要按 Fractional Amounts and Asset Scale 的方式映射把该币种的最小有用单位映射为1。例如1 USD 100分asset scale 为2所以100.00 USD记为整数100008242.14 INR记为824214INR 的 scale 为2。应用在渲染或与外部系统对接时再按 scale 换算回小数而内部计算一律使用整数避免浮点精度损失。链接链以最后一个不带flags.linked的转账收尾。第一条转账带flags.linked true表示结果绑定到下一个转账第二条不带该标志表示链到此结束。如果链中最后一个事件仍设置了linked服务端会返回linked_event_chain_open错误见 create_transfers 状态码。链接语义的细节链接事件的具体规则在 Linked Events 中有完整说明请求内的每个事件默认独立成功或失败只有显式设置flags.linked才会形成同生共死的链条链内事件按顺序执行若中途出错则回滚使前序事件的效果对后续事件可见链内第一个失败的事件返回其真实错误码链内其余事件统一返回linked_event_failed同一请求内可以存在多条独立的链各自独立成败链执行完之后链接关系不会持久化在数据库中——若要记录这几笔转账属于同一次兑换需要把关联 ID 写入某个user_data字段见 Data Modeling: user_data 与 Linked Events 末尾的提示。在源码层面链接链的遍历与回滚逻辑位于 src/state_machine.zig它以chain/chain_broken追踪当前链状态链断后后续事件直接返回linked_event_failed链完成遇到第一个非 linked 事件后统一提交。汇率舍入向流动性账户倾斜以抑制套利在上述示例中由于L₁与L₂同属流动性提供者这一实体实体在该交易中不会亏损若汇率精确可整除实体不赚不亏break even若汇率无法整除应用应当把舍入误差倾向于流动性账户一侧从而抑制套利arbitrage。这个建议的直觉是如果舍入总是对交易者有利交易者就可以通过反复兑换在两种货币间循环套利让流动性提供者持续承担微小但可累积的亏损。把舍入固定到流动性账户一侧等价于把不可精确表示的那部分汇率差赠送给了做市方从而消除套利动机。收取点差Spread单独转账而非篡改汇率上一节的例子是流动性提供者不赚不亏的情形。如果流动性提供者要收取手续费即点差、SpreadRecipe 的推荐做法是把费用作为一条单独的转账加入linked链从源账户转到源流动性账户A₁ → L₁。为什么不能用调整汇率来代替直接在汇率上做手脚例如把1.00 USD 82.42 INR调成对做市方有利的82.30虽然也能让做市方盈利但会带来一个致命问题汇率与点差被揉合在一起事后无法区分。而把点差建模为独立转账等于在账本上显式记录成交时的汇率和成交时的点差这两个独立事实——这是任何事后审计、对账、风控都需要的原始信息。TigerBeetle 账本不可变、可追溯的特性账户与转账一经创建不可修改删除见 Account 与 Transfer保证了这条记录永久可查。示例收取 0.10 USD 手续费延续前面的场景流动性提供者对这笔交易收取0.10 USD费用。此时linked链由三条转账组成LedgerDebit AccountCredit AccountAmountflags.linkedUSDA₁L₁10000trueUSDA₁L₁10trueINRL₂A₂824214false逐条解读第一条客户本金100.00 USD10000个最小单位从A₁转入L₁第二条手续费0.10 USD10个最小单位同样从A₁转入L₁——这是做市方的收入第三条客户应收8242.14 INR824214从L₂转入A₂链在此结束。三条转账绑定在同一linked链中任一失败则整体回滚保证客户不会出现本金被扣、外币未到账的半完成状态。从账本角度看客户A₁净借记10010本金 手续费做市方的L₁获得10010L₂支付824214客户A₂贷记824214全局借贷仍然平衡。扩展阅读与关联资源本 Recipe 属于 docs/coding/recipes 系列同一模式控制账户 链接转账也用于 Multi-Debit, Multi-Credit Transfers单借多贷/多借多贷的复合分录与 Balance-Conditional Transfers余额条件转账跨ledger关系的持久化把交易组 ID 写入user_data_128多个账户间的归属关系也建议用user_data表达因为id在集群内全局唯一、并非按ledger分区见 Data Modelingflags.linked的完整约束见 Transfer.flags.linked链接链的实现与回滚逻辑可阅读 src/state_machine.zig 中create_transfer相关代码各语言客户端的createTransfers用法可参考 Node 示例以及 .NET、Java、Go、Python、Rust 等客户端实现。小结TigerBeetle 用ledger划分币种、用flags.linked保证跨币种兑换的原子性二者组合构成了一套严谨的多币种建模方案四个账户两两成对、两条转账一链绑定金额以整数 asset scale 表达规避浮点误差舍入向流动性账户倾斜以抑制套利点差作为链内独立转账显式记录从而把汇率与费用两个事实永久固化在不可变账本中。这套模式同时适用于多币种银行账本、跨境汇款、交易所出入金等场景且与复合分录、余额条件转账等 Recipe 组合使用可以覆盖绝大多数真实的资金流转需求。【免费下载链接】tigerbeetleThe financial transactions database designed for mission critical safety and performance.项目地址: https://gitcode.com/GitHub_Trending/ti/tigerbeetle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表