6

如何在 DFINITY 上铸造自己的 Token?关于 Token 标准的讨论

 3 years ago
source link: https://learnblockchain.cn/article/2644
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
如何在 DFINITY 上铸造自己的 Token?关于 Token 标准的讨论

如何在 DFINITY 上铸造自己的 Token?关于 Token 标准的讨论

6月10号,ICP League 联合社区开发者举办了第三期的开发者电话会,邀请了 DFinance 项目的开发者共同探讨了如何在 DFINITY 上发行代币,以及类似 ERC-20 代币标准的设计思路。

6月10号,ICP League 联合社区开发者举办了第三期的开发者电话会,邀请了 DFinance 项目的开发者共同探讨了如何在 DFINITY 上发行代币,以及类似 ERC-20 代币标准的设计思路。

本期亮点:

  • ICP 本身就是 DFINITY 的第一个代币,是以智能合约的形式部署在链上的,因此可以作为实现标准的参考;
  • 在 DFINITY 上实现类 ERC-20 标准时,与以太坊不同,DFINITY 的区块链上不会保留交易的 massage,因此需要在代币标准下记录交易记录;
  • 因为有限的容器空间中需要保存交易记录,因此代币合约存在扩容问题;
  • DFINITY 使用了反向 gas 模型,用户使用无需消耗 gas,因此为了避免大量垃圾交易攻击,需要在代币标准中写入转账扣费或手续费;

ICP 代币的实现

在以太坊网络中,ETH 代币是区块链底层的原生代币,其挖矿、转账、与合约交互、支付 gas 等交易事件也被打包放在区块中,与区块链耦合;而在 DFINITY 上,ICP 代币实际上搭建在网络上被称为“Ledger”的智能合约,ICP 代币的查询、转账、交易管理与质押等功能是现在智能合约中(archive_node.rs)。

由于 DFINITY 的智能合约更类似于互联网微服务下的容器,而智能合约的状态是保存在 Ledger 容器内部。实际上,ICP 的所以交易记录是保存在智能合约内部的,需要使用该合约的函数进行查询。

实际上,只有 DFINITY 的 gas 代币 cycles 是链上唯一的底层原生代币,而只有通过燃烧 ICP 才能获取 cycles。

所有操作都记录为 Ledger 容器内的交易,同时 DFINITY 在 Ledger 容器中记录账本时使用了区块链式的数据结构。注意,这里的区块链只是存账本数据的格式,并不是我们理解的有共识的区块链。以下是实现的状态。

因此,ICP 可以看成 DFINITY 上第一个代币规范,他的代码已经开源,在实现类似 ERC-20 标准时最好沿用 ICP 代币的设计,开源链接:https://github.com/dfinity/ic/tree/master/rs/rosetta-api/ledger_canister

沿用 ERC-20 的代币标准

访问 https://github.com/dfinance-tech/ic-token/blob/main/simple-erc20/src/token.mo,可以查看 DFinance 沿用 ERC-20 的 DFINITY 代币标准的源码,使用了官方开发的语言 Motoko 编写。

private stable var owner_ : Principal = _owner;
private stable var name_ : Text = _name;
private stable var decimals_ : Nat = _decimals;
private stable var symbol_ : Text = _symbol;
private stable var totalSupply_ : Nat = _totalSupply;

private var balances =  HashMap.HashMap<Principal, Nat>(1, Principal.equal, Principal.hash);
private var allowances = HashMap.HashMap<Principal, HashMap.HashMap<Principal, Nat>>(1, Principal.equal, Principal.hash);

owner_ 表示 token 创建者,一般是容器的部署者;name_ 表示名称;decimals_ 表示代币的精确位数;symbol_ 是代币的标志;totalSupply_ 是代币的总供应量。以上是一些基础。

但其实表示代币位数的 decimals_ 可以考虑删除,在以太坊合约中需要这个参数是因为以太坊使用的 solidy 无法支持浮点数的计算,但是 DFINITY 的语言是可以支持浮点数运算的。

balances 是一个数据库下的类型,表示一个账户对应的余额是多少。这里使用了 DFINITY 的持久化数据库 HashMap,在账户与余额间建立了联系。allowance 记录的是 Approve,这在以太坊中经常使用,允许一个账户或智能合约使用你的余额。

这个实现沿用了 ERC-20 的 transfer、transferFrom、balanceOf、allowance、approve 这些操作。关于代币的铸造与销毁功能,在以太坊上很多项目会选择直接把代币转入 0x0 地址进行销毁,因为不可能有人能逆向算出 0x0 地址的私钥,所以再也无法转出。但在 DFinance 的标准下并没有这么操作,因为 DFINITY 目前还没有公认的销毁地址,因此实现了一个 burn 方法,在数据库中直接减去余额。

更符合 DFINITY 的代币标准

从 DFINITY 上线后官方开源的了 ICP 的实现代码,在沿用 ERC-20 的情况下更贴近了官方的做法,尽量实现兼容,也变得更为复杂,开源代码:https://github.com/dfinance-tech/ic-token/tree/ledger/src

DFINITY 的 ICP 实现用中,账户使用的是 account ID,而在该实现中使用的是 Principal ID,关于两者区别我在《对DFINITY的去中心化身份、账户与钱包介绍,开发者能如何利用?》中有过介绍,关于两者的选择社区也不同的意见。

最大的区别在于增加了记录转账历史消息的数据库:因为代币同样也是 DFINITY 上的智能合约的实现,因此和 ICP 存在同样的问题,即以数据最终一致性为先,而区块上查不到交易信息。因此必须在容器内建立数据结构来保存 message。在核心代码下找到 OpRecord.mo,每一次转账、铸造、销毁、approve 的操作都以一条 OpRecord 的记录,一条 OpRecord 下有详尽的相关信息,方便用户日后查询。

public type OpRecord = {
  caller: Text;
  op: Operation;
  status: Status;
  index: Nat;
  hash: Text;
  rom: ?Text;
  to: ?Text;
  amount: Nat64;
  fee: ?Nat64;
  memo: ?Nat64;
  timestamp: Time.Time;
 };

在此前我们多次聊过扩容问题,同样在代币标准中又出现了。因为现在的需要在智能合约中保存代币的转账记录,这将是非常庞大的数据,而 DFINITY 目前只支持最大 4GB 的容量。

实际上所有 DFINITY 的应用都会遇到容器容量限制的问题,终极解决方案是实现一套自动扩容的数据库基础设施,它会会在一个容器容量消耗殆尽前,把数据划分到新的容器里。

这个基础设施相当于一个标准化的数据库中间层,上层 DApps 可以直接调用数据库中间层的接口,而数据库容器的扩容问题由中间层。目前虽然有尝试去实现数据库引擎的 sudograph,但他目前更多是方便开发者自定义数据类型,还没有去尝试自动扩容。

当然短期内,也可以定期打包一些交易历史到外部静态存储中去,然后删掉 DFINITY 容器内的历史,只保留一段时间。而且 DFINITY 的 WASM 可能会支持 64 位,这样可以扩大单个容器的内存。

手续费抵抗垃圾交易攻击

在《为什么说是下一代区块链,DFINITY的8大核心优势!》中介绍过,DFINITY 使用了反向的 gas 模型,以太坊上用户为自己的发送的交易付 gas,而 DFINITY 上由部署合约的支付 gas,普通用户不需要付手续费就能享受合约的服务,当然包括代币转账。

但可能会遭受潜在的攻击,如果有人恶意发出一大堆垃圾交易,或者不停地调用合约,又或者在你的合约里面塞满垃圾数据,消耗合约的存储空间与 gas,就会出现宕机。在代币合约上的直接表现就是所有人都无法转账,甚至可以利用这种 DDOS 攻击阻止大家交易,从而操纵市场。

DFINITY 的 ICP 代币在实现时考虑到了这一点,每次调用转账都需要扣去手续费,现在一笔操作回固定扣走 0.0001,来防止攻击。而代币合约在设计时,可以衍生出更多有意思的设计:

1、转什么币,扣什么币手续费。代币合约的每次转账、铸造等操作,都扣取或销毁一定的数量或比例的代币,这种方案非常简单,听起来很像以太坊上的通缩代币设计。

2、转币扣 ICP 当手续费,类似 ICP 自身的实现。

3、在以太坊上每个计算操作都有固定的 gas 消耗数量,开发者可以去估算一个操作消耗的 gas 数量。目前在 DFINITY 上还么有这样的接口,但是是可以实现的。而且 DFINITY 的 gas 是使用稳定价格的 cycles 支付。因此可以先估算操作需要消耗多少 cycles 来计算操作的单价,然后根据交易所中 cycles 与该代币的交易对,来扣取对应数量的该代币,实现手续费完全覆盖交易处理成本。

进一步优化

去掉 Approve

以太坊网络中因为 ETH 与 ERC-20 标准之间的差异,并且为了避免重入攻击,导致了 approve 这么一个额外的操作。但在 DFINITY 中,有人提议可以去掉 approve 功能,来提升使用体验,并提出来“订阅”的替代方案。并且这样也能防止攻击,因为在 DFINITY 模型下的 approve,攻击者可以发送一大堆 approve 来占满容器的内存让其宕机。当让也有一些人提出来反对意见,具体社区讨论可以查看:https://forum.dfinity.org/t/thoughts-on-the-token-standard/4694/4

使用 Principal ID 节省空间

在《对DFINITY的去中心化身份、账户与钱包介绍,开发者能如何利用?》中我们介绍来 DFINITY 的 Principal ID 和 Account ID 两种类似的 ID:Principal ID 被用于容器的使用,而 Account ID 被用于账本,两者同源。目前 DFINITY 的 ICP 实现中使用的是 Account ID,但社区也有人提出希望在代币合约中使用 Principal ID。因为 Principal ID 更短,可以节省 25% 的空间。

官方在 AMA 中表示,建议开发者使用 Rust 来编写对安全性要求更高的代码,比如代币合约。

管理合约控制者

因为 DFINITY 的合约允许升级,因此合约的控制者具备较大权力,甚至可以增发代币,回滚业务,因此需要更好的去管理控制者。可以把控制者分配给零地址让合约永远无法升级,也可以把控制者替换为一个 DAO,由社区集体管理。

关于 DFinance

感谢 DFinance 开发者的分享,DFinanace 正在建立 DFINITY 的代币标准,并帮助用户一键发行代币,并建立 swap 等金融基础。可以通过关注 https://twitter.com/DFinance_AI 获取他们的消息,也可以通过后续的测试链接铸造自己的第一个代币。

请访问 icpleague.com中文开发论坛,与社区与开发者聊天,提交你的想法,申请我们的资助与投资!

查看视频回放:。

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 1天前
  • 阅读 ( 46 )
  • 学分 ( 2 )
  • 分类:DeFi

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK