比特派官方最新版下载|erc20代币交易所钱包

作者: 比特派官方最新版下载
2024-03-16 05:12:26

教程 | 教你如何一步步创建ERC20代币 - 知乎

教程 | 教你如何一步步创建ERC20代币 - 知乎切换模式写文章登录/注册教程 | 教你如何一步步创建ERC20代币xpanxcomPython Excle艾伯特AI人工智能(公众号:aibbtcom)按:看这篇文章需要对以太坊,智能合约,代币等概念有基本的了解。什么是ERC20可以把ERC20简单理解成以太坊上的一个代币协议,所有基于以太坊开发的代币合约都遵守这个协议。遵守这些协议的代币我们可以认为是标准化的代币,而标准化带来的好处是兼容性好。这些标准化的代币可以被各种以太坊钱包支持,用于不同的平台和项目。说白了,你要是想在以太坊上发行代币融资,必须要遵守ERC20标准。ERC20的标准接口是这样的:contract ERC20 {

function name() constant returns (string name)

function symbol() constant returns (string symbol)

function decimals() constant returns (uint8 decimals)

function totalSupply() constant returns (uint totalSupply);

function balanceOf(address _owner) constant returns (uint balance);

function transfer(address _to, uint _value) returns (bool success);

function transferFrom(address _from, address _to, uint _value) returns (bool success);

function approve(address _spender, uint _value) returns (bool success);

function allowance(address _owner, address _spender) constant returns (uint remaining);

event Transfer(address indexed _from, address indexed _to, uint _value);

event Approval(address indexed _owner, address indexed _spender, uint _value);

}name返回ERC20代币的名字,例如"My test token"。symbol返回代币的简称,例如:MTT,这个也是我们一般在代币交易所看到的名字。decimals返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示。totalSupply返回token的总供应量balanceOf返回某个地址(账户)的账户余额transfer从代币合约的调用者地址上转移 _value的数量token到的地址 _to,并且必须触发Transfer事件。transferFrom从地址 _from发送数量为 _value的token到地址 _to,必须触发Transfer事件。transferFrom方法用于允许合同代理某人转移token。条件是from账户必须经过了approve。这个后面会举例说明。approve允许 _spender多次取回您的帐户,最高达 _value金额。 如果再次调用此函数,它将以 _value覆盖当前的余量。allowance返回 _spender仍然被允许从 _owner提取的金额。后面三个方法不好理解,这里还需要补充说明一下,approve是授权第三方(比如某个服务合约)从发送者账户转移代币,然后通过 transferFrom() 函数来执行具体的转移操作。账户A有1000个ETH,想允许B账户随意调用他的100个ETH,过程如下:A账户按照以下形式调用approve函数approve(B,100)B账户想用这100个ETH中的10个ETH给C账户,调用transferFrom(A, C, 10)调用allowance(A, B)可以查看B账户还能够调用A账户多少个token另外,我推荐这篇文章,对这部分概念讲解的比较清楚。干货 | 代币支付的以太坊智能服务(http://www.aibbt.com/a/26166.html)(编者按:亦见文末超链接《科普 | 释放阻塞的以太坊交易》)后面两个是事件,事件是为了获取日志方便提供的。前者是在代币被转移时触发,后者是在调用approve方法时触发。基于ERC20编写的一个代币合约pragma solidity ^0.4.16;

contract Token{

uint256 public totalSupply;

function balanceOf(address _owner) public constant returns (uint256 balance);

function transfer(address _to, uint256 _value) public returns (bool success);

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

(bool success);

function approve(address _spender, uint256 _value) public returns (bool success);

function allowance(address _owner, address _spender) public constant returns

(uint256 remaining);

event Transfer(address indexed _from, address indexed _to, uint256 _value);

event Approval(address indexed _owner, address indexed _spender, uint256

_value);

}

contract TokenDemo is Token {

string public name; //名称,例如"My test token"

uint8 public decimals; //返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示.

string public symbol; //token简称,like MTT

function TokenDemo(uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol) public {

totalSupply = _initialAmount * 10 ** uint256(_decimalUnits); // 设置初始总量

balances[msg.sender] = totalSupply; // 初始token数量给予消息发送者,因为是构造函数,所以这里也是合约的创建者

name = _tokenName;

decimals = _decimalUnits;

symbol = _tokenSymbol;

}

function transfer(address _to, uint256 _value) public returns (bool success) {

//默认totalSupply 不会超过最大值 (2^256 - 1).

//如果随着时间的推移将会有新的token生成,则可以用下面这句避免溢出的异常

require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);

require(_to != 0x0);

balances[msg.sender] -= _value;//从消息发送者账户中减去token数量_value

balances[_to] += _value;//往接收账户增加token数量_value

Transfer(msg.sender, _to, _value);//触发转币交易事件

return true;

}

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

(bool success) {

require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);

balances[_to] += _value;//接收账户增加token数量_value

balances[_from] -= _value; //支出账户_from减去token数量_value

allowed[_from][msg.sender] -= _value;//消息发送者可以从账户_from中转出的数量减少_value

Transfer(_from, _to, _value);//触发转币交易事件

return true;

}

function balanceOf(address _owner) public constant returns (uint256 balance) {

return balances[_owner];

}

function approve(address _spender, uint256 _value) public returns (bool success)

{

allowed[msg.sender][_spender] = _value;

Approval(msg.sender, _spender, _value);

return true;

}

function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {

return allowed[_owner][_spender];//允许_spender从_owner中转出的token数

}

mapping (address => uint256) balances;

mapping (address => mapping (address => uint256)) allowed;

}代码不必过多的解释,注释都写得很清楚了。这里可能有人会有疑问,name,totalSupply这些按照标准不应该都是方法吗,怎么这里定义的是属性变量? 这是因为solidity会自动给public变量生成同名的getter接口。部署测试我会提供两个环境的部署测试流程,都是亲测过的,大家可以根据自己的喜好选择。我个人平时用得比较多的是后者。Remix+MetaMask环境部署测试这部分要求你的浏览器已经安装了MetaMask插件,至于什么是MetaMask以及如何安装和使用请自行搜索查询。MetaMask我们用的是测试环境的网络,在测试网络中可以申请一些以太币进行测试。我们把代码复制到remix编译,没问题的话如下图所示点击create创建合约,参数可以按照下图的方式设置。注意环境选择injected web3,这样会打开浏览器插件MetaMask进行测试部署。-image-点击create后会弹出合约确认界面,直接点击submit,等待合约确认。-image-我们可以在MetaMask里点击该笔合约提交的明细,就会跳转到以太坊的浏览器中,可以在这里看到合约的各种信息:-image-如上图所示,1表示该笔交易(合约也是一种交易)的hash值,2是当前合约所处的区块位置(当然是测试环境)和已经被确认的区块链数量,3是合约的创建地址,4是合约本省所在的地址。3和4的概念容易混淆,注意理解。进入MetaMask的token界面中,点击add token,然后我们把合约的地址复制到过去提交就可以看到我们的代币了。还可以点击代币的图标打开浏览器查看代币的详细信息。-image-到这里你已经完成了代币的开发部署。接下来我们还要看看如何进行代币的转账,这个也是代币比较常用的操作。转账我们需要结合以太坊钱包MyEtherWallet,这是个以太坊的网页版轻量级钱包,利用它可以很方便的对我们的以太币和其它代币进行管理。转账前我们首先要把代币加入到钱包中,-image--image-注意在上图中,我们选择的环境同样是测试环境并且和MetaMask中的环境一致。点击add custome token,输入代币地址等信息就可以看到代币了,然后进行转账操作。-image-我们随便转入一个地址,转账完成后,发现代币余额确实减少了。-image-以太坊钱包mist+geth私有环境部署测试我个人开发用这个环境比较多,不过这个环境安装起来比较麻烦,具体流程可以看下我以前的文章。打开mist钱包,进入合约界面,然后点击deploy new contact,然后把代码复制进去编译。-image-然后点击deploy-image-输入账户密码开始部署。随着挖矿的进行,合约就被部署到我的geth私有环境中了,-image-回到钱包的合约界面已经可以看到合约了,-image-点击transfer ether&tokens,进入转账界面,进行转账。-image--image-成功后可以看到余额已经减少,并且转入账户的余额增加。-image--image-参考干货 | 代币支付的以太坊智能服务(http://www.aibbt.com/a/26166.html)区块链学习(4)发布代币(token)并通过智能合约与网页交互(mac版)(http://www.aibbt.com/a/29159.html)发布于 2018-04-10 14:59区块链(Blockchain)​赞同 17​​3 条评论​分享​喜欢​收藏​申请

创建并部署ERC20代币 | 登链社区 | 区块链技术社区

创建并部署ERC20代币 | 登链社区 | 区块链技术社区

文章

问答

讲堂

专栏

集市

更多

提问

发表文章

活动

文档

招聘

发现

Toggle navigation

首页 (current)

文章

问答

讲堂

专栏

活动

招聘

文档

集市

搜索

登录/注册

创建并部署ERC20代币

aisiji

更新于 2022-03-11 15:22

阅读 7612

本文通过创建一个代币深入讲解ERC20

> 本文通过创建一个代币深入讲解ERC20

![1_FhxeUTY3vrk3oECG3-hC2w](https://img.learnblockchain.cn/2022/03/02/1_FhxeUTY3vrk3oECG3-hC2w.png!/scale/70)

图片来源: Undraw.co

## ERC20代币标准

第一个标准由Fabian Vogelsteller于2015年11月以ethereum request for Comments(ERC)引入,它被自动分配到GitHub第20个议题,所以叫“ERC20代币”。目前绝大多数代币都基于ERC20标准。ERC20后来变成了以太坊改进提案20(EIP-20),但是大部分仍然使用它最初的名字,ERC20。

ERC20是一个同质化代币标准,意思是不同的ERC20代币是可互换的并且不具有独特属性。

[ERC20标准](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md)为实现代币的合约定义了一个通用接口,这样任何兼容的代币都可以用同样的方式访问和使用。这个接口由许多必须在每次实现中都出现的函数构成,以及一些开发者可能添加的可选函数和属性。

## ERC20需要的函数和事件

一个ERC20的代币合约必须至少提供下面这些函数和事件:

`totalSupply`: 返回当前代币总量,可以是一个固定值或者变量。

`balanceOf`:返回给定地址的代币余额

`transfer`: 从执行转账的地址余额中将指定数量的代币转移到指定地址。

`transferFrom`: 从一个账户到另一个账户,指定发送者,接收者和转移的代币数量。与`approve`结合使用。

`approve`: 指定一个被委托地址和委托代币数量,被委托地址可以在不超过委托数量的前提下多次从委托账户转移代币。

`allowance`: 给定一个所有者地址和一个被委托地址,返回被委托代币余额。

Transfer: 在成功转移(调用`transfer`或者`transferFrom`)后触发的事件(即使转移数量为0)。

Approval: 成功调用`approve`的事件日志。

## ERC20 可选函数

`name`: 返回代币的可读名称(如“US Dollars”)。

`symbol`: 返回代币的可读符号(如“USD”)。

`decimals`: 返回代币数量的小数点位数。例如,如果`decimals`为2,表示小数点后2位。

ERC20 接口是用 Solidity 定义的。

下面是Solidity 的 ERC20接口规范:

```

contract ERC20 {

function totalSupply() constant returns (uint theTotalSupply);

function balanceOf(address _owner) constant returns (uint balance);

function transfer(address _to, uint _value) returns (bool success);

function transferFrom(address _from, address _to, uint _value) returns

(bool success);

function approve(address _spender, uint _value) returns (bool success);

function allowance(address _owner, address _spender) constant returns

(uint remaining);

event Transfer(address indexed _from, address indexed _to, uint _value);

event Approval(address indexed _owner, address indexed _spender, uint _value);

}

```

## ERC20 数据结构

如果你检查任何一个ERC20实现,你会发现它包含两个数据结构,一个用来跟踪余额(balance),另一个用来跟踪委托代币余额(allowance)。在Solidity中,都是用数据映射实现的。

第一个数据映射允许代币合约跟踪谁拥有代币。每次交易都是从一个余额扣除同时在另一个余额增加:

```

mapping(address => uint256) balances;

```

第二个数据结构是委托代币余额(allowance)的数据映射。正如我们将在下一节看到的,ERC20代币所有者可以让一个被委托者花费自己余额中一定数量的代币(allowance) 。

ERC20 合约用一个二维映射跟踪委托代币余额,其主键是代币所有者的地址,映射到被委托地址和对应的委托代币余额:

```

mapping (address => mapping (address => uint256)) public allowed;

```

## ERC20工作流程:“transfer” 和 “approve + transferFrom”

ERC20代币标准有两个交易函数。你可能想知道为什么。

ERC20允许两种不同的工作流程。第一种是一笔交易,使用`transfer`函数的的简单流程。这个流程用于一个钱包发送代币到另一个钱包。

执行转账合约非常简单。如果Alice想要发送10个代币给Bob,她的钱包会发送一笔交易到代币合约的地址,调用`transfer`函数,并且参数为Bob的地址和10。代币合约修改Alice的余额(-10)和Bob的余额(+10),然后发出一个`Transfer`事件。

第二种流程是两笔交易,`approve`+`transferFrom`。这个流程允许代币所有者将控制权委托给另一个地址。通常用于将控制权委托给一个分配代币的合约,也可以被交易所使用。

例如,如果一个公司正在为ICO发售代币,他们可以委托一个众筹合约地址来分发一定数量的代币。这个众筹合约可以通过`transferFrom`将代币合约所有者的余额转给每一个代币买家,如下图所示。

> 注意:首次代币发行(ICO)是公司或者组织为了筹集资金而出售代币的众筹机制。这个术语源自首次公开募股(IPO),这是上市公司在证券交易所向投资者出售股票的过程。与高度监管的IPO市场不同,ICO是开放的、全球化的、混乱的。本文对ICO的示例和解释并非对此类筹款活动的认可。

![1_eLTjPYZzUpalJTbsVDyZZw](https://img.learnblockchain.cn/2022/03/02/1_eLTjPYZzUpalJTbsVDyZZw.png!/scale/60)ERC20 workflow

## ERC20实现

虽然大约30行Solidity代码就可以实现一个ERC20代币,但大部分的实现都是更复杂的。这是为了解决潜在的漏洞。EIP-20标准提到两种实现:

[Consensys EIP20](https://github.com/ConsenSys/Tokens/blob/master/contracts/eip20/EIP20.sol) —— 一种简单且易读的ERC20代币的实现。

[OpenZeppelin StandardToken](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v1.12.0/contracts/token/ERC20/StandardToken.sol) —— 这个实现兼容ERC20,并且有额外安全措施。它形成了OpenZeppelin库的基础,可以实现更复杂ERC20代币,如筹款上限,拍卖,期权等功能。

## 发起自己的ERC20代币

接下来我们创建并发起自己的代币。下面的例子,将使用Truffle框架。假设你已经安装了Truffle,如果没有安装,请用npm安装:

```

npm i truffle

```

假设我们的代币叫“Mastering Ethereum Token”,我们用符号“MET”代表它。

> 注意:你可以在[这里](https://github.com/ac12644/METoken.git)找到这个例子。

首先,我们创建并初始化一个Truffle项目目录。运行下面4个命令并接受所有默认答案:

```

$ mkdir METoken

$ cd METoken

METoken $ truffle init

METoken $ npm init

```

你现在应该有下面的目录结构了:

```

METoken/

+---- contracts

| `---- Migrations.sol

+---- migrations

| `---- 1_initial_migration.js

+---- package.json

+---- test

`---- truffle-config.js

```

编辑`truffle-config.js`配置文件,配置Truffle环境,或者复制下面的示例:

```

// Install dependencies:

// npm init

// npm install --save-dev dotenv truffle-wallet-provider ethereumjs-wallet

// Create .env in project root, with keys:

// ROPSTEN_PRIVATE_KEY="123abc"

// MAINNET_PRIVATE_KEY="123abc"

require('dotenv').config();

const Web3 = require("web3");

const web3 = new Web3();

const WalletProvider = require("truffle-wallet-provider");

const Wallet = require('ethereumjs-wallet');

var mainNetPrivateKey = new Buffer(process.env["MAINNET_PRIVATE_KEY"], "hex")

var mainNetWallet = Wallet.fromPrivateKey(mainNetPrivateKey);

var mainNetProvider = new WalletProvider(mainNetWallet, "https://mainnet.infura.io/");

var ropstenPrivateKey = new Buffer(process.env["ROPSTEN_PRIVATE_KEY"], "hex")

var ropstenWallet = Wallet.fromPrivateKey(ropstenPrivateKey);

var ropstenProvider = new WalletProvider(ropstenWallet, "https://ropsten.infura.io/");

module.exports = {

networks: {

dev: { // Whatever network our local node connects to

network_id: "*", // Match any network id

host: "localhost",

port: 8545,

},

mainnet: { // Provided by Infura, load keys in .env file

network_id: "1",

provider: mainNetProvider,

gas: 4600000,

gasPrice: web3.utils.toWei("20", "gwei"),

},

ropsten: { // Provided by Infura, load keys in .env file

network_id: "3",

provider: ropstenProvider,

gas: 4600000,

gasPrice: web3.utils.toWei("20", "gwei"),

},

kovan: {

network_id: 42,

host: "localhost", // parity --chain=kovan

port: 8545,

gas: 5000000

},

ganache: { // Ganache local test RPC blockchain

network_id: "5777",

host: "localhost",

port: 7545,

gas: 6721975,

}

}

};

```

-truffle-config.js-

如果你用示例`truffle-config.js`,记住在包含你的测试私钥的`METoken`文件夹中创建一个`.env`文件,以便在以太坊公共测试网(如Ropsten or Kovan)上部署和测试。你可以从 MetaMask 导出测试网私钥。

这时,你的目录应该是这样的:

```

METoken/

+---- contracts

| `---- Migrations.sol

+---- migrations

| `---- 1_initial_migration.js

+---- package.json

+---- test

+---- truffle-config.js

`---- .env *new file*

```

### 警告

只能使用没有在以太坊主网上持有资产的测试密钥或者测试助记词。切勿将真正持有资产的密钥用于测试。

在我们的示例中,我们将导入 OpenZeppelin 库,这个库实现了一些重要的安全检查并且容易扩展:

```

$ npm install openzeppelin-solidity@1.12.0

+ openzeppelin-solidity@1.12.0

added 1 package from 1 contributor and audited 2381 packages in 4.074s

```

`openzeppelin-solidity`包会在`node_modules`目录下添加大约250个文件。OpenZeppelin库并不仅仅包含ERC20代币,我们只会使用其中一小部分。

接下来,开始写代币合约。创建一个新文件,`METoken.sol`,并从下面复制[示例](https://github.com/ac12644/METoken/blob/main/contracts/METoken.sol)代码。

```

pragma solidity ^0.4.21;

import 'openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol';

contract METoken is StandardToken {

string public constant name = 'Mastering Ethereum Token';

string public constant symbol = 'MET';

uint8 public constant decimals = 2;

uint constant _initial_supply = 2100000000;

function METoken() public {

totalSupply_ = _initial_supply;

balances[msg.sender] = _initial_supply;

emit Transfer(address(0), msg.sender, _initial_supply);

}

}

```

-METoken.sol-

`METoken.sol`合约——实现ERC20代币的Solidity合约,非常简单,因为它从OpenZeppelin库继承了所有功能。

示例 1. `METoken.sol`: 实现ERC20代币的Solidity合约

这里,我们定义了可选变量名,符号,和小数位数,也定义了一个`_initial_supply`变量——设为2100万个代币,代币数量可以细分到小数点后2位,也就是总共21亿份。在合约的初始化函数(构造函数)中我们设置`totalSupply`等于`_initial_supply`,并且将所有`_initial_supply`全部分配给创建`METoken`合约的账户(`msg.sender`)的余额。

现在我们用truffle来编译METoken代码:

```

$ truffle compile

Compiling ./contracts/METoken.sol...

Compiling ./contracts/Migrations.sol...

Compiling openzeppelin-solidity/contracts/math/SafeMath.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol...

```

如你所见,truffle 编译了 OpenZeppelin 库的必要依赖。

接下来我们编写一个迁移脚本来部署`METoken`合约。在`METoken/migrations` 文件夹中创建一个新文件`2_deploy_contracts.js`。复制下面[示例](https://github.com/ac12644/METoken/blob/main/migrations/2_deploy_contracts.js)代码:

```

var METoken = artifacts.require("METoken");

module.exports = function(deployer) {

// Deploy the METoken contract as our only task

deployer.deploy(METoken);

};

```

-2_deploy_contracts.js-

在部署到以太坊测试网之前,我们先启动一个本地区块链来测试。可以从命令行`ganache-cli` 或者图形用户界面来启动[ganache](https://learnblockchain.cn/article/3501)区块链。

ganache 启动,我们就可以部署 METoken 合约并且看到是否一切正常:

```

$ truffle migrate --network ganache

Using network 'ganache'.

Running migration: 1_initial_migration.js

Deploying Migrations...

... 0xb2e90a056dc6ad8e654683921fc613c796a03b89df6760ec1db1084ea4a084eb

Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0

Saving successful migration to network...

... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956

Saving artifacts...

Running migration: 2_deploy_contracts.js

Deploying METoken...

... 0xbe9290d59678b412e60ed6aefedb17364f4ad2977cfb2076b9b8ad415c5dc9f0

METoken: 0x345ca3e014aaf5dca488057592ee47305d9b3e10

Saving successful migration to network...

... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0

Saving artifacts...

```

在 ganache 控制台,我们可以看到已经创建了四笔新的交易:

![1_HMf2Ba_xvS8Oj1fkQ1wp3g](https://img.learnblockchain.cn/2022/03/02/1_HMf2Ba_xvS8Oj1fkQ1wp3g.png!/scale/50)

-ganache-

### 用 Truffle 控制台与 METoken 交互

我们可以通过 truffle 控制台在 ganache 区块链上与合约交互。这是一个交互式 JavaScript 环境,提供了对 truffle 环境的访问,并通过 web3 访问区块链。下面,我们将 truffle 控制台与 ganache 区块链连接:

```

$ truffle console --network ganache

truffle(ganache)>

```

`truffle(ganache)>`表明我们已经连接到 ganache 区块链,并且已经准备好输入命令。truffle 控制台支持所有 truffle 命令,所以我们可以从控制台编译和迁移。

我们已经运行了命令,所以让我们直接进入到合约本身。`METoken`合约在 truffle 环境中就像一个 JavaScript 对象。在提示符的地方输入METoken,就会清除整个合约定义:

```

truffle(ganache)> METoken

{ [Function: TruffleContract]

_static_methods:

[...]

currentProvider:

HttpProvider {

host: 'http://localhost:7545',

timeout: 0,

user: undefined,

password: undefined,

headers: undefined,

send: [Function],

sendAsync: [Function],

_alreadyWrapped: true },

network_id: '5777' }

```

`METoken`对象也揭露了几个属性,如合约地址(因为是用 migrate 命令部署的):

```

truffle(ganache)> METoken.address

'0x345ca3e014aaf5dca488057592ee47305d9b3e10'

```

如果我们想要与部署的合约交互,我们必须使用异步调用,以JavaScript “promise” 的形式。用 deployed 函数来获取合约实例,然后调用`totalSupply`函数:

```

truffle(ganache)> METoken.deployed().then(instance => instance.totalSupply())

BigNumber { s: 1, e: 9, c: [ 2100000000 ] }

```

接下来,让我们用 ganache 创建的账户来检查 METoken 余额,并且发送一些 METoken 到另一个地址。首先,获取账户地址:

```

truffle(ganache)> let accounts

undefined

truffle(ganache)> web3.eth.getAccounts((err,res) => { accounts = res })

undefined

truffle(ganache)> accounts[0]

'0x627306090abab3a6e1400e9345bc60c78a8bef57'

```

账户列表包含 ganache 创建的所有账户,`accounts[0]`是部署`METoken`合约的账户。它应该有`METoken`余额的,因为我们的`METoken`构造函数将所有token给到了这个地址。我们检查一下:

```

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(accounts[0]).then(console.log) })

undefined

truffle(ganache)> BigNumber { s: 1, e: 9, c: [ 2100000000 ] }

```

最后,通过调用合约的`transfer`函数从`accounts[0]`转移 1000.00 个 METoken 到`accounts[1]`:

```

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.transfer(accounts[1], 100000) })

undefined

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(accounts[0]).then(console.log) })

undefined

truffle(ganache)> BigNumber { s: 1, e: 9, c: [ 2099900000 ] }

undefined

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(accounts[1]).then(console.log) })

undefined

truffle(ganache)> BigNumber { s: 1, e: 5, c: [ 100000 ] }

```

> 提示:METoken可以精确到小数点后2位,意思是1个METoken在合约中其实是100份。当我们转移1000个METoken时,我们在调用`transfer`函数时指定的值是100000

如你所见,在会话中,`accounts[0]`现在有20,999,000 个MET,`accounts[1]`有1000个MET。

![1_z7tDVitXZ_XTytKu3bBU8Q](https://img.learnblockchain.cn/2022/03/02/1_z7tDVitXZ_XTytKu3bBU8Q.png!/scale/50)

-ganache-

## 向合约地址发送ERC20代币

到目前为止,我们已经创建了一个ERC20代币并从一个账户发送了一些代币到另一个账户。前面我们用来演示的账户都是[外部账户(external owned accouts)](https://learnblockchain.cn/article/320),意思是由[私钥](https://learnblockchain.cn/article/3624)控制的账户,不是一个合约。如果我们发送 MET 到一个合约地址又会发生什么呢?

首先,我们在测试环境部署另一个合约。这个例子,我们将直接用水龙头合约`Faucet.sol`。将它复制到`contracts` 目录下,这样就把它添加到 METoken 项目下。现在目录是这样的:

```

METoken/

+---- contracts

| +---- Faucet.sol

| +---- METoken.sol

| `---- Migrations.sol

```

**还要再添加一个迁移,将**`Faucet`**和**`METoken`**分开部署:**

```

var Faucet = artifacts.require("Faucet");

module.exports = function(deployer) {

// Deploy the Faucet contract as our only task

deployer.deploy(Faucet);

};

```

**在 truffle 控制台编译并迁移合约:**

```

$ truffle console --network ganache

truffle(ganache)> compile

Compiling ./contracts/Faucet.sol...

Writing artifacts to ./build/contracts

truffle(ganache)> migrate

Using network 'ganache'.

Running migration: 1_initial_migration.js

Deploying Migrations...

... 0x89f6a7bd2a596829c60a483ec99665c7af71e68c77a417fab503c394fcd7a0c9

Migrations: 0xa1ccce36fb823810e729dce293b75f40fb6ea9c9

Saving artifacts...

Running migration: 2_deploy_contracts.js

Replacing METoken...

... 0x28d0da26f48765f67e133e99dd275fac6a25fdfec6594060fd1a0e09a99b44ba

METoken: 0x7d6bf9d5914d37bcba9d46df7107e71c59f3791f

Saving artifacts...

Running migration: 3_deploy_faucet.js

Deploying Faucet...

... 0x6fbf283bcc97d7c52d92fd91f6ac02d565f5fded483a6a0f824f66edc6fa90c3

Faucet: 0xb18a42e9468f7f1342fa3c329ec339f254bc7524

Saving artifacts...

```

赞,现在我们向 Faucet 合约发送 MET :

```

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.transfer(Faucet.address, 100000) })

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(Faucet.address).then(console.log)})

truffle(ganache)> BigNumber { s: 1, e: 5, c: [ 100000 ] }

```

我们已经将 1000MET 转给了 Faucet 合约。现在,我们要如何取出这些代币呢?

记住,`Faucet.sol`是一个非常简单的合约。它只有一个用来提取以太币的函数`withdraw`,没有用来提取 MET 的函数,或者任何其他 ERC20 代币。如果我们用`withdraw`,它就会尝试发送以太币,但是因为 Faucet 没有以太币余额,所以会失败。

METoken 合约知道 Faucet 有余额,但是要转移这些余额唯一的办法就是让 Faucet 合约调用`METoken`的`transfer`函数。

下一步怎么办,没有办法了。发送给 Faucet 的 MET 永远卡住了。只有 Faucet 合约可以转移代币,但是 Faucet 合约没有调用 ERC20 代币合约的 transfer 函数的代码。

或许你已经预料到这个问题了,也有可能,你没有。事实上,数百名以太坊用户意外的将各种代币转移到没有 ERC20 功能的合约,据估计,这些代币价值超过250万美元(在写这篇文章时),已经像上面的例子一样永远被卡住,永远丢失了。

ERC20 代币用户在交易中无意丢失代币的一个原因,是他们试图将代币转移到一个交易所或者其他服务,以为可以简单的将代币发送到从交易所网站上复制的以太坊地址,然而,很多交易所发布的接收地址其实是一个合约!这些合约只接收以太币,而不是 ERC20 代币,通常这些资金会被清扫到他们的“冷藏库”或者其他中心化钱包。尽管很多警告说“不要将代币发送到这个地址”,依然有很多代币这样丢失。

## ERC20代币的问题

ERC20 标准的使用确实具有突破性,已经推出了上千种代币,既有新功能的实现,又有如众筹拍卖和ICO等各种资金筹集。然而,正如我们在前面向合约地址发送代币时所看到的,它有一些潜在风险。

ERC代币一个不太明显的问题,揭露了代币和以太币之间的细微差异。以太币是通过以接收地址为目标的交易进行转移的,代币转移发生在代币合约的状态中,以代币合约作为目标,而不是接收者的地址。代币合约跟踪余额并触发事件。在代币转移中,实际没有交易发送给代币接收者,接收者的地址只是被添加到代币合约的映射。向一个地址发送以太币的交易会改变地址状态。转移代币到一个地址的交易只会改变代币合约的状态,而不是接收者地址的状态。即使ERC20代币的钱包也不会知道代币余额,除非用户特地添加一个代币合约来“看”。一些钱包会“看”主流代币合约,来检查它们所控制的地址持有的余额,但是这仅限于现有ERC20合约的小部分。

事实上,用户并不会想要跟踪所有可能的ERC20代币合约的所有余额。很多ERC20代币更像是垃圾邮件,而不是可用的代币。为了吸引用户,他们会自动为有以太币活跃的账户创建余额。如果你有一个长期活跃的以太坊地址,尤其如果它是在预售中创建的,你就会发现它充满了不知从哪里冒出来的垃圾代币。当然,这个地址并不是真的充满了代币,那只是有你的地址的代币合约。只有在区块浏览器看到这些代币合约或者你的钱包查看你的地址时,你才会看到这些余额。

代币的行为方式与以太币不同。以太币是由send函数发送并且由合约中的payable函数或者外部地址接收。代币是用只存在于ERC20合约中的`transfer` 或 `approve` 和 `transferFrom` 函数发送,并且不会在接收合约触发任何payable函数(至少在ERC20中)。代币在功能上是像以太币一样的加密货币,但是他们的一些差异打破了这种幻想。

考虑另一个问题。要发送以太币或者使用任何以太坊合约,你需要以太币来支付gas。发送代币,你也需要以太币。你不能用代币为交易支付gas,并且代币合约也不能为你支付gas。这可能会在不久的将来有所改变,但同时也会导致一些奇怪的用户体验。

> 原文:[https://betterprogramming.pub/creating-erc20-token-on-ethereum-35e109dd96e0](https://betterprogramming.pub/creating-erc20-token-on-ethereum-35e109dd96e0)

本文通过创建一个代币深入讲解ERC20

图片来源: Undraw.co

ERC20代币标准

第一个标准由Fabian Vogelsteller于2015年11月以ethereum request for Comments(ERC)引入,它被自动分配到GitHub第20个议题,所以叫“ERC20代币”。目前绝大多数代币都基于ERC20标准。ERC20后来变成了以太坊改进提案20(EIP-20),但是大部分仍然使用它最初的名字,ERC20。

ERC20是一个同质化代币标准,意思是不同的ERC20代币是可互换的并且不具有独特属性。

ERC20标准为实现代币的合约定义了一个通用接口,这样任何兼容的代币都可以用同样的方式访问和使用。这个接口由许多必须在每次实现中都出现的函数构成,以及一些开发者可能添加的可选函数和属性。

ERC20需要的函数和事件

一个ERC20的代币合约必须至少提供下面这些函数和事件:

totalSupply: 返回当前代币总量,可以是一个固定值或者变量。

balanceOf:返回给定地址的代币余额

transfer: 从执行转账的地址余额中将指定数量的代币转移到指定地址。

transferFrom: 从一个账户到另一个账户,指定发送者,接收者和转移的代币数量。与approve结合使用。

approve: 指定一个被委托地址和委托代币数量,被委托地址可以在不超过委托数量的前提下多次从委托账户转移代币。

allowance: 给定一个所有者地址和一个被委托地址,返回被委托代币余额。

Transfer: 在成功转移(调用transfer或者transferFrom)后触发的事件(即使转移数量为0)。

Approval: 成功调用approve的事件日志。

ERC20 可选函数

name: 返回代币的可读名称(如“US Dollars”)。

symbol: 返回代币的可读符号(如“USD”)。

decimals: 返回代币数量的小数点位数。例如,如果decimals为2,表示小数点后2位。

ERC20 接口是用 Solidity 定义的。

下面是Solidity 的 ERC20接口规范:

contract ERC20 {

function totalSupply() constant returns (uint theTotalSupply);

function balanceOf(address _owner) constant returns (uint balance);

function transfer(address _to, uint _value) returns (bool success);

function transferFrom(address _from, address _to, uint _value) returns

(bool success);

function approve(address _spender, uint _value) returns (bool success);

function allowance(address _owner, address _spender) constant returns

(uint remaining);

event Transfer(address indexed _from, address indexed _to, uint _value);

event Approval(address indexed _owner, address indexed _spender, uint _value);

}

ERC20 数据结构

如果你检查任何一个ERC20实现,你会发现它包含两个数据结构,一个用来跟踪余额(balance),另一个用来跟踪委托代币余额(allowance)。在Solidity中,都是用数据映射实现的。

第一个数据映射允许代币合约跟踪谁拥有代币。每次交易都是从一个余额扣除同时在另一个余额增加:

mapping(address => uint256) balances;

第二个数据结构是委托代币余额(allowance)的数据映射。正如我们将在下一节看到的,ERC20代币所有者可以让一个被委托者花费自己余额中一定数量的代币(allowance) 。

ERC20 合约用一个二维映射跟踪委托代币余额,其主键是代币所有者的地址,映射到被委托地址和对应的委托代币余额:

mapping (address => mapping (address => uint256)) public allowed;

ERC20工作流程:“transfer” 和 “approve + transferFrom”

ERC20代币标准有两个交易函数。你可能想知道为什么。

ERC20允许两种不同的工作流程。第一种是一笔交易,使用transfer函数的的简单流程。这个流程用于一个钱包发送代币到另一个钱包。

执行转账合约非常简单。如果Alice想要发送10个代币给Bob,她的钱包会发送一笔交易到代币合约的地址,调用transfer函数,并且参数为Bob的地址和10。代币合约修改Alice的余额(-10)和Bob的余额(+10),然后发出一个Transfer事件。

第二种流程是两笔交易,approve+transferFrom。这个流程允许代币所有者将控制权委托给另一个地址。通常用于将控制权委托给一个分配代币的合约,也可以被交易所使用。

例如,如果一个公司正在为ICO发售代币,他们可以委托一个众筹合约地址来分发一定数量的代币。这个众筹合约可以通过transferFrom将代币合约所有者的余额转给每一个代币买家,如下图所示。

注意:首次代币发行(ICO)是公司或者组织为了筹集资金而出售代币的众筹机制。这个术语源自首次公开募股(IPO),这是上市公司在证券交易所向投资者出售股票的过程。与高度监管的IPO市场不同,ICO是开放的、全球化的、混乱的。本文对ICO的示例和解释并非对此类筹款活动的认可。

ERC20 workflow

ERC20实现

虽然大约30行Solidity代码就可以实现一个ERC20代币,但大部分的实现都是更复杂的。这是为了解决潜在的漏洞。EIP-20标准提到两种实现:

Consensys EIP20 —— 一种简单且易读的ERC20代币的实现。

OpenZeppelin StandardToken —— 这个实现兼容ERC20,并且有额外安全措施。它形成了OpenZeppelin库的基础,可以实现更复杂ERC20代币,如筹款上限,拍卖,期权等功能。

发起自己的ERC20代币

接下来我们创建并发起自己的代币。下面的例子,将使用Truffle框架。假设你已经安装了Truffle,如果没有安装,请用npm安装:

npm i truffle

假设我们的代币叫“Mastering Ethereum Token”,我们用符号“MET”代表它。

注意:你可以在这里找到这个例子。

首先,我们创建并初始化一个Truffle项目目录。运行下面4个命令并接受所有默认答案:

$ mkdir METoken

$ cd METoken

METoken $ truffle init

METoken $ npm init

你现在应该有下面的目录结构了:

METoken/

+---- contracts

| `---- Migrations.sol

+---- migrations

| `---- 1_initial_migration.js

+---- package.json

+---- test

`---- truffle-config.js

编辑truffle-config.js配置文件,配置Truffle环境,或者复制下面的示例:

// Install dependencies:

// npm init

// npm install --save-dev dotenv truffle-wallet-provider ethereumjs-wallet

// Create .env in project root, with keys:

// ROPSTEN_PRIVATE_KEY="123abc"

// MAINNET_PRIVATE_KEY="123abc"

require('dotenv').config();

const Web3 = require("web3");

const web3 = new Web3();

const WalletProvider = require("truffle-wallet-provider");

const Wallet = require('ethereumjs-wallet');

var mainNetPrivateKey = new Buffer(process.env["MAINNET_PRIVATE_KEY"], "hex")

var mainNetWallet = Wallet.fromPrivateKey(mainNetPrivateKey);

var mainNetProvider = new WalletProvider(mainNetWallet, "https://mainnet.infura.io/");

var ropstenPrivateKey = new Buffer(process.env["ROPSTEN_PRIVATE_KEY"], "hex")

var ropstenWallet = Wallet.fromPrivateKey(ropstenPrivateKey);

var ropstenProvider = new WalletProvider(ropstenWallet, "https://ropsten.infura.io/");

module.exports = {

networks: {

dev: { // Whatever network our local node connects to

network_id: "*", // Match any network id

host: "localhost",

port: 8545,

},

mainnet: { // Provided by Infura, load keys in .env file

network_id: "1",

provider: mainNetProvider,

gas: 4600000,

gasPrice: web3.utils.toWei("20", "gwei"),

},

ropsten: { // Provided by Infura, load keys in .env file

network_id: "3",

provider: ropstenProvider,

gas: 4600000,

gasPrice: web3.utils.toWei("20", "gwei"),

},

kovan: {

network_id: 42,

host: "localhost", // parity --chain=kovan

port: 8545,

gas: 5000000

},

ganache: { // Ganache local test RPC blockchain

network_id: "5777",

host: "localhost",

port: 7545,

gas: 6721975,

}

}

};

-truffle-config.js-

如果你用示例truffle-config.js,记住在包含你的测试私钥的METoken文件夹中创建一个.env文件,以便在以太坊公共测试网(如Ropsten or Kovan)上部署和测试。你可以从 MetaMask 导出测试网私钥。

这时,你的目录应该是这样的:

METoken/

+---- contracts

| `---- Migrations.sol

+---- migrations

| `---- 1_initial_migration.js

+---- package.json

+---- test

+---- truffle-config.js

`---- .env *new file*

警告

只能使用没有在以太坊主网上持有资产的测试密钥或者测试助记词。切勿将真正持有资产的密钥用于测试。

在我们的示例中,我们将导入 OpenZeppelin 库,这个库实现了一些重要的安全检查并且容易扩展:

$ npm install openzeppelin-solidity@1.12.0

+ openzeppelin-solidity@1.12.0

added 1 package from 1 contributor and audited 2381 packages in 4.074s

openzeppelin-solidity包会在node_modules目录下添加大约250个文件。OpenZeppelin库并不仅仅包含ERC20代币,我们只会使用其中一小部分。

接下来,开始写代币合约。创建一个新文件,METoken.sol,并从下面复制示例代码。

pragma solidity ^0.4.21;

import 'openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol';

contract METoken is StandardToken {

string public constant name = 'Mastering Ethereum Token';

string public constant symbol = 'MET';

uint8 public constant decimals = 2;

uint constant _initial_supply = 2100000000;

function METoken() public {

totalSupply_ = _initial_supply;

balances[msg.sender] = _initial_supply;

emit Transfer(address(0), msg.sender, _initial_supply);

}

}

-METoken.sol-

METoken.sol合约——实现ERC20代币的Solidity合约,非常简单,因为它从OpenZeppelin库继承了所有功能。

示例 1. METoken.sol: 实现ERC20代币的Solidity合约

这里,我们定义了可选变量名,符号,和小数位数,也定义了一个_initial_supply变量——设为2100万个代币,代币数量可以细分到小数点后2位,也就是总共21亿份。在合约的初始化函数(构造函数)中我们设置totalSupply等于_initial_supply,并且将所有_initial_supply全部分配给创建METoken合约的账户(msg.sender)的余额。

现在我们用truffle来编译METoken代码:

$ truffle compile

Compiling ./contracts/METoken.sol...

Compiling ./contracts/Migrations.sol...

Compiling openzeppelin-solidity/contracts/math/SafeMath.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol...

Compiling openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol...

如你所见,truffle 编译了 OpenZeppelin 库的必要依赖。

接下来我们编写一个迁移脚本来部署METoken合约。在METoken/migrations 文件夹中创建一个新文件2_deploy_contracts.js。复制下面示例代码:

var METoken = artifacts.require("METoken");

module.exports = function(deployer) {

// Deploy the METoken contract as our only task

deployer.deploy(METoken);

};

-2_deploy_contracts.js-

在部署到以太坊测试网之前,我们先启动一个本地区块链来测试。可以从命令行ganache-cli 或者图形用户界面来启动ganache区块链。

ganache 启动,我们就可以部署 METoken 合约并且看到是否一切正常:

$ truffle migrate --network ganache

Using network 'ganache'.

Running migration: 1_initial_migration.js

Deploying Migrations...

... 0xb2e90a056dc6ad8e654683921fc613c796a03b89df6760ec1db1084ea4a084eb

Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0

Saving successful migration to network...

... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956

Saving artifacts...

Running migration: 2_deploy_contracts.js

Deploying METoken...

... 0xbe9290d59678b412e60ed6aefedb17364f4ad2977cfb2076b9b8ad415c5dc9f0

METoken: 0x345ca3e014aaf5dca488057592ee47305d9b3e10

Saving successful migration to network...

... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0

Saving artifacts...

在 ganache 控制台,我们可以看到已经创建了四笔新的交易:

-ganache-

用 Truffle 控制台与 METoken 交互

我们可以通过 truffle 控制台在 ganache 区块链上与合约交互。这是一个交互式 JavaScript 环境,提供了对 truffle 环境的访问,并通过 web3 访问区块链。下面,我们将 truffle 控制台与 ganache 区块链连接:

$ truffle console --network ganache

truffle(ganache)>

truffle(ganache)>表明我们已经连接到 ganache 区块链,并且已经准备好输入命令。truffle 控制台支持所有 truffle 命令,所以我们可以从控制台编译和迁移。

我们已经运行了命令,所以让我们直接进入到合约本身。METoken合约在 truffle 环境中就像一个 JavaScript 对象。在提示符的地方输入METoken,就会清除整个合约定义:

truffle(ganache)> METoken

{ [Function: TruffleContract]

_static_methods:

[...]

currentProvider:

HttpProvider {

host: 'http://localhost:7545',

timeout: 0,

user: undefined,

password: undefined,

headers: undefined,

send: [Function],

sendAsync: [Function],

_alreadyWrapped: true },

network_id: '5777' }

METoken对象也揭露了几个属性,如合约地址(因为是用 migrate 命令部署的):

truffle(ganache)> METoken.address

'0x345ca3e014aaf5dca488057592ee47305d9b3e10'

如果我们想要与部署的合约交互,我们必须使用异步调用,以JavaScript “promise” 的形式。用 deployed 函数来获取合约实例,然后调用totalSupply函数:

truffle(ganache)> METoken.deployed().then(instance => instance.totalSupply())

BigNumber { s: 1, e: 9, c: [ 2100000000 ] }

接下来,让我们用 ganache 创建的账户来检查 METoken 余额,并且发送一些 METoken 到另一个地址。首先,获取账户地址:

truffle(ganache)> let accounts

undefined

truffle(ganache)> web3.eth.getAccounts((err,res) => { accounts = res })

undefined

truffle(ganache)> accounts[0]

'0x627306090abab3a6e1400e9345bc60c78a8bef57'

账户列表包含 ganache 创建的所有账户,accounts[0]是部署METoken合约的账户。它应该有METoken余额的,因为我们的METoken构造函数将所有token给到了这个地址。我们检查一下:

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(accounts[0]).then(console.log) })

undefined

truffle(ganache)> BigNumber { s: 1, e: 9, c: [ 2100000000 ] }

最后,通过调用合约的transfer函数从accounts[0]转移 1000.00 个 METoken 到accounts[1]:

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.transfer(accounts[1], 100000) })

undefined

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(accounts[0]).then(console.log) })

undefined

truffle(ganache)> BigNumber { s: 1, e: 9, c: [ 2099900000 ] }

undefined

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(accounts[1]).then(console.log) })

undefined

truffle(ganache)> BigNumber { s: 1, e: 5, c: [ 100000 ] }

提示:METoken可以精确到小数点后2位,意思是1个METoken在合约中其实是100份。当我们转移1000个METoken时,我们在调用transfer函数时指定的值是100000

如你所见,在会话中,accounts[0]现在有20,999,000 个MET,accounts[1]有1000个MET。

-ganache-

向合约地址发送ERC20代币

到目前为止,我们已经创建了一个ERC20代币并从一个账户发送了一些代币到另一个账户。前面我们用来演示的账户都是外部账户(external owned accouts),意思是由私钥控制的账户,不是一个合约。如果我们发送 MET 到一个合约地址又会发生什么呢?

首先,我们在测试环境部署另一个合约。这个例子,我们将直接用水龙头合约Faucet.sol。将它复制到contracts 目录下,这样就把它添加到 METoken 项目下。现在目录是这样的:

METoken/

+---- contracts

| +---- Faucet.sol

| +---- METoken.sol

| `---- Migrations.sol

还要再添加一个迁移,将Faucet和METoken分开部署:

var Faucet = artifacts.require("Faucet");

module.exports = function(deployer) {

// Deploy the Faucet contract as our only task

deployer.deploy(Faucet);

};

在 truffle 控制台编译并迁移合约:

$ truffle console --network ganache

truffle(ganache)> compile

Compiling ./contracts/Faucet.sol...

Writing artifacts to ./build/contracts

truffle(ganache)> migrate

Using network 'ganache'.

Running migration: 1_initial_migration.js

Deploying Migrations...

... 0x89f6a7bd2a596829c60a483ec99665c7af71e68c77a417fab503c394fcd7a0c9

Migrations: 0xa1ccce36fb823810e729dce293b75f40fb6ea9c9

Saving artifacts...

Running migration: 2_deploy_contracts.js

Replacing METoken...

... 0x28d0da26f48765f67e133e99dd275fac6a25fdfec6594060fd1a0e09a99b44ba

METoken: 0x7d6bf9d5914d37bcba9d46df7107e71c59f3791f

Saving artifacts...

Running migration: 3_deploy_faucet.js

Deploying Faucet...

... 0x6fbf283bcc97d7c52d92fd91f6ac02d565f5fded483a6a0f824f66edc6fa90c3

Faucet: 0xb18a42e9468f7f1342fa3c329ec339f254bc7524

Saving artifacts...

赞,现在我们向 Faucet 合约发送 MET :

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.transfer(Faucet.address, 100000) })

truffle(ganache)> METoken.deployed().then(instance =>

{ instance.balanceOf(Faucet.address).then(console.log)})

truffle(ganache)> BigNumber { s: 1, e: 5, c: [ 100000 ] }

我们已经将 1000MET 转给了 Faucet 合约。现在,我们要如何取出这些代币呢?

记住,Faucet.sol是一个非常简单的合约。它只有一个用来提取以太币的函数withdraw,没有用来提取 MET 的函数,或者任何其他 ERC20 代币。如果我们用withdraw,它就会尝试发送以太币,但是因为 Faucet 没有以太币余额,所以会失败。

METoken 合约知道 Faucet 有余额,但是要转移这些余额唯一的办法就是让 Faucet 合约调用METoken的transfer函数。

下一步怎么办,没有办法了。发送给 Faucet 的 MET 永远卡住了。只有 Faucet 合约可以转移代币,但是 Faucet 合约没有调用 ERC20 代币合约的 transfer 函数的代码。

或许你已经预料到这个问题了,也有可能,你没有。事实上,数百名以太坊用户意外的将各种代币转移到没有 ERC20 功能的合约,据估计,这些代币价值超过250万美元(在写这篇文章时),已经像上面的例子一样永远被卡住,永远丢失了。

ERC20 代币用户在交易中无意丢失代币的一个原因,是他们试图将代币转移到一个交易所或者其他服务,以为可以简单的将代币发送到从交易所网站上复制的以太坊地址,然而,很多交易所发布的接收地址其实是一个合约!这些合约只接收以太币,而不是 ERC20 代币,通常这些资金会被清扫到他们的“冷藏库”或者其他中心化钱包。尽管很多警告说“不要将代币发送到这个地址”,依然有很多代币这样丢失。

ERC20代币的问题

ERC20 标准的使用确实具有突破性,已经推出了上千种代币,既有新功能的实现,又有如众筹拍卖和ICO等各种资金筹集。然而,正如我们在前面向合约地址发送代币时所看到的,它有一些潜在风险。

ERC代币一个不太明显的问题,揭露了代币和以太币之间的细微差异。以太币是通过以接收地址为目标的交易进行转移的,代币转移发生在代币合约的状态中,以代币合约作为目标,而不是接收者的地址。代币合约跟踪余额并触发事件。在代币转移中,实际没有交易发送给代币接收者,接收者的地址只是被添加到代币合约的映射。向一个地址发送以太币的交易会改变地址状态。转移代币到一个地址的交易只会改变代币合约的状态,而不是接收者地址的状态。即使ERC20代币的钱包也不会知道代币余额,除非用户特地添加一个代币合约来“看”。一些钱包会“看”主流代币合约,来检查它们所控制的地址持有的余额,但是这仅限于现有ERC20合约的小部分。

事实上,用户并不会想要跟踪所有可能的ERC20代币合约的所有余额。很多ERC20代币更像是垃圾邮件,而不是可用的代币。为了吸引用户,他们会自动为有以太币活跃的账户创建余额。如果你有一个长期活跃的以太坊地址,尤其如果它是在预售中创建的,你就会发现它充满了不知从哪里冒出来的垃圾代币。当然,这个地址并不是真的充满了代币,那只是有你的地址的代币合约。只有在区块浏览器看到这些代币合约或者你的钱包查看你的地址时,你才会看到这些余额。

代币的行为方式与以太币不同。以太币是由send函数发送并且由合约中的payable函数或者外部地址接收。代币是用只存在于ERC20合约中的transfer 或 approve 和 transferFrom 函数发送,并且不会在接收合约触发任何payable函数(至少在ERC20中)。代币在功能上是像以太币一样的加密货币,但是他们的一些差异打破了这种幻想。

考虑另一个问题。要发送以太币或者使用任何以太坊合约,你需要以太币来支付gas。发送代币,你也需要以太币。你不能用代币为交易支付gas,并且代币合约也不能为你支付gas。这可能会在不久的将来有所改变,但同时也会导致一些奇怪的用户体验。

原文:https://betterprogramming.pub/creating-erc20-token-on-ethereum-35e109dd96e0

学分: 171

分类: 以太坊

标签:

ERC20 

智能合约 

代币 

点赞 5

收藏 3

分享

Twitter分享

微信扫码分享

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

你可能感兴趣的文章

星航计划 - DeTask找活网 0基础开发入门到精通 (9)

90 浏览

1.轻松入门Sui Move: 快速了解基本概念

98 浏览

SharkTeam:合约精度计算漏洞与安全建议

379 浏览

Remix v0.43.0 更新日志

209 浏览

使用铭文思路对智能合约改进

2141 浏览

花式发币法之发行各类 ERC20 代币

3968 浏览

相关问题

请问智能合约是究竟怎么在以太坊上运行的?

1 回答

请教下大家,Swap如何实现卖币手续费

2 回答

关于交易字段内容的问题

1 回答

地址部署合约部署失败,但是换个地址部署相同的合约代码可以部署成功,详细描述如下,麻烦各位大佬帮忙分析分析原因

1 回答

如何将合约字节码反编译成solidity伪代码

1 回答

Foundry Test: 无效的 MockCall

3 回答

3 条评论

请先 登录 后评论

aisiji

关注

贡献值: 228

学分: 1344

江湖只有他的大名,没有他的介绍。

文章目录

关于

关于我们

社区公约

学分规则

Github

伙伴们

DeCert

ChainTool

GCC

合作

广告投放

发布课程

联系我们

友情链接

关注社区

Discord

Twitter

Youtube

B 站

公众号

关注不错过动态

微信群

加入技术圈子

©2024 登链社区 版权所有 |

Powered By Tipask3.5|

粤公网安备 44049102496617号

粤ICP备17140514号

粤B2-20230927

增值电信业务经营许可证

×

发送私信

请将文档链接发给晓娜,我们会尽快安排上架,感谢您的推荐!

发给:

内容:

取消

发送

×

举报此文章

垃圾广告信息:

广告、推广、测试等内容

违规内容:

色情、暴力、血腥、敏感信息等内容

不友善内容:

人身攻击、挑衅辱骂、恶意行为

其他原因:

请补充说明

举报原因:

取消

举报

×

如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!

ERC-20 代币标准 | ethereum.org

20 代币标准 | ethereum.org跳转至主要内容学习用法构建参与研究搜索​​​​语言 ZH帮助更新此页面本页面有新版本,但现在只有英文版。请帮助我们翻译最新版本。翻译页面没有错误!此页面未翻译,因此特意以英文显示。不再显示Change page概述基础主题以太坊简介以太币简介去中心化应用程序简介Web2 与 Web3 的对比帐户交易区块以太坊虚拟机 (EVM)操作码Gas费用节点和客户端运行节点客户端多样性节点即服务节点架构轻客户端归档节点引导节点网络共识机制工作量证明矿工挖矿算法Dagger-HashimotoEthash权益证明Gasper弱主观性认证权益证明机制的奖励和惩罚权益证明攻击与防御密钥权益证明与工作量证明提出区块权益正明常见问题以太坊堆栈堆栈简介智能合约智能合约语言智能合约结构智能合约库测试用智能合约编译智能合约部署智能合约验证智能合约升级智能合约智能合约安全性智能合约形式化验证可组合性开发网络开发框架以太坊客户端APIJavaScript API后端APIJSON-RPC数据和分析区块浏览器存储集成开发环境 (IDE)编程语言DartDelphi.NETGolangJavaJavaScriptPythonRubyRust语言高级链桥标准令牌标准ERC-20:同质化代币ERC-721:非同质化代币 (NFT)ERC-777ERC-1155ERC-4626最大可提取价值 (MEV)预言机缩放乐观卷叠零知识卷叠状态通道侧链以太坊 Plasma 扩容解决方案Validium数据可用性网络层网络地址门户网络数据结构与编码默克尔前缀树递归长度前缀编码 (RLP)简单序列化 (SSZ)Web3 密钥存储定义设计基础设计和用户体验简介ERC-20 代币标准p上次修改时间: @penglaishan.cn(opens in a new tab), Invalid DateTime查看贡献者在本页面介绍前提条件正文方法事件示例延伸阅读介绍什么叫做代币?代币可以在以太坊中表示任何东西:在线平台中的信誉积分游戏中一个角色的技能彩票卷金融资产类似于公司股份的资产像美元一样的法定货币一盎司黄金及更多...以太坊的这种强大特点必须以强有力的标准来处理,对吗? 这正是 ERC-20 发挥其作用的地方! 此标准允许开发者构建可与其他产品和服务互相操作的代币应用程序。什么是 ERC-20?ERC-20 提出了一个同质化代币的标准,换句话说,它们具有一种属性,使得每个代币都与另一个代币(在类型和价值上)完全相同。 例如,一个 ERC-20 代币就像以太币一样,意味着一个代币会并永远会与其他代币一样。前提条件帐户智能合约代币标准正文ERC-20(以太坊意见征求 20)由 Fabian Vogelsteller 提出于 2015 年 11 月。这是一个能实现智能合约中代币的应用程序接口标准。ERC-20 的功能示例包括:将代币从一个帐户转到另一个帐户获取帐户的当前代币余额获取网络上可用代币的总供应量批准一个帐户中一定的代币金额由第三方帐户使用如果智能合约实施了下列方法和事件,它可以被称为 ERC-20 代币合约,一旦部署,将负责跟踪以太坊上创建的代币。来自 EIP-20(opens in a new tab):方法1function name() public view returns (string)2function symbol() public view returns (string)3function decimals() public view returns (uint8)4function totalSupply() public view returns (uint256)5function balanceOf(address _owner) public view returns (uint256 balance)6function transfer(address _to, uint256 _value) public returns (bool success)7function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)8function approve(address _spender, uint256 _value) public returns (bool success)9function allowance(address _owner, address _spender) public view returns (uint256 remaining)显示全部 复制事件1event Transfer(address indexed _from, address indexed _to, uint256 _value)2event Approval(address indexed _owner, address indexed _spender, uint256 _value) 复制示例让我们看看如此重要的一个标准是如何使我们能够简单地检查以太坊上的任何 ERC-20 代币合约。 我们只需要合约的应用程序二进制接口 (ABI) 来创造一个 ERC-20 代币界面。 下面我们将使用一个简化的应用程序二进制接口,让例子变得更为简单。Web3.py 示例首先,请确保您已安装 Web3.py(opens in a new tab) Python 库:1pip install web31from web3 import Web3234w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com"))56dai_token_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F" # DAI7weth_token_addr = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" # Wrapped ether (WETH)89acc_address = "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11" # Uniswap V2: DAI 21011# This is a simplified Contract Application Binary Interface (ABI) of an ERC-20 Token Contract.12# It will expose only the methods: balanceOf(address), decimals(), symbol() and totalSupply()13simplified_abi = [14 {15 'inputs': [{'internalType': 'address', 'name': 'account', 'type': 'address'}],16 'name': 'balanceOf',17 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],18 'stateMutability': 'view', 'type': 'function', 'constant': True19 },20 {21 'inputs': [],22 'name': 'decimals',23 'outputs': [{'internalType': 'uint8', 'name': '', 'type': 'uint8'}],24 'stateMutability': 'view', 'type': 'function', 'constant': True25 },26 {27 'inputs': [],28 'name': 'symbol',29 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}],30 'stateMutability': 'view', 'type': 'function', 'constant': True31 },32 {33 'inputs': [],34 'name': 'totalSupply',35 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],36 'stateMutability': 'view', 'type': 'function', 'constant': True37 }38]3940dai_contract = w3.eth.contract(address=w3.to_checksum_address(dai_token_addr), abi=simplified_abi)41symbol = dai_contract.functions.symbol().call()42decimals = dai_contract.functions.decimals().call()43totalSupply = dai_contract.functions.totalSupply().call() / 10**decimals44addr_balance = dai_contract.functions.balanceOf(acc_address).call() / 10**decimals4546# DAI47print("===== %s =====" % symbol)48print("Total Supply:", totalSupply)49print("Addr Balance:", addr_balance)5051weth_contract = w3.eth.contract(address=w3.to_checksum_address(weth_token_addr), abi=simplified_abi)52symbol = weth_contract.functions.symbol().call()53decimals = weth_contract.functions.decimals().call()54totalSupply = weth_contract.functions.totalSupply().call() / 10**decimals55addr_balance = weth_contract.functions.balanceOf(acc_address).call() / 10**decimals5657# WETH58print("===== %s =====" % symbol)59print("Total Supply:", totalSupply)60print("Addr Balance:", addr_balance)显示全部 复制延伸阅读EIP-20:ERC-20 代币标准(opens in a new tab)OpenZeppelin - 代币(opens in a new tab)OpenZeppelin - ERC-20 实施(opens in a new tab)back-to-top ↑本文对你有帮助吗?是否前一页令牌标准下一页ERC-721:非同质化代币 (NFT)编辑页面(opens in a new tab)在本页面介绍前提条件正文方法事件示例延伸阅读网站最后更新: 2024年3月13日(opens in a new tab)(opens in a new tab)(opens in a new tab)学习学习中心什么是以太坊?什么是以太币 (ETH)?以太坊钱包什么是 Web3?智能合约Gas fees运行节点以太坊安全和预防欺诈措施测试中心以太坊词汇表用法指南选择钱包获取以太币Dapps - 去中心化应用稳定币NFT - 非同质化代币DeFi - 去中心化金融DAO - 去中心化自治组织去中心化身份质押ETH二层网络构建构建者首页教程相关文档通过编码来学习设置本地环境资助基础主题用户体验/用户界面设计基础Enterprise - Mainnet EthereumEnterprise - Private Ethereum参与社区中心在线社区以太坊活动为 ethereum.org 做贡献翻译计划以太坊漏洞悬赏计划以太坊基金会以太坊基金会的博客(opens in a new tab)生态系统支持方案(opens in a new tab)Devcon(opens in a new tab)研究以太坊白皮书以太坊路线图安全性增强以太坊技术史开放研究以太坊改进提案 (Eip)以太坊治理关于我们以太坊品牌资产Code of conduct工作机会隐私政策使用条款缓存政策联系我们(opens in a new tab)本页面对你有帮

ERC20解读 | 登链社区 | 区块链技术社区

ERC20解读 | 登链社区 | 区块链技术社区

文章

问答

讲堂

专栏

集市

更多

提问

发表文章

活动

文档

招聘

发现

Toggle navigation

首页 (current)

文章

问答

讲堂

专栏

活动

招聘

文档

集市

搜索

登录/注册

ERC20解读

Confucian

更新于 2022-04-04 19:54

阅读 6960

对ERC20代币标准的个人解读

# ERC20解读

**参考 **[**OpenZepplin文档**](https://docs.openzeppelin.com/contracts/4.x/erc20)** 和 **[**以太坊官方开发者文档**](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/)**,结合自己的理解。**

博客的 Markdown 编辑器暂不支持 Solidity 语法高亮,为了更好阅读代码,可以去 [**我的GitHub仓库**](https://github.com/Blockchain-Engineer-Learning/Contract-Interpretation/tree/main/ERC20) 。

## **什么是ERC20**

**ERC20(Ethereum Request for Comments 20)一种代币标准。**[**EIP-20**](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) 中提出。

**ERC20 代币合约跟踪同质化(可替代)代币:任何一个代币都完全等同于任何其他代币;没有任何代币具有与之相关的特殊权利或行为。这使得 ERC20 代币可用于交换货币、投票权、质押等媒介。**

## **为什么要遵守ERC20**

**EIP-20 中的动机:**

> **允许以太坊上的任何代币被其他应用程序(从钱包到去中心化交易所)重新使用的标准接口。**

**以太坊上的所有应用都默认支持 ERC20 ,如果你想自己发币,那么你的代码必须遵循 ERC20 标准,这样钱包(如MetaMask)等应用才能将你的币显示出来。**

## **代码实现**

**需要实现以下函数和事件:**

```

function name() public view returns (string)

function symbol() public view returns (string)

function decimals() public view returns (uint8)

function totalSupply() public view returns (uint256)

function balanceOf(address _owner) public view returns (uint256 balance)

function transfer(address _to, uint256 _value) public returns (bool success)

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

function approve(address _spender, uint256 _value) public returns (bool success)

function allowance(address _owner, address _spender) public view returns (uint256 remaining)

event Transfer(address indexed _from, address indexed _to, uint256 _value)

event Approval(address indexed _owner, address indexed _spender, uint256 _value)

```

**使用 OpenZeppllin 提供的库能够轻松快速地构建 ERC20 Token 。**

### **快速构建**

**这是一个 GLD token 。**

```

// contracts/GLDToken.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract GLDToken is ERC20 {

constructor(uint256 initialSupply) ERC20("Gold", "GLD") {

_mint(msg.sender, initialSupply);

}

}

```

**通常,我们定义代币的发行量和代币名称及符号。**

### **IERC20**

**先来看下 ERC20 的接口(IERC20),这方便我们在开发中直接定义 ERC20 代币。**

**同样地,OpenZepplin 为我们提供了相应的库,方便开发者导入即用。**

```

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

```

****EIP 中定义的 ERC20 标准接口:****

```

pragma solidity ^0.8.0;

interface IERC20 {

event Transfer(address indexed from, address indexed to, uint256 value);

event Approval(address indexed owner, address indexed spender, uint256 value);

function totalSupply() external view returns (uint256);

function balanceOf(address account) external view returns (uint256);

function transfer(address to, uint256 amount) external returns (bool);

function allowance(address owner, address spender) external view returns (uint256);

function approve(address spender, uint256 amount) external returns (bool);

function transferFrom(

address from,

address to,

uint256 amount

) external returns (bool);

}

```

#### **逐一分析**

**函数:**

* `totalSupply()` :返回总共的代币数量。

* `balanceOf(address account)` :返回 `account` 地址拥有的代币数量。

* `transfer(address to, uint256 amount)` :将 **`amount`** 数量的代币发送给 **`to`** 地址,返回布尔值告知是否执行成功。触发 **`Transfer`** 事件。

* `allowance(address owner, address spender)` :返回授权花费者 **`spender`** 通过 **`transferFrom`** 代表所有者花费的剩余代币数量。默认情况下为零。当 **`approve`** 和 **`transferFrom`** 被调用时,值将改变。

* `approve(address spender, uint256 amount)` :授权 **`spender`** 可以花费 **`amount`** 数量的代币,返回布尔值告知是否执行成功。触发 **`Approval`** 事件。

* `transferFrom(address from, address to, uint256 amount)` :将 **`amount`** 数量的代币从 **`from`** 地址发送到 **`to`** 地址,返回布尔值告知是否执行成功。触发 **`Transfer`** 事件。

**事件(定义中的 **`indexed`** 便于查找过滤):**

* `Transfer(address from, address to, uint256 value)` :当代币被一个地址转移到另一个地址时触发。注意:转移的值可能是 0 。

* `Approval(address owner, address spender, uint256 value)` :当代币所有者授权别人使用代币时触发,即调用 **`approve`** 方法。

#### **元数据**

**一般除了上述必须实现的函数外,还有一些别的方法:**

* `name()` :返回代币名称

* `symbol()` :返回代币符号

* `decimals()` :返回代币小数点后位数

### **ERC20**

**来看下 ERC20 代币具体是怎么写的。**

**同样,OpenZepplin 提供了现成的合约代码:**

```

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

```

这里贴一个GitHub源码链接 [**OpenZepplin ERC20**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)

#### **函数概览**

```

constructor(name_, symbol_)

name()

symbol()

decimals()

totalSupply()

balanceOf(account)

transfer(to, amount)

allowance(owner, spender)

approve(spender, amount)

transferFrom(from, to, amount)

increaseAllowance(spender, addedValue)

decreaseAllowance(spender, subtractedValue)

_transfer(from, to, amount)

_mint(account, amount)

_burn(account, amount)

_approve(owner, spender, amount)

_spendAllowance(owner, spender, amount)

_beforeTokenTransfer(from, to, amount)

_afterTokenTransfer(from, to, amount)

```

****事件(同 IERC20)****

```

Transfer(from, to, value)

Approval(owner, spender, value)

```

#### **逐一分析**

* `constructor(string name, string symbol)` :设定代币的名称和符号。**`decimals`** 默认是 18 ,要修改成不同的值你应该重载它。这两个值是不变的,只在构造时赋值一次。

* `name()` :返回代币的名称。

* `symbol()` :返回代币的符号,通常是名称的缩写。

* `decimals()` :返回小数点后位数,通常是 18 ,模仿 Ether 和 wei 。要更改就重写它。

`totalSupply()、balanceOf(address account)、transfer(address to, uint256 amount)、 allowance(address owner, address spender)、approve(address spender, uint256 amount)、transferFrom(address from, address to, uint256 amount)` 都参考 IERC20 。

* `increaseAllowance(address spender, uint256 addedValue)` :以原子的方式增加 **`spender`** 额度。返回布尔值告知是否执行成功,触发 **`Approval`** 事件。

* `_transfer(address from, address to, uint256 amount)` :转账。这个内部函数相当于 **`transfer`** ,可以用于例如实施自动代币费用,削减机制等。触发 **`Transfer`** 事件。

* `_mint(address account, uint256 amount)` :铸造 **`amount`** 数量的代币给 **`account`** 地址,增加总发行量。触发 **`Transfer`** 事件,其中参数 **`from`** 是零地址。

* `_burn(address account, uint256 amount)` :从 **`account`** 地址中烧毁 **`amount`** 数量的代币,减少总发行量。触发 **`Transfer`** 事件,其中参数 **`to`** 是零地址。

* `_approve(address owner, uint256 spender, uint256 amount)` :设定允许 **`spender`** 花费 **`owner`** 的代币数量。这个内部函数相当于 **`approve`** ,可以用于例如为某些子系统设置自动限额等。

* `spendAllowance(address owner, address spender, uint256 amount)` :花费 **`amount`** 数量的 **`owner`** 授权 **`spender`** 的代币。在无限 allowance 的情况下不更新 allowance 金额。如果没有足够的余量,则恢复。可能触发 **`Approval`** 事件。

* `_beforeTokenTransfer(address from, address to, uint256 amount)` :在任何代币转账前的 Hook 。它包括铸币和烧毁。调用条件:

* **当 **`from`** 和 **`to`** 都不是零地址时,**`from` 手里 **`amount`** 数量的代币将发送给 **`to`** 。

* **当 **`from`** 是零地址时,将给 **`to`** 铸造 **`amount`** 数量的代币。**

* **当 **`to`** 是零地址时,**`from` 手里 **`amount`** 数量的代币将被烧毁。

* `from` 和 **`to`** 不能同时为零地址。

* `_afterTokenTransfer(address from, address to, uint256 amount)` :在任何代币转账后的 Hook 。它包括铸币和烧毁。调用条件:

* **当 **`from`** 和 **`to`** 都不是零地址时,**`from` 手里 **`amount`** 数量的代币将发送给 **`to`** 。

* **当 **`from`** 是零地址时,将给 **`to`** 铸造 **`amount`** 数量的代币。**

* **当 **`to`** 是零地址时,**`from` 手里 **`amount`** 数量的代币将被烧毁。

* `from` 和 **`to`** 不能同时为零地址。

#### **小结**

**ERC20 代码中的 **`_transfer`**、**`_mint`**、**`_burn`**、**`_approve`**、**`_spendAllowance`**、**`_beforeTokenTransfer`**、**`_afterTokenTransfer` 都是 **`internal`** 函数(其余为 **`public`** ),也就是说它们只能被派生合约调用。

## **从零开始,自己动手**

### **1.编写IERC20**

[**IERC20.sol**](https://github.com/Blockchain-Engineer-Learning/Contract-Interpretation/blob/main/ERC20/contracts/IERC20.sol)

```

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC20 {

/// @dev 总发行量

function totoalSupply() external view returns (uint256);

/// @dev 查看地址余额

function balanceOf(address account) external view returns (uint256);

/// @dev 单地址转账

function transfer(address account, uint256 amount) external returns (bool);

/// @dev 查看被授权人代表所有者花费的代币余额

function allowance(address owner, address spender) external view returns (uint256);

/// @dev 授权别人花费你拥有的代币

function approve(address spender, uint256 amount) external returns (bool);

/// @dev 双地址转账

function transferFrom(

address from,

address to,

uint256 amount

) external returns (bool);

/// @dev 发生代币转移时触发

event Transfer(address indexed from, address indexed to, uint256 value);

/// @dev 授权时触发

event Approval(address indexed owner, address indexed spender, uint256 value);

}

```

### **2.加上Metadata**

[**IERC20Metadata.sol**](https://github.com/Blockchain-Engineer-Learning/Contract-Interpretation/blob/main/ERC20/contracts/IERC20Metadata.sol)

```

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "IERC20.sol";

interface IERC20Metadata is IERC20 {

/// @dev 代币名称

function name() external view returns (string memory);

/// @dev 代币符号

function symbol() external view returns (string memory);

/// @dev 小数点后位数

function decimals() external view returns (uint8);

}

```

### **3.编写ERC20**

[**ERC20.sol**](https://github.com/Blockchain-Engineer-Learning/Contract-Interpretation/blob/main/ERC20/contracts/ERC20.sol)

```

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";

import "./IERC20Metadata.sol";

contract ERC20 is IERC20, IERC30Metadata {

// 地址余额

mapping(address => uint256) private _balances;

// 授权地址余额

mapping(address => mapping(address => uint256)) private _allowances;

uint256 private _totalSupply;

string private _name;

string private _symbol;

/// @dev 设定代币名称符号

constructor(string memory name_, string memory symbol_) {

_name = name_;

_symbol = symbol_;

}

function name() public view virtual override returns (string memory) {

return _name;

}

function symbol() public view virtual override returns (string memory) {

return _symbol;

}

/// @dev 小数点位数一般为 18

function decimals() public view virtual override returns (uint8) {

return 18;

}

function totalSupply() public view virtual override returns (uint256) {

return _totalSupply;

}

function balanceOf(address account) public view virtual override returns (uint256) {

return _balances[account];

}

function transfer(address to, uint256 amount) public virtual override returns (bool) {

address owner = msg.sender;

_transfer(owner, to, amount);

return true;

}

function allowance(address owner, address spender) public view virtual override returns (uint256) {

return _allowances[owner][spender];

}

function approve(address spender, uint256 amount) public virtual override returns (bool) {

address owner = msg.sender;

_approve(owner, spender, amount);

return true;

}

function transferFrom(

address from,

address to,

uint256 amount

) public virtual override returns (bool) {

address spender = msg.sender;

_spendAllowance(from, spender, amount);

_transfer(from, to, amount);

return true;

}

function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {

address owner = msg.sender;

_approve(owner, spender, _allowances[owner][spender] + addedValue);

return true;

}

function decreaseAllowance(address spender, uint256 substractedValue) public virtual returns (bool) {

address owner = msg.sender;

uint256 currentAllowance = _allowances[owner][spender];

require(currentAllowance >= substractedValue, "ERC20: decreased allowance below zero");

unchecked {

_approval(owner, spender, currentAllowance - substractedValue);

}

return true;

}

function _transfer(

address from,

address to,

uint256 amount

) internal virtual {

require(from != address(0), "ERC20: transfer from the zero address");

require(to != address(0), "ERC20: transfer to the zero address");

_beforeTokenTransfer(from, to, amount);

uint256 fromBalance = _balances[from];

require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");

unchecked {

_balances[from] = fromBalance - amount;

}

_balances[to] += amount;

emit Transfer(from, to, amount);

_afterTokenTransfer(from, to, amount);

}

function _mint(address account, uint256 amount) internal virtual {

require(account != address(0), "ERC20: mint to the zero address");

_beforeTokenTransfer(address(0), account, amount);

_totalSupply += amount;

_balances[account] += amount;

emit Transfer(address(0), account, amount);

_afterTokenTransfer(address(0), account, amount);

}

function _burn(address account, uint256 amount) internal virtual {

require(account != address(0), "ERC20: burn from the zero address");

_beforeTokenTransfer(account, address(0), amount);

uint256 accountBalance = _balances[account];

require(accountBalance >= amount, "ERC20: burn amount exceeds balance");

unchecked {

_balances[account] = accountBalance - amount;

}

_totalSupply -= amount;

emit Transfer(account, address(0), amount);

_afterTokenTransfer(account, address(0), amount);

}

function _approve(

address owner,

address spender,

uint256 amount

) internal virtual {

require(owner != address(0), "ERC20: approve from the zero address");

require(spender != address(0), "ERC20: approve to the zero address");

_allowances[owner][spender];

emit Approval(owner, spender, amount);

}

function _spendAllowance(

address owner,

address spender,

uint256 amount

) internal virtual {

uint256 currentAllowance = allowance(owner, spender);

if (currentAllowance != type(uint256).max) {

require(currentAllowance >= amount, "ERC20: insufficient allowance");

unchecked {

_approve(owner, spender, currentAllowance - amount);

}

}

}

function _beforeTokenTransfer(

address from,

address to,

uint256 amount

) internal virtual {}

function _afterTokenTransfer(

address from,

address to,

uint256 amount

) internal virtual {}

}

```

## **总结**

**ERC20 其实就是一种最常见的代币标准,它明确了同质化代币的经典功能并规范了开发者编写 token 时的代码,从而方便各种应用适配。**

ERC20解读

参考 OpenZepplin文档 和 以太坊官方开发者文档,结合自己的理解。

博客的 Markdown 编辑器暂不支持 Solidity 语法高亮,为了更好阅读代码,可以去 我的GitHub仓库 。

什么是ERC20

ERC20(Ethereum Request for Comments 20)一种代币标准。EIP-20 中提出。

ERC20 代币合约跟踪同质化(可替代)代币:任何一个代币都完全等同于任何其他代币;没有任何代币具有与之相关的特殊权利或行为。这使得 ERC20 代币可用于交换货币、投票权、质押等媒介。

为什么要遵守ERC20

EIP-20 中的动机:

允许以太坊上的任何代币被其他应用程序(从钱包到去中心化交易所)重新使用的标准接口。

以太坊上的所有应用都默认支持 ERC20 ,如果你想自己发币,那么你的代码必须遵循 ERC20 标准,这样钱包(如MetaMask)等应用才能将你的币显示出来。

代码实现

需要实现以下函数和事件:

function name() public view returns (string)

function symbol() public view returns (string)

function decimals() public view returns (uint8)

function totalSupply() public view returns (uint256)

function balanceOf(address _owner) public view returns (uint256 balance)

function transfer(address _to, uint256 _value) public returns (bool success)

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

function approve(address _spender, uint256 _value) public returns (bool success)

function allowance(address _owner, address _spender) public view returns (uint256 remaining)

event Transfer(address indexed _from, address indexed _to, uint256 _value)

event Approval(address indexed _owner, address indexed _spender, uint256 _value)

使用 OpenZeppllin 提供的库能够轻松快速地构建 ERC20 Token 。

快速构建

这是一个 GLD token 。

// contracts/GLDToken.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract GLDToken is ERC20 {

constructor(uint256 initialSupply) ERC20("Gold", "GLD") {

_mint(msg.sender, initialSupply);

}

}

通常,我们定义代币的发行量和代币名称及符号。

IERC20

先来看下 ERC20 的接口(IERC20),这方便我们在开发中直接定义 ERC20 代币。

同样地,OpenZepplin 为我们提供了相应的库,方便开发者导入即用。

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

EIP 中定义的 ERC20 标准接口:

pragma solidity ^0.8.0;

interface IERC20 {

event Transfer(address indexed from, address indexed to, uint256 value);

event Approval(address indexed owner, address indexed spender, uint256 value);

function totalSupply() external view returns (uint256);

function balanceOf(address account) external view returns (uint256);

function transfer(address to, uint256 amount) external returns (bool);

function allowance(address owner, address spender) external view returns (uint256);

function approve(address spender, uint256 amount) external returns (bool);

function transferFrom(

address from,

address to,

uint256 amount

) external returns (bool);

}

逐一分析

函数:

totalSupply() :返回总共的代币数量。

balanceOf(address account) :返回 account 地址拥有的代币数量。

transfer(address to, uint256 amount) :将 amount 数量的代币发送给 to 地址,返回布尔值告知是否执行成功。触发 Transfer 事件。

allowance(address owner, address spender) :返回授权花费者 spender 通过 transferFrom 代表所有者花费的剩余代币数量。默认情况下为零。当 approve 和 transferFrom 被调用时,值将改变。

approve(address spender, uint256 amount) :授权 spender 可以花费 amount 数量的代币,返回布尔值告知是否执行成功。触发 Approval 事件。

transferFrom(address from, address to, uint256 amount) :将 amount 数量的代币从 from 地址发送到 to 地址,返回布尔值告知是否执行成功。触发 Transfer 事件。

事件(定义中的 indexed 便于查找过滤):

Transfer(address from, address to, uint256 value) :当代币被一个地址转移到另一个地址时触发。注意:转移的值可能是 0 。

Approval(address owner, address spender, uint256 value) :当代币所有者授权别人使用代币时触发,即调用 approve 方法。

元数据

一般除了上述必须实现的函数外,还有一些别的方法:

name() :返回代币名称

symbol() :返回代币符号

decimals() :返回代币小数点后位数

ERC20

来看下 ERC20 代币具体是怎么写的。

同样,OpenZepplin 提供了现成的合约代码:

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

这里贴一个GitHub源码链接 OpenZepplin ERC20

函数概览

constructor(name_, symbol_)

name()

symbol()

decimals()

totalSupply()

balanceOf(account)

transfer(to, amount)

allowance(owner, spender)

approve(spender, amount)

transferFrom(from, to, amount)

increaseAllowance(spender, addedValue)

decreaseAllowance(spender, subtractedValue)

_transfer(from, to, amount)

_mint(account, amount)

_burn(account, amount)

_approve(owner, spender, amount)

_spendAllowance(owner, spender, amount)

_beforeTokenTransfer(from, to, amount)

_afterTokenTransfer(from, to, amount)

事件(同 IERC20)

Transfer(from, to, value)

Approval(owner, spender, value)

逐一分析

constructor(string name, string symbol) :设定代币的名称和符号。decimals 默认是 18 ,要修改成不同的值你应该重载它。这两个值是不变的,只在构造时赋值一次。

name() :返回代币的名称。

symbol() :返回代币的符号,通常是名称的缩写。

decimals() :返回小数点后位数,通常是 18 ,模仿 Ether 和 wei 。要更改就重写它。

totalSupply()、balanceOf(address account)、transfer(address to, uint256 amount)、 allowance(address owner, address spender)、approve(address spender, uint256 amount)、transferFrom(address from, address to, uint256 amount) 都参考 IERC20 。

increaseAllowance(address spender, uint256 addedValue) :以原子的方式增加 spender 额度。返回布尔值告知是否执行成功,触发 Approval 事件。

_transfer(address from, address to, uint256 amount) :转账。这个内部函数相当于 transfer ,可以用于例如实施自动代币费用,削减机制等。触发 Transfer 事件。

_mint(address account, uint256 amount) :铸造 amount 数量的代币给 account 地址,增加总发行量。触发 Transfer 事件,其中参数 from 是零地址。

_burn(address account, uint256 amount) :从 account 地址中烧毁 amount 数量的代币,减少总发行量。触发 Transfer 事件,其中参数 to 是零地址。

_approve(address owner, uint256 spender, uint256 amount) :设定允许 spender 花费 owner 的代币数量。这个内部函数相当于 approve ,可以用于例如为某些子系统设置自动限额等。

spendAllowance(address owner, address spender, uint256 amount) :花费 amount 数量的 owner 授权 spender 的代币。在无限 allowance 的情况下不更新 allowance 金额。如果没有足够的余量,则恢复。可能触发 Approval 事件。

_beforeTokenTransfer(address from, address to, uint256 amount) :在任何代币转账前的 Hook 。它包括铸币和烧毁。调用条件:

当 from 和 to 都不是零地址时,from 手里 amount 数量的代币将发送给 to 。

当 from 是零地址时,将给 to 铸造 amount 数量的代币。

当 to 是零地址时,from 手里 amount 数量的代币将被烧毁。

from 和 to 不能同时为零地址。

_afterTokenTransfer(address from, address to, uint256 amount) :在任何代币转账后的 Hook 。它包括铸币和烧毁。调用条件:

当 from 和 to 都不是零地址时,from 手里 amount 数量的代币将发送给 to 。

当 from 是零地址时,将给 to 铸造 amount 数量的代币。

当 to 是零地址时,from 手里 amount 数量的代币将被烧毁。

from 和 to 不能同时为零地址。

小结

ERC20 代码中的 _transfer、_mint、_burn、_approve、_spendAllowance、_beforeTokenTransfer、_afterTokenTransfer 都是 internal 函数(其余为 public ),也就是说它们只能被派生合约调用。

从零开始,自己动手

1.编写IERC20

IERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC20 {

/// @dev 总发行量

function totoalSupply() external view returns (uint256);

/// @dev 查看地址余额

function balanceOf(address account) external view returns (uint256);

/// @dev 单地址转账

function transfer(address account, uint256 amount) external returns (bool);

/// @dev 查看被授权人代表所有者花费的代币余额

function allowance(address owner, address spender) external view returns (uint256);

/// @dev 授权别人花费你拥有的代币

function approve(address spender, uint256 amount) external returns (bool);

/// @dev 双地址转账

function transferFrom(

address from,

address to,

uint256 amount

) external returns (bool);

/// @dev 发生代币转移时触发

event Transfer(address indexed from, address indexed to, uint256 value);

/// @dev 授权时触发

event Approval(address indexed owner, address indexed spender, uint256 value);

}

2.加上Metadata

IERC20Metadata.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "IERC20.sol";

interface IERC20Metadata is IERC20 {

/// @dev 代币名称

function name() external view returns (string memory);

/// @dev 代币符号

function symbol() external view returns (string memory);

/// @dev 小数点后位数

function decimals() external view returns (uint8);

}

3.编写ERC20

ERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";

import "./IERC20Metadata.sol";

contract ERC20 is IERC20, IERC30Metadata {

// 地址余额

mapping(address => uint256) private _balances;

// 授权地址余额

mapping(address => mapping(address => uint256)) private _allowances;

uint256 private _totalSupply;

string private _name;

string private _symbol;

/// @dev 设定代币名称符号

constructor(string memory name_, string memory symbol_) {

_name = name_;

_symbol = symbol_;

}

function name() public view virtual override returns (string memory) {

return _name;

}

function symbol() public view virtual override returns (string memory) {

return _symbol;

}

/// @dev 小数点位数一般为 18

function decimals() public view virtual override returns (uint8) {

return 18;

}

function totalSupply() public view virtual override returns (uint256) {

return _totalSupply;

}

function balanceOf(address account) public view virtual override returns (uint256) {

return _balances[account];

}

function transfer(address to, uint256 amount) public virtual override returns (bool) {

address owner = msg.sender;

_transfer(owner, to, amount);

return true;

}

function allowance(address owner, address spender) public view virtual override returns (uint256) {

return _allowances[owner][spender];

}

function approve(address spender, uint256 amount) public virtual override returns (bool) {

address owner = msg.sender;

_approve(owner, spender, amount);

return true;

}

function transferFrom(

address from,

address to,

uint256 amount

) public virtual override returns (bool) {

address spender = msg.sender;

_spendAllowance(from, spender, amount);

_transfer(from, to, amount);

return true;

}

function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {

address owner = msg.sender;

_approve(owner, spender, _allowances[owner][spender] + addedValue);

return true;

}

function decreaseAllowance(address spender, uint256 substractedValue) public virtual returns (bool) {

address owner = msg.sender;

uint256 currentAllowance = _allowances[owner][spender];

require(currentAllowance >= substractedValue, "ERC20: decreased allowance below zero");

unchecked {

_approval(owner, spender, currentAllowance - substractedValue);

}

return true;

}

function _transfer(

address from,

address to,

uint256 amount

) internal virtual {

require(from != address(0), "ERC20: transfer from the zero address");

require(to != address(0), "ERC20: transfer to the zero address");

_beforeTokenTransfer(from, to, amount);

uint256 fromBalance = _balances[from];

require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");

unchecked {

_balances[from] = fromBalance - amount;

}

_balances[to] += amount;

emit Transfer(from, to, amount);

_afterTokenTransfer(from, to, amount);

}

function _mint(address account, uint256 amount) internal virtual {

require(account != address(0), "ERC20: mint to the zero address");

_beforeTokenTransfer(address(0), account, amount);

_totalSupply += amount;

_balances[account] += amount;

emit Transfer(address(0), account, amount);

_afterTokenTransfer(address(0), account, amount);

}

function _burn(address account, uint256 amount) internal virtual {

require(account != address(0), "ERC20: burn from the zero address");

_beforeTokenTransfer(account, address(0), amount);

uint256 accountBalance = _balances[account];

require(accountBalance >= amount, "ERC20: burn amount exceeds balance");

unchecked {

_balances[account] = accountBalance - amount;

}

_totalSupply -= amount;

emit Transfer(account, address(0), amount);

_afterTokenTransfer(account, address(0), amount);

}

function _approve(

address owner,

address spender,

uint256 amount

) internal virtual {

require(owner != address(0), "ERC20: approve from the zero address");

require(spender != address(0), "ERC20: approve to the zero address");

_allowances[owner][spender];

emit Approval(owner, spender, amount);

}

function _spendAllowance(

address owner,

address spender,

uint256 amount

) internal virtual {

uint256 currentAllowance = allowance(owner, spender);

if (currentAllowance != type(uint256).max) {

require(currentAllowance >= amount, "ERC20: insufficient allowance");

unchecked {

_approve(owner, spender, currentAllowance - amount);

}

}

}

function _beforeTokenTransfer(

address from,

address to,

uint256 amount

) internal virtual {}

function _afterTokenTransfer(

address from,

address to,

uint256 amount

) internal virtual {}

}

总结

ERC20 其实就是一种最常见的代币标准,它明确了同质化代币的经典功能并规范了开发者编写 token 时的代码,从而方便各种应用适配。

学分: 39

分类: 以太坊

标签:

ERC20 

点赞 3

收藏 5

分享

Twitter分享

微信扫码分享

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

你可能感兴趣的文章

花式发币法之发行各类 ERC20 代币

3968 浏览

Michael.W基于Foundry精读Openzeppelin第39期——ERC20.sol

506 浏览

教程:如何在没有 Web 界面的情况下创建 ERC20桥

1574 浏览

一个简单的ERC20代币空投合约

2653 浏览

发布一款ERC20代币,并开发成Dapp

1548 浏览

Aptos合约开发之部署ERC20合约

3944 浏览

相关问题

请教下大家,Swap如何实现卖币手续费

2 回答

如何从发起部署的地址中,转移一部分代币到已经部署的合约地址中,麻烦那位大佬看一下

5 回答

空投的默克尔树如何防止生日攻击?

2 回答

bsc链上的erc20合约,要求只有一点买卖的时候2%兑换成bnb发送到营销钱包,现在的问题是添加流动性会一直报错Fail with error 'TransferHelper::transferFrom: transferFrom failed'

2 回答

eth中如何判断合约是erc20合约

2 回答

寻找使用Vyper部署的带有交易税的ERC20代币模版

1 回答

0 条评论

请先 登录 后评论

Confucian

关注

贡献值: 57

学分: 83

Keep Learning

文章目录

关于

关于我们

社区公约

学分规则

Github

伙伴们

DeCert

ChainTool

GCC

合作

广告投放

发布课程

联系我们

友情链接

关注社区

Discord

Twitter

Youtube

B 站

公众号

关注不错过动态

微信群

加入技术圈子

©2024 登链社区 版权所有 |

Powered By Tipask3.5|

粤公网安备 44049102496617号

粤ICP备17140514号

粤B2-20230927

增值电信业务经营许可证

×

发送私信

请将文档链接发给晓娜,我们会尽快安排上架,感谢您的推荐!

发给:

内容:

取消

发送

×

举报此文章

垃圾广告信息:

广告、推广、测试等内容

违规内容:

色情、暴力、血腥、敏感信息等内容

不友善内容:

人身攻击、挑衅辱骂、恶意行为

其他原因:

请补充说明

举报原因:

取消

举报

×

如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!

智能合约ERC20代币详解 - 知乎

智能合约ERC20代币详解 - 知乎首发于区块链技术详解切换模式写文章登录/注册智能合约ERC20代币详解Zarten​计算机技术与软件专业技术资格证持证人作者:Zarten知乎专栏:区块链技术详解知乎ID:Zarten简介: 互联网一线工作者,尊重原创并欢迎评论留言指出不足之处,也希望多些关注和点赞是给作者最好的鼓励 !概述ERC20并不是一项技术或者说一套程序,而是以太坊平台的数据通讯标准或者说规则 。ERC20简单理解成以太坊上的一个代币协议,所有基于以太坊开发的代币合约都遵守这个协议。遵守这些协议的代币我们可以认为是标准化的代币,而标准化带来的好处是兼容性好。这些标准化的代币可以被各种以太坊钱包支持,用于不同的平台和项目。ERC20标准官方介绍说明:https://theethereum.wiki/erc20_token_standard/标准规定,一共包括:6个函数,2个event,3个变量。 contract ERC20Interface {

function totalSupply() public constant returns (uint);

function balanceOf(address tokenOwner) public constant returns (uint balance);

function allowance(address tokenOwner, address spender) public constant returns (uint remaining);

function transfer(address to, uint tokens) public returns (bool success);

function approve(address spender, uint tokens) public returns (bool success);

function transferFrom(address from, address to, uint tokens) public returns (bool success);

event Transfer(address indexed from, address indexed to, uint tokens);

event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

string public constant name = "Zarten Token";

string public constant symbol = "ZAR";

uint8 public constant decimals = 18; // 18 is the most common number of decimal places

// 0.0000000000000000001 个代币

}

解释如下:totalSupply()代币发行总量。balanceOf(address tokenOwner)查询某个账户的代币余额。allowance(address tokenOwner, address spender)查询某个账户可转账金额。用于控制代币的交易。transfer(address to, uint tokens)从当前的自己账户,实现代币的交易。approve(address spender, uint tokens)设置允许某个账户spender从此地址可使用的代币数。transferFrom(address from, address to, uint tokens)实现用户之间的代币交易(非自己账户)。event Transfer(address indexed from, address indexed to, uint tokens)当代币交易时会触发此函数。event Approval(address indexed tokenOwner, address indexed spender, uint tokens)当成功调用approve函数后会触发此函数。name代币名称symbol 代币简称decimals 返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示。一般为18位。ERC20工作原理变量及函数实现定义变量一般会定义几个映射变量:mapping (address => uint256) public balances保存着每个地址对应的余额。mapping (address => mapping (address => uint256)) public allowed两层映射。保存着某个地址A允许另一个地址B可操作的金额。最外层映射为某个地址A,内层映射为另一个地址B,值为可操作(发起交易)金额总量。函数实现balanceOf()function balanceOf(address tokenOwner) public constant returns (uint balance) {

return balances[tokenOwner];

}

从映射变量balances中取出某个地址的余额。transfer()function transfer(address to, uint tokens) public returns (bool success) {

balances[msg.sender] = balances[msg.sender].sub(tokens);

balances[to] = balances[to].add(tokens);

Transfer(msg.sender, to, tokens);

return true;

}

当前账户转账操作。msg.sender为保留字,指这个函数的地址。sub:减 add:加首先从当前账户减去相应金额。同时往对方账户加上对应金额。并调用Transfer函数做通知。transferFrom()function transferFrom(address from, address to, uint tokens) public returns (bool success){

balances[from] = balances[from].sub(tokens);

allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);

balances[to] = balances[to].add(tokens);

Transfer(from, to, tokens);

return true;

}

用户之间账户转账操作。由from地址发起转账交易。from地址账户减去相应金额。from从msg.sender总共可操作金额减少相应金额。to地址账户增加相应金额。调用Transfer函数做通知。approve() function approve(address spender, uint tokens) public returns (bool success) {

allowed[msg.sender][spender] = tokens;

Approval(msg.sender, spender, tokens);

return true;

}

设置某账户spender可操控msg.sender的代币数。设置spender地址从msg.sender可使用的代币数。调用Approval函数做通知。举例说明假设2个钱包地址如下:balances[0x1111111111] = 100balances[0x2222222222] = 200 balanceOf()tokenContract.balanceOf(0x1111111111) will return 100tokenContract.balanceOf(0x2222222222) will return 200 transfer()若0x1111111111转账10个代币给0x2222222222,则0x1111111111将执行tokenContract.transfer(0x2222222222, 10)转账成功后得到如下结果:balances[0x1111111111] = 90balances[0x2222222222] = 210 approve()若0x1111111111允许0x2222222222拥有转账操作30个代币的权利,则0x1111111111将执行tokenContract.approve(0x2222222222, 30)设置成功后得到如下结果:tokenContract.allowed[0x1111111111][0x2222222222] = 30transferFrom()若0x2222222222转移0x1111111111的20个代币给自己,则0x2222222222将执行tokenContract.transferFrom(0x1111111111, 0x2222222222, 20)转账成功后得到如下结果:tokenContract.balances[0x1111111111] = 70tokenContract.balances[0x2222222222] = 230tokenContract.allowed[0x1111111111][0x2222222222] = 10 ERC20基本功能代码注:完整代币已上传至Github:GitHub - Zartenc/ZAR-ERC20: Zarten ERC20 Token is ZAR实现ERC标准接口,代码如下:pragma solidity ^0.4.0;

contract ERC20Interface {

function totalSupply() public view returns (uint);

function balanceOf(address tokenOwner) public view returns (uint balance);

function allowance(address tokenOwner, address spender) public view returns (uint remaining);

function transfer(address to, uint tokens) public returns (bool success);

function approve(address spender, uint tokens) public returns (bool success);

function transferFrom(address from, address to, uint tokens) public returns (bool success);

event Transfer(address indexed from, address indexed to, uint tokens);

event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

}

contract ZartenToken is ERC20Interface{

string public name;

string public symbol;

uint8 public decimals;

uint256 public _totalSupply;

mapping (address => uint256) public balances;

mapping (address => mapping (address => uint256)) public allowed;

constructor() public {

symbol = "ZAR";

name = "Zarten Token";

decimals = 18;

_totalSupply = 100000000 * 10**uint256(decimals);

balances[msg.sender] = _totalSupply;

}

function totalSupply() public view returns (uint256) {

return _totalSupply;

}

function balanceOf(address tokenOwner) public view returns (uint256 balance) {

return balances[tokenOwner];

}

function allowance(address tokenOwner, address spender) public view returns (uint remaining) {

return allowed[tokenOwner][spender];

}

function transfer(address to, uint256 tokens) public returns (bool success) {

// 检验接收者地址是否合法

require(to != address(0));

// 检验发送者账户余额是否足够

require(balances[msg.sender] >= tokens);

// 检验是否会发生溢出

require(balances[to] + tokens >= balances[to]);

// 扣除发送者账户余额

balances[msg.sender] -= tokens;

// 增加接收者账户余额

balances[to] += tokens;

// 触发相应的事件

emit Transfer(msg.sender, to, tokens);

return true;

}

function approve(address spender, uint256 tokens) public returns (bool success) {

allowed[msg.sender][spender] = tokens;

emit Approval(msg.sender, spender, tokens);

return true;

}

function transferFrom(address from, address to, uint tokens) public returns (bool success) {

// 检验地址是否合法

require(to != address(0) && from != address(0));

// 检验发送者账户余额是否足够

require(balances[from] >= tokens);

// 检验操作的金额是否是被允许的

require(allowed[from][msg.sender] <= tokens);

// 检验是否会发生溢出

require(balances[to] + tokens >= balances[to]);

balances[from] -= tokens;

allowed[from][msg.sender] -= tokens;

balances[to] += tokens;

emit Transfer(from, to, tokens);

return true;

}

}

以上代码可直接部署并可调用。ERC20高级功能代码ERC20代币有时需要其他一些额外的高级功能,比如代币管理、代币增发、空投代币、代币冻结、销毁代币、代币兑换等。代币管理有时代币需要有一个管理者功能。添加一个owned合约,如下:contract Owned {

address public owner;

constructor() public {

owner = msg.sender;

}

modifier onlyOwner {

require(msg.sender == owner);

_;

}

function transferOwnership(address newOwner) onlyOwner public {

owner = newOwner;

}

}

上面modifier关键字为修饰器,修饰器所修饰的函数体会被插入到特殊符号 _; 的位置,如果是 owner 调用这个函数,则函数会被执行,否则会抛出异常。之后自己的合约继承ERC20Interface合约和owned合约,并msg.sender换为owner。contract ZartenToken is ERC20Interface, Owned{}代币增发代币增发可使代币总供应量增加,可以指定某个账户的代币增加,同时总供应量也随之增加。 //代币增发 function mintToken(address target, uint256 mintedAmount) onlyOwner public {

balances[target] += mintedAmount;

_totalSupply += mintedAmount;

emit Transfer(address(0), address(this), mintedAmount);

emit Transfer(address(this), target, mintedAmount);

}

使用onlyOwner修饰器,只能owner调用。this表示当前合约。代币销毁首先添加一个通知客户端代币消费的事件。event Burn(address indexed from, uint256 value);销毁代币非为销毁管理者代币和销毁用户代币。此时需要管理者去进行销毁。销毁管理者代币 //管理者代币销毁 function burn(uint256 _value) onlyOwner public returns (bool success) {

require(balances[owner] >= _value);

balances[owner] -= _value;

_totalSupply -= _value;

emit Burn(owner, _value);

return true;

}

销毁用户代币 //用户代币销毁 function burnFrom(address _from, uint256 _value) onlyOwner public returns (bool success) {

require(balances[_from] >= _value);

require(_value <= allowed[_from][owner]);

balances[_from] -= _value;

allowed[_from][owner] -= _value;

_totalSupply -= _value;

emit Burn(_from, _value);

return true;

}

代币冻结有时需要冻结账户代币,也就是此账户不能转账操作。1.首先添加一个账户冻结代币的映射mapping (address => bool) public frozenAccount;2.添加冻结的通知函数event FrozenFunds(address target, bool frozen);3..添加冻结的函数 //冻结账户代币 function freezeAccount(address target, bool freeze) onlyOwner public {

frozenAccount[target] = freeze;

emit FrozenFunds(target, freeze);

}

4.在转账函数中判断涉及账户是否为冻结账户,否则不允许转账操作 require(!frozenAccount[from]); require(!frozenAccount[to]);批量代币空投有时需要往很多地址空投一些代币,这样可以使用批量转账。假设从管理员账户空投。关键字memory为声明内存型的,存储的内容会在函数被调用(包括外部函数)时擦除,所以其使用开销相对较小。 //空投代币

function AirDrop(address[] memory _recipients, uint _values) onlyOwner public returns (bool) {

require(_recipients.length > 0);

for(uint j = 0; j < _recipients.length; j++){

transfer(_recipients[j], _values);

}

return true;

}

代币兑换有时代币需要与其他货币(Ether)进行兑换。msg.value表示随消息发送的wei的数量,payable修饰函数表示允许从调用中接收以太币。设置买卖价格的变量 uint256 public sellPrice; uint256 public buyPrice;设置价格函数 function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {

sellPrice = newSellPrice;

buyPrice = newBuyPrice;

}

接收以太币进行买操作 function buy() payable public {

uint amount = msg.value / buyPrice;

emit Transfer(address(this), owner, amount);

}

卖操作 function sell(uint256 amount) public {

require(address(this).balance >= amount * sellPrice);

emit Transfer(owner, address(this), amount);

owner.transfer(amount * sellPrice);

}

注:完整代币已上传至Github:GitHub - Zartenc/ZAR-ERC20: Zarten ERC20 Token is ZAR合约编译部署使用remix进行合约代码的编译与部署。官网:http://remix.ethereum.org/编译点击编译按钮;注意编译器版本与代码指定版本要对应。部署remix左侧的第三个按钮是发布按钮。点击发布按钮,会看到有ENVIRONMENT、ACCOUNT 、GAS LIMIT、CONTRACT等。其中,ENVIRONMENT有如下几个选项:1.JavaScript VM:这是Remix自己的内部沙箱。它不连接到MainNet,TestNet或任何专用网络。这是一个内存中的区块链,可用于简单测试和快速挖掘。2.Injected Web3:这是用于浏览器插件(MetaMask)的选项。在这里,Remix将对区块链集成的所有控制权交给MetaMask插件。此时,MetaMask控制要连接到的网络。3.Web3 Provider:这允许在Remix中输入URL以连接到区块链。此处最常见的设置是运行本地节点并通过其IP/端口连接到该节点此时选择 Injected Web3选项。点击Deploy部署后,小狐狸钱包会弹出确认框,此时需要注意选择的网络(主网或测试网等)。这里选择Goerli测试网络。部署成功后,可看到输出的日志和合约地址。此时部署已完成,也可在官方区块链浏览器中查看部署情况。钱包添加代币可把已经部署的代币添加到钱包方便查看,点击钱包添加代币,输入代币合约地址(上面箭头处)、代币符号、小数精度。输入信息如下:代币合约地址:0x9989a0ffB957D3eFf0262d43786df66176785F86代币符号:ZAR小数精度:18添加代币完成后如下所示:应用转账向另外一个地址转账1000个ZAR币,如下所示:转账成功后,另外一个账户收到1000个ZAR币。如下:代币信息总览可在浏览器中查看token详情,如下所示:查看ZAR币详情地址:https://goerli.etherscan.io/token/0x9989a0ffb957d3eff0262d43786df66176785f86#balances发布源代码若需要发布源代码可在浏览器中合约地址页面,Contract选项卡点击Verify and Publish ,接下来按提示步骤操作即可。发布于 2021-07-21 17:20token代币​赞同 36​​7 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录区块链技术详解区块链技术深

ERC20 钱包 - 保护您的 ERC20 (ERC20) 资产 | Ledger

ERC20 钱包 - 保护您的 ERC20 (ERC20) 资产 | Ledger

抓住比特币的涨势。 即刻入手比特币版 Ledger 硬件钱包

在此购买

Our Website now exists in . Do you want to change languages?

Yes, please

No, I'm good

You can revert to English at any time by clicking on the language menu on the top right corner of the page.

产品

Ledger Stax

Ledger Nano X

Ledger Nano S Plus

比较我们的设备

套装

配件

品牌合作

查看所有产品

下载 Ledger Live

已支持的币种

应用程序和服务

Ledger Live

Ledger Recover

CL 卡

支持的服务

加密货币价格

学习

Ledger 学院

学而赚取

课堂

博客

什么是加密钱包

如何购买

如何互换

如何质押

企业

Ledger 企业解决方案

Ledger 合作伙伴

Ledger 联名合作

Ledger 开发

支持

简体中文

العربية

Français

Deutsch

Русский

Español

日本語

한국어

Türkçe

Português

ERC20 钱包

保护您的 ERC20 资产

使用最受信任的硬件钱包来保护您的 ERC20 资产。 冷存储钱包通常是加密设备,可离线存储用户的 ERC20 资产,提供一层安全保护,以抵御因连接至互联网而出现的不断演变的威胁。

一流的 安全性

简单

多币种

探索我们的钱包

了解如何使用 Ledger Live 管理 ERC20

保护您的 ERC20 (ERC20)

使用 Ledger 硬件钱包保护多种资产,包括 ERC20。认证安全芯片安全存储着访问您加密资产的私钥。

Ledger Nano S

使用市场上首款也是唯一一款经独立认证的硬件钱包来保护您的 ERC20 资产。

了解更多

Ledger Nano X

Ledger Nano X 是一款支持蓝牙、安全且荣获 CES 大奖的设备保护您的 ERC20 资产

了解更多

如何管理您的 ERC20 (ERC20)

Ledger Live

通过我们自己的桌面和手机应用程序 Ledger Live 直接管理您的 ERC20 代币。 直接通过 Ledger Live 实时查看余额以及收发 ERC20 代币等 5500 余种资产。

了解如何使用 Ledger Live 管理 ERC20

深受社区赞赏

Maria R.

我认为 Ledger 钱包是安全保护加密货币的最佳解决方案。

Dennis G.

安心是质量的标准。

Walter F.

买了 3 台 nano-s。一切都好。产品好,送货快。感谢!

Antonio B.

很棒的设备,我 100% 推荐,做你自己的银行!!!!!!

查看更多

什么是 ERC20 (ERC20)

ERC20 是一个协议标准,它定义了在以太坊网络上发行代币的具体规则和标准。 在以太坊区块链上发行的大多数代币都符合 ERC-20。 它允许将一种代币与另一种代币进行交易。

ERC20 (ERC20) 功能

ERC-20(以太坊意见征求)是一项正式的以太坊改进提案,已作为公共区块链上的智能合约代币标准予以采纳。 ERC-20 最初由开发人员 Fabian Vogelsteller 提出,目前已扩张至包含一系列功能,如支持 2017 年的 ICO 募资方法和 ICO 热潮,强调公共网络中标准化协议的潜力等。

概括而言,以太坊是一个公共区块链网络,用于使用智能合约开发去中心化应用程序 (DApp),其中智能合约采用编程语言 Solidity 编写。 以太坊的原生加密货币称为以太币 (ETH),用于在网络上转移价值并支付 Gas 费用,这些费用需要覆盖整个网络的计算成本并阻止垃圾邮件。

然而,网络上智能合约的存在(表面上是自主账户和计算机程序)在以太坊中启用了一套比特币中未提供的全新功能。 以太坊是一个图灵完备性平台,这意味着几乎任何逻辑均可通过编程写入网络上的应用程序中。 智能合约是在网络上自动执行各项功能的账户,共同达成更广泛用途的一组智能合约将形成 DApp(去中心化应用程序)。

为便于沟通,同时简化可互操作的功能性 DApp 和智能合约的开发,创建了一个标准化的代币智能合约框架。 此框架中最引人注目的便是 ERC-20。

ERC-20 是一种用于在以太坊上创建、发行和管理可替代代币的标准化格式。 这些代币具有不同的用例和应用程序(如实用型代币),且由开发人员以 ERC-20 作为参考创建。 该标准提供了用于传输 ERC-20 代币以及与 ERC-20 代币交互的基本格式,随后各种钱包使用此类格式来支持代币的存储、传输和管理。

标准化促进了快速创新且强调互联网的设计。

借助 ERC-20,项目可以轻松创建和发行代币,以在各种 DApp 中用作激励结构或筹款工具。 值得注意的是,ERC-20 是首次代币发行 (ICO) 的基础,其中 ICO 是一种直接以加密货币形式筹集资金来为项目注资的工具,如以太坊上的 DApp。 ICO 在 2018 年筹集了 63 亿美元,独特的众筹方法将用户和投资者直接与项目对接。

ERC-20 代币设计为可替代代币,这意味着每个代币单位都与下一个等值。 例如,使用 Maker DAO ERC20,1 MKR 在价值上总是等价于 1 MKR。

ERC-20 的标准化技术格式和不断扩张的网络效应相结合,使该标准在以太坊上得到广泛采用。 网络上的大多数代币都兼容 ERC-20,且可以在网络上无缝兑换和转移。 您在币聚合网站上找到的大多数与以太坊相关的代币均为 ERC-20 代币,如 Maker、Dai 和 Augur REP。

重要的一点是,ERC-20 代币在加密货币领域引发了有关标准化协议和合约所充当角色的更广泛对话,目的是提高创新和互操作性。 区块链的发展目标是能够在彼此间传输价值和数据,因此协议的标准化成为讨论的核心。

除了以太坊上的 ERC-20 之外,还出现了其他几个标准(即 ERC-721),它们分别专注于不同类型的代币,如非同质化代币。 这些非同质化代币旨在代表独特的数字资产,如虚拟猫,随着《迷恋猫》的兴起,虚拟猫成为非同质化代币可实现内容的最佳示例。

ERC-20 的总体影响是以太坊上资产、DApp 和创新(即 DeFi)生态系统的长足发展。 ERC-20 作为代币标准的流行程度揭示了将标准化进一步扩张到公共区块链的潜在可能,而该行业才刚刚开始加足马力。

请记住,ERC-20 代币虽然建立在以太坊上,但和 DApp 一样是存在于网络生态系统中的代币,这一点很重要。

支持的加密货币

直接使用 Ledger Live 安全管理 种币和 ERC20 代币。 更多使用外部钱包。

VET

VeChain

币安币(BNB)

币安币

TRX

波场(Tron)

LINK

ChainLink

EOS

EOS

联系我们

可以在我们的博客查看公告。 媒体联系: [email protected]

订阅我们的 简报

在收件箱中直接查看支持的新币种、博客更新以及专属优惠

输入您的电子邮件地址

注册订阅新闻简报

您的电子邮件地址将仅用于向您发送我们的简报,以及更新和优惠信息。您可通过简报中的链接随时取消订阅。

详细了解我们如何管理您的数据和您的权利。

简体中文

العربية

Français

Deutsch

Русский

Español

日本語

한국어

Türkçe

Português

版权所有 © Ledger SAS。 保留所有权利。 Ledger、Ledger Stax、Ledger Nano S、Ledger Vault、Bolos 是 Ledger SAS 拥有的商标。

1 rue du Mail, 75002 Paris, France

付款方式

 

 

 

 

 

 

 

产品Ledger Stax

Ledger Nano X

Ledger Nano S Plus

比较我们的设备

捆绑销售

配件

所有产品

下载

加密资产比特币钱包

以太坊钱包

卡尔达诺钱包

瑞波币钱包

门罗币钱包

泰达币钱包

查看所有资产

加密服务加密货币价格

买入加密货币

权益质押

互换加密货币

企业Ledger 企业解决方案

对于初创公司来自 Ledger Cathay Capital 的资金

开发者开发者门户

使用入门开始使用 Ledger 设备

兼容的钱包和服务

如何购买比特币

比特币购买指南

比特币硬件钱包

其他链接支持

赏金计划

转销商

Ledger 媒体资料包

联署营销

状态

合作伙伴

职场加入我们

全部职位

简介我们的愿景

Ledger 学院

公司

人员

多样性

博客

法律销售条款与条件

网站使用条款

Ledger Live 使用条款

隐私政策

Cookie 政策

Ledger 保修

免责声明

其他

什么是ERC20?以太坊代币标准指南

什么是ERC20?以太坊代币标准指南

产品

加密支付网关

彻底改变支付方式

加密钱包

保护数字资产

加密货币发票

轻松的计费解决方案

批量支付

简化批量传输

White Label

定制品牌解决方案

Donations

通过加密货币增强捐赠能力

连接

API

整合与创新

整合解决方案

优化的插件和库以实现平滑集成

学习

博客

见解和更新

常问问题

澄清您的疑问

帮助

支持与指导

公司

安全

保护您的数字资产

漏洞赏金

奖励安全研究

联系我们

寻求帮助

价钱

登录

报名

什么是ERC20?以太坊代币标准指南

发表于 Feb 8, 2024

分享到

ERC20 是在以太坊区块链上制定和部署智能合约的关键标准,是该生态系统中数字化代币的支柱。源于以太坊托管智能合约的能力——自动执行合约,协议条款直接写入代码行——ERC20 代币是以太坊功能的基石。这些代币支持创建各种去中心化应用程序 (dApp)和平台,从实用代币到去中心化金融 (DeFi)解决方案,所有这些都遵循 ERC20 准则以确保网络兼容性。以太坊是世界领先的可编程区块链,允许用户利用其技术铸造自己的代币,这些代币可以体现各种资产或权利,例如数字积分、公司股票,甚至法定货币的数字表示形式。 ERC20 标准概述了一组规则,确保这些代币在以太坊生态系统中无缝集成和运行,从而促进不同应用程序和服务之间的互操作性和功能。 ERC-20 是什么意思? ERC-20 标准是以太坊区块链上可替代代币创建的基石,由以太坊开发者Fabian Vogelsteller于 2015 年 11 月 19 日提出。该技术规范的正式名称为以太坊征求意见20 (ERC-20),为在以太坊生态系统中发行、创建和部署可互换代币奠定了基础。名称“ERC”表示开发人员建议增强区块链的方法,“20”标记专用于这套操作规则的具体提案编号。 Fungible token 的特点是能够在一对一的基础上无区别地进行交换,已广泛采用 ERC-20 标准,这表明它在以太坊网络上数十万个合约的扩散和运行中发挥着关键作用。该标准不仅促进了代币创建的统一方法,而且还通过为开发人员提供强大的框架来刺激以太坊平台的发展。 ERC-20 作为以太坊改进协议(称为 EIP-20)的认可和正式采用发生在 2017 年底。EIP-20 由 Vogelsteller 和以太坊联合创始人Vitalik Buterin共同撰写,EIP-20 的认可巩固了其作为重要协议的地位。以太坊区块链中的协议,支撑了大量可替代代币,这些代币已成为平台生态系统和更广泛的区块链社区不可或缺的一部分。 ERC-20 的工作原理ERC-20 标准为以太坊区块链上的加密代币功能制定了一个全面的框架,将操作分类为 getter、函数和事件,以确保生态系统内集成的一致性和易用性。 Getters 的目的是在不改变区块链状态的情况下检索和显示数据。 ERC-20 中概述的主要吸气剂包括:总供应量:此函数报告已发行的代币总数,提供对特定代币流通规模的深入了解。 Balance Of :返回特定账户的代币余额,让用户轻松验证其持有情况。津贴:这一独特功能促进了委托支出,其中一个账户可以授权另一个账户代表其支出指定的代币金额。例如,如果用户 A 授权用户 B 使用 50 个代币,则用户 B 可以使用这些代币进行交易,最多可达分配的金额,但不能超过。函数是面向操作的命令,可实现代币管理和传输:转账:这一核心功能用于将代币从一个账户转移到另一个账户,这是代币流通的一个基本方面。批准:它允许代币持有者指定另一个帐户的支出限额,从而实现以太坊网络内的自动支付和津贴等场景。转账来源:基于“批准”功能,允许第三方在批准的限额内在账户之间转移代币,从而简化涉及多方的交易。事件是智能合约发出的信号,表明已发生重大操作,提供透明度和可追溯性:转移事件:每当转移代币时都会触发该事件,该事件会记录交易,提供代币移动的可见性和验证。批准事件:当一个帐户批准另一个帐户花费特定代币金额时,会发出此事件,作为对委托权限的公开确认。除了核心功能之外,值得注意的是 ERC-20 在促进以太坊上去中心化应用程序 (dApp) 之间的互操作性方面的重要性。通过遵守一套标准化规则,ERC-20 代币可以轻松集成到钱包、交易所和其他 dApp 中,从而增强整个生态系统的流动性和实用性。此外,该标准为创新的金融应用程序和协议铺平了道路,通过支持从简单的转账到复杂的智能合约执行等广泛的交易,为去中心化金融(DeFi)的发展做出了重大贡献。作为其基础作用的证明,ERC-20 标准继续影响新代币标准和区块链技术的开发,突显其对以太坊区块链和更广泛的加密领域的关键影响。创建 ERC-20 代币ERC-20 代币通过在以太坊区块链上部署智能合约而存在。这些嵌入了自动执行代码的合约为代币创建和分配开辟了可能性领域,反映了传统金融机制的某些方面,但又具有创新性。一个说明性的场景涉及一个智能合约,旨在接受上限数量的以太坊,例如 10 ETH。收到 ETH 后,合约会激活其代币铸造功能,直接向贡献者的钱包发行预定义数量的代币(例如,每个 ETH 100 个代币)。这种机制可以有效地生成 100,000 个假设的“ABC”代币,并将它们分散给参与者以换取他们的以太坊贡献。这种方法类似于股票市场中首次公开募股(IPO)的概念,即公司向公众发行股票以换取投资资本。同样,智能合约的代币发行过程充当筹集资金的去中心化变体,投资者收到代币而不是股票。这种方法不仅通过消除中央机构实现投资民主化,而且还引入了一种在数字生态系统内资助项目和分配资产的新方式。除了筹款之外,ERC-20 代币标准还促进了各种应用程序,从在去中心化自治组织 (DAO)中授予投票权的治理代币到提供平台内服务访问权限的实用代币。智能合约的可编程特性允许实现限时释放、股息分配和自动奖励等创造性功能,通过灵活和创新的金融工具丰富生态系统。什么是天然气?在以太坊区块链生态系统中,“gas”表示用于量化进行交易或执行智能合约所需的计算量的计量单位。用“ gwei ”表示——以太坊原生加密货币以太币(ETH)的较小面额,通常等同于 nanoeth——气体充当将资源分配给以太坊虚拟机(EVM)的媒介。这种分配有利于去中心化应用程序的自主运行,包括以安全和去中心化的方式执行智能合约。天然气成本是通过供应和需求的动态相互作用来确定的,其中包括提供交易处理和智能合约执行所需计算能力的矿工,以及寻求这些处理能力的网络用户。如果提供的 Gas 价格未能符合其运营成本预期,矿工可以自行决定拒绝交易,从而建立一个 Gas 价格根据网络活动水平和矿工需求波动的市场。该机制通过防止垃圾邮件交易并将资源分配给那些愿意为计算服务支付市场价格的人来确保以太坊网络保持高效。它还强调了以太坊的去中心化性质,其中交易和智能合约的执行是通过平衡网络参与者的需求与矿工的运营能力的系统来激励的。 ERC-20 代币的种类ERC-20 代币通过提供通用且标准化的代币创建框架,彻底改变了以太坊区块链,支持跨不同领域的广泛应用。这些代币可以代表一切,从类似于公司股票的金融资产(在某些司法管辖区可能作为证券进行监管)到忠诚奖励和黄金或房地产等实物资产。例如,一些 ERC-20 代币的运作方式与公司股票类似,根据监管角度,其发行人可能需要承担特定的法律义务。另一些则在数字生态系统中提供创新的实用性,例如来自在线预订平台的忠诚度积分,可用于未来的服务或与其他人进行交易,从而在其原始背景之外增加一层价值和实用性。这种多功能性延伸到了像 Tether (USDT) 这样的稳定币,它们与现实世界的货币挂钩,并提供传统货币的数字对应物,并具有区块链技术的额外优势,例如易于转移和通过智能合约产生潜在收益。然而,用 ERC-20 代币代表物理对象或法定货币会带来挑战,特别是在维持数字到物理链接的准确性方面。例如,USDT 的价值与 Tether Limited 持有的美元挂钩,需要信任传统的审计方法以确保支持的存在,这凸显了数字领域和物理领域之间潜在的脱节。 ERC-20 代币的采用进一步体现在它们与各种应用程序的集成: 美元硬币 (USDC) 和 Tether (USDT) 等稳定币为加密市场提供了稳定性。治理代币,例如 Maker (MKR),可以参与去中心化决策。实用令牌授予对特定服务的访问权限,例如 Brave 浏览器中的基本注意令牌 (BAT) 。资产支持代币将数字代币与现实世界的资产联系起来,提供有形的价值。游戏内货币和Metaverse 平台利用 ERC-20 代币来管理虚拟经济并促进数字世界中的交易。去中心化金融 (DeFi)应用程序使用Aave (AAVE)等代币来实现治理和实用目的。成功的 ERC-20 代币,包括Uniswap (UNI) 、ApeCoin (APE)、 Wrapped Bitcoin (WBTC)和 Chainlink (LINK),展示了该标准的适应性及其在以太坊生态系统内促进创新方面的作用。这些代币具有多种功能,从促进数字社区内的去中心化交易和治理,到在DeFi应用程序中使用比特币,以及将智能合约与外部数据连接起来。 ERC-20 代币的广泛采用和成功凸显了促进整个以太坊网络兼容性和互操作性的统一标准的重要性。这种标准化对于使区块链技术超越那些具有深厚技术知识的人来说至关重要,为数字代币继续丰富数字世界和物理世界的未来铺平了道路。 ERC-20、ERC-721、ERC-1155以太坊区块链支持各种代币标准,每个标准旨在满足生态系统内的不同需求。除了众所周知的 ERC-20 标准之外,另外两个重要标准是 ERC-721 和 ERC-1155,它们扩展了可以在区块链上表示的资产的功能和类型。 ERC-20 设定了可替代代币的标准,这意味着每个代币在类型和价值上都与另一个代币相同,类似于传统加密货币的运作方式。该标准对于创建可互换且统一的数字货币至关重要。 ERC-721引入了不可替代代币(NFT)的概念,它们彼此不同并代表独特的资产。该标准通常用于数字收藏品和艺术品,可以对具有特定特征的单个物品进行标记化。 ERC-1155 被称为多代币标准,提供多功能智能合约接口,能够在单个合约中处理多种代币类型。这种创新方法允许 ERC-1155 代币封装 ERC-20 和 ERC-721 标准的功能,支持可替代和不可替代代币。这种灵活性使得 ERC-1155 对于需要混合可替代和不可替代资产的应用程序特别有用,例如游戏或去中心化金融。这些标准共同增强了以太坊生态系统托管广泛数字资产的能力,从可互换的货币代币到独特的数字收藏品和混合应用程序,展示了该平台的适应性和区块链领域的巨大创新潜力。 ERC-20 代币的优点和缺点ERC-20代币的优点互操作性:ERC-20 代币的一个突出特点是它们能够在以太坊生态系统中无缝交互,从而实现不同代币之间的轻松交换。这种互操作性支持从交易到项目融资的各种应用程序。增强的安全性:ERC-20 代币建立在以太坊区块链之上,受益于其强大的安全措施。不变性和去中心化等功能可防止操纵,确保代币完整性。定制灵活性:开发人员可以自由定制 ERC-20 代币以满足项目特定要求,包括代币供应、小数精度和独特功能。透明交易:以太坊区块链的透明度允许跟踪 ERC-20 代币变动,提供清晰的交易历史并增强参与者之间的信任。市场流动性:ERC-20代币以其流动性而闻名,这使其对投资者和交易者具有吸引力。在交易所买卖这些代币的便捷性有助于其受欢迎。用户友好:通过 MyEtherWallet 和 MetaMask 等工具促进 ERC-20 代币的可访问性,促进区块链社区内的广泛使用和创新。 ERC-20代币的缺点功能有限:尽管稳定,但 ERC-20 代币的标准化性质可能会限制复杂智能合约或自动化流程所需的高级功能,从而给需要更大多功能性的项目带来挑战。安全漏洞:ERC-20代币在继承以太坊安全特性的同时,也存在一些漏洞,包括易受智能合约漏洞和网络拥塞等影响,从而导致潜在的安全风险。可变汽油费:涉及 ERC-20 代币的交易会产生汽油费,该费用可能会随着网络拥塞而大幅波动,影响成本可预测性,并可能给小投资者带来负担。交易所兼容性问题:并非所有加密货币交易所都支持 ERC-20 代币,这可能会限制其流动性和投资者的交易选择。对兼容交易所的研究对于获得最佳交易体验至关重要。治理和透明度问题:治理不善和缺乏透明度可能会导致代币倾销和内幕交易等问题,从而损害投资者的信心和代币的可信度。无可否认,ERC-20 代币标准塑造了以太坊区块链的格局,提供了促进创新和参与的一系列好处。然而,它带来的挑战,包括安全问题和某些应用程序的有限功能,凸显了生态系统内持续开发和治理改进的重要性。

请注意,Plisio 还为您提供:

单击 2 次即可创建加密发票 and 接受加密捐赠

12 整合

BigCommerce

Ecwid

Magento

Opencart

osCommerce

PrestaShop

VirtueMart

WHMCS

WooCommerce

X-Cart

Zen Cart

Easy Digital Downloads

6 最流行的编程语言库

PHP 图书馆

Python 图书馆

React 图书馆

Vue 图书馆

NodeJS 图书馆

Android sdk 图书馆

19 加密货币和 12 区块链

Bitcoin (BTC)

Ethereum (ETH)

Ethereum Classic (ETC)

Tron (TRX)

Litecoin (LTC)

Dash (DASH)

DogeCoin (DOGE)

Zcash (ZEC)

Bitcoin Cash (BCH)

Tether (USDT) ERC20 and TRX20 and BEP-20

Shiba INU (SHIB) ERC-20

BitTorrent (BTT) TRC-20

Binance Coin(BNB) BEP-20

Binance USD (BUSD) BEP-20

USD Coin (USDC) ERC-20

TrueUSD (TUSD) ERC-20

Monero (XMR)

分享到

最新的文章

CoinSpot 评论:2024 年的详细信息、费用和功能

Mar 15, 2024

Dex Screener:2024 年如何使用

Mar 14, 2024

2024 年葡萄牙加密货币税收指南

Mar 13, 2024

什么是 Chainlink(LINK)?

Mar 13, 2024

Bybit 评论:优点、缺点和特点

Mar 12, 2024

2024 年如何兑现加密货币和比特币

Mar 12, 2024

美国国税局 (IRS) 能否在 2024 年追踪加密货币?

Mar 11, 2024

最佳 DeFi 交易所

Mar 11, 2024

dYdX 评论:优点、缺点和功能

Mar 10, 2024

托管钱包与非托管加密钱包

Mar 10, 2024

Exodus 钱包评论:2024 年的优点、缺点和功能

Mar 8, 2024

Kraken 评论:2024 年的优点、缺点和功能

Mar 8, 2024

加拿大加密货币税收指南(2024 年 CRA 规则)

Mar 7, 2024

Polymarket:去中心化预测市场如何运作

Mar 6, 2024

2024 年最佳 DeFi 加密货币

Mar 6, 2024

体育用品进入加密世界。轻松接受付款。

Mar 6, 2024

MEV Bot:以太坊套利分步手册

Mar 6, 2024

什么是闪电贷?

Mar 5, 2024

最佳区块链游戏公司

Mar 5, 2024

2024 年最佳白标 NFT 市场

Mar 4, 2024

产品

商业

个人的

价钱

批量支付

白色标签

发票

捐款

集成

资源

应用程序接口

博客

安全

漏洞赏金

常问问题

联系我们

政策

隐私政策

服务条款

跟着我们

简体中文

English

اَلْعَرَبِيَّةُ

Deutsch

ελληνικά

Español

فارسی

Français

हिन्दी

Bahasa Indonesia

Italiano

日本語

한국어

Polski

Português

Русский

ไทย

Türkçe

Українська

Tiếng Việt

简体中文

© 2024 Plisio, 公司。保留所有权利。

Buy/Sell Bitcoin, Ether and Altcoins | Cryptocurrency Exchange | Binance

Buy/Sell Bitcoin, Ether and Altcoins | Cryptocurrency Exchange | Binance

Error 403 Forbidden - This request is blocked.

For security reasons you can't connect to the server for this app or website at this time.

It maybe that you have too many requests or the illegal request payload is identified as an attack.

Please try again later.

ERC-20 合约概览 | ethereum.org

20 合约概览 | ethereum.org跳转至主要内容学习用法构建参与研究搜索​​​​语言 ZH帮助更新此页面本页面有新版本,但现在只有英文版。请帮助我们翻译最新版本。翻译页面没有错误!此页面未翻译,因此特意以英文显示。不再显示ERC-20 合约概览solidityerc-20初学者Ori Pomerantz 2021年3月9日35 分钟阅读 minute read在本页面简介接口实际合约导入声明合约定义变量的定义构造函数用户接口函数读取代币信息代币转账许可额度函数修改代币信息的函数修改小数点设置变量钩子简介以太坊最常见的用途之一是由一个团队来打造一种可以交易的代币,在某种意义上是他们自己的货币。 这些代币通常遵循一个标准, ERC-20。 此标准使得人们能够以此来开发可以用于所有 ERC-20 代币的工具,如流动资金池和钱包。 在这篇文章中,我们将带领大家分析 OpenZeppelin Solidity ERC20 实现(opens in a new tab)以及 ERC20 接口定义(opens in a new tab)。这里使用的是附加说明的源代码。 如果想要实现 ERC-20, 请阅读此教程(opens in a new tab)。接口像 ERC-20 这样的标准,其目的是允许符合标准的多种代币,都可以在应用程序之间进行互操作,例如钱包和分布式交易所。 为实现这个目的,我们要创建一个 接口(opens in a new tab)。 任何需要使用代币合约的代码 可以在接口中使用相同的定义,并且与使用它的所有代币合约兼容。无论是像 MetaMask 这样的钱包、 诸如 etherscan.io 之类的去中心化应用程序,或一种不同的合约,例如流动资金池。如果您是一位经验丰富的程序员,您可能记得在 Java(opens in a new tab) 中,甚至在 C 头文件(opens in a new tab) 中看到过类似的构造。这是来自 OpenZeppelin 的 ERC-20 接口(opens in a new tab) 的定义。 这是将人类可读标准(opens in a new tab)转换为 Solidity 代码。 当然, 接口本身并不定义如何做事。 这一点在下文合约的源代码中作了解释。1// SPDX-License-Identifier: MIT 复制Solidity 文件中一般需要标识软件许可证。 您可以在这里看到许可证列表(opens in a new tab)。 如果需要不同的 许可证,只需在注释中加以说明。1pragma solidity >=0.6.0 <0.8.0; 复制Solidity 语言仍在迅速地发展,新版本可能不适配旧的代码 (请点击此处查看(opens in a new tab))。 因此,最好不仅指定一个最低的 语言版本,也指定一个最高的版本,即测试过代码的最新版本。1/**2 * @dev Interface of the ERC20 standard as defined in EIP.3 */ 复制注释中的 @dev 是 NatSpec 格式(opens in a new tab)的一部分,用于 从源代码生成文档。1interface IERC20 { 复制根据惯例,接口名称以 I 开头。1 /**2 * @dev Returns the amount of tokens in existence.3 */4 function totalSupply() external view returns (uint256); 复制此函数标记为 external,表示它只能从合约之外调用(opens in a new tab)。 它返回的是合约中代币的总供应量 这个值按以太坊中最常见的类型返回,即无符号的 256 位(256 位是 以太坊虚拟机的原生字长宽度)。 此函数也是视图 view 类型,这意味着它不会改变合约状态,这样它可以在单个节点上执行,而不需要在区块链的每个节点上执行。 这类函数不会生成交易,也不会消耗燃料。注意:理论上讲,合约创建者可能会通过返回比实际数量少的总供应量来做骗局,让每个代币 比实际看起来更有价值。 然而,这种担忧忽视了区块链的真正内涵。 所有在区块链上发生的事情都要通过每个节点 进行验证。 为了实现这一点,每个合约的机器语言代码和存储都可以在每个节点上找到。 虽然无需发布您的合约代码,但这样其它人都不会认真对待您,除非您发布源代码和用于编译的 Solidity 版本,这样人们可以用它来验证您提供的机器语言代码。 例如,请查看此合约(opens in a new tab)。1 /**2 * @dev Returns the amount of tokens owned by `account`.3 */4 function balanceOf(address account) external view returns (uint256); 复制顾名思义,balanceOf 返回一个账户的余额。 以太坊帐户在 Solidity 中通过 address 类型识别,该类型有 160 位。 它也是 external 和 view 类型。1 /**2 * @dev Moves `amount` tokens from the caller's account to `recipient`.3 *4 * Returns a boolean value indicating whether the operation succeeded.5 *6 * Emits a {Transfer} event.7 */8 function transfer(address recipient, uint256 amount) external returns (bool); 复制transfer 函数将代币从调用者地址转移到另一个地址。 这涉及到状态的更改,所以它不是 view 类型。 当用户调用此函数时,它会创建交易并消耗燃料。 还会触发一个 Transfer 事件,以通知区块链上的所有人。该函数有两种输出,对应两种不同的调用:直接从用户接口调用函数的用户。 此类用户通常会提交一个交易 并且不会等待响应,因为响应可能需要无限期的时间。 用户可以查看交易收据 (通常通过交易哈希值识别)或者查看 Transfer 事件,以确定发生了什么。将函数作为整个交易一部分调用的其他合约 这些合约可立即获得结果, 由于它们在相同的交易里运行,因此可以使用函数返回值。更改合约状态的其他函数创建的同类型输出。限额允许帐户使用属于另一位所有者的代币。 比如,当合约作为卖方时,这个函数就很实用。 合约无法 监听事件,如果买方要将代币直接转给卖方合约, 该合约无法知道已经获得付款。 因此,买方允许 卖方合约支付一定的额度,而让卖方转账相应金额。 这通过卖方合约调用的函数完成,这样卖方合约 可以知道是否成功。1 /**2 * @dev Returns the remaining number of tokens that `spender` will be3 * allowed to spend on behalf of `owner` through {transferFrom}. This is4 * zero by default.5 *6 * This value changes when {approve} or {transferFrom} are called.7 */8 function allowance(address owner, address spender) external view returns (uint256); 复制allowance 函数允许任何人查询一个 地址 (owner) 给另一个地址 (spender) 的许可额度。1 /**2 * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.3 *4 * Returns a boolean value indicating whether the operation succeeded.5 *6 * IMPORTANT: Beware that changing an allowance with this method brings the risk7 * that someone may use both the old and the new allowance by unfortunate8 * transaction ordering. One possible solution to mitigate this race9 * condition is to first reduce the spender's allowance to 0 and set the10 * desired value afterwards:11 * https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472912 *13 * Emits an {Approval} event.14 */15 function approve(address spender, uint256 amount) external returns (bool);显示全部 复制approve 函数创建了一个许可额度。 请务必阅读关于 如何避免函数被滥用的信息。 在以太坊中,您可以控制自己交易的顺序, 但无法控制其他方交易的执行顺序, 除非在看到其他方的交易发生之前 不提交您自己的交易。1 /**2 * @dev Moves `amount` tokens from `sender` to `recipient` using the3 * allowance mechanism. `amount` is then deducted from the caller's4 * allowance.5 *6 * Returns a boolean value indicating whether the operation succeeded.7 *8 * Emits a {Transfer} event.9 */10 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);显示全部 复制最后,消费者使用 transferFrom 函数用来使用许可额度。12 /**3 * @dev Emitted when `value` tokens are moved from one account (`from`) to4 * another (`to`).5 *6 * Note that `value` may be zero.7 */8 event Transfer(address indexed from, address indexed to, uint256 value);910 /**11 * @dev Emitted when the allowance of a `spender` for an `owner` is set by12 * a call to {approve}. `value` is the new allowance.13 */14 event Approval(address indexed owner, address indexed spender, uint256 value);15}显示全部 复制在 ERC-20 合约状态发生变化时就会激发这些事件。实际合约这是实现 ERC-20 标准的实际合约, 摘自此处(opens in a new tab)。 不能照原样使用,但可以 通过继承(opens in a new tab)将其扩展,使之可用。1// SPDX-License-Identifier: MIT2pragma solidity >=0.6.0 <0.8.0; 复制导入声明除了上述接口定义外,合约定义还要导入两个其他文件:12import "../../GSN/Context.sol";3import "./IERC20.sol";4import "../../math/SafeMath.sol"; 复制GSN/Context.sol 是使用 OpenGSN(opens in a new tab) 所需的文件,该系统允许用户在没有以太币的情况下 使用区块链。 请注意,这里的文件是旧版本,如果需要集成 OpenGSN, 请使用此教程(opens in a new tab)。SafeMath 库(opens in a new tab),用于 完成没有溢出问题的加法和减法。 这非常必要,否则会出现,用户仅有一个代币,花掉 两个代币后,反而有了 2^256-1 个代币。这里的注释说明了合约的目的。1/**2 * @dev Implementation of the {IERC20} interface.3 *4 * This implementation is agnostic to the way tokens are created. This means5 * that a supply mechanism has to be added in a derived contract using {_mint}.6 * For a generic mechanism see {ERC20PresetMinterPauser}.7 *8 * TIP: For a detailed writeup see our guide9 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How10 * to implement supply mechanisms].11 *12 * We have followed general OpenZeppelin guidelines: functions revert instead13 * of returning `false` on failure. This behavior is nonetheless conventional14 * and does not conflict with the expectations of ERC20 applications.15 *16 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.17 * This allows applications to reconstruct the allowance for all accounts just18 * by listening to said events. Other implementations of the EIP may not emit19 * these events, as it isn't required by the specification.20 *21 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}22 * functions have been added to mitigate the well-known issues around setting23 * allowances. See {IERC20-approve}.24 */25显示全部 复制合约定义1contract ERC20 is Context, IERC20 { 复制此行为 OpenGSN 指定继承,在本例中来自上面的 IERC20 和 Context。12 using SafeMath for uint256;3 复制此行将 SafeMath 库附加到 uint256 类型。 您可以在 此处(opens in a new tab)找到此程序库。变量的定义这些定义具体指定了合约的状态变量。 虽然声明这些变量为 private,但 这只意味着区块链上的其他合约无法读取它们。 区块链上 没有秘密,所有节点上的软件在每个区块上 都有每个合约的状态。 根据惯例,状态变量名称为 _。前两个变量是映射(opens in a new tab), 表示它们的结果与关联数组(opens in a new tab)相同, 不同之处在于关键词为数值。 存储空间仅分配给数值不同于 默认值(零)的条目。1 mapping (address => uint256) private _balances; 复制第一个映射,_balances,是代币地址和对应的余额。 要查看 余额,请使用此语法:_balances[
]。1 映射 (address => mapping (address => uint256)) private _allowances; 复制此变量,_allowances 存储之前提到过的许可限额。 第一个索引是 代币的所有者,第二个索引是获得许可限额的合约。 要查询地址 A 可以 从地址 B 账户中支出的额度,请使用 _allowances[B][A]。1 uint256 private _totalSupply; 复制顾名思义,此变量记录代币供应总量。1 string private _name;2 string private _symbol;3 uint8 private _decimals; 复制这三个变量用于提高可读性。 前两项的含义不言自明,但 _decimals 并非如此。一方面,以太坊不具有浮点数或分数变量。 另一方面, 人们希望能够拆分代币。 人们选择将黄金做为货币的一个原因是 当有人想要购买一只牛的一小部分时,就很难找零。解决方案是保持整数值,但是计数时使用一个价值非常小的分数代币, 而不是真正的代币。 就以太币而言,分数代币称为 wei,10^18 个 wei 等于一个 以太币。 在撰写本文时,10,000,000,000,000 wei 约等于一美分或欧分。应用程序需要知道如何显示代币余额。 如果某位用户有 3,141,000,000,000,000,000 wei,那是否是 3.14 个以太币? 31.41 个以太币? 还是 3,141 个以太币? 对于以太币,10^18 个 wei 等于 1 个以太币,但对于您的 代币,您可以选择一个不同的值。 如果无法合理拆分代币,您可以将 _decimals 值设为零。 如果想要使用与以太币相同的标准,请使用 18。构造函数1 /**2 * @dev Sets the values for {name} and {symbol}, initializes {decimals} with3 * a default value of 18.4 *5 * To select a different value for {decimals}, use {_setupDecimals}.6 *7 * All three of these values are immutable: they can only be set once during8 * construction.9 */10 constructor (string memory name_, string memory symbol_) public {11 _name = name_;12 _symbol = symbol_;13 _decimals = 18;14 }显示全部 复制构造函数在首次创建合约时调用。 根据惯例,函数参数名为 _。用户接口函数1 /**2 * @dev Returns the name of the token.3 */4 function name() public view returns (string memory) {5 return _name;6 }78 /**9 * @dev Returns the symbol of the token, usually a shorter version of the10 * name.11 */12 function symbol() public view returns (string memory) {13 return _symbol;14 }1516 /**17 * @dev Returns the number of decimals used to get its user representation.18 * For example, if `decimals` equals `2`, a balance of `505` tokens should19 * be displayed to a user as `5,05` (`505 / 10 ** 2`).20 *21 * Tokens usually opt for a value of 18, imitating the relationship between22 * ether and wei. This is the value {ERC20} uses, unless {_setupDecimals} is23 * called.24 *25 * NOTE: This information is only used for _display_ purposes: it in26 * no way affects any of the arithmetic of the contract, including27 * {IERC20-balanceOf} and {IERC20-transfer}.28 */29 function decimals() public view returns (uint8) {30 return _decimals;31 }显示全部 复制这些函数,name、symbol 和 decimals 帮助用户界面了解合约,从而正常演示合约。返回类型为 string memory,意味着返回在内存中存储的字符串。 变量,如 字符串,可以存储在三个位置:有效时间合约访问燃料成本内存函数调用读/写几十到几百不等(距离越远费用越高)调用数据函数调用只读不可用作返回类型,只可用作函数参数存储直到被修改读/写高(读取需要 800,写入需要 2 万)在这种情况下,memory 是最好的选择。读取代币信息这些是提供代币信息的函数,不管是总量还是 账户余额。1 /**2 * @dev See {IERC20-totalSupply}.3 */4 function totalSupply() public view override returns (uint256) {5 return _totalSupply;6 } 复制totalSupply 函数返回代币的总量。1 /**2 * @dev See {IERC20-balanceOf}.3 */4 function balanceOf(address account) public view override returns (uint256) {5 return _balances[account];6 } 复制读取一个帐户的余额。 请注意,任何人都可以查看他人账户的余额。 试图隐藏此信息没有意义,因为它在每个节点上 都是可见的。 区块链上没有秘密代币转账1 /**2 * @dev See {IERC20-transfer}.3 *4 * Requirements:5 *6 * - `recipient` cannot be the zero address.7 * - the caller must have a balance of at least `amount`.8 */9 function transfer(address recipient, uint256 amount) public virtual override returns (bool) {显示全部 复制调用 transfer 函数以从发送人的帐户转移代币到另一个帐户。 注意 虽然函数返回的是布尔值,但那个值始终为真实值。 如果转账失败, 合约会撤销调用。1 _transfer(_msgSender(), recipient, amount);2 return true;3 } 复制_transfer 函数完成了实际工作。 这是一个私有函数,只能由 其他合约函数调用。 根据常规,私人函数名为 _,与状态 变量相同。在 Solidity 中,我们通常使用 msg.sender 代表信息发送人。 然而,这会破坏 OpenGSN(opens in a new tab) 的规则。 如果我们想使用代币进行交易而不用以太币,我们 需要使用 _msgSender()。 对于正常交易,它返回 msg.sender,但是对于没有以太币的交易, 则返回原始签名而不是传递信息的合约。许可额度函数这些是实现许可额度功能的函数:allowance、approve、transferFrom 和 _approve。 此外,除基本标准外,OpenZeppelin 实现还包含了一些能够提高 安全性的功能:increaseAllowance 和 decreaseAllowance。许可额度函数1 /**2 * @dev See {IERC20-allowance}.3 */4 function allowance(address owner, address spender) public view virtual override returns (uint256) {5 return _allowances[owner][spender];6 } 复制allowance 函数使每个人都能检查任何许可额度。审批函数1 /**2 * @dev See {IERC20-approve}.3 *4 * Requirements:5 *6 * - `spender` cannot be the zero address.7 */8 function approve(address spender, uint256 amount) public virtual override returns (bool) { 复制调用此函数以创建许可额度。 它与上述 transfer 函数相似:该函数仅调用一个完成真正工作的内部函数(本例中为 _approve)。函数要么返回 true(如果成功),要么撤销(如果失败)。1 _approve(_msgSender(), spender, amount);2 return true;3 } 复制我们使用内部函数尽量减少发生状态变化之处。 任何可以改变状态的 函数都是一种潜在的安全风险,需要对其安全性进行审核。 这样我们就能减少出错的机会。TransferFrom 函数这个函数被消费者用于使用许可额度。 这里需要两步操作:将消费的金额转账, 并在许可额度中减去这笔金额。1 /**2 * @dev See {IERC20-transferFrom}.3 *4 * Emits an {Approval} event indicating the updated allowance. This is not5 * required by the EIP. See the note at the beginning of {ERC20}.6 *7 * Requirements:8 *9 * - `sender` and `recipient` cannot be the zero address.10 * - `sender` must have a balance of at least `amount`.11 * - the caller must have allowance for ``sender``'s tokens of at least12 * `amount`.13 */14 function transferFrom(address sender, address recipient, uint256 amount) public virtual15 override returns (bool) {16 _transfer(sender, recipient, amount);显示全部 复制a.sub(b, "message") 函数调用做了两件事。 首先,它计算了 a-b,这是新的许可额度。 之后,它检查这一结果是否为负数。 如果结果为负,将撤销调用,并发出相应的信息。 请注意,撤销调用后,之前在调用中完成的任何处理都会被忽略,所以我们不需要 撤消 _transfer。1 _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount,2 "ERC20: transfer amount exceeds allowance"));3 return true;4 } 复制OpenZeppelin 安全加法将许可额度从一个非零值设定为另一个非零值是有危险的, 因为您只能控制自己的交易顺序,而无法控制其他人的交易顺序。 假设现在有两个用户,天真的 Alice 和不诚实的 Bill。 Alice 想要从 Bill 处获取一些服务, 她认为值五个代币,所以她给了 Bill 五个代币的许可额度。之后有了一些变化,Bill 的价格提高到了十个代币。 Alice 仍然想要购买服务,就发送了一笔交易,将 Bill 的许可额度设置为 10。 当 Bill 在交易池中看到这个新的交易时, 他就会发送一笔交易,以花费 Alice 的五个代币,并且设定高得多的 燃料价格,这样就会更快挖矿。 这样的话,Bill 可以先花五个代币,然后 当 Alice 的新许可额度放款后,他就可以再花费十个代币,这样总共花费了 15 个代币, 超过了 Alice 本欲授权的金额。 这种技术叫做 抢先交易(opens in a new tab)Alice 的交易Alice 的随机数Bill 的交易Bill 的随机数Bill 的许可额度Bill 从 Alice 处获得的总收入approve(Bill, 5)1050transferFrom(Alice, Bill, 5)10,12305approve(Bill, 10)11105transferFrom(Alice, Bill, 10)10,124015为了避免这个问题,有两个函数(increaseAllowance 和 decreaseAllowance)使您 能够修改指定数额的许可额度。 所以,如果 Bill 已经花费了五个代币, 他就只能再花五个代币。 根据时间的不同,有两种方法可以生效, 这两种方法都会使 Bill 最终只得到十个代币:A:Alice 的交易Alice 的随机数Bill 的交易Bill 的随机数Bill 的许可额度Bill 从 Alice 处获得的总收入approve(Bill, 5)1050transferFrom(Alice, Bill, 5)10,12305increaseAllowance(Bill, 5)110+5 = 55transferFrom(Alice, Bill, 5)10,124010B:Alice 的交易Alice 的随机数Bill 的交易Bill 的随机数Bill 的许可额度Bill 从 Alice 处获得的总收入approve(Bill, 5)1050increaseAllowance(Bill, 5)115+5 = 100transferFrom(Alice, Bill, 10)10,1240101 /**2 * @dev Atomically increases the allowance granted to `spender` by the caller.3 *4 * This is an alternative to {approve} that can be used as a mitigation for5 * problems described in {IERC20-approve}.6 *7 * Emits an {Approval} event indicating the updated allowance.8 *9 * Requirements:10 *11 * - `spender` cannot be the zero address.12 */13 function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {14 _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));15 return true;16 }显示全部 复制a.add(b) 函数是一个安全加法。 在罕见的情况下,a+b>=2^256,不会发生 普通加法会出现的溢出错误。12 /**3 * @dev Atomically decreases the allowance granted to `spender` by the caller.4 *5 * This is an alternative to {approve} that can be used as a mitigation for6 * problems described in {IERC20-approve}.7 *8 * Emits an {Approval} event indicating the updated allowance.9 *10 * Requirements:11 *12 * - `spender` cannot be the zero address.13 * - `spender` must have allowance for the caller of at least14 * `subtractedValue`.15 */16 function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {17 _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue,18 "ERC20: decreased allowance below zero"));19 return true;20 }显示全部 复制修改代币信息的函数这些是完成实际工作的四个函数:_transfer、_mint、_burn 和 _approve。_transfer 函数 {#_transfer}1 /**2 * @dev Moves tokens `amount` from `sender` to `recipient`.3 *4 * This is internal function is equivalent to {transfer}, and can be used to5 * e.g. implement automatic token fees, slashing mechanisms, etc.6 *7 * Emits a {Transfer} event.8 *9 * Requirements:10 *11 * - `sender` cannot be the zero address.12 * - `recipient` cannot be the zero address.13 * - `sender` must have a balance of at least `amount`.14 */15 function _transfer(address sender, address recipient, uint256 amount) internal virtual {显示全部 复制_transfer 这个函数将代币从一个账户转到另一个账户。 有两个函数调用它,分别是 transfer(从发送人本人账户发送)和 transferFrom(使用许可额度,从其他人的账户发送)。1 require(sender != address(0), "ERC20: transfer from the zero address");2 require(recipient != address(0), "ERC20: transfer to the zero address"); 复制实际上以太坊中没有人拥有零地址(即不存在对应公钥可以转换为零地址的私钥)。 有人使用该地址时,通常是一个软件漏洞,所以 如果将零地址用作发送人或接收人,交易将失败。1 _beforeTokenTransfer(sender, recipient, amount);2 复制使用该合约有两种方法:将其作为模板,编写自己的代码从它继承(opens in a new tab)一个合约,并且重写您需要修改的函数第二种方法要好得多,因为 OpenZeppelin ERC-20 代码已经过审核,其安全性也已得到证实。 当您的合约继承它时, 可以清楚地表明修改了哪些函数,只需要审核这些特定的函数,人们就会信任您的合约。代币每次易手时,通常都需要调用一个函数。 然而,_transfer 是一个非常重要的函数, 重新编写可能会不安全(见下文),所以最好不要重写。 解决方案是重写 _beforeTokenTransfer 函数,这是一个挂钩函数(opens in a new tab)。 您可以重写此函数,之后每次转账都会调用它。1 _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");2 _balances[recipient] = _balances[recipient].add(amount); 复制这些是实际实现转账的代码。 请注意,将转账金额从发送人帐户上扣除,然后加到接收人帐户之间, 不得有任何动作。 这很重要,因为如果 中间调用不同的合约,可能会被用来骗过这个合约。 目前转账为最小操作单元,即中间什么都不会发生。1 emit Transfer(sender, recipient, amount);2 } 复制最后,激发一个 Transfer 事件。 智能合约无法访问事件,但区块链外运行的代码 可以监听事件并对其作出反应。 例如,钱包可以跟踪所有者获得更多代币事件。_mint 和 _burn 函数 {#_mint-and-_burn}这两个函数(_mint 和 _burn)修改代币的总供应量。 它们都是内部函数,在原有合约中没有任何调用它们的函数。 因此,仅通过继承合约并添加您自己的逻辑, 来决定在什么条件下可以铸造新代币或消耗现有代币时, 它们才是有用的。注意:每一个 ERC-20 代币都通过自己的业务逻辑来决定代币管理。 例如,一个固定供应总量的合约可能只在构造函数中调用 _mint,而从不调用 _burn。 一个销售代币的合约 将在支付时调用 _mint,并大概在某个时间点调用 _burn, 以避免过快的通货膨胀。1 /** @dev Creates `amount` tokens and assigns them to `account`, increasing2 * the total supply.3 *4 * Emits a {Transfer} event with `from` set to the zero address.5 *6 * Requirements:7 *8 * - `to` cannot be the zero address.9 */10 function _mint(address account, uint256 amount) internal virtual {11 require(account != address(0), "ERC20: mint to the zero address");12 _beforeTokenTransfer(address(0), account, amount);13 _totalSupply = _totalSupply.add(amount);14 _balances[account] = _balances[account].add(amount);15 emit Transfer(address(0), account, amount);16 }显示全部 复制当代币总数发生变化时,请务必更新 _totalSupply。1 /**2 * @dev Destroys `amount` tokens from `account`, reducing the3 * total supply.4 *5 * Emits a {Transfer} event with `to` set to the zero address.6 *7 * Requirements:8 *9 * - `account` cannot be the zero address.10 * - `account` must have at least `amount` tokens.11 */12 function _burn(address account, uint256 amount) internal virtual {13 require(account != address(0), "ERC20: burn from the zero address");1415 _beforeTokenTransfer(account, address(0), amount);1617 _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");18 _totalSupply = _totalSupply.sub(amount);19 emit Transfer(account, address(0), amount);20 }显示全部_burn 函数与 _mint 函数几乎完全相同,但它们的方向相反。_approve 函数 {#_approve}这是实际设定许可额度的函数。 请注意,它允许所有者指定 一个高于所有者当前余额的许可额度。 这是允许的,因为在转账时 会核查余额,届时可能不同于 创建许可额度时的金额。1 /**2 * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.3 *4 * This internal function is equivalent to `approve`, and can be used to5 * e.g. set automatic allowances for certain subsystems, etc.6 *7 * Emits an {Approval} event.8 *9 * Requirements:10 *11 * - `owner` cannot be the zero address.12 * - `spender` cannot be the zero address.13 */14 function _approve(address owner, address spender, uint256 amount) internal virtual {15 require(owner != address(0), "ERC20: approve from the zero address");16 require(spender != address(0), "ERC20: approve to the zero address");1718 _allowances[owner][spender] = amount;显示全部 复制激发一个 Approval 事件。 根据应用程序的编写, 消费者合约可以从代币所有者或监听事件的服务器获知审批结果。1 emit Approval(owner, spender, amount);2 }3 复制修改小数点设置变量123 /**4 * @dev Sets {decimals} to a value other than the default one of 18.5 *6 * WARNING: This function should only be called from the constructor. Most7 * applications that interact with token contracts will not expect8 * {decimals} to ever change, and may work incorrectly if it does.9 */10 function _setupDecimals(uint8 decimals_) internal {11 _decimals = decimals_;12 }显示全部 复制此函数修改了 >_decimals 变量,此变量用于设置用户接口如何计算金额。 您应该从构造函数里面调用。 在之后的任何时候调用都是不正当的, 应用程序一般不会处理。钩子12 /**3 * @dev Hook that is called before any transfer of tokens. This includes4 * minting and burning.5 *6 * Calling conditions:7 *8 * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens9 * will be to transferred to `to`.10 * - when `from` is zero, `amount` tokens will be minted for `to`.11 * - when `to` is zero, `amount` of ``from``'s tokens will be burned.12 * - `from` and `to` are never both zero.13 *14 * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].15 */16 function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }17}显示全部 复制这是转账过程中要调用的挂钩函数。 该函数是空的,但如果你需要 它做一些事情,只需覆盖它即可。总结复习一下,这些是我认为此合约中最重要的概念(你们的看法可能与我不同)区块链上没有秘密 智能合约可以访问的任何信息 都可以提供给全世界。您可以控制自己交易的订单,但在其他人的交易发生时, 则不能控制。 这就是为什么更改许可额度时会有风险,因为它 允许消费者花掉这两个许可额度的总和。uint256 类型值的溢出。 换言之,0-1=2^256-1。 如果这不是预期的 行为,您必须自行检查(或使用 SafeMath 库执行该服务)。 请注意, Solidity 0.8.0(opens in a new tab) 中对此进行了更改。将特定类型变量的状态改变放在一个特定的地方,这样可以使审核更容易。 这就是我们使用以下等函数的原因,例如 _approve 函数,它可以被approve、transferFrom、 increaseAllowance 和 decreaseAllowance 调用。状态更改应为最小操作单元,其中没有任何其他动作 (如在 _transfer 中所见)。 这是因为在状态更改期间,会出现不一致的情况。 例如, 在减少发送人的余额,和增加接收人的余额之间, 代币总量会小于应有总量。 如果在这两个时刻之间有任何操作, 特别是调用不同的合约,则可能出现滥用。现在您已经了解了 OpenZeppelin ERC-20 合约是怎么编写的, 尤其是如何使之更加安全,您即可编写自己的安全合约和应用程序。m上次修改时间: @mdranger(opens in a new tab), Invalid DateTime查看贡献者本教程对你有帮助吗?是否编辑页面(opens in a new tab)在本页面简介接口实际合约导入声明合约定义变量的定义构造函数用户接口函数读取代币信息代币转账许可额度函数修改代币信息的函数修改小数点设置变量钩子网站最后更新: 2024年3月13日(opens in a new tab)(opens in a new tab)(opens in a new tab)学习学习中心什么是以太坊?什么是以太币 (ETH)?以太坊钱包什么是 Web3?智能合约Gas fees运行节点以太坊安全和预防欺诈措施测试中心以太坊词汇表用法指南选择钱包获取以太币Dapps - 去中心化应用稳定币NFT - 非同质化代币DeFi - 去中心化金融DAO - 去中心化自治组织去中心化身份质押ETH二层网络构建构建者首页教程相关文档通过编码来学习设置本地环境资助基础主题用户体验/用户界面设计基础Enterprise - Mainnet EthereumEnterprise - Private Ethereum参与社区中心在线社区以太坊活动为 ethereum.org 做贡献翻译计划以太坊漏洞悬赏计划以太坊基金会以太坊基金会的博客(opens in a new tab)生态系统支持方案(opens in a new tab)Devcon(opens in a new tab)研究以太坊白皮书以太坊路线图安全性增强以太坊技术史开放研究以太坊改进提案 (Eip)以太坊治理关于我们以太坊品牌资产Code of conduct工作机会隐私政策使用条款缓存政策联系我们(opens in a new tab)本页面对你有帮

2023年最佳ERC20钱包完整列表

2023年最佳ERC20钱包完整列表

All

精选

最值得投资的新加密货币项目

最佳边动边赚型加密货币

最佳长线投资加密项目

价值低于1美元最佳加密货币

上涨最多十大加密货币

最佳以太坊体育博彩网站

最佳比特币真人赌场

最佳元宇宙赌场

新闻

比特币新闻

以太坊新闻

NFT新闻

DeFi新闻

替代币新闻

区块链新闻

新闻发布

赞助

加密货币新闻交易

产业对谈

快速评论

财经新闻

科技新闻

独家新闻

焦点

观点

人物

视频

比特币

以太坊

替代币

区块链

市场趋势

加密货币安全

指南

比特币

以太坊

替代币

加密货币

首次代币发行

Events

交易所

货币

价格追踪器

新闻

比特币新闻

以太坊新闻

NFT新闻

DeFi新闻

替代币新闻

区块链新闻

新闻发布

赞助

加密货币新闻交易

产业对谈

快速评论

财经新闻

科技新闻

独家新闻

焦点

观点

人物

视频

比特币

以太坊

替代币

区块链

市场趋势

加密货币安全

指南

比特币

以太坊

替代币

加密货币

首次代币发行

交易所

工具

价格追踪器

货币

精选

最值得投资的新加密货币项目

最佳边动边赚型加密货币

2023年让你致富的13种加密货币

价值低于1美元最佳加密货币

上涨最多十大加密货币

最佳以太坊体育博彩网站

最佳比特币真人赌场

最佳元宇宙赌场

CN

English

Deutsch

Français

Русский

Türkçe

日本語

Nederlands

Italiano

العربية

فارسی

中文

Español

Português

Svenska

Dansk

Norsk Bokmål

Suomi

한국어

Indonesia

Tiếng Việt

ไทย

全部的

CN+

English

Deutsch

Français

Русский

Türkçe

日本語

Nederlands

Italiano

العربية

فارسی

中文

Español

Português

Svenska

Dansk

Norsk Bokmål

Suomi

한국어

Indonesia

Tiếng Việt

ไทย

Cryptonews

Exclusives

2023年最佳ERC20钱包完整列表

2023年最佳ERC20钱包完整列表

Esther Hui

十二月 13, 2023 20:13 GMT+8

| 2 min read

正在寻找最佳的ERC20钱包,但不确定从哪里开始?需要考虑许多因素,例如托管、费用、安全性、支持的网络,以及是否提供质押和兑换工具。在本指南中,我们将回顾2023年的7款最佳ERC20钱包。2023年最佳ERC20钱包列表

以下是投资者的7款最佳ERC20钱包:

Best Wallet – 最适合存储ERC20代币的综合性加密钱包,最佳钱包是一款非托管钱包,通过其内置的DEX提供去中心化存储和代币交易。然而,它不仅仅是一个钱包,还提供质押、增强安全性以及对热门加密货币和新项目的独特洞察。通过质押其原生代币$BEST,将会空投给活跃用户,用户还可以享受免费交易。

eToro – 一家受监管的钱包和交易所,提供托管存储。它代表用户保护私钥,这对初学者来说很有吸引力。除了存储ERC20代币外,eToro还允许用户以每滑1%的费率交易加密货币。eToro钱包还配备了一个具有灵活条款和竞争性年收益率的质押工具。

Trust Wallet – 与所有ERC20代币兼容,还支持数十个其他加密货币网络。如果没有预先列出,可以通过合同地址手动添加ERC20代币。Trust Wallet提供免费的质押和代币交换。它还支持ERC20的dApps,如Yearn.finance、UniSwap和OpenSea。

MetaMask – 另一款非托管钱包,支持所有ERC20代币。它免费使用,并作为iOS和Android应用程序提供。MetaMask还作为Chrome、Brave、Firefox和Edge的浏览器扩展程序提供。MetaMask具有内置的投资组合仪表板,支持质押和代币交换。

Ledger – 被认为是最安全的ERC20钱包之一,Ledger通过小型硬件设备提供冷存储。可以选择三种不同的Ledger型号,价格从79美元到279美元不等。所有Ledger型号都将私钥保存在离线状态,因此ERC20代币持有者可以放心持有而不担心被黑客攻击。

Coinbase Wallet – 面向iOS和Android用户的去中心化钱包。它支持各种网络上的自定义代币,包括以太坊。因此,它支持所有ERC20代币。使用Coinbase的去中心化钱包无需开设账户。事实上,Coinbase钱包可以匿名使用。

币安 – 在一个平台下提供了ERC20钱包和交易所。用户只需登录他们的账户在两者之间转移资金。Binance支持超过350种加密货币,包括主要的ERC20代币。Binance还提供储蓄账户和其他DeFi产品。

最佳ERC20钱包:全面评测

随着市场上不断增加的ERC20钱包数量,选择哪个选项可能会让人感到困难。为了帮助您澄清疑虑,我们现在将对2023年的7款最佳ERC20钱包进行全面评测。1. Best Wallet – 存储和管理ERC20代币的综合最佳钱包我们将Best Wallet评为综合最佳的ERC20钱包,因为它内置了支持所有450,000多个ERC20代币以及其他链上代币(如币安智能链)的去中心化交易所。这款去中心化、非托管的多链钱包还具备其他钱包所不具备的功能,使其不仅仅是一个交易和存储代币的地方。除了内置的DEX,它还具有其他DeFi功能,这些功能是通过持有原生ERC20代币$BEST实现的,该代币即将推出。该代币提供质押奖励,还使持有者在交易其他代币时享有降低的费用。Best Wallet还提供了有关热门加密项目、空投和NFT收藏品的独特洞察,以及提供新代币ICO和预售的早期访问。此外,我们喜欢Best Wallet内置了安全工具 – 包括生物识别和多因素认证。Best Wallet用户可以在不离开钱包的情况下立即交换ERC20代币。用户还可以质押代币以赚取被动奖励。虽然Best Wallet还支持法定货币支付,但用户应该注意会收取4%的费用。然而,支付是由在美国和欧盟获得许可的监管实体Wert处理的。Best Wallet还支持比特币、达世币、莱特币、狗狗币以及许多其他主要加密货币。这是一个去中心化的钱包,因此用户可以匿名存储、发送和接收ERC20代币。只有用户可以访问他们的私钥,这使他们完全控制所存储的加密货币。该钱包刚刚发布,写作时并未推出所有功能。然而,$BEST代币将在不久的将来空投给活跃用户,其中将分发最大供应量的10%。

ERC20钱包类型

托管方式

支持的代币

购买ERC20代币的费用

应用程序?

质押/利息?

质押/利息率

桌面钱包和移动应用

非托管

所有ERC20代币,还支持其他区块链,包括比特币、币安智能链、XRP和Avalanche。

由其支付处理器WERT收取4%的费用

是,内置的质押工具

未指定

优点

2023年综合最佳ERC20钱包

与所有ERC20代币兼容,甚至包括未上市的代币

内置DEX和多链功能

对新的加密项目、NFT、空投提供独特洞察

早期访问新代币和降低的费用

$BEST代币空投

缺点

在撰写时,尚未推出所有功能

点击这里访问 Best Wallet

 2. eToro – 受监管交易所支持的Web和移动钱包eToro是考虑的下一个最佳ERC20钱包,也是最佳的托管钱包。这个钱包提供商得到了多个一流牌照的支持,背后有一个成熟的交易所。监管来自FINRA(美国)、ASIC(澳大利亚)、FCA(英国)和CySEC(塞浦路斯)。这确保了ERC20代币由一家认真对待监管的知名提供商保管。eToro钱包是托管的,因此投资者无需自行保管私钥。eToro设有全天候的风险管理团队,并将大部分加密货币保存在冷钱包中。此外,访问该钱包需要两因素认证。我们还喜欢eToro钱包可以通过其iOS和Android的原生应用程序以及在线方式访问。这两个选择都用户友好,而且功能丰富。例如,用户可以自动质押代币,无需选择加入。eToro将高达90%的质押奖励直接分发到用户的钱包中。eToro还提供支持加密货币对法定货币的交易所。这意味着用户可以用美元交易ERC20代币。此外,eToro支持通过借记/信用卡和电子钱包进行法定货币存款。以美元进行存款时不收取费用(其他货币为0.5%)。此外,eToro钱包支持复制交易。这是一种创新工具,允许用户复制经验丰富的加密货币交易员。所有仓位将自动按比例复制。

ERC20钱包类型

托管方式

支持的代币

购买ERC20代币的费用

应用程序?

质押/利息?

质押/利息率

Web钱包和移动应用

托管

90多种加密货币,包括比特币、XRP、以太坊和一系列ERC20代币

1%的交易佣金。存入美元无费用。非美元存款费用为0.5%。

是,支持无锁定期的质押。

分发高达90%的质押奖励。

优点

受监管的ERC20钱包,具有托管存储

账户受到两因素认证和全天候风险管理团队的保护

大多数客户拥有的加密货币存储在冷钱包中

支持超过90种加密货币

以1%的佣金交易ERC20代币

复制交易工具支持被动加密货币投资

缺点

用户需要在访问钱包之前上传他们的身份证明

从Web钱包转移代币到eToro应用程序会产生2%的费用

点击这里访问eToro

加密资产是高度波动的投资产品。您的资本面临风险。3. Trust Wallet –支持所有ERC20代币和其他70个区块链标准Trust Wallet是一款非托管的ERC20钱包,免费且易于使用。它支持多种设备,包括浏览器扩展和智能手机。后者包括iOS和Android的应用程序。Trust Wallet受PIN和12个单词的口令保护。口令被加密存储在用户的设备上,Trust Wallet无法访问它。因此,这是存储ERC20代币的最佳去中心化加密钱包之一。事实上,我们喜欢Trust Wallet支持自定义代币。简而言之,这意味着可以添加任何ERC20代币。此外,Trust Wallet与CoinMarketCap集成。这意味着如果ERC20代币在CoinMarketCap上列出,Trust Wallet会实时显示其价值。除了ERC20代币,Trust Wallet还支持70多个其他区块链,包括比特币、XRP、Arbitrum、莱特币、卡尔达诺和币安智能链。Trust Wallet应用程序配备了质押工具,并允许用户立即交换ERC20代币。这些功能在浏览器扩展中不可用。

ERC20钱包类型

托管方式

支持的代币

购买ERC20代币的费用

应用程序?

质押/利息?

质押/利息率

 浏览器扩展和移动应用

 非托管

支持70个区块链网络上的450万种加密货币和NFT。支持所有ERC20代币。

最高可达5%,因为交易由Simplex处理

是,支持应用内的免费质押。

高可达19.7%

优点

最适合iOS和Android用户的ERC20钱包

支持所有ERC20代币

还与其他70个区块链兼容,包括比特币

在应用内质押或交换ERC20代币无需支付费用

与CoinMarketCap集成,实时显示投资组合价值

缺点

Simplex处理法定货币支付 – 意味着最高可达5%的费用

浏览器扩展具有有限的功能

4. MetaMask – 面向桌面用户的用户友好浏览器扩展MetaMask是桌面用户的最佳ERC20钱包之一。它的浏览器扩展用户友好,支持Chrome、Edge、Firefox和Brave。下载和设置新的MetaMask钱包只需要几秒钟。用户只需选择强密码并记下他们的12个备份口令。MetaMask预装以仅支持以太坊网络。这使其成为存储ERC20代币的理想之地。如果一种ERC20代币最初没有被识别,用户可以通过合同地址手动添加它。MetaMask支持其他五个网络 – Arbitrum、币安智能链、Optimism、Avalanche和Polygon。这些网络需要手动添加,支持所有本机代币。MetaMask支持在其钱包界面内进行质押,但仅限于以太坊。此功能由 Rocket Pool 和Lido提供。用户还可以在MetaMask上交换ERC20代币。这会导致0.875%的费用,已内置在汇率中。

ERC20钱包类型

托管方式

支持的代币

购买ERC20代币的费用

应用程序 ?

 质押/利息?

质押/利息率

 浏览器扩展和移动应用

 非托管

所有ERC20代币。还支持Arbitrum、币安智能链、Optimism、Avalanche和Polygon网络。

根据支付处理器而定,介于3-5%之间。

是,仅支持以太坊

 最高可达3.89%

优点

最适合非托管存储的ERC20钱包

用户友好的浏览器扩展,支持Chrome、Edge、Firefox和Brave

还提供适用于iOS和Android的原生移动应用

只需几秒钟即可设置

缺点

唯一支持质押的加密货币是以太坊

在代币交换交易中收取0.875%的费用

不支持比特币

5. Ledger – 用于离线存储ERC20代币的硬件钱包Ledger是安全性最高的ERC20钱包之一。与迄今为止讨论的其他提供商不同,这是一个硬件钱包。它以物理设备的形式出现,内部加密私钥。关键的安全性在于Ledger从不连接到互联网。相反,ERC20交易通过蓝牙或USB电缆(根据型号不同)广播到网络上。所有的Ledger型号都要求在设备上授权外发交易。这需要用户输入他们的PIN码。如果PIN码被遗忘,钱包可以通过备份口令来恢复。这是在安装钱包时由Ledger提供的,应该保存在纸上。如果Ledger设备丢失或被盗,备份口令也是必需的。尽管Ledger提供市场上最安全的ERC20钱包之一,但它远非便捷。这对于长期投资者来说不会是问题,但那些希望质押或交换ERC20代币的人会发现这一过程繁琐。Ledger Nano S Plus可购买79美元。最先进的型号 – Ledger Stax,零售价为279美元。

ERC20钱包类型

托管方式

支持的代币

购买ERC20代币的费用

应用程序 ?

质押/利息 ?

质押/利息率

硬件钱包

 非托管

所有ERC20代币。还支持其他区块链网络,包括比特币、币安智能链、波场、小蚁和Polygon。

法定货币支付由Coinify处理,最高可收取5%的费用

是,支持一些最佳的质押币,包括以太坊、Solana、宇宙和波场

未公布

优点

领先的长期投资者冷存储钱包

永远不要将私钥暴露在互联网上

支持最好的替代币,包括所有ERC20代币

入门级型号的合理价格为79美元

缺点

借记/信用卡支付最高可达5%

不适合频繁交易的投资者

点击这里访问Ledger

6. Coinbase Wallet – 支持任何ERC20代币的DeFi钱包应用   Coinbase Wallet也是市场上最好的ERC20钱包之一。Coinbase Wallet不仅支持任何ERC20代币,还支持比特币、Solana、Optimism、Avalanche等。该钱包可以免费下载,并作为Android和iOS的应用程序提供。Coinbase Wallet是非托管的,所以只有用户可以访问私钥。这些私钥存储在用户的智能手机上,并已完全加密。重要的是要记住,如果私钥丢失,Coinbase无法恢复它们。如果钱包被入侵,Coinbase也无法帮助用户恢复被盗的加密货币。

Coinbase Wallet应用程序通过PIN和生物识别技术进行了安全保护。但不支持双因素认证或多重签名权限。另一方面,我们喜欢Coinbase Wallet支持dApps。这包括OpenSea、PancakeSwap、ENS、SushiSwap和Curve。该钱包还允许用户购买、出售和交易NFT。

ERC20钱包类型

 托管方式

支持的代币

购买ERC20代币的费用

应用程序 ?

质押/利息?

 质押/利息率

 移动应用程序

 非托管

所有ERC20代币。还支持其他区块链网络,包括比特币、币安智能链和Solana。

不直接支持法定货币支付。需要通过集中式的Coinbase交易所进行支付,意味着高额的费用。

否,但可以连接到支持质押的dApps

 不适用

优点

用户友好的非托管存储钱包应用

与所有ERC20代币兼容

允许用户购买、出售和交易NFT

连接到多个网络上的dApps

缺点

没有内置的质押工具

安全功能有限

没有浏览器扩展或桌面软件

7. 币安 – 积极交易者常用的ERC20钱包  积极交易者可能会认为币安是最好的ERC20钱包。这是一个连接到币安交易所的中心化钱包 – 因此用户将无法访问他们的私钥。相反,币安负责保管客户的加密货币。该钱包通过双因素认证进行保护,登录时需要进行认证。币安会向用户的手机和电子邮件发送单独的代码,提供了额外的安全层。选择币安钱包的用户将获得业内领先的佣金。这仅相当于每滑一次0.1% – 当持有BNB代币时,这个费用会降低。币安交易所有超过350个交易对,其中包括许多ERC20代币。

更多的ERC20代币可以在币安创新区找到,它也连接到币安的钱包。币安还是在ERC20代币上获得收益的不错选择。这包括流动性挖矿、储蓄账户和质押。币安还允许用户交易杠杆加密产品。币安钱包也与其原生应用程序兼容,但提供的功能较少。

ERC20钱包类型

托管方式

支持的代币

购买ERC20代币的费用

应用程序?

质押/利息?

质押/利息率

 网络钱包和移动应用

 托管

支持350多种加密货币,包括许多ERC20代币。其他ERC20代币可以在币安创新区找到。

根据居住国家的不同,法定货币支付费用有所不同。标准佣金为0.1%。

是,支持质押、储蓄账户和流动性挖矿。

最高可达19.8%的质押利率。

储蓄账户最高可达32%。

优点

最适合ERC20代币交易的钱包

行业内一些最低的交易费用

将大部分客户拥有的加密货币存放在冷存储中

通过质押、储蓄账户和流动性挖矿轻松赚取ERC20代币的收益

缺点

一些DeFi产品需要锁定120天

不与用户共享私钥

ERC20钱包的基础知识在投资了类似Tether或Aave的ERC20项目后,这些代币需要存储在加密钱包中。ERC20代币可以存储在支持以太坊网络的钱包中。即使特定代币未受支持,一些ERC20钱包允许用户手动添加它们。ERC20代币需要存储在支持以太坊网络的加密货币钱包中。作为全球市值第二大的加密货币,这意味着市场上存在大量的ERC20钱包。不仅如此,还有许多不同类型的ERC20钱包可供选择。

例如,虽然一些ERC20代币持有者更喜欢基于网络的钱包,但其他人可能更愿意使用硬件设备。

有些投资者选择移动钱包应用程序以获得额外的便利性。

无论哪种方式,ERC20钱包都具有独特的以太坊地址。这个地址将支持所有ERC20代币。尽管如此,用户应该检查是否可以将自定义代币添加到ERC20钱包中。如果不能,那么用户只能存入受支持的ERC20代币。尽管如此,将ERC20代币发送到钱包地址通常只需15秒。然而,钱包到钱包的交易需要支付 GAS 费用。而当结束ERC20代币时,需要使用以太币支付GAS费用。

例如,假设一位投资者想要将他们的ERC20钱包中的Aave转移到交易所。

无论发送多少AAVE代币,用户都需要支付以太坊的GAS费用。

这取决于交易时以太坊区块链的繁忙程度。

ERC20钱包附带一个唯一的密码,称为“私钥”。但并非所有ERC20钱包都共享这些信息。这将取决于用户是否选择托管或非托管钱包。为什么需要一个ERC20钱包?

ERC20钱包提供许多不同的功能。不仅用于存储和转移ERC20代币,还用于访问DeFi产品。继续阅读,了解为什么ERC20投资者需要一个合适的钱包来参与以太坊生态系统。存储无论是短期还是长期投资者,都需要一个安全的地方来存储他们的ERC20代币。这意味着将代币保存在未受监管的加密货币交易所之外。最好的ERC20钱包提供各种安全工具,以保护代币免受黑客攻击。例如,托管钱包通常通过短信和/或电子邮件提供双因素认证。非托管钱包让用户控制他们的私钥,这些私钥通常加密存储在相应的设备上。钱包到钱包的转账要发送或接收ERC20代币,需要一个钱包。用户只需在发送ERC20代币时提供以太坊钱包地址。这将是钱包的唯一地址,但所有ERC20代币都将发送到同一个地址。例如,假设用户由他们选择的钱包提供以下以太坊地址:0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe在这种情况下,所有收到的ERC20代币将发送到这个地址。以太坊DeFi生态系统以太坊区块链是DeFi平台的首选网络。一些最受欢迎的DeFi平台包括UniSwap、Curve、SushiSwap、DODO、OpenSea和Kine Protocol。最好的ERC20钱包允许用户直接连接到DeFi平台。这意味着用户可以在不离开钱包界面的情况下交换代币、赚取质押奖励,甚至借款资金。法定货币支付一些ERC20钱包允许用户使用法定货币购买加密货币,从而省去了使用外部交易所的需求。然而,用户应当注意费用。例如,虽然eToro钱包提供美元免费的法定货币支付,但在Trust Wallet上进行相同交易将花费高达5%。最佳ERC20钱包:我们的排名标准尽管安全性是选择最佳ERC20钱包的关键因素,但还需要考虑其他指标。这包括可用性、费用、客户服务、支持的网络和核心功能。

在编制我们的最佳ERC20钱包列表时,我们关注以下因素:

Custodianship: 首先,ERC20代币持有者应该探讨钱包的托管性质。这决定了用户是否能访问他们的私钥。如果可以,这是一个非托管钱包。如果不能,那么这个钱包是托管的。

Fees: 最佳的ERC20钱包不应该收取存储代币的费用。也不应该有额外的发送交易费用。相反,这应该复制区块链的矿工费。只要记住,尽管软件钱包是免费使用的,硬件钱包需要购买。

钱包类型 初学者最适合使用移动或Web浏览器钱包,因为它们提供了便捷性。但是,一些ERC20代币持有者根据他们的需求更喜欢桌面或硬件钱包。我们涵盖了广泛的钱包类型以满足所有需求。

支持的代币: 请确保选择支持所有ERC20代币的钱包。钱包应该具有允许用户手动添加自定义代币的功能。如果没有这个功能,钱包将只支持有限数量的ERC20代币。领先的ERC20钱包还支持比特币、XRP、Solana和最好的Arbitrum网络代币。

安全性:ERC20钱包的主要目的是保护投资安全。这意味着选择的ERC20钱包应该具备适当的安全功能。例如,Best Wallet配备了生物识别安全功能,而eToro提供了双因素身份验证。

总的来说,最适合ERC20代币的最佳钱包在安全性和便利性之间取得了良好的平衡,还支持广泛的ERC20代币和功能。ERC20钱包如何工作?基础知识

ERC20钱包有一些基本原理需要了解。首先,投资者将获得一个独特的ERC20钱包地址。这个地址不仅可以让他们接收以太币,还可以接收所有ERC20代币。这是因为ERC20代币是建立在以太坊框架之上的。因此,以太币和ERC20代币使用相同的钱包标准。不过,重要的是要评估所选择的钱包是否接受自定义ERC20代币。如果接受的话,用户可以将ERC20代币添加到他们的钱包中,即使它没有在交易所上市。用户只需将合同地址粘贴到钱包中。从那时起,任何进入的ERC20代币交易都将反映在钱包地址中。当将ERC20代币发送到另一个钱包时,用户需要正确的地址。如果出现任何错误,交易将被发送到一个无效的钱包地址。换句话说,ERC20代币将无法找回。请记住,发送ERC20代币需要支付 GAS 费用。正如前面提到的,GAS 费用必须用以太坊(ETH)支付,而不是要发送的ERC20代币。例如,如果一名投资者想要转账Dai代币,他们必须在其ERC20钱包中拥有足够的ETH来支付交易费用。这些费用是由以太坊网络报价的,将根据需求而变化。目前,ERC20代币的转账费用约为1.73美元,或者大约0.0010 ETH。这被认为是具有竞争力的,因为ERC20 GAS费用通常会超过10美元。此外,ERC20代币持有者还应了解私钥的工作原理。毕竟,如果选择非托管钱包,私钥就是用户的责任。今天讨论的所有非托管钱包都会将私钥转换为一个包含12或24个单词的密码短语。这样做可以更容易地写下并在需要时恢复ERC20钱包。不同类型的ERC20钱包

我们已经介绍了ERC20钱包的基本工作原理。接下来,让我们探讨最常见的ERC20钱包类型,包括硬件钱包、软件钱包和纸钱包。ERC20软件钱包大多数ERC20代币持有者会选择软件钱包,特别是那些积极购买、出售和交易ERC20代币的用户。选择包括移动钱包,这是iOS或Android的应用程序。这是最便利的选择,因为用户可以随时随地发送和接收ERC20代币。此外,移动钱包受到屏幕锁定、生物识别和备份密码的保护。桌面和基于浏览器的钱包也很受欢迎。这些选择适用于喜欢在笔记本电脑或个人电脑上交易ERC20代币的用户。在某些情况下,桌面钱包配有双因素身份验证,要求用户通过短信验证码来验证访问。ERC20硬件钱包ERC20硬件钱包将吸引两类投资者。首先,那些在其投资组合中拥有大量ERC20代币的投资者。或者那些希望长期持有他们的ERC20代币的投资者。这是因为硬件钱包配有无与伦比的安全控制。例如,在授权交易时,需要在设备上输入PIN码。而且,硬件设备保持在冷存储状态,因为它从不连接到互联网。ERC20纸钱包另一种选择是使用ERC20纸钱包。

用户首先需要创建一个ERC20钱包地址。

这可以从大多数软件钱包中完成,比如Trust Wallet。

然后,用户将ERC20代币转账到新生成的钱包地址。

接下来,他们将钱包地址和私钥打印到一张纸上。

然后,将纸放在一个安全的地方,因此私钥始终保持在冷存储状态。

尽管这使得积极地发送和接收资金具有挑战性,但纸钱包是存储ERC20代币的最安全和成本效益最高的方式之一。

ERC20钱包有多安全?

ERC20钱包的安全性取决于各种因素,例如:

钱包是非托管的还是托管的。

钱包是热钱包还是冷钱包。

钱包提供的具体安全功能。

让我们更详细地分解上面的列表,从托管开始。托管钱包负责保管用户的ERC20代币。尽管它们不会共享用户的私钥,但最好的托管钱包提供了一系列安全控制。

例如,eToro将大部分客户资金存放在冷存储中。

它还拥有全天候的安全团队,并允许用户使用双因素身份验证来保护他们的钱包。

此外,eToro受到多个许可机构的监管,包括英国、美国、欧盟和澳大利亚的监管机构。

非托管钱包的安全性将取决于用户是否选择热存储或冷存储。

冷存储,可作为硬件或纸钱包使用,始终将私钥保持脱机。这消除了远程黑客攻击的威胁。

热存储将ERC20代币始终保持在线,提供了额外的便利性。大多数非托管的热钱包都采用PIN码、密码或生物识别技术进行安全保护。但由于非托管钱包是分散的,所以不提供双因素身份验证选项。

最终,ERC20代币持有人在使用钱包之前应该对钱包的安全性进行尽职调查。如何设置一个ERC20钱包?

建立一个ERC20钱包相对来说是相当简单的。初学者可以按照以下的逐步指南来开始使用Best Wallet。步骤1:下载Best WalletBest Wallet目前是一个手机应用,桌面浏览器版本正在开发中。您可以在Android/iOS的应用商店中找到它,免费下载。步骤2:创建账户用户只需要输入一个有效的电子邮件地址来创建一个账户,因为Best Wallet是去中心化和非托管的,所以无需完成KYC流程。接下来,用户可以决定添加什么安全设置 – 四位数密码是最低要求,但还可以选择添加双因素认证和/或指纹识别。这些设置也可以在之后进行添加/移除。步骤3:转账或购买ERC20代币现在已经创建了一个Best Wallet账户,用户将被重定向到仪表板,他们可以在那里通过第三方WERT购买ERC20代币,或者在内置的去中心化交易所上交易成千上万的其他代币。结论

在对2023年的顶级ERC20钱包进行了审查后,我们发现Best Wallet是我们的首选。这个去中心化、非托管的钱包刚刚作为免费的移动应用程序推出,使用户完全能够管理他们的加密货币持有。我们还喜欢Best Wallet具有许多其他功能,使其不仅仅是一个钱包,还包括有关代币的独特见解,提供新项目的早期访问以及在交易时降低费用。这是通过$BEST代币实现的,尽管它尚未推出,但将在不久的将来空投给该钱包的活跃用户。

点击这里访问 Best Wallet

 参考资料

https://coinmarketcap.com/https://www.coinbase.com/blog/scaling-ethereum-crypto-for-a-billion-usershttps://ethereum.org/en/developers/docs/gas/https://support.simplex.com/hc/en-gb/articles/360014078420-What-fees-do-you-charge-for-card-paymentshttps://docs.rocketpool.net/guides/staking/overview.htmlhttps://shop.ledger.com/pages/hardware-wallets-comparisonhttps://mycoinify.com/fees/https://www.binance.com/en/fee/tradinghttps://etherscan.io/gastrackerhttps://www.swift.com/your-needs/financial-crime-cyber-security/know-your-customer-kyc/kyc-process问与答什么是ERC20钱包的示例?ERC20钱包支持以太坊标准的代币,示例包括Best Wallet、eToro、MetaMask和Trust Wallet。我在哪里可以获得ERC20钱包?数十种ERC20钱包可以免费下载为应用程序或浏览器扩展程序,其中一些主要示例包括Best Wallet、eToro、Exodus和MetaMask。如何知道我是否拥有ERC20钱包?如果钱包位于以太坊区块链上,并且接收地址以’0x’开头,那么它支持ERC20代币。什么是最好的ERC20钱包?总的来说,我们喜欢Best Wallet,它不仅为任何ERC20代币提供非托管存储,还支持比特币、XRP、Solana和其他主要加密货币。它还具有其他独特的功能,使它不仅仅是一个非托管钱包。

2023年

加密市场

加密货币

加密钱包

区块链

推荐

比特币新闻

比特币价格预测:BTC达到7万美元并回调 发生了什么?

比特币新闻

特斯拉是全球持有比特币第三多的公司 数据显示较一月增持1,789枚比特币

比特币新闻

韩国分析师共识:比特币价格增长可能会持续

比特币新闻

比特币价格预测:市场乐观情绪和关键事件推动涨势 或将冲向75000美元

比特币新闻

比特币价格预测:在黑石ETF激增和市场乐观情绪中 目标75,000美元

财经新闻

台湾内政部警政署:境外交易所众多 只有币安与国内执法机关合作

最新消息

财经新闻

台湾内政部警政署:境外交易所众多 只有币安与国内执法机关合作

财经新闻

Bybit HK已向证监会提交牌照申请 惟Bybit Global仍被列入可疑平台名单

区块链新闻

Bybit 受到香港证监会的审查 公开警告无牌加密货币交易平台

News

我们询问ChatGPT 2024年Floki、Shiba Inu、DogWifHat、Pepe和Dogecoin的价格可能会达到多高

比特币新闻

市传卡塔尔基金投5,000亿美元购买比特币 短期内真的可行?

比特币新闻

比特币短暂跌破69,000美元 抄底的多头或将价格推回至70,500美元

News

5thScape ($5SCAPE) 价格预测 2024 – 2030 年价格分析

快速阅读 3 分钟了解今天的加密货币新闻!

输入你的电子邮箱以获取我们的免费每日通讯

注册

This site is protected by reCAPTCHA and the Google

Privacy Policy and

Terms of Service apply.

类似新闻

区块链新闻

报告:法国青少年正倾向投资加密货币 对高回报有著期待

News

今日最佳加密货币投资:dogwifhat、FLOKI、Pepe

产业对谈

DogWifHat投资者纷纷转投Sponge V2 追逐1000% ROI大幅增长

比特币新闻

比特币价格预测:BTC达到7万美元并回调 发生了什么?

cryptonews

输入你的电子邮箱以获取我们的免费每日通讯

快速阅读 3 分钟了解今天的加密货币新闻!

注册

This site is protected by reCAPTCHA and the Google

Privacy Policy and

Terms of Service apply.

条款与规范

关于我们

用户协议

免责声明

你有任何想法吗?

Advertising

新闻

以太坊新闻

NFT新闻

DeFi新闻

替代币新闻

区块链新闻

新闻发布

赞助

加密货币新闻交易

产业对谈

快速评论

财经新闻

科技新闻

比特币新闻

独家新闻

焦点

观点

人物

视频

比特币

以太坊

替代币

区块链

市场趋势

加密货币安全

指南

比特币

以太坊

替代币

加密货币

首次代币发行

精选

最佳边动边赚型加密货币

最佳长线投资加密项目

价值低于1美元最佳加密货币

上涨最多十大加密货币

最佳以太坊体育博彩网站

最佳比特币真人赌场

最佳元宇宙赌场

最值得投资的新加密货币项目

活动

播客

我们的撰稿人

交易所

货币

价格追踪器

© 2024 Cryptonews. All rights reserved

条款与规范

关于我们

用户协议

免责声明

你有任何想法吗?

Advertising