之前一直在忙于通用跨链公链PalletOne的研发,没有怎么做技术分享的博客,最近PalletOne主网上线也有几个月的时间了,即将进行PTN(PalletOne上面的主Token)从ERC20到主网的转网工作。在转网进行时,正好将这其中的技术原理与大家分享。
一、Token转网的方式
因为ERC20同质化通证标准的流行,大量区块链项目都是通过先在以太坊上以ERC20的形式发行Token,进行募资、糖果发放、Token买卖等,等到自己的主链研发完成,就会将ERC20上的Token销毁或者冻结,而将对应数量的Token在主网上发放到各个持币用户,这个过程叫做Token转网。
Token转网一般有两种方式,通过交易所转网或者通过项目方转网。通过交易所转网对用户来说最简单,用户只需要将ERC20充币到对应的交易所,然后再提币时,提的就是主网的Token。而通过项目方转网的实现方式就比较多了,有通过以太坊合约进行地址映射,通过专门的转网网站进行转网操作,通过以太坊快照确认每个地址的Token余额,通过创世区块进行Token分配等多种方式,看项目方根据自己链的特点来决定。
二、交易所转网的技术原理
交易所要支持一个新的公链,那么必然会在交易所建立该公链的全账本节点,而交易所本来就支持ERC20代币,所以也有以太坊的全账本节点。交易所转网分为一次性转网和持续转网两种操作方式。
一次性转网
一次性转网就是交易所规定一个时间,在该时间后,不再支持该ERC20的充币提币,交易所获得一个确定的ERC20余额,然后将这些ERC20按项目方的要求进行销毁或者转移到某个锁定地址。项目方将对应数量的主网Token转移到交易所的新公链钱包地址。这些操作完成后,交易所重新打开该Token的充币提币通道,只不过现在充币只能接受主网的Token,充币地址也是该主网的新地址,而提币也只能提取主网的Token。
持续性转网
持续转网是指交易所不规定停止ERC20充币的时间,用户随时都可以将ERC20充币到交易所,也就是说充币支持主网Token和ERC20两种方式,而提币只支持主网Token。交易所先按一次性转网的流程,将自己持有的ERC20兑换成主网Token,以后当用户充值的是ERC20时,交易所会定时将所有充值的ERC20进行销毁或者转移到项目方规定的锁定地址,然后向项目方发出ERC20兑换的请求,这个请求一般会发送到项目方的一个RPC API,项目方的该API确认ERC20锁定后,会将自己持有的主网Token以对应数量发送给交易所指定的地址。
三、PTN转网合约的技术原理
PalletOne调色板因为本身就是一个支持比特币、以太坊等公链的通用跨链公链,所以其上的Token PTN转网就基于其跨链的特点,再配合上陪审团和以太坊适配器执行跨链合约,实现主网智能合约的Token转网。下面详细介绍一下其中的技术原理。
1.以太坊发布地址映射与Token锁定合约
要进行异构链的Token转网,一般来说需要3步操作:
- 以太坊地址与主网地址的映射
- ERC20的锁定
- 主网Token的释放
其中步骤1和2都可以在以太坊上通过智能合约来实现。如果以太坊上面ERC20 Token转账时能够附上一句话,那么就太简单了,只需要在将ERC20转移到锁定地址的这个交易中,以字符串形式附上本次锁定的Token在主网中对应的映射地址即可。但是我们看看ERC20的标准:https://eips.ethereum.org/EIPS/eip-20
function transfer(address _to, uint256 _value) public returns (bool success) function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
无论是transfer还是transferFrom,都只有金额,没有备注字段,所以我们想要在转账时附加上主网映射地址是不现实的。所以我们需要专门发布一个地址映射的合约方法,持币用户调用该方法时,合约将持币用户地址与传入的主网地址进行关联,再使用一个查询方法,即可查询以太坊地址对应的主网地址。另外还有一个方案是发布一个地址映射的网站,持币用户到该网站注册以太坊地址和主网地址的映射,然后网站给出一个字符串,用户用以太坊的私钥对该字符串进行签名,并提交签名给网站,这样网站就可以验证这次映射确定是该以太坊用户自己发出,而不是别人冒充的。
以上提出的2个方案都有个验证的问题,那就是对持币用户要求很高。一个普通的持币用户,没有太多的计算机知识,没有广泛被使用的合约调用或者签名的钱包工具,那么是很难操作“调用地址映射方法”和“对消息进行签名”的。普通的支持ERC20的钱包,主要就是对ERC20标准的支持,也就是对transfer函数的支持,所以PalletOne地址映射方法被包装成了transfer方法,用户只需要用普通的以太坊钱包即可实现地址映射。
其中的具体原理是,以太坊的address _to地址是20字节,而PalletOne的地址虽然形如:P1CumdbKemvLLFXQxH7ufHgjRSzcednFvgd 这样的形式,但是其本质上也是20字节,所以我们可以将PalletOne地址转换为以太坊地址:0x82a445064ac1de016719c653fcd2d13e5b62575c,所以我们定义一个新的ERC20 Token,名字叫PTNMap,持币用户在钱包中添加这种Token,然后就可以看到余额为1(表示没有进行映射),发起转账,将接收方设置为PalletOne地址转换后的以太坊地址即可。转账成功后,可以看到余额为0,则说明地址映射成功了。
该合约不仅仅是一个包装成了ERC20的地址映射合约,也是一个Token锁定合约。持币用户在进行了PTNMap的转账(地址映射)后,即可将ERC20转账到该合约地址。由于该合约没有提出ERC20的合约方法,所以这是一个锁定(销毁)合约。
2.PalletOne的以太坊适配器
PalletOne基于对大量主流区块链的抽象,完成了区块链操作的适配器抽象接口定义,在适配器的接口定义中,定义了区块链通用操作、加密货币操作、智能合约操作3大类。Eth-Adaptor以太坊适配器是一种针对以太坊ETH和ERC20的实现。https://github.com/palletone/eth-adaptor
针对PTN转网来说,以太坊适配器主要使用了
GetTransferTx(input *GetTransferTxInput) (*GetTransferTxOutput, error)
GetPalletOneMappingAddress(addr *GetPalletOneMappingAddressInput) (*GetPalletOneMappingAddressOutput, error)
这两个方法,一个用于转网合约查询某笔ERC20转账交易是否成功,源地址、目标地址、金额等,一个用户计算在主网的地址,然后就可以根据金额和主网地址进行主网Token的发放。
3.PalletOne主网部署转网合约
PalletOne支持图灵完备的智能合约,并且从设计上能够支持多语言(Golang、Java、NodeJS等),支持多链的操作(比特币、以太坊等)。
PalletOne的智能合约与其他公链不同,智能合约并不在记账节点运行,而是在选出的陪审团内运行。一个陪审团由至少4个陪审员节点组成(当然也可以采用更多陪审员节点以进一步加强安全性),每个陪审员分别独立的运行合约,得到合约执行结果,并进行签名,如果3/4的节点都对同一个结果达成共识并签名,那么这个结果就被认为是可信的,记账节点会将这个结果进行打包。
本次PTN转网合约由Golang写成,PTN转网合约的核心方法是:
func (p *PTNMain) PayoutPTNByTxID(ethTxID string, stub shim.ChaincodeStubInterface) pb.Response
其主要逻辑就是通过传入的锁定ERC20的以太坊交易Hash,调用适配器查询交易是否真实存在,并获得交易细节,根据交易金额和映射地址,将合约上的PTN转移给对应的用户地址。当然还有很多关于错误判断、重放攻击检查之类的,就不一一详述了。
4.定时任务扫描以太坊,触发转网合约
原本是计划让用户自己来调用PalletOne合约,将ERC20锁定转账的交易Hash作为参数传入的,但是发现一个矛盾的地方,就是用户还没有进行转网的话,就没有PTN,没有PTN就没办法发起合约调用,所以就没办法获得转网的PTN。所以就由我们发布一个定时任务来做。该程序不断的循环扫描以太坊上的ERC20 PTN的事件日志,如果发现有PTN的转账,则看转账的接收方是不是锁定合约地址,如果是,则说明有人要进行转网。接下来就是判断该交易是否被足够的块确认,一旦确认的块数达到一定数量(比如15个确认),那么就触发PalletOne转网合约的调用。
最后,PalletOne的转网合约操作步骤嵌入到了PalletOne钱包中,用户可以下载钱包,自行转网:https://pallet.one/wallet/