DEX 样本

要在 IC 上启用 DEFI 应用程序,容器需要与代币容器和分类帐容器交互。 这个示例 dapp 说明了如何促进这些交互。

示例交换在 MotokoRust 并且可以看到https://gzz56-daaaa-aaaal-qai2a-cai.ic0.app/[在IC上运行]。

体系

IC 的设计允许更复杂的链上计算。 结合廉价存储,可以拥有链上订单簿。 此示例代码利用这些功能并将用户余额和订单存储在交换容器中。 样本交换功能可以浓缩为以下步骤:

  • 交易所托管资金(代币和ICP的不同机制,见下文)。

  • 交易所更新内部资产负债表。

  • 用户在交易所进行交易,导致交易所更新其内部资产负债表。

  • 从交易所提取资金会将保管权归还给用户。

界面

从交易所请求用户特定的分类帐帐户标识符。 这个唯一的账户标识符代表了交易所总账账户中用户特定的子账户,允许它区分用户存款。

getDepositAddress: () -> (blob);

发起用户存款兑换。 如果用户想要存入 ICP,交易所将资金从用户特定的存入地址转移到其默认子地址,并调整用户在 DEX 上的 ICP 余额。 如果用户想要存入 DIP 代币,交易所会尝试将批准的资金转移到其代币账户并调整用户的余额。

deposit: (Token) -> (DepositReceipt);

向交易所撤回请求。 如果用户有足够的余额,交易所会将资金返还给用户。

withdraw: (Token, nat, principal) -> (WithdrawReceipt);

下新订单以进行交换。 如果订单与现有订单匹配,它将被执行。

placeOrder: (Token, nat, Token, nat) -> (OrderPlacementReceipt);

允许用户取消提交的订单。

cancelOrder: (OrderId) -> (CancelOrderReceipt);

请求用户在交换特定代笔时的余额。

getBalance: (Token) -> (nat) query;

费用

交易所有责任从交易中扣除费用。这很重要,因为交易所必须为取款和内部转账支付费用。

代币兑换演练

本节包含核心交换功能的详细演练。大多数交互需要多个步骤,并通过使用提供的前端进行简化。由于交易所容器功能是公开的,高级用户可以使用 dfx 与交易所进行交互。

存入ICP

分类帐容器提供了一个独特的接口,因此需要单独解决与 ICP 的交互。

  • 用户调用“getDepositAddress”函数。响应包含一个唯一的账户标识符,代表由交易所控制的用户特定子账户。交易所可以通过这个地址识别出负责存款的用户。

  • 用户将 ICP 转入获取的存款地址,等待转账完成。

  • 为了通知交易所,用户使用 ICP 令牌主体调用“存款”。交易所会查看用户的子账户,调整用户在交易所的余额。第二步,交易所将资金从用户子账户转移到其默认子账户,交易所保留其所有 ICP。

存入代币

存入代币更直接,因为 DIP20 提供了更丰富的交互界面。

  • 用户调用代币容器的“批准”函数。这使交易所能够代表用户将资金转移给自己。

  • 与ICP充值类似,用户调用交易所的“充值”功能。交易所然后将批准的代币资金转给自己,并调整用户的交易所余额。

下单

用户将资金存入交易所后,即可下单。一个订单由两个元组组成。 来自:(Token1,amount1)to:(Token2,amount2)。这些订单被添加到交易所。这些订单会发生什么特定于交易所的实施。此示例提供了一个简单的交易所,它只执行完全匹配的订单。请注意,这只是一个玩具交换,交换功能只是为了完整性。提示:交换有时会很贪心;)

提取资金

与存入资金相比,提取资金更简单。由于交易所拥有资金的保管权,因此交易所将在“提款”请求时将资金返还给用户。内部汇兑余额作相应调整。

常见错误

  • 并发执行:如果容器函数有 await 语句,则执行可能是交错的。 为了避免错误,有必要仔细考虑数据结构更新的位置,以防止双花攻击。

  • 浮点数:更高级的交易所应注意浮点数并确保限制小数。 *等待后没有恐慌:当发生恐慌时,状态会回滚。 这可能会导致交换的正确性出现问题。