Flow USDC合约分析与链上链下多签实现分享

Created
Mar 21, 2022 09:11 AM
作者
翻译
Tags
Cadence
USDC
原文链接
Circle部署在Flow上的FiatToken.cdc合约写的较为复杂,因为该USDC合约不仅仅为了支持Flow Fungible Token标准,还尝试在Flow上兼容ERC20与CENTRE TOKEN的相关标准,比如黑名单、交易冻结、allowance等。
 
为此,Circle描述了一个FiatTokenInterface.cdc接口,但在主网实际部署USDC合约时,因为某种原因,并没有继承该interface,只实现了一些角色管理和基础FT接口。
https://flow-view-source.com/mainnet/account/0xb19436aae4d94622/contract/FiatToken
 
allowance/approve其实FiatTokenInterface.cdcTRANSACTIONS.md中是有实现的,不过withdraw_allowance.cdc中存在一定漏洞(没有对tx发起人做检验)。

FiatToken的角色管理

FiatToken.cdc一个长达1300多行的FT合约,绝大部分都是在做角色管理:admin,owner,masterMinter,minter,pauser,blacklister 。
下面是Docs里的图:
notion image
notion image
Flow的代码结构偏组件化编程,不太方便阅读,换一种示意以有助于理解角色关系:
notion image
  1. Minter负责mint和burn,MinterController负责设置allowance值,且Minter与Mintercontroller是一一对应的,需要绑定通过MasterMinter认证。
  1. 各种Executor资源都是唯一创建并存储在合约部署地址下的。
  1. 可以有多个Admin资源拥有者,通过AdminExecutor进行ExecutorCapability签发。
  1. Pause、MasterMinter、Blocklist的ExecutorCapability获取则需要通过Owner来控制。
  1. 对权限的管理都是通过资源uuid完成的,Minter可以恶意转移或是暴露cap。

Circle链上多签协议OnChainMultiSig.cdc

https://flow-view-source.com/mainnet/account/0x220c1b4155f86f2f/contract/OnChainMultiSig
Circle实现了一套链上的多签协议,允许多个签名在链上来授权一笔tx,而绕过链下多次签名的流程限制。如果有相同的多签需求或是投票治理等场景可以有些借鉴。
用FiatToken.cdc中Admin resource的多签使用举例:
notion image
值得注意的是:
  1. 待多签的tx的代码实现需要被封装在合约里,并在Payload里进行描述,比如tx序列id、method 名字,参数等,需要签名的部分也是这个Playload描述。
  1. 每个签名者都可以单独对这笔tx上传签名认证。
  1. 当完成签名的钥匙权重合>1000后,可以调用readyForExecution执行相关tx代码;否则继续等待签名。
  1. 多种不同的等待签名的tx都会在OnChainMultiSig.Manager中进行管理。
  1. 这个多签体系有个地方需要讨论:假设一笔tx,当前有5个人可签名,但增加第6个签名者的操作只需要5个人中的任意1人即可发起

补充正常多签流程

Flow文档描述:https://docs.onflow.org/concepts/transaction-signing/
包含4种: 单地址单key、单地址多key、多地址单key,多地址多key

使用Cli完成多签流程:

一次tx的签名管线如下:
  1. Build: encode the source code using rlp or the "Recursive Length Prefix" encoding.
  1. Sign: cryptographically sign the encoded source code.
  1. Send: deliver the encoded source code with the signatures to a Flow Access Node.
举例:
transaction() { prepare(signerA: AuthAccount, signerB: AuthAccount) {
一次tx可以被拆解成多步,由中间签名字串传递。
Step 1:
flow transactions build ./helloworld_tx.cdc \ --proposer testnet-A \ --payer testnet-A \ --authorizer testnet-A \ --authorizer testnet-B \ --filter payload \ --save transaction.build.rlp
Step 2:
flow transactions sign ./transaction.build.rlp \ --signer testnet-B \ --filter payload \ --save transaction.signed.B.rlp \ -y flow transactions sign ./transaction.signed.B.rlp \ --signer testnet-A \ --filter payload \ --save transaction.signed.rlp \ -y
Step 3:
flow transactions send-signed ./transaction.signed.rlp -y
Tips:
  1. 注意签名顺序,payer需要最后签
  1. 当同地址多个key时,在accounts里可以这么配置:
"key1": { "address": "0x4", "key": "444...444" }, "key2": { "address": "0x4", "key": "555...555" }

Fcl链下多签

可以参考:
  1. 与Cli的分步签名接口类似,Fcl中有类似的接口。
  1. 该工程里使用supabase做了baas服务,发起的签名请求payload和生成的rlp中间编码字串都会在云数据库里存储。待签名的人可以fcl前端登录,然后查询数据库获取需要签名的rlp字串进行签名。