区块链应用饱为诟病的原因,就是高门槛。比如每发送一笔交易,都需要消耗一定数量的Gas费用,而很多拥有ERC20 代币的用户去使用Dapp,必须先在钱包中保存一定数量的ETH用以支付Gas费用。
Ethereum以太坊的实现方式——元交易合约
如果能够为新用户代付Gas费用,将会大大降低Dapp的使用门槛。而以太坊没有提供原生方法来实现这一点。于是就有了元交易,让没有持有ETH的帐户可以和区块链进行交互,并可能使用ERC20代币去支付Gas。所谓元交易(Meta transaction),就是让用户用自己的密钥来签名发起交易,但不需要用户来支付交易手续费(即 Gas 费用),而由 “中继者(relay)” 来为 TA 支付 Gas 费。中继者作为发送方,将交易提交至网络,并支付 Gas 费用。交易的目标合约可以确定原始用户及其意图,并相应地处理合约的调用。
元交易比较典型的是守卫代理(Bouncer Proxy),它包含4个基本部分:
- 用户帐户:未持有ETH的一对公私钥,这个帐户能够为消息签名。
- 矿工账户:持有ETH的一对公私钥,能够为用户支付Gas费用,也即代付Gas的元交易矿工
- 守卫代理合约(Bouncer Proxy):合约可以接收第三方的签名消息作为输入
- 合约接收方:用户真正想与之交互的Dapp相关的合约## NetCloth区块链网络手续费代付
一个元交易的守卫代理合约,可以参考这里。
元交易的使用场景
元交易的使用场景,参演是这样的:
- 一个用户,没有ETH的账户。
- 用户是守卫代理合约的所有者,只有当输入消息由用户自己或者白名单账户签名时,守卫代理合约才能进一步执行转发调用。
- 守卫代理合约需要持有ETH或者ERC20代币,这些代币用于对矿工(中继者)进行奖励。
元交易的流程
- 用户创建一个不需要支付任何费用的交易,包含以下部分:
- 用户地址
- 守卫代理合约地址
- 交易的合约接收地址,用户真正想调用的Dapp合约
- 用户交易的value字段
- 用户交易的data字段,即合约调用的payload
- 用于奖励给元交易矿工的资产地址
- 用户奖励给元交易矿工的资产数量
- 守卫代理合约的nonce,跟踪帐户进行交易的次数,以防止重放攻击并且保持交易顺序
- 哈希签名,用户用私钥对上述字段的签名
- 矿工接收到用户的元交易消息后,调用守卫代理合约的forward函数,进行转发调用,并支付本次调用的Gas费用。 forward的函数输入为:
- 用户地址
- 交易的合约接收地址
- 用户交易的value 字段
- 用户交易的data字段,即合约调用的payload
- 用于奖励给元交易矿工的资产地址
- 用户奖励给元交易矿工的资产数量
- 用户的哈希签名
守卫代理合约的forward函数,通过验证哈希签名的方式,确认只有用户或者白名单账户签名的元交易,才能被守卫代理合约转发,且元交易的矿工才能被奖励。
当签名验证通过后,相应数量的奖励会从守卫代理合约转移到矿工的帐户上。
然后守卫代理合约,带上用户指定的参数,调用用户指定的合约,并负责Gas的支付。
这样,就实现了一个用户账户,它没有持有ETH但实现了自身交易的提交,并且可能使用ERC20代币来支付Gas。
优缺点
这样的实现方式也有缺点,如果元交易的合约接收地址,是基于msg.sender的应用逻辑,那么整个交互流程将不会顺畅,因为msg.sender标识的是合约的调用者,而元交易的情况下变为代理合约的地址,而不是元交易的用户地址。
如果是第三方帮用户代付Gas费用的话,部署一个守卫代理合约倒没问题。而如果是用户使用ERC20支付Gas的话,那么每个用户需要能够部署自己的代理合约,并且奖励给矿工的代币必须由代理合约持有,每个用户需要能够管理和充值自己在代理合约中的代币。
NetCloth区块链网络手续费代付
ETH用合约解决元交易问题,那自然有项目会实现原生的元交易。NetCloth链不久前升级了最新的功能,以原生的方式,支持了第三方的Gas代付。实现原理是:当一笔交易消息体中包含多个signatures时,NetCloth区块链网络将按交易签名顺序,选择排第一位的收取交易费用。
NetCloth手续费代付技术文档,参考这里。
手续费代付原理
NetCloth链上的交易结构:
{
"type": "nch/StdTx", // 交易type,固定为nch/StdTx
"value": { // 交易value
"msg": [], // msg数组
"fee": {}, // 交易费用
"signatures": [], // 交易签名,和msg一一对应
"memo": "" // 交易附带的memo
}
}
当一个第三方愿意帮用户支付Gas费用时,可以和用户协作生成一笔交易,同时将自己的交易签名放第一位。由于msg和 signatures是一一对应的,所以第三方需要生成一笔由自己发起的交易,放msg数组中的第一位。
交互流程如下:
流程
Gas费用代付流程
- 用户生成一笔交易,先不签名,发送给第三方
- 第三方修改交易,增加自己的msg,并签名后,其中msg和签名均放在交易中的第一个位置,返还给用户
- 用户对收到的交易,使用自己的私钥签名
- 用户将最终的交易发送到网络,链上执行交易的时候,将向交易中的第三方收取Gas费用
优点
1.交易是基于各自签名的,用户和第三方之间无需信任
2.第三方代付的Gas费用,可以通过链外结算方式向用户收取
3.即使合约有基于msg.sender的应用逻辑,用户也可以正常使用
4.整个流程参与只有3个角色,没有合约层面的交互
总结
单纯从实现上来说,很难评判合约实现与原生实现孰优孰劣。不过对于非熟练区块链开发者而言,理解合约和正确使用合约,并规避安全问题,是比较高的门槛。如果能有比较好的原生支持手段,不论是对于开发者使用,还是集成至客户端给小白用户使用,都会极大降低小白用户使用Dapp和区块链应用的门槛。
参考:
[1]: https://medium.com/@andreafspeziale/understanding-ethereum-meta-transaction-d0d632da4eb2
[2]: https://docs.netcloth.org/advanced/fee-payment.html