Mixin 新系统相关的 API 已经基本完善,但是相关的文档目前还欠缺,我刚刚完成了 @我信 和 @Quill 的相关适配工作,顺手整理一下注意事项,供各位机器人开发者参考。
目前已知的支持 Mixin 新系统 API 的 SDK 有
- Mixin 官方维护的 Golang SDK 和 Nodejs SDK;
- Pando 团队维护的 Golang 版本: mixin-sdk-go
- 我本人维护的 Ruby 版本: mixin_bot
因为每个机器人的业务不一样,需要适配的具体工作当然也不一样。但总体来说,需要适配的工作应该主要是两方面
- 机器人收款
- 机器人支付
关于机器人收款
只要你的机器人在新系统注册成功,那就可以正常收款了。
你需要为用户生成新系统的支付链接,格式如下
如果是直接用机器人的钱包收款,这里的 address
直接填机器人的 UUID 即可,如果是多签组收款,则需要构造一个 MIX 开头的地址,SDK 里有相关的方法。
在旧系统时,我们通常是通过轮询 /network/snapshots
来触发收款之后的业务逻辑。在新系统里,API 只要改为 /safe/snapshots?asset=UUID&app=UUID&opponent=UUID&offset=RFC3339NANO&limit=500
, 然后注意返回的 JSON 对象里部分格式的变化,就可以了。
这里需要注意的一点是,如果加了 app=UUID
参数,返回的结果则除了机器人本身钱包收到的 snapshot,还会包含所有该机器人创建的用户收到的 snapshot。
关于机器人支付
相对于旧系统,新系统的支付 API 改动比较大一些。
在旧系统,支付的时候主要是 /transfers
接口,用交易信息和加密的 PIN 码进行调用。UTXO 相关的操作都是由 Mixin API 完成的。新系统里,则需要开发者自行管理 UTXO。如果你之前使用过多签相关的 API,对新的 API 理解起来应该比较容易。
总结一下每笔支付的流程,大概是
- 拉取钱包里未使用的 utxo,根据支付的金额选择合适数量的 utxo;
- 用
POST /safe/keys
接口获取收款信息(Ghost keys); - 用
POST /safe/transaction/requests
接口验证交易格式; - 在本地用
spend_key
对交易进行签名; - 将签名完成的交易数据发送主网。
具体可以参考 Nodejs SDK 里的这个从注册新系统到完成交易的完整例子: https://github.com/MixinNetwork/bot-api-nodejs-client/blob/main/example/safe.js
这个例子里,每个步骤都有对应的 SDK 方法,很好理解。
但是在实践时,还是有几点需要注意。
Spend key 千万不能丢
消费 UTXO 需要用 spend_key
进行签名,而 spend_key
就是注册新系统时提交的那个公钥对应的私钥。注册新系统时可以直接用机器人的应用 session 里的 private_key
,也可以自行生成一个新的 Ed25519 私钥。
需要特别注意的是,一旦注册完成,这个 spend_key
就不可更改、不可重置了,所以千万不能丢。在旧系统里,即使 PIN 码遗忘,也可以在开发者后台生成一个新的应用 session,得到新的 PIN 码。这一条在新系统不再适用,所以当注册完成后,要妥善管理好 spend_key
。
封装一个简单的转账方法
为了更容易适配旧系统,可以考虑把新系统的转账流程全部步骤封装成一个方法,这样只需要修改一个方法就能完成适配,对原有业务逻辑的影响最小。
例如我在 mixin_bot 里就封装了一个这样的方法: https://github.com/an-lee/mixin_bot/blob/main/lib/mixin_bot/api/transfer.rb#L59
这个方法的入参跟原来旧系统的支付方法基本一致,但是使用时依然有需要注意的地方。
避免重复转账
旧系统转账时,我们通常会用一个唯一的 trace_id
来防止重复支付,如果用了重复的 trace_id
转账,API 会直接返回交易成功的结果。
类似地,在新系统我们用一个唯一的 request_id
来实现类似的效果。
举个例子,你为一笔转账生成了一个固定的 request_id
,随机选取一个满足金额的 UTXO 用作交易消费。在调用 Mixin API 时,因为网络或者其他原因导致没有收到成功支付的结果,但实际上在 Mixin Network 上已经交易完成。你的程序在重试时,即使使用了相同的 request_id
再次转账,还是可能会发生错误。
这是因为虽然使用了相同的 request_id
,但如果选取的 UTXO 不相同,生成的交易数据也会不一致,系统就会报错。一个简单的解决办法是,在你的程序执行失败后重试时,先用 /safe/transactions/:request_id
进行查询,如果有结果即代表转账已经成功,没必要重复转账了。
一笔转账的 UTXO 最多 256 个
每一笔转账最多使用 256 个 UTXO,如果你钱包里的 UTXO 太碎,就没办法完成支付(就是在旧系统里可能碰到 insufficent pool
错误),这时候需要先将小额的 UTXO 归集。
比如有 257 个用户分别向你的机器人支付了 1 USDT,那你的机器人钱包里就有了 257 个金额是 1、资产是 USDT 的 UTXO。如果你想要将 257 USDT 全部转到你的个人钱包上,显然就没办法通过一笔转账完成。这时你有两个选择:
- 分成两笔对收款人完成支付,比如第一笔转 256 个 UTXO,第二笔再转 1 个 UTXO;
- 先归集,将 256 个 UTXO 转到机器人自己的钱包,这样机器人账上就有一个金额 256 的 UTXO 和一个金额 1 的UTXO,再将这两个 UTXO 放到一笔转账里,完成对收款人的支付。
本地管理 UTXO
根据不同的业务需要,你也可以选择将钱包里的所有 UTXO 实时同步至本地进行精细化管理。
比如生成每笔交易的同时,根据实际需要分配好相应的 UTXO,然后对已分配的 UTXO 进行标记。只要每笔交易使用不同的 UTXO,就可以实现并发转账。
批量转账
一笔交易中,UTXO 最多 256 个,收款人最多也可以是 256 个。这个场景在 @Quill 里就有应用场景。新读者购买文章时,Quill 收到的是一笔 UTXO,利用新系统的 API,一笔转账里可以同时给 256 位早期读者分发收益(不过目前 Quill 还没有使用批量转账)。
但是实践时,只有你的交易不需要“找零”时,才能一次分配 256 位收款人。否则,你需要留一个收款位给自己作为“找零”。
比如你有一笔金额为 257 USDT 的 UTXO,需要给 256 个地址分别转 1 个 USDT。这时你就没办法通过一笔转账完成,因为 257 USDT 消费掉 256 USDT,还剩 1 USDT 就是找零,需要转回到自己的钱包。所以这种情况就需要分成两笔交易完成,第一笔包含 255 个收款人地址,最后一个是自己钱包地址,找零 2 USDT。第一笔完成后,会收到一个 2 USDT 的新 UTXO,再转给最后一个收款人。
检查收款人是否支持新系统
使用新系统转账时,要保证收款人也已经升级到新系统。如果是 Mixin Messenger 用户,只要升级到最新版本,就会自动在新系统注册。
机器人在转账前,可以通过 /users/:uuid
API 读取用户信息中 has_safe
字段来判断用户是否已经支持新系统。如果给未注册的用户转账,会收到 10404
的错误,也可以通过捕获这个错误来给用户发消息,提醒用户升级 Mixin Messenger。
兼容旧系统的 API
当机器人迁移到 TIP 后,原来的 6 位数字 PIN 就作废了。新的这个 TIP PIN 也是一个 Ed25519 的私钥,除了注册新系统时需要使用,在调用旧系统 API 时也需要使用。旧系统的 API 在 SDK 中一般都做了兼容,传入新的 TIP PIN 即可。
需要注意的是,在迁移 TIP 之后,虽然目前在开发者管理后台重新生成应用 Session 里还会有 6 位数字 PIN,但是这个 PIN 已经没有意义了。依旧需要用 TIP PIN,而 TIP PIN 也是无法重置,记得妥善保管好。
最后
以上就是目前我在实践中的一些总结,希望对开发者们有些帮助,少走弯路。
总的来说,只要大致理解 UTXO 的工作原理,配合 SDK 封装的 API,将原来机器人的一般性业务适配至 Mixin 新系统并不太难。
当然,新系统的官方文档还没有完成,API 也可能会有改动,一切以官方解释为准。