以太坊Solidity迁移Flow Cadence指南7-ERC20/TOKEN迁移

Flow作为专门为NFT设计的区块链,其合约语言主要侧重于NFT功能,当然,实现基本的ERC20 token 更不在话下。

由于ERC20合约相对比较简单,迁移也比较容易,因此,本节在完成迁移讲解的同时,重点对比下ERC20 token和Flow token合约的差异,并探讨下Flow的token 空投问题。

标准ERC20合约分析

以太坊ERC20 Token核心功能大致是这样的:

contract ERC20Basic {

mapping(address => uint256) balances; // 余额

function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {

    balances[_from] = balances[_from].sub(_value); 

balances[_to] = balances[_to].add(_value);

return true;

  }

}

如果完整对应的改成Flow Cadence合约的形式,可以是这样的:

contract ERC20Basic {

    access(contract) let balances: {Address: UFix64}

    pub fun transfer(from: Address, to: Address, amount: UFix64) {

        balances[from] = balances[from] - amount

        balances[to] = balances[to] + amount

    }

}

这样的实现是完全可以的,但就无法享受flow Cadence编程的各种自带好处了。举个简单的例子,solidity使用中会经常担心,把token发送到未知/错误地址,直接就”烧纸”了,但这在Cadence中是不会出现的。因为Cadence中钱包必须先执行金库的初始化操作,也就是先开户,才能转账,一个未知/错误的地址肯定是无法开户的,即使转错了,系统就会报错回滚,不用担心转错账的问题。这个就是面向资源编程的优势体现。

合约迁移

按照程序分析的一般套路,还是先分析数据结构,然后再看对应的增删改查功能函数。

ERC20和Flow推荐token标准合约数据结构对应关系如下图所示:

1 ERC20和Flow Token数据结构对应图

ERC20的核心数据结构就是一个字典,key为用户钱包地址,而value则是对应钱包的余额,所有转账查询等操作都是基于这个字典展开的,这样的方式类似于银行账号,其实是一种中心化的实现。而Cadence则只需定义了余额,token是作为一个资源类型,存放在对应用户的存储空间内的,也就是vault金库路径里面。也就是说Flow Cadence是一种真正的“去中心化”,用户的token都存储在自己的账号下,而以太坊Solidity的token则是存放在合约账号上的。

举个例子,如果合约不开源,Solidity完全可以随意操纵用户账号,类似某些城乡银行的高端操作,而Flow Cadence合约中,即使铸造token的合约都消失了、重写了,用户的token也不会受到任何影响,更不会存在合约账号暗箱操纵用户token的问题。

ERC20和Flow推荐的Token标准合约的功能函数对应关系如下图所示:

2 ERC20和Flow Token功能结构对应图

Flow token提供了token相关的铸造、转账、查询功能,但并不提供Approve相关的三方托管功能。具体迁移的时候,只需迁移核心的mint和transfer功能即可,approve的功能可以忽略,保留核心功能就行。Flow相关的approve托管合约,可通过ERC20类似的中心化实现试试,也可以利用“能力”相关的功能实现,具体可参考NFT市场一节。

Cadence上已经有类似ERC20的基础标准合约。我们就以openzeppelin对应实现的基础ERC20合约为准(https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol),对应的为Flow推荐的元数据标准合约实现(https://github.com/onflow/flow-ft),然后找到对齐关系,看需要修改的Cadence继承实现代码即可。这里暂时不考虑各种合约扩展功能。

从数据结构和功能函数来看, Solidity ERC721标准合约和flow cadence NFT合约都存在完整的对应关系,对于标准Token合约的迁移,我们只需要对flow合约进行“字符串替换”即可,具体如下图所示:

        

图3 ERC20合约迁移具体流程

如上图所示,核心就是修改合约名称,代码中对应合约名称的引用部分,也进行对应的修改即可。包括合约、交易、脚本都按此修改即可。合约部分有资源集接口,也进行对应的字符串修改即可。另外还有包含Token名称的资源路径和函数名称,替换成新的合约名称字符串即可。

熟悉linux shell脚本的同学,使用一句shell脚本即可完成上面所说的替换:

#!/bin/sh

nft_name="Wow" #token名称

find ./ -name "*.cdc"|xargs -i sed 's/Example/'''${nft_name}'''/g' {}

理解资源

分析Flow token和ERC20 token的转账功能,可以非常清晰的看到flow“资源”的使用方式:

transaction(amount: UFix64, to: Address) {

    let sentVault: @FungibleToken.Vault

    prepare(signer: AuthAccount) {

        let vaultRef = signer.borrow<&ExampleToken.Vault>(from: ExampleToken.VaultStoragePath)

?? panic("Could not borrow reference to the owner's Vault!")

        

self.sentVault <- vaultRef.withdraw(amount: amount) //取出token

    }

    execute {

        let recipient = getAccount(to)

        let receiverRef = recipient.getCapability(ExampleToken.ReceiverPublicPath)

            .borrow<&{FungibleToken.Receiver}>()

?? panic("Could not borrow receiver reference to the recipient's Vault")

        receiverRef.deposit(from: <-self.sentVault) //存放token

    }

}

ERC20的token,就是合约的字典数据中,先从源账号key中减去一个值,然后在目标账号key中加一个值。

Flow的token,则先从源账号的金库中withdraw取出一定的token,然后再deposit存储到模板账号的金库中。

具体对比如下图所示,flow这样的方式好处是啥,有啥不足,除了前面说的安全性之外,大家可以自己想一想。

图4 以太坊和Flow转账模式对比

Flow空投

Flow面向资源编程带来安全性无可比拟,但相应的,所得必有所失。在Flow的空投上,就会存在一定的问题。

因为Flow的账号转账,不管是NFT,还是一般的token,目标账号都必须先授权并初始化一个对应vault仓库,才能进行转账操作。类似于你用身份证当钱包地址,但如果在不同的银行存钱取钱,还是要用身份证去对应银行“开户”。

简而言之,Flow没法像以太坊那样,无需用户许可、骚扰式的发送token,这对很多应用而言,少了一个重要的推广方式,类似于不能发骚扰短信、不能发垃圾邮件、不能打骚扰电话了。。。。

目前flow社区暂时没有确定的方案,但有一些合约按照如下一些方式,间接的实现了flow空投功能:

最简单的方式,就是先发送,后领取。相当于一种中心化的实现,具体的数据结构设计方面,可以采用本文开始说的那种中心化的Cadence方式,先把发送的token存放到合约的字典数据里面,用户查看时,搜索字典,命中后会提示有token可以领取,然后再把token 转移到用户账号即可。

第二种,交易市场类实现。也就是做一个类似candy糖果类的NFT市场,有用户在这里领token,有开发者在这里发token,当然,如果是空投,设置价格为0即可。

猜你喜欢

转载自blog.csdn.net/wangliang_f/article/details/125340823