Aptos合约开发之部署ERC20合约

  • 时间:
  • 浏览:128
  • 来源:区块链技术网

本篇教程使用Aptos-Cli V0.3.1进行开发。

一、前言

距上篇教程发出后不久,Aptos官方对合约框架进行了版本升级,目前的版本是0.3.1 。因此在本篇文章开始之前,各位需要注意下开发环境。否则,这会对你后续的开发和部署造成很多麻烦!

二、关键词

框架升级、测试网升级、ERC20合约部署、代币合约开发、Resource资源类型

三、注意

1、本篇教程使用Aptos-Cli V0.3.1进行开发。

2、在本篇以及后续教程中,Move.toml中的依赖路径将使用local path替代远程链接这种形式。这么做的目的是为了避免因为网络等原因导致的合约无法部署等问题。因此,请去官方github下载最新Aptos-core到你的WSL2中。

[dependencies]
#AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "devnet" }
#MoveStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/move-stdlib", rev = "devnet" }
AptosFramework = { local = "/home/ouhuang/aptos-core-main/aptos-move/framework/aptos-framework" }
AptosStdlib = { local = "/home/ouhuang/aptos-core-main/aptos-move/framework/aptos-stdlib" }

3、window环境下,在文件资源管理器目录下 \\wsl$ 打开虚拟机文件夹目录,因此可以直接把window下的任何文件拖到WSL2中。

4、由于Aptoes-Cli与Devnet版本不匹配导致的无法部署问题,官方表示在接下来版本中会修复这个问题。

四、创建项目

1、创建项目工程

//创建项目文件夹
mkdir erc20_aptos

//创建账号
aptos init 

//创建合约目录目录
mkdir sources
mkdir sources/modules

//创建项目配置文件
touch Move.toml

2、修改Move.toml

[package]
name = "StandardErc20"
version = "0.0.1"

[dependencies]
#AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "devnet" }
#MoveStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/move-stdlib", rev = "devnet" }
AptosFramework = { local = "/home/ouhuang/aptos-core-main/aptos-move/framework/aptos-framework" }
AptosStdlib = { local = "/home/ouhuang/aptos-core-main/aptos-move/framework/aptos-stdlib" }
[addresses]
TestCoin = '032621a894a17d900a7f8cfd7581380f02afdedb9818a07138fde2bb1a420516'

3、检查账号是否有Gas

ouhuang@LAPTOP-HM465BTT:~/erc20_aptos$ aptos account list --query resources --account  032621a894a17d900a7f8cfd7581380f02afdedb9818a07138fde2bb1a420516

4、编写Erc20合约

在modules下创建standard_erc20.move文件。

module TestCoin::StandardErc20{
    use std::signer;
    use std::string;

    struct Coin has store {
        value : u128,
    }

    struct CoinStore has key {
        coin : Coin,
    }

    struct CoinInfo has key {
        // name
        name: string::String,
        // symbol
        symbol: string::String,
        // decimals
        decimals: u8,
        // suppley
        supply: u128,
        // capcity
        cap: u128,
    }

        /// Address of the owner of this module
    const MODULE_OWNER: address = @TestCoin;

    const THE_ACCOUNT_HAS_BEEN_REGISTERED : u64 = 1;

    const INVALID_TOKEN_OWNER : u64 = 2;

    const THE_ACCOUNT_IS_NOT_REGISTERED : u64 = 3;

    const INSUFFICIENT_BALANCE : u64 = 4;

    const ECOIN_INFO_ALREADY_PUBLISHED : u64 = 5;

    const EXCEEDING_THE_TOTAL_SUPPLY : u64 = 6;

    public fun getBalance(owner: address) : u128 acquires CoinStore{

        assert!(is_account_registered(owner), THE_ACCOUNT_IS_NOT_REGISTERED);

        borrow_global<CoinStore>(owner).coin.value
    }

    public fun is_account_registered(account_addr : address) : bool{
        exists<CoinStore>(account_addr)
    }

    fun deposit(account_addr : address, coin : Coin) acquires CoinStore {

        assert!(is_account_registered(account_addr), THE_ACCOUNT_IS_NOT_REGISTERED);

        let balance = getBalance(account_addr);

        let balance_ref = &mut borrow_global_mut<CoinStore>(account_addr).coin.value;

        *balance_ref = balance + coin.value;

        let Coin { value:_ } = coin;
    }

    fun withdraw(account_addr : address, amount : u128) : Coin acquires CoinStore {
        assert!(is_account_registered(account_addr), THE_ACCOUNT_IS_NOT_REGISTERED);
        let balance = getBalance(account_addr);

        assert!(balance >= amount, INSUFFICIENT_BALANCE);

        let balance_ref = &mut borrow_global_mut<CoinStore>(account_addr).coin.value;

        *balance_ref = balance - amount;

        Coin { value: amount }
    }

    public entry fun initialize(address : &signer, name : vector<u8>, symbol : vector<u8>, decimals : u8, supply : u128)  {

        assert!(signer::address_of(address) == MODULE_OWNER, INVALID_TOKEN_OWNER);

        assert!(!exists<CoinInfo>(MODULE_OWNER), ECOIN_INFO_ALREADY_PUBLISHED);

        move_to(address, CoinInfo{name : string::utf8(name), symbol : string::utf8(symbol), decimals, supply, cap : 0});
    }

    public entry fun register(address : &signer) {
        let account = signer::address_of(address);

        assert!(!exists<CoinStore>(account), THE_ACCOUNT_HAS_BEEN_REGISTERED);

        move_to(address, CoinStore{ coin : Coin{ value : 0 } });
    }

    public entry fun mint(owner : &signer,to : address,amount : u128) acquires CoinStore,CoinInfo{

        assert!(signer::address_of(owner) == MODULE_OWNER, INVALID_TOKEN_OWNER);

        assert!(borrow_global<CoinInfo>(MODULE_OWNER).cap + amount <= borrow_global<CoinInfo>(MODULE_OWNER).supply,EXCEEDING_THE_TOTAL_SUPPLY);

        deposit(to, Coin { value : amount });

        let cap = &mut borrow_global_mut<CoinInfo>(MODULE_OWNER).cap;
        *cap = *cap + amount;
    }

    public entry fun transfer(from : &signer, to : address, amount : u128) acquires CoinStore {

        let coin = withdraw(signer::address_of(from), amount);

        deposit(to, coin);
    }

    public entry fun burn(owner : &signer, amount : u128) acquires CoinStore,CoinInfo {

        assert!(signer::address_of(owner) == MODULE_OWNER, INVALID_TOKEN_OWNER);

        let coin = withdraw(signer::address_of(owner), amount);
        let Coin { value: amount } = coin;

        let cap = &mut borrow_global_mut<CoinInfo>(MODULE_OWNER).cap;
        *cap = *cap - amount;

        let supply = &mut borrow_global_mut<CoinInfo>(MODULE_OWNER).supply;
        *supply = *supply - amount;
    }
}

5、合约编译部署 由于aptos链不断在更新迭代,所以请务必注意你的cli版本和devnet版本。不然你肯定是部署不成功的。遇到类似下面这种API error时,请先更新你的cli脚手架。

ouhuang@LAPTOP-HM465BTT:~/erc20_aptos$ aptos move publish --named-addresses  Erc20Token=032621a894a17d900a7f8cfd7581380f02afdedb9818a07138fde2bb1a420516
{
  "Error": "API error: error decoding response body: missing field `state_root_hash`"
}

更新完cli后,编译部署成功。

ouhuang@LAPTOP-HM465BTT:~/erc20_aptos$ aptos move compile --package-dir .
{
  "Result": [
    "032621a894a17d900a7f8cfd7581380f02afdedb9818a07138fde2bb1a420516::Erc20"
  ]
}
ouhuang@LAPTOP-HM465BTT:~/erc20_aptos$ aptos move publish --package-dir /home/ouhuang/erc20_aptos/
package size 2600 bytes
{
  "Result": {
    "transaction_hash": "0x4ebef2c4857f75bc9ecae21e2bc9383bfaeb68cc1b0e9b924b2fc1b9a0356344",
    "gas_used": 852,
    "gas_unit_price": 1,
    "sender": "032621a894a17d900a7f8cfd7581380f02afdedb9818a07138fde2bb1a420516",
    "sequence_number": 9,
    "success": true,
    "timestamp_us": 1661787424248832,
    "version": 21297869,
    "vm_status": "Executed successfully"
  }
}

6、合约调用 aptos合约调用和solidity调用类似,要么是在区块链浏览器中调用,或者是使用前端sdk调用。

https://explorer.devnet.aptos.dev/account/0xe13c36e921448a601f2de9dc5341525ca6619a44e1444f302fba37fb39c5cf93

五、合约解析

Solidity是代码和数据放一起,因此在Solidity中想表示地址和余额的关系可以用mapping

//定义地址==》余额 映射关系
mapping (address => uint256) private _rOwned;
mapping (address => uint256) private _tOwned;
mapping (address => bool) private _isExcluded;

//查询余额
return _rOwned[address]

而Move是代码和数据分离。每个账户地址下拥有的是资源类型。要想表达地址和余额的关系。需要先根据地址找到资源类型,然后再从类型找到余额。

// 余额
struct Coin has store {
    value : u128,
}
//定义资源类型
struct CoinStore has key {
    coin : Coin,
}

//查询余额:地址Owner==》资源类型CoinStore==>余额 地址.资源类型.coin.value
borrow_global<CoinStore>(owner).coin.value
  • signer

引入signer类型的原因之一是要明确显示哪些函数需要发送者权限,哪些不需要。因此,函数不能欺骗用户未经授权访问其 Resource

  • Acquires 关键字

该关键字放在函数返回值之后,用来显式定义此函数获取的所有 Resource。我们必须指定所有获取的 Resource。

七、小结

按照上述步骤,我们就能部署属于自己的ERC20合约。在接下来的文章里,我们将一起构建Dapp来实现Claim Token等常用功能。

本文参与区块链技术网 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2022-09-15 10:16
  • 阅读 ( 1431 )
  • 学分 ( 54 )
  • 分类:Aptos

猜你喜欢

头戴巨星皇冠的Aptos,原生生态项目实力究竟如何?

Aptos是基于Move语言开发的公链项目,Aptos对开发者更加友好,因此已经有不少项目开始在这条链上布局。本文将盘点现在Aptos生态上的项目,看一看含着金汤匙出生的Apt

2022-11-30

刚上主网的Aptos被高估了吗?承诺达到10万TPS实则仅有4

Aptos于今日(18日)凌晨正式上线主网,引起大批社群的兴奋。自2月正式曝光以来,公链Aptos就一直备受关注和期待。在上线主网后,不少知名加密货币交易所(币安、火币、FTX

2022-11-30

Aptos公布代币经济学,供应量10亿,82%APT被质押,与预期一致

18日凌晨,新公链Aptos上线,但迟迟未发布的代币经济学却引起了不少投资者的质疑。不久后,Aptos在推特上发布了官方代币经济概览,其中APT的初始总供应量为10亿个,51.

2022-11-30

两大热门公链的竞争,Aptos 与Sui 的现状与差异

前段时间除了ETH的Merge之外,Move系Aptos与Sui的新公链也是占据「币圈热搜榜」最多的词。Aptos和Sui团队都来自Meta的原始Diem团队,它们使用权益证明

2022-11-30

Aptos 公链生态介绍|Aptos 会是下一个Solana 吗?

Aptos公链简介Aptos背景-被称为Meta区块链项目Diem的继承者Meta(前身为Facebook)的全球稳定币项目Diem(前身为Libra)因为受各国监管机构强烈反

2022-11-30