在这个简短的概述中,我们描述了我们在eToro标记化资产背后实施技术的初步经验,即MoveIR语言中的(eToken),用于在Libra网络上进行部署。

Libra协议是一个确定性状态机,它将数据存储在版本化数据库中。使用新颖的领域特定语言:Move。Move允许可编程事务和模块重用代码和状态 - 类似于我们定义为智能合约。

目前,Libra不允许发布模块,这就是为什么eToken的源代码应该作为测试运行的原因。可以在此处找到此Move IR eToken实现的完整源代码。

此测试已在提交哈希中使用Libra版本执行#004d472。可以在此处找到存储库。

Move中间表示语言
随着Libra的发布,定义了一种名为Move的新的特定于域的语言。直到现在,Libra团队尚未提供更高级别的实施。随着该协议的最近宣布,一个名为'Move IR'的lanaguge的一个不太符合人体工程学的中间表示被释放

Move内化了内存所有权和借用的概念,与Rust的运作方式非常相似。然而,Move语言的新颖性是定义“资源”的方式。

“资源”是一种利用所有权模型的结构数据类型,但永远不能仅复制Move和借用。这是Move语言的核心功能,因为它保证没有定义的资源意外重复,从而消除了双重支出或重新发生攻击的可能性。

因此,“资源”的概念与数字资产概念很​​好地对应是明智的

eToken实施

modules:module Capability {// Capability is responsible for declaring an account's permissions.// We define the notion of an owner, minter and blacklisted.// Only the owner can assign blacklisted and minter capabilities.// The owner is defined by hardcoding its account before publishing the module.// -----------------------------------------------------------------// Declare owner as a resource. It's only meant to be published once
    resource Owner { }// Declare a resource that declares an address's capabilities.// Every address using EToken will need to publish a resource themselves.// However, only the owner can change its content.
    resource T {minter: bool,blacklisted: bool,}// Every account should execute this once before using Capability and EToken module.// If the sender is the hardcoded owner, then owner capability is published.// Reverts if already publishedpublic publish() {let sender: address;sender = get_txn_sender();// Publish owner capability if sender is the privileged account// Uncomment the following line in production and use a real owner account: if (move(sender) == 0x0) {if (true) {// Always branch to here when testing, otherwise the test can't complete as the sender address is randomly chosen.
            Self.grant_owner_capability();}// Publish a new capability with no permissions.move_to_sender<T>(T{ minter: false, blacklisted: false });return;    }// Internal function that grants owner capability
    grant_owner_capability() {move_to_sender<Owner>(Owner {});return;}// Grants minter capability to receiver, but can only succeed if sender owns the owner capability.public grant_minter_capability(receiver: address, owner_capability: &R#Self.Owner) {let capability_ref: &mut R#Self.T;release(move(owner_capability));// Pull a mutable reference to the receiver's capability, and change its permission.capability_ref = borrow_global<T>(move(receiver));*(&mut move(capability_ref).minter) = true;return;}// Grants blacklist capability to receiver, but can only succeed if sender owns the owner capability.public grant_blacklisted_capability(receiver: address, owner_capability: &R#Self.Owner) {let capability_ref: &mut R#Self.T;release(move(owner_capability));// Pull a mutable reference to the receiver's capability, and change its permission.capability_ref = borrow_global<T>(move(receiver));*(&mut move(capability_ref).blacklisted) = true;return;}// This returns an immutable reference to the owner capability if it exists.// Is used by the owner to show ownership to privileged functions.// Reverts if owner capability does not exist.public borrow_owner_capability(): &R#Self.Owner {let sender: address;let owner_capability_ref: &mut R#Self.Owner;let owner_capability_immut_ref: &R#Self.Owner;sender = get_txn_sender();owner_capability_ref = borrow_global<Owner>(move(sender));owner_capability_immut_ref = freeze(move(owner_capability_ref));return move(owner_capability_immut_ref);}// This returns an immutable reference to the general capability if it exists.// Should be used by every account to prove capabilities.// Reverts if capability does not exist.public borrow_capability(): &R#Self.T {let sender: address;let capability_ref: &mut R#Self.T;let capability_immut_ref: &R#Self.T;sender = get_txn_sender();capability_ref = borrow_global<T>(move(sender));capability_immut_ref = freeze(move(capability_ref));return move(capability_immut_ref);}// Return whether the capability allows minting.public is_minter(capability: &R#Self.T): bool {let is_minter: bool;is_minter = *(&move(capability).minter);return move(is_minter);}// Return true the capability is not blacklisted.public is_not_blacklisted(capability: &R#Self.T): bool {let is_blacklisted: bool;is_blacklisted = *(&move(capability).blacklisted);return !move(is_blacklisted);}// Reverts if capability does not allow mintingpublic require_minter(capability: &R#Self.T) {let is_minter: bool;is_minter = Self.is_minter(move(capability));assert(move(is_minter), 0);return;}// Reverts if capability is blacklistedpublic require_not_blacklisted(capability: &R#Self.T) {let is_not_blacklisted: bool;is_not_blacklisted = Self.is_not_blacklisted(move(capability));assert(move(is_not_blacklisted), 0);return;}
}module EToken {// This module is responsible for an actual eToken.// For it to be useful a capability has to be published by using the Capability module above.// -----------------------------------------------------------------
import Transaction.Capability;// Declare the eToken resource, storing an account's total balance.
    resource T {value: u64,}// Publishes an initial zero eToken to the sender.// Should be called once before using this module.public publish() {move_to_sender<T>(T{ value: 0 });return;}// Mint new eTokens.// Reverts if capability does not allow it.public mint(value: u64, capability: &R#Capability.T): R#Self.T {Capability.require_minter(move(capability));return T{value: move(value)};}// Returns an account's eToken balance.// Reverts if an initial eToken hasn't been published.public balance(): u64 {let sender: address;let token_ref: &mut R#Self.T;let token_value: u64;sender = get_txn_sender();token_ref = borrow_global<T>(move(sender));token_value = *(&move(token_ref).value);return move(token_value);}// Deposit owned tokens to an payee's address, and destroy the tokens to deposit,// Reverts if user is blacklisted.public deposit(payee: address, to_deposit: R#Self.T, capability: &R#Capability.T) {let payee_token_ref: &mut R#Self.T;let payee_token_value: u64;let to_deposit_value: u64;Capability.require_not_blacklisted(move(capability));payee_token_ref = borrow_global<T>(move(payee));payee_token_value = *(&copy(payee_token_ref).value);// Unpack and destroy to_deposit tokensT{ value: to_deposit_value } = move(to_deposit);// Increase the payees balance with the destroyed token amount*(&mut move(payee_token_ref).value) = move(payee_token_value) + move(to_deposit_value);return;}// Withdraw an amount of tokens of the sender and return it.// This works by splitting the token published and returning the specified amount as tokens. public withdraw(amount: u64, capability: &R#Capability.T): R#Self.T {let sender: address;let sender_token_ref: &mut R#Self.T;let value: u64;Capability.require_not_blacklisted(move(capability));sender = get_txn_sender();sender_token_ref = borrow_global<T>(move(sender));value = *(&copy(sender_token_ref).value);// Make sure that sender has enough tokensassert(copy(value) >= copy(amount), 1);// Split the senders token and return the amount specified*(&mut move(sender_token_ref).value) = move(value) - copy(amount);return T{ value: move(amount) };}
}script:// Performs simple testing to crudely verify the published modules above.

import Transaction.Capability;
import Transaction.EToken;main() {let sender: address;let owner_capability: &R#Capability.Owner;let capability: &R#Capability.T;let minted_tokens: R#EToken.T;let balance: u64;sender = get_txn_sender();// Publish initial capability
    Capability.publish();// Borrow owner_capability for minter delegationowner_capability = Capability.borrow_owner_capability();// Delegate itself as a minter
    Capability.grant_minter_capability(copy(sender), move(owner_capability));// Borrow general capability for proof of minting capabilitycapability = Capability.borrow_capability();// Publish an eToken account
    EToken.publish();// Mint 100 eTokens and prove minter capabilityminted_tokens = EToken.mint(100, copy(capability));// Deposit the freshly minted tokens to itself
    EToken.deposit(move(sender), move(minted_tokens), move(capability));// Test that the balance corresponds with the intended behaviourbalance = EToken.balance();assert(move(balance) == 100, 3);return;
}

View Code

eToken目前部署在以太坊区块链上,包括为生产中使用标记化而实现的几个重要功能。

最重要的功能如下所列。粗体功能也已在Move IR中实现。

角色(破坏者,黑名单)
造币
燃烧
暂停
可升级
我们将一个角色定义为Move实现中的一个功能,命名更改是为了遵守Libra自己的硬币实现的标准。

能力
为了能够授予minter和blacklist权限,我们必须指定模块的所有者。作为模块的所有者,用户可以将帐户添加为小工具和黑名单。

我们首先定义所有者资源,该资源仅用于发布一次。它在Capability模块中声明。

resource Owner { }
然后,我们通过将已发布资源Move到指定所有者来授予所有权。在这里,我们在尝试使用该语言时遇到了一些问题,以保证所有者功能只发布一次。

在初始模块发布期间,Move IR定义似乎不支持仅定义为可执行一次的函数,也称为构造函数。

当然,这将是授予“所有者”能力的理想场所。

此外,Move IR不直接支持全局变量,这可能是将函数定义为已执行的不安全方式。

为了规避这些限制,我们使用硬编码的所有者地址创建了模块,从而创建了单例资源。因此,只有在所有者作为发件人发布功能资源时才会执行所有权授予:

public publish() {
let sender: address;
sender = get_txn_sender();

// Publish owner capability if sender is the privileged account
// Replace 0x0 address with a real owner account address
if (move(sender) == 0x0) {
Self.grant_owner_capability();
}

...
模块不能代表发件人之外的其他帐户发布资源。从而,让帐户完全控制与他们相关的内容。publish()因此,该功能必须由希望获得有效能力的所有帐户执行,这对于进一步的令牌使用是强制性的。

Neverthelss,强制执行硬编码的所有者地址并不是一个优雅的解决方案。我们向Libra团队提出了这个问题,团队成员建议实施合成糖替换硬编码地址fx。Self.publisher_address。

实际所有权授予是通过调用内部函数来完成的,该函数grant_owner_capability()创建Owner资源并将其发布到发件人帐户。这是通过执行以下表达式完成的:

move_to_sender<Owner>(Owner {});
通过将所述功能实现为内部,VM保证它只能由模块内部执行。通过仅在发件人是指定的所有者地址时调用该函数,我们确保它只发布一次。

该publish()还发布没有权限调用它,因为需要进一步令牌使用的所有帐户的能力。

它只会在已经存在的情况下恢复。

通过将所有权定义为资源,我们可以确保它不能被复制。它还为我们提供了一种令人愉快的类型安全的方式来保护特权功能,例如授予其他人的铸造能力。这是通过简单地要求借用Owner资源作为特权函数的参数来实现的。帐户只能通过调用borrow_owner_capability()函数来获取借用的引用,如果函数存在于发送方地址,则返回借用的引用。以下摘录举例说明了所有者特权函数:

// Grants minter capability to receiver, but can only succeed if sender owns the owner capability.
public grant_minter_capability(receiver: address, owner_capability: &R#Self.Owner) {
let capability_ref: &mut R#Self.T;

release(move(owner_capability));

...
借用的所有者功能仅用于类型安全性,因此立即释放给发送方:如果功能成功执行,则会改变位于该receiver地址的功能资源。

...

// Pull a mutable reference to the receiver's capability, and change its permission.
capability_ref = borrow_global<T>(move(receiver));
*(&mut move(capability_ref).minter) = true;

...
代币
通过使用功能模块定义eToken的角色和权限,我们现在可以继续实际的令牌实现。

我们首先声明令牌资源,该资源包含所述令牌的数量。

resource T {
value: u64,
}
与其他智能合约语言相比,Move的优势显而易见。如果我们要存放一些令牌,我们必须控制令牌的内存所有权。我们只能通过拆分现有的自有令牌(也称为撤销)或铸造新鲜令牌来获得此所有权。

这种所有权属性保证了相同的令牌不能存在于其他地方,从而消除了因错误复制而导致的错误,从而导致双重花费和其他错误行为。

此外,内存所有权模型还要求必须明确销毁拥有的令牌或将其Move到另一个所有者。这可以保证令牌不会被意外锁定在模块内,永远不会被再次检索。

通过利用这种类型安全的属性,我们可以定义存放自有令牌的功能。

public deposit(payee: address, to_deposit: R#Self.T, capability: &R#Capability.T) {

...

Capability.require_not_blacklisted(move(capability));

payee_token_ref = borrow_global<T>(move(payee));
payee_token_value = *(&copy(payee_token_ref).value);

// Unpack and destory to_deposit tokens
T{ value: to_deposit_value } = move(to_deposit);

// Increase the payees balance with the destroyed token amount
*(&mut move(payee_token_ref).value) = move(payee_token_value) + move(to_deposit_value);

...
我们首先确保用户未被列入黑名单。接下来,我们通过解压缩其内部数量变量来销毁所拥有的令牌。最后,我们通过解压缩的金额增加收款人的代币。

与存款相反,当从发件人的帐户中提取令牌时,我们将令牌分成两部分,并将新令牌的所有权归还给来电者。

通过首先减少发件人令牌数量,然后返回新的令牌资源来完成拆分。

*(&mut move(sender_token_ref).value) = move(value) - copy(amount);
return T{ value: move(amount) };
结论
总而言之,Libra和Move IR是智能合约开发中值得欢迎的一步。拥有强大的资产保证可以帮助开发人员减少容易出错的代码并加快Move速度。

尽管如此,Move IR仍然处于早期阶段,并且在当前迭代中不是用户友好的。由于某种原因,它被称为“中间代表”:-)

我们将密切关注这一发展,并对新的发展感到兴奋。

尝试并运行测试
如果您有兴趣了解Libra网络和Move IR,我们建议您运行测试以熟悉上述概念。要运行原始eToken实现测试,您应该执行以下步骤:

克隆Libra存储库(最好是在引言中声明的提交哈希)
跟随LibraREADME如何编译和安装它。
克隆此存储库
将位于src/eToken.mvir此存储库中的eToken Move IR源代码复制到位于的Libra存储库中的测试文件夹language/functional_tests/tests/testsuite/modules/
在Libra存储库中的某处执行以下命令: cargo test -p functional_tests eToken

Libra国内开发者微信交流群:

不能入群请加管理微信

转载于:https://www.cnblogs.com/x-poior/p/11216432.html

Facebook币Libra学习-6.发行属于自己的代币Token案例(含源码)相关推荐

  1. MySQL学习第四弹——多表查询分类以及案例练习源码详解

    多表查询(续) 连接查询 内连接: 相当于查询集合A与集合B的交集部分 外连接 左外连接:查询左表所有数据,以及两张表交集部分数据 右外连接:查询右表所有数据,以及两张表交集部分数据 自连接:当前表与 ...

  2. 分布式定时任务—xxl-job学习(四)——调度中心web页面端api调用源码分析

    分布式定时任务-xxl-job学习(四)--调度中心web页面端api调用源码分析 前言 一.controller目录下非controller类 1.1 PermissionLimit自定义注解 1. ...

  3. 前车碰撞预警——FCW,基于深度学习和单目摄像头测距的前车碰撞预警源码

    前车碰撞预警--FCW,基于深度学习和单目摄像头测距的前车碰撞预警源码. 单目测距,多目标跟踪. 车辆检测,智能adas,FCW,价格只包括源码及设计文档讲解. 我使用的版本说明: gpu版本: an ...

  4. 基于深度学习和单目摄像头测距的前车碰撞预警源码

    前车碰撞预警--FCW,基于深度学习和单目摄像头测距的前车碰撞预警源码 单目测距,多目标跟踪. 车辆检测,智能adas,FCW,编号只包括源码及设计文档讲解. 我使用的版本说明: gpu版本: ano ...

  5. 【深度学习】人群距离监测 DeepSOCIAL 最全汉化论文+源码导读

    内容一览:在疫情期间,公共场所中尽量避免人群聚集,可以有效控制疫情扩散.英国利兹大学的研究团队开源了 DeepSOCIAL 人群距离监测项目,通过 YOLOv4+SORT 的方式快速实现了这一应用. ...

  6. Linux系统入门学习:在Debian或Ubuntu上安装完整的内核源码

    问题:我需要为我的Debian或Ubuntu下载并安装完整树结构的内核源码以供编译一个定制的内核.那么在Debian或Ubuntu上有什么可行的方法来下载完整的内核源码呢? 在给你的Linux安装完整 ...

  7. java存入光盘_java 这是 学习笔记(jdk7)书中的光盘里的源码,不知大家需要不,里面都是新手 的好 Develop 238万源代码下载- www.pudn.com...

    文件名称: java下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 1272 KB 上传时间: 2013-04-01 下载次数: 18 提 供 者: 孙鹏启 详细 ...

  8. TensorFlow (RNN)深度学习 双向LSTM(BiLSTM)+CRF 实现 sequence labeling 序列标注问题 源码下载...

    http://blog.csdn.net/scotfield_msn/article/details/60339415 在TensorFlow (RNN)深度学习下 双向LSTM(BiLSTM)+CR ...

  9. Java虚拟机启动整体流程和基础学习(内容很多,不可快餐阅读),推理+源码论证

    不啰嗦,直接看: ISA指令强关联CPU平台,那么汇编语言也一定强关联CPU平台,而C语言又是对汇编最简单的抽象,也就一定会耦合不同CPU平台的代码,这也就是意味着,在写C/C++项目的时候,必须要考 ...

  10. 了不起的 Webpack HMR 学习指南(含源码分析)

    学习时间:2020.06.14 学习章节:<Webpack HMR 原理解析> 一.HMR 介绍 Hot Module Replacement(以下简称:HMR 模块热替换)是 Webpa ...

最新文章

  1. docker nodejs 基本应用
  2. 手写webpack系列一:了解认识loader-utils
  3. Web Worker的最好文章
  4. 查询Linux系统网卡流量负载,超好用linux系统查询网卡等流量参数的工具,分享给大家!!!...
  5. docker显示镜像的摘要信息
  6. python金字塔_高斯金字塔与拉普拉斯金字塔的原理与python构建
  7. java实现2-3树_2-3-4树的分裂核心代码【JAVA实现】 | 学步园
  8. R con not resolved of types
  9. 鼠标经过背景图片变换
  10. python - class类 (七) 三大特性 - 封装 结尾
  11. 忘记using namespace std;
  12. QComboBox显示文本居中问题
  13. python拆分参数列表_Python序列拆分操作符与映射拆分操作符实例
  14. 使用PMOS管构建电源延时供电电路
  15. 学习java随堂练习-20220610
  16. Serverless开源框架对比
  17. 『迷你教程』识别人类活动的一维卷积神经网络模型,附完整代码
  18. 20135203齐岳 信息安全系统设计基础期中总结
  19. IP地址定位功能在网站上的应用
  20. 求助大神Mac换硬盘后的奇葩问题

热门文章

  1. 计算机专业英语unit6,计算机专业英语郭敏 计算机专业英语Unit6
  2. 获取ie窗口的IHTMLDocument2对象
  3. ubuntu18.04安装OpenCV3.4.12步骤及安装中遇到的一些问题
  4. C++ 万年历 查找年、月、日、星期数以及节日等信息
  5. Python学习_案例for循环嵌套
  6. C++输入一系列数字,以换行结束输入
  7. ECCV 2022 | 基于去遮挡和移除的3D交互双手姿态估计
  8. apk+html启动页,案例——APP启动页
  9. 6月书讯 | 初夏,正好读新书
  10. 即使最平凡的人,也有不妥协的一面