Hero Circle Shape
Hero Moon Shape
Hero Right Shape
比特app官网下载|erc20是以太坊主网络么

比特app官网下载|erc20是以太坊主网络么

  • 作者: 比特app官网下载
  • 2024-03-16 05:17:08

什么是ERC-20? - 知乎

什么是ERC-20? - 知乎切换模式写文章登录/注册什么是ERC-20?穆逸扬Myytydy​用注意力写作,用比特币存钱摘要简单来说,ERC-20就是一套基于以太坊网络的标准代币发行协议。有了ERC-20,开发者们得以高效、可靠、低成本地创造专属自己项目的代币;我们甚至可以将ERC-20视为以太坊网络为早期区块链世界做出的最重要贡献,也是以太坊网络第一个真正意义上的杀手级应用。以下是正文这次的更新我们来聊聊ERC-20这个你很可能听过,但大概率一知半解的区块链“黑话”。如果你是定投人生课堂的成员,或者正在践行定投区块链数字资产的策略,相信ERC-20这个词对你而言一定不陌生。ERC-20的定义如同CoinDesk专栏作者 Alyssa Hertig 在 What is the ERC-20 Ethereum Token Standard? 中所说的:ERC-20以太坊代币标准是创建与更广泛的以太坊网络兼容的可替换代币的蓝图。以太坊,或称Ethereum,是一种加密货币,允许创建各种应用,包括代币,与大多数传统应用不同,它不需要中心化服务机构就可以运作。上面引述的内容可能不太好理解,简单来说,ERC-20就是一套基于以太坊网络的标准代币发行协议。其中的ERC是"EthereumRequest for Comment"也就是“以太坊征求意见协议”的缩写。和其他的开源社区一样,以太坊会使用这样的方式收集开发者的反馈、并在批准后作为后续开发的执行标准。ERC-20的价值和影响毫无疑问,ERC-20是所有ERC协议中最广为人知的一个。我们甚至可以将ERC-20视为以太坊网络为早期区块链世界做出的最重要贡献(此处完全可以去掉“之一”,我甚至不介意再去掉“早期”)。是的,在我看来ERC-20就是以太坊网络第一个真正意义上的杀手级应用。正是因为有了ERC-20,开发者们得以高效、可靠、低成本地创造专属自己项目的代币。也正是这一协议提供的这种极大的便利,使得首次代币发行,也就是大名鼎鼎同时饱受争议的ICO,能一度在区块链世界大行其道——助长大量骗局的同时,也在客观上推动了区块链相关技术与应用的爆发式增长。更有趣的是,ERC-20的火爆甚至直接催生了一些类似TRC-20这样,连协议的数字代号都懒得改一下的像素级山寨竞品。一个便于理解的类比如果上面的这些叙述还是让你一知半解,甚至完全摸不到头脑,我们不妨打个容易理解的比方:如果我们把众多区块链项目的开发者,看作是在一个小区门口商铺里,经营不同业态的众多商户。这些商户根据自己的专长提供各自不同的商品和服务,也都希望发行自己店铺专属的消费储值卡。方便消费者光顾的同时,也能提升用户的体验和粘性。以太坊就像是运营这个小区底商的物业公司,它提供一整套标准化的储值卡发放协议和配套服务。借助这套叫做ERC-20的整体解决方案,每个商户(开发者)都可以傻瓜式地发行专属于自己店铺的消费储值卡,同时由于这种储值卡采用了统一的协议,可以非常方便地和其他商户的储值卡做无缝兑换。于是借助ERC-20,用户可以通过持有其中一种储值卡(token)很方便地享受整个生态的各种服务;商户(开发者)则节约了开发运营成本、同时提升了获取用户的效率;而物业公司(以太坊基金会和矿工)则可以通过做大生态体量实现更多的租金(ETH增值)和储值卡结算手续费(Gas费用)收入。ERC-20就是用这种做大生态价值的方式,实现了用户、开发者和以太坊网络三方面的共赢。ERC-20的应用案例为了让你对ERC-20有更具象化的认识,这里援引 Alyssa Hertig 在 What is the ERC-20 Ethereum Token Standard? 中列举的一些比较知名的基于ERC-20协议代币:Tether (USDT)Chainlink (LINK)Binance coin (BNB)USD coin (USDC)Wrapped bitcoin (WBTC)Dai (DAI)需要特别指出的是,这上面提到的Tether发行的稳定币USDT除了基于ERC-20协议的版本之外,其实还有基于其他公链发行的多个版本,只不过ERC-20版的发行量最大,知名度也最高。ERC-20与BOX的关系ERC-20版本的USDT,在我们定投人生课堂的战友定投BOX的过程中,也有很广泛的应用。比如通过ExinOne(Mixin ID:7000101276),可以轻松实现存USDT自动执行每周/每日定投BOX的操作。说到BOX这个区块链数字资产开源配方,它和ERC-20的关系也十分密切——其中的两个成分,XIN、UNI就是基于ERC-20协议发行的代币,此外BOX本身同样是一个基于此协议发行的Token——可以说,如果没有ERC-20,BOX这个区块链数字资产开源配方就不会是现在这个样子了。参考内容What is the ERC-20 Ethereum Token Standard?ERC 协议终极解读:ERC-20你常听到的 ERC20 和 ERC721 到底是什么?一文弄懂什么是 ERC20BOX简介发布于 2021-12-02 16:01虚拟货币区块链(Blockchain)ethereum​赞同 5​​添加评论​分享​喜欢​收藏​申请

USDT充币提币ERC20、TRC20、Omni如何选择?有啥区别? - 知乎

USDT充币提币ERC20、TRC20、Omni如何选择?有啥区别? - 知乎切换模式写文章登录/注册USDT充币提币ERC20、TRC20、Omni如何选择?有啥区别?usdt区块链是现在,区块链是未来。在充提USDT的时候,投资者发现有3个不同的链类型供选择,分别是ERC20、TRC20和Omni,而大多数投资者就卡在这里了,在三者之间不知道该如何选择,甚至都不了解这三者是什么,简单点说ERC20是以太坊区块链的链类型,TRC20是波场区块链的链类型,而Omni是比特币区块链网络的链类型。USDT充币提币ERC20、TRC20、Omni如何选择?除了地址不同之外,选择不同的链类型,转转账的速度和手续费也是不一样的。如果你希望可以快速转账,追求的是速度,那就应该选择波场区块链的TRC20链类型。波场网络TPS达到1500TPS,目前来说转账最快到账的是波场USDT。如果你在意的是手续费,希望转账手续费能低一些,那也应该选择TRC20链类型。因为TRC20链类型转账,手续费为0。而ERC20链类型的手续费是2USDT,大概是14块钱。OMIN链类型手续费最贵,需要5个USDT,大概是35人民币。但是如果你希望转账能安全一点,那就选择比特币网络的OMIN链类型,这个链类型虽然手续费高了一点,但是安全性好。贵,也是有道理的嘛。USDT充币提币ERC20、TRC20、Omni有啥区别?1、Omni-USDT的安全性最好,但转账速度太慢。要是你有不着急交易的大额订单,可以优先选择Omni-USDT。2014年,USDT于比特币网络上诞生,于2015年2月正式上线几大主流交易所。在2018年之前,USDT的转账路径只有一条,那就是基于比特币网络的Omni-USDT。Omni-USDT存储在比特币地址上,因此每次转账的时候,需要支付比特币作为矿工手续费。Omni-USDT于比特币网络的链上,黑客攻击的成本很高,所以资产相对安全性较高。但是其交易速度非常慢,已经无法满足当今加密交易市场的需求,但很多大宗交易还是会倾向于Omni-USDT。2、ERC20-USDT的安全性和转账速度居中。适用于数字货币市场的频繁交易。要是你经常做短线交易,可以优先选择ERC20-USDT。2018年,以太坊网络开始流行,在区块链应用也大面积展开,ERC20-USDT出现。和Omni-USDT一样,使用ERC20-USDT同样需要支付旷工费,但转账速度有了显著的提升。由于安全性好、转账速度快,ERC20-USDT被市场广泛接受,USDT的发行者泰达公司也开始支持更高效的以太坊ERC20。由于综合指数比较高,在主流交易平台比较受欢迎。3、TRC20-USDT的转账速度最快,而且链上转账无需手续费,但安全性比较低。适合需要快速到账的朋友,建议小额为主,现在一次转账一般都只需要几分钟时间。2019年,泰达公司宣布在波场上发行了基于TRC-20协议的USDT,TRC20-USDT诞生。发行时承诺完全公开透明,零转账费,秒级到账。和前两者不同的是,目前TRC20-USDT转账是不收取手续费的。ERC20、TRC20、Omni这三种类型的USDT在交易所内并没有差别,但在链上是不互通的,也就是说Omni上的USDT是无法转到另外两条链上的,所以在交易所充提USDT时一定要留意地址种类。发布于 2021-03-15 14:34比特币 (Bitcoin)USDT比特币合约​赞同 136​​30 条评论​分享​喜欢​收藏​申请

ERC-20是什么? - 知乎

ERC-20是什么? - 知乎切换模式写文章登录/注册ERC-20是什么?爱丽森梦游市场MBA/ 金融管理/区块链/人工智能什么是Token(代币)?在Ethereum中,代币几乎可以代表任何东西,从在线平台的信誉点、游戏中角色的技能、彩票到金融资产债券,再到真正的商品,如公司的股份、货币、金盎司等!如此强大的功能,值得也必须处理好。如此强大的功能,理应也必须由一个强大的标准来处理,对吗?这正是ERC-20的作用所在,ERC-20就是针对这些发布的Token(代币)制定的一个固定的基础的标准原则。什么是ERC-20?ERC-20引入了可替代Token(代币)的标准,换句话说,它们具有使每个Token(代币)与另一个Token(代币)完全相同(在类型和价值上)的属性。例如,ERC-20,Token(代币)的行为与ETH相同,这意味着任意1个遵循ERC-20规则的Token(代币)与所有其他所有Token(代币)是平等和相同的。由Fabian Vogelsteller在2015年11月提出的ERC-20(以太坊请求注释20)是一种Token标准,在智能合约中实现了Token的API。(注:API(token)是一个通用术语。通常,API(token)是请求访问您的服务的应用程序的唯一标识符。您的服务将为应用程序生成API(token),以供您在请求服务时使用。然后,您可以将它们提供的令牌与您存储的令牌进行匹配,以进行身份 验证)它提供的功能类似于将Token(代币)从一个帐户转移到另一个帐户,以获取帐户的当前Token(代币)钱包内的余额以及网络上可用Token(代币)的总供应量。除了这些之外,它还具有其他一些功能,例如批准第三方帐户可以使用帐户中的Token(代币)数量。如果智能合约实施以下方法和事件,则可以称为ERC-20 ,Token(代币)合约,一旦部署,它将负责在以太坊上跟踪创建的Token(代币)(注:网上拥有这种标准的ERC-20代码,就是为了方便程序员编程时候可以直接应用,有兴趣的可以自己搜索看看)ERC-20 定义通用规则?截至2019年10月,以太坊的主网络上存在超过200,000个与ERC-20兼容的Token(代币)。ERC-20至关重要。它定义了所有以太坊Token(代币)必须遵守的通用规则列表。这些规则中,包括如何传输Token(代币),如何批准交易,用户如何访问有关Token(代币)的数据以及Token(代币)的总供应量。 因此,这个特殊的Token(代币)使所有类型的开发人员都能准确地预测新Token(代币)在更大的以太坊系统中将如何运行。这简化了为开发人员设定的任务;他们可以继续进行自己的工作,因为只要Token(代币)遵循规则,就不需要在每次发布新Token(代币)时都重做每个新项目。它确保以太坊发行的许多不同令牌之间的兼容性。许多著名的数字货币都使用ERC-20标准:包括Maker(MKR),Basic Attention Token(BAT),Augur(REP)和OmiseGO(OMG)等,以及今年火爆的Defi(去中心化金融概念),诞生了如AAVE、Compound等优质项目,用户拥有USDT便可参与这些项目。如果您打算购买任何以ERC-20,Token(代币)发行的数字货币,则必须拥有一个与这些Token(代币)兼容的钱包。幸运的是,由于ERC-20,Token(代币)非常流行,因此钱包有很多不同的选择。如何确定某个代币是否为ERC20,Token(代币)呢?通过etherscan或者其他区块链平台查询:ERC-20代币有什么用?ERC20代币的出现,大幅降低了代币发行门槛。只要复制网上的标准代码,一个不懂编程的人也能在几分钟内,发行出一种新的Token(代币)。这一便利,也催生了2017年的「1CO」热潮,从而进一步推动了比特币牛市。目前全球Token(代币)总数超过5000种,绝大部分是ERC20的代币,据估计,至少占比超过95%,由此可见,ERC20是一种十分流行的代币格式。因为ERC20的标准token(代币)规则的便利性和统一性,前段时间的Defi热潮中ERC20,Token(代币)项目也表现得非常火爆:例如:LINK(预言机概念)取得了超过100倍的涨幅、UNI(去中心化交易所代币)创出了史上最强空投(人均1000美元)、UMA(衍生资产概念)获得了50倍的涨幅等等。发布于 2020-11-26 14:06token智能合约​赞同 16​​4 条评论​分享​喜欢​收藏​申请

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)本页面对你有帮

3分钟了解TRC20、ERC20到底差在哪? - 知乎

3分钟了解TRC20、ERC20到底差在哪? - 知乎切换模式写文章登录/注册3分钟了解TRC20、ERC20到底差在哪?托尼金铲铲赏金赛,招高玩选手➡️znifc9999我们在转帐时,常常需要选择主网类型(提领地址的协议),会出现TRC-20、ERC-20、Omni 等等,不同的选项有不同的手续费,那这些英文代表什么意思呢?我们到底要怎么选?相信看完这篇你一定搞懂TRC20 ERC20 差别! ! !代币协议标准一般的加密货币都有自己依附的区块链,例如以太币就是建立在以太坊这个区块链上面、比特币建立在比特币区块链上而想要在这些区块链上面发行货币,就必须遵守各区块链的规则例如想在以太链上发行加密货币,就必须遵守以太链上的「ERC-20协议」,ERC全名是” Ethereum Request for Comment ” ,这个协议中包含了发行货币的标准和注意事项那我们平常转帐最常转的应该是USDT,USDT 不只发行在一个区块链上,Tether公司发行USDT在比特币链、以太坊、Tron链…等区块链上,那发行在不同区块链上就要遵守不同区块链的协议在转帐时常看到的Omni、ERC-20、TRC-20分别是比特币区块链、以太坊、TRON区块链上的协议下面会介绍三种链上转帐的差异!OmniOmni 是比特币区块链上的协议2014年,Tether公司基于比特币区块链「Omni协议」发行USDT,转帐需要支付一些BTC做为手续费转帐速度虽然慢,但是因为是基于比特币区块链,所以安全性相较其他两者高,所以如果是大笔金额的转帐通常会用Omni转帐手续费:通常>10 USD (各交易所不一样)最小转帐数量:最高到帐时间:慢,十几分钟到几天安全性:最安全转帐帐号地址开头:1、3ERC-20ERC-20 是以太坊上的协议2018年以太坊开始热门,所以Tether公司在以太坊上面发行USDT,转帐速度大幅上升转帐手续费(以币安为例):10 USDT (各交易所不一样)最小转帐数量(以币安为例):50 USDT (各交易所不一样)到帐时间:普通、易堵塞,几分钟到几十分钟安全性:普通转帐帐号地址开头:0xTRC-20TRC-20 是波场(TRON)区块链上的协议因为以太坊过于壅塞,转帐手续费越来越高,所以在2019年4月泰达公司(Tether)在TRON 上发行USDT,TRC-20上的USDT特色就是转帐速度快、手续费相当低! ! ! 目前被广泛使用~转帐手续费(以币安为例):1 USDT (各交易所不一样,MAX交易所不用手续费)最小转帐数量(以币安为例):10 USDT (各交易所不一样)到帐时间:快,几秒钟安全性:相较其他两者低转帐帐号地址开头:Tx因为TRC-20的手续费相当便宜且快速,所以大部分可能会选择TRC-20比较多,如果是加密货币新手可以选择TRC-20来转USDT~结论所以平常看到的TRC-20、ERC-20、Omni,其实就是Tether公司在不同区块链上发行的USDT,可以想成用不同管道转帐比较好理解,手续费、速度等等会有所不同例如把用Omni转帐想成去银行临柜办理,要排队排比较久;用TRC-20转帐想成用网络银行转帐,速度相当快,有时手续费还不用钱~要注意不同区块链上的资产是不能互相转帐的!所以在转帐的时候一定要选择正确的链、协议,转帐前要注意地址是否正确希望看完这篇文章,有帮助你了解TRC20 ERC20 差别!发布于 2023-06-28 16:36・IP 属地江西$BTC​赞同 1​​添加评论​分享​喜欢​收藏​申请

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.

ERC20 - 廖雪峰的官方网站

ERC20 - 廖雪峰的官方网站

Index

廖雪峰的官方网站

Blog

Java教程

手写Spring

手写Tomcat

Makefile教程

Python教程

JavaScript教程

区块链教程

SQL教程

Git教程

文章

问答

More

Java教程

手写Spring

手写Tomcat

Makefile教程

Python教程

JavaScript教程

区块链教程

SQL教程

Git教程

文章

问答

Java教程

手写Spring

手写Tomcat

Makefile教程

Python教程

JavaScript教程

区块链教程

SQL教程

Git教程

文章

问答

 

Profile

Passkey

Sign Out

Sign In

English

简体中文

Index

区块链教程

比特币

区块链原理

P2P交易原理

私钥

公钥和地址

签名

挖矿原理

可编程支付原理

多重签名

UTXO模型

Segwit地址

HD钱包

钱包层级

助记词

地址监控

以太坊

账户

区块结构

交易

智能合约

编写合约

部署合约

调用合约

编写Dapp

常用合约

ERC20

Wrapped Ether

关注公众号不定期领红包:

加入知识星球社群:

关注微博获取实时动态:

ERC20

Last updated: ...

/

Reads: 59010

Edit

ERC20是以太坊定义的一个合约接口规范,符合该规范的合约被称为以太坊代币。

一个ERC20合约通过mapping(address => uint256)存储一个地址对应的余额:

contract MyERC20 {

mapping(address => uint256) public balanceOf;

}

如果要在两个地址间转账,实际上就是对balanceOf这个mapping的对应的kv进行加减操作:

contract MyERC20 {

mapping(address => uint256) public balanceOf;

function transfer(address recipient, uint256 amount) public returns (bool) {

// 不允许转账给0地址:

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

// sender的余额必须大于或等于转账额度:

require(balanceOf[msg.sender] >= amount, "ERC20: transfer amount exceeds balance");

// 更新sender转账后的额度:

balanceOf[msg.sender] -= amount;

// 更新recipient转账后的额度:

balanceOf[recipient] += amount;

// 写入日志:

emit Transfer(sender, recipient, amount);

return true;

}

}

安全性

早期ERC20转账最容易出现的安全漏洞是加减导致的溢出,即两个超大数相加溢出,或者减法得到了负数导致结果错误。从Solidity 0.8版本开始,编译器默认就会检查运算溢出,因此,不要使用早期的Solidity编译即可避免溢出问题。

没有正确实现transfer()函数会导致交易成功,却没有任何转账发生,此时外部程序容易误认为已成功,导致假充值:

function transfer(address recipient, uint256 amount) public returns (bool) {

if (balanceOf[msg.sender] >= amount) {

balanceOf[msg.sender] -= amount;

balanceOf[recipient] += amount;

emit Transfer(sender, recipient, amount);

return true;

} else {

return false;

}

}

实际上transfer()函数返回bool毫无意义,因为条件不满足必须抛出异常回滚交易,这是ERC20接口定义冗余导致部分开发者未能遵守规范导致的。

ERC20另一个严重的安全性问题来源于重入攻击:

function transfer(address recipient, uint256 amount) public returns (bool) {

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

uint256 senderBalance = balanceOf[msg.sender];

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

// 此处调用另一个回调:

callback(msg.sender);

// 更新转账后的额度:

balanceOf[msg.sender] = senderBalance - amount;

balanceOf[recipient] += amount;

emit Transfer(sender, recipient, amount);

return true;

}

先回调再更新的方式会导致重入攻击,即如果callback()调用了外部合约,外部合约回调transfer(),会导致重复转账。防止重入攻击的方法是一定要在校验通过后立刻更新数据,不要在校验-更新中插入任何可能执行外部代码的逻辑。

Comments

Make a comment

Sign in to

make a comment

Index

区块链教程

比特币

区块链原理

P2P交易原理

私钥

公钥和地址

签名

挖矿原理

可编程支付原理

多重签名

UTXO模型

Segwit地址

HD钱包

钱包层级

助记词

地址监控

以太坊

账户

区块结构

交易

智能合约

编写合约

部署合约

调用合约

编写Dapp

常用合约

ERC20

Wrapped Ether

廖雪峰的官方网站

©Copyright 2019-2021

Powered by iTranswarp

Feedback

License

以太坊主流ERC20应用代币分析 - 知乎

以太坊主流ERC20应用代币分析 - 知乎首发于区块链大数据分析切换模式写文章登录/注册以太坊主流ERC20应用代币分析白噪音Ƀlockchain Đata Ξxpl0it量子链(QTUM)量子链致力于开发比特币和以太坊之外的第三种区块链生态系统,通过价值传输协议(“Value Transfer Protocol”)来实现点对点的价值转移,并根据此协议,构建一个支持多个行业(包括金融、物联网、供应链、社交、游戏等)的去中心化的应用开发平台(DApp Platform)https://www.zhihu.com/video/881665750945923072EOS EOS是一种全新的区块链架构,旨在实现分布式应用的性能拓展。EOS 项目的目标是实现一个类似操作系统一样的支撑应用程序的区块链架构。该架构可以提供账户,身份认证,数据库,异步通信以及可在数以百计的 CPU 或群集上的程序调度。该技术的最终形式是一个区块链体系架构,该区块链每秒可以支持数百万个交易,同时普通用户无需支付使用费用。https://www.zhihu.com/video/881669030837104640TENX(PAY)TenX电子钱包能够实现让用户通过智能手机或信用卡消费他们的区块链资产,TenX钱包支持多币种,用户和企业能够以去中心的方式无缝地交易其区块链资产,消除与当前中心化解决方案相关的任何风险。在现实支付中,用户可以在 TenX 应用上自由选择不同的区块链资产作为支付来源,通过 TenX 电子钱包,极为便利地实现大范围的区块链资产转换支付,如 BTC、ETH 和 DASH 等。在实际交易发生之前,加密货币不需要转换为法定货币,这种转换将会在交易中实时进行。https://www.zhihu.com/video/881666014083940352OmiseGo(OMG) OmiseGo 是基于以太坊的新型金融平台,是处理支付处理器、网关和金融机构之间基本协调问题的区块链网络,通过实现大量的、低成本的去中心化交易,提供跨越不同货币和资产类型和公司分类账的新一代资产转移服务。OmiseGo的目标客户群是东南亚国家的人口,无论其是否正在使用正规金融服务。通过OmiseGo网络,为每个人提供可替代的金融和数字商业工具,无需再通过传统的银行,机构和卡片网络,这些终端用户将能够在低成本的条件下灵活完成支付、汇款、薪水存储、B2B 商业、供应链融资、信用制度、资产管理和贸易以及各种随需应变的金融服务。https://www.zhihu.com/video/881666152466632704Augur(REP)Augur 是建立在以太坊平台上的去中心化预测市场平台。利用 Augur ,任何人都可以为任何自己感兴趣的主题(比如美国大选谁会获胜)创建一个预测市场,并提供初始流动性,这是一个去中心化的过程。作为回报,该市场的创建者将从市场中获得一半的交易费用。普通用户可以根据自己的信息和判断在 Augur 上预测、买卖事件的股票,例如美国总统大选。当事件发生以后,如果你预测正确、持有正确结果的股票,每股你将获得1美元,从而你的收益是1美元减去当初的买入成本。如果你预测错误、持有错误结果的股票,你将不会获得奖励,从而你的亏损就是当初的买入成本。https://www.zhihu.com/video/881666219839750144GOLEM(GNT)Golem 是建立在以太坊平台上的去中心化计算机算力租赁平台。通过 Golem 平台,任何用户都可以成为算力的发售方和租用者。无论用户提供的是一台闲置的家用电脑还是几台大型的数据中心,都可以加入到 Golem 平台中。基于以太坊的交易系统被应用于 Golem 平台,用于结算算力提供者的收益和算力使用者所需要支付的费用。https://www.zhihu.com/video/881666279306579968STATUS(SNT)SNT 是一款开源通讯平台 Status ——用于与运行在以太坊网络上的去中心化应用进行交互的移动应用的网络代币。SNT 作为用来为 Status 网络提供支持的模块化实用代币,包括去中心化的推送式通知市场,Status 客户端的管理,社区内容的归纳整理,以及如 Tribute to Talk 等的社交通讯工具。Status 还提出了法币兑换加密货币的“柜员网络”,去中心化应用程序目录,贴纸市场,并展示了在用户获取引擎方面的研究,从而得以扩大网络。https://www.zhihu.com/video/881668957214507008FirstBlood(1ST)第一滴血,是一个可以让玩家随时随地挑战对手并获得赏金的去中心化电竞平台。全球电竞市场正在迅猛增长,而电子竞技平台所提供的公平性与安全性却参差不齐。当前电子竞技平台面临的首要问题是没法提供一个可以信赖的仲裁机制并且没有自动化的赏金分发系统。第一滴血项目,是搭建于以太坊上的区块链平台。该平台致力于使用去中心化的方式解决中心平台的信任问题,并利用智能合约解决赏金支付问题。https://www.zhihu.com/video/881669174152294400Bancor(BNT)班科协议使得智能合约区块链上代币们的价格发现和流动机制成为可能。这些“智能代币”持有一种或多种其它代币作为准备金。这些被持有的代币,我们统称为“准备金代币”。持有这些“智能代币”的人,可以即时的买入或卖出这些“智能代币”以交换它持有的某种“准备金代币”。这些即时的买入或卖出过程是通过“智能合约”实现的。交易价格是通过一个以与交易量为变量的数学公式计算得出的。https://www.zhihu.com/video/881666685411659776BasicAttentionToken(BAT)基本注意力代币是数字广告行业的全新货币,使用此代币可以支付内容商的内容费和用户的注意力,同时让广告商得到很理想的投资回报。https://www.zhihu.com/video/881666735030276096以太坊与ICO基础数据根据Etherscan数据显示:截至8月17日,以太坊拥有余额账号总量达到450万个,智能合约地址136万个;ERC20代币种类5300个,其中市值在1000万美元以上的43个;持有主流ICO代币的账号数量约30万个,占全体ETH有效账号的6.7%以太坊主网络交易次数在2000次以上且持有ERC20代币的ETH账户只有60个,以交易所冷钱包为主,包括Parity多重签名钱包漏洞的白帽地址。66%的以太坊账号交易次数在10次以内,账户数与交易频次呈显著的幂律分布OMG与量子链市值超过8亿美元PAY与EOS市值约5亿美元ICN、REP、BAT、GNT、CVC、GNO、SNT市值在2亿~3亿之间BNT、STORJ、FUN、DNT、1ST代币总市值约为1亿美元ERC20代币基础数据EOS与GNT拥有最多的账户,分别超过5万个REP与SNT数量在2万~3万之间PAY、STORJ、BNT、OMG、CVC、量子链、ICN与BAT账户数约为1万量子链与OMG账号平均持有该代币的价值较高,约7万美元GNO单账号价值约4.5万美元1ST、FUN、PAY、BAT、ICN单账号价值在2万~3万之间造成此局面的原因有:①项目本身质量好,人均持有量较高 ②升值幅度较大 ③交易所账户等大户持有量较高,筹码较为集中1ST、OMG、GNO、BAT、ICN等币种换手率较高,平均单账户交易次数超过6次GNT、PAY、SNT、EOS、QTUM、CVC平均交易次数在4~6次之间DNT、BNT、STORJ、FUN、REP的换手率较低,尚未得到市场有效炒作从合约内总交易次数上看,GNT与EOS占据第一阵营,交易次数均超过25万次;SNT、PAY、OMG、ICN、BAT、QTUM紧随其后,交易次数超过5万次;其余币种交易总次数显著较低结论:ICO仍处于市场发展初期,投资者人数仅为数十万量级大部分成功ICO的代币持有账户数量并不多,基本都在1万以内项目价值与持有代币账户数并无必然关系,OMG与量子链用户回报显著较高有落地场景的币种如OMG与PAY,得到市场认可也较高BNT、EOS、CVC、SNT等币种的升幅较小,未来有较大的运作空间更多ICO数据分析请关注微信公众号:区块链大数据分析编辑于 2017-08-30 00:21区块链(Blockchain)比特币 (Bitcoin)​赞同 16​​5 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录区块链大数据分析基于EOS/ETH区块链的交易数

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)本页面对你有帮

引爆区块链背后的以太坊 ERC-20,到底是什么? - 腾讯云开发者社区-腾讯云

链背后的以太坊 ERC-20,到底是什么? - 腾讯云开发者社区-腾讯云腾讯云开发者社区文档建议反馈控制台首页学习活动专区工具TVP最新优惠活动文章/答案/技术大牛搜索搜索关闭发布登录/注册引爆区块链背后的以太坊 ERC-20,到底是什么?文章来源:企鹅号 - 链眼各位同学们,这里是由链眼发起的「链眼大学」栏目,顾名思义:这是一个旨在帮助区块链爱好者学习区块链和加密技术概念、原理、技术、知识为一体的科普性栏目,在这里我们会以能够让你听得懂,学得会的大白话,帮助你深入浅出学习区块链。番外话:嗯,我是你们的校长:Gootor,大家可以叫我 G 校(感觉怪怪的... 随便你们怎么叫吧,反正当校长了 :)以后除了校长,还有其他老师讲解,敬请期待(๑•̀ㅂ•́)و如果说区块链能够在当下如此火爆,其背后的底层架构平台——以太坊不得不提,它是近两年来最大的公有链项目,其 Dapps 生态也是做得如火如荼,就如同一个繁荣的城市甚至国家一样存在,而如果你再深入研究,你就会发现其背后的 ERC-20 技术协议是支撑以太坊的最大创新之一。我们知道,区块链的最大价值就是建立「信任」,而信任也是驱动全球经济运转的核心所在,倘若没有信任的建立自然也无法构成如今的繁荣社会,因为不存在协作关系,就不会有我们所说的经济共同体。而区块链的信任所在,就是你不需要信任任何其中一个第三方,你只需要遵守智能合约和节点共识(记账/挖矿)即可,就像我们经常提到的代码即法律(Code Is Law)类同,我们都只要遵守预先编程好的程序的执行即可,它不会有外界的干扰,除非规则改变(即使规则更改,也会公开透明或者投票表决),它的执行结果都是一样的。就像一台机器,没有感情和其他情绪及利益的注入,它的程序执行结果都是一样的。既然然信任建立之后,就需要有资产的流通,Token 便是这样的一种基于以太坊的权益代表,它可以让区块链的资产/权益进行流通。那么,既然涉及到资产/权益,必定需要一个标准和规范形成统一,才能实现「自由流通」呀,因为标的物是一样的,所以 ERC-20 便是这样的一种标准协议,它约束了发行 Token 的人和项目都需要遵守统一的格式,形成价值对等。举个栗子:跨国的货币如日元和美元是没法直接使用的,需要兑换才能实现价值对等;我们经常使用的 USB 接口,如果不统一规范接口,你的终端设备也需要转换接口。因此,你可以把 ERC-20 理解成为,基于以太坊区块链的统一标准规范,只有基于 ERC-20 的 Token,才能在其体系自由流通,完成权益转移。发表于: 2018-07-192018-07-19 07:58:25原文链接:https://kuaibao.qq.com/s/20180719A09NGG00?refer=cp_1026腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。如有侵权,请联系 cloudcommunity@tencent.com 删除。USB接口无法使用以太坊区块链技术以太身是什么区块链以太坊关系深入浅出区块链0分享分享快讯到朋友圈分享快讯到 QQ分享快讯到微博复制快讯链接到剪贴板上一篇:谷歌AI猜画小歌刷屏,于是诞生了这些大神,笑死了……下一篇:北大开源ECCV2018深度去雨算法:RESCAN相关快讯什么是ERC-20?2018-02-28ERC-20 背后的小知识2018-12-26区块链之TPS和ERC-20协议2018-12-27维基链科普系列之ERC-20和主网2018-07-28以太坊代币合约 ERC-20和ERC-721的区别2018-01-30以太坊ERC-20智能合约被爆存在漏洞!你的币很快就不值钱了!2018-04-26什么是ERC-20、ERC-223?2019-09-20浅谈分布式身份标准,以太坊ERC-725如何定义区块链身份?2018-08-15以太坊ERC-20 Token标准发明者宣布即将推出Layer1区块链项目LUKSO2023-04-06关于ERC-20的十四个问题,知道了你就知道为何ETH是区块链2.0了2018-05-130xcert简介-基于以太坊最新标准ERC-721的开源协议2018-07-10比ERC-20更厉害的ERC-721到底是什么?2018-07-26智能合约与以太坊(一)2018-01-27ERC-20联合创建者推出Layer 1公链LUKSO2023-04-06每天一个知识点:ERC-20 代币标准2018-07-06区块链细数那些足以替代ERC20的以太坊代币协议2018-05-28什么是ERC-721 代币?2018-04-06BTC.com正式发布以太坊区块浏览器,完美支持ETH和ERC20 Token查询2018-11-01以太坊ERC-20代币标准发明者计划发布Layer 1区块链“LUKSO”2023-04-06以太坊将会进行重大改进,ERC721令牌标准到底是什么?2018-06-28扫码添加站长 进交流群领取专属 10元无门槛券私享最新 技术干货社区专栏文章阅读清单互动问答技术沙龙技术视频团队主页腾讯云TI平台活动自媒体分享计划邀请作者入驻自荐上首页技术竞赛资源技术周刊社区标签开发者手册开发者实验室关于社区规范免责声明联系我们友情链接腾讯云开发者扫码关注腾讯云开发者领取腾讯云代金券热门产品域名注册云服务器区块链服务消息队列网络加速云数据库域名解析云存储视频直播热门推荐人脸识别腾讯会议企业云CDN加速视频通话图像分析MySQL 数据库SSL 证书语音识别更多推荐数据安全负载均衡短信文字识别云点播商标注册小程序开发网站监控数据迁移Copyright © 2013 - 2024 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有 深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号1101080202028

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

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

文章

问答

讲堂

专栏

集市

更多

提问

发表文章

活动

文档

招聘

发现

Toggle navigation

首页 (current)

文章

问答

讲堂

专栏

活动

招聘

文档

集市

搜索

登录/注册

创建并部署ERC20代币

aisiji

更新于 2022-03-11 15:22

阅读 7613

本文通过创建一个代币深入讲解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

增值电信业务经营许可证

×

发送私信

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

发给:

内容:

取消

发送

×

举报此文章

垃圾广告信息:

广告、推广、测试等内容

违规内容:

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

不友善内容:

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

其他原因:

请补充说明

举报原因:

取消

举报

×

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