Imtoken官网地址下载|ethereum是erc20吗
Imtoken官网地址下载|ethereum是erc20吗
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比特币合约赞同 13630 条评论分享喜欢收藏申请
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年2月16日(opens in a new tab)(opens in a new tab)(opens in a new tab)使用以太坊查找钱包获取以太币Dapps - 去中心化应用二层网络运行节点稳定币质押ETH学习学习中心什么是以太坊?什么是以太币 (ETH)?以太坊钱包Gas fees以太坊安全和预防欺诈措施什么是 Web3?智能合约以太坊能源消耗以太坊路线图以太坊改进提案 (Eip)以太坊的历史以太坊白皮书以太坊词汇表以太坊治理区块链桥零知识证明测试中心开发者开始体验相关文档教程通过编码来学习设置本地环境生态系统社区中心以太坊基金会以太坊基金会的博客(opens in a new tab)生态系统支持方案(opens in a new tab)以太坊漏洞悬赏计划生态系统资助计划以太坊品牌资产Devcon(opens in a new tab)企业级应用主网以太坊私密以太坊企业级应用关于ethereum.org关于我们工作机会参与贡献语言支持隐私政策使用条款缓存政策联系我们(opens in a new tERC-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智能合约赞同 164 条评论分享喜欢收藏申请
什么是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添加评论分享喜欢收藏申请
ERC20解读 | 登链社区 | 区块链技术社区
ERC20解读 | 登链社区 | 区块链技术社区
文章
问答
讲堂
专栏
集市
更多
提问
发表文章
活动
文档
招聘
发现
Toggle navigation
首页 (current)
文章
问答
讲堂
专栏
活动
招聘
文档
集市
搜索
登录/注册
ERC20解读
Confucian
更新于 2022-04-04 19:54
阅读 6894
对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 代币
3917 浏览
Michael.W基于Foundry精读Openzeppelin第39期——ERC20.sol
487 浏览
教程:如何在没有 Web 界面的情况下创建 ERC20桥
1566 浏览
一个简单的ERC20代币空投合约
2619 浏览
发布一款ERC20代币,并开发成Dapp
1524 浏览
Aptos合约开发之部署ERC20合约
3923 浏览
相关问题
如何从发起部署的地址中,转移一部分代币到已经部署的合约地址中,麻烦那位大佬看一下
5 回答
空投的默克尔树如何防止生日攻击?
2 回答
bsc链上的erc20合约,要求只有一点买卖的时候2%兑换成bnb发送到营销钱包,现在的问题是添加流动性会一直报错Fail with error 'TransferHelper::transferFrom: transferFrom failed'
2 回答
eth中如何判断合约是erc20合约
2 回答
寻找使用Vyper部署的带有交易税的ERC20代币模版
1 回答
如何实现同质化代币(ERC20标准)购买非同质化代币(ERC721)两份合约如何交互
3 回答
0 条评论
请先 登录 后评论
Confucian
关注
贡献值: 57
学分: 83
Keep Learning
文章目录
关于
关于我们
社区公约
学分规则
Github
伙伴们
ChainTool
为区块链开发者准备的开源工具箱
合作
广告投放
发布课程
联系我们
友情链接
关注社区
Discord
Youtube
B 站
公众号
关注不错过动态
微信群
加入技术圈子
©2024 登链社区 版权所有 |
Powered By Tipask3.5|
粤公网安备 44049102496617号
粤ICP备17140514号
粤B2-20230927
增值电信业务经营许可证
×
发送私信
请将文档链接发给晓娜,我们会尽快安排上架,感谢您的推荐!
发给:
内容:
取消
发送
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
取消
举报
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
了解ERC-20通证智能合约 | ethereum.org
C-20通证智能合约 | ethereum.org跳转至主要内容学习用法构建参与研究搜索语言 ZH帮助更新此页面本页面有新版本,但现在只有英文版。请帮助我们翻译最新版本。翻译页面没有错误!此页面未翻译,因此特意以英文显示。不再显示了解ERC-20通证智能合约智能合约通证solidityerc-20初学者jdourlensEthereumDev(opens in a new tab) 2020年4月5日6 分钟阅读 minute readcomp-tutorial-metadata-tip-author 0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE 在本页面取值器函数事件ERC-20 通证的基本实现ERC-20是以太坊上最重要的智能合约标准之一。它已经成为以太坊区块链上用于可替换通证实现的所有智能合约的技术标准。ERC-20 定义了所有可替换的以太坊通证都应该遵守的通用规则列表。 因此,该通证标准使所有类型的开发者能够准确预测新通证在更大的以太坊系统中将如何工作。 这简化了开发者的任务,因为他们可以继续他们的工作,知道只要通证遵循规则,每次发布新的通证时就不需要重做每个新项目。这里以接口的形式介绍了 ERC-20 必须实现的函数。 如果您不知道什么是接口:请查看我们关于使用 Solidity 进行 OOP 编程(opens in a new tab)的文章。1pragma solidity ^0.6.0;23interface IERC20 {45 function totalSupply() external view returns (uint256);6 function balanceOf(address account) external view returns (uint256);7 function allowance(address owner, address spender) external view returns (uint256);89 function transfer(address recipient, uint256 amount) external returns (bool);10 function approve(address spender, uint256 amount) external returns (bool);11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);121314 event Transfer(address indexed from, address indexed to, uint256 value);15 event Approval(address indexed owner, address indexed spender, uint256 value);16}显示全部 复制下面逐行解释每个函数的用途。 在这之后,我们将展示一个 ERC-20 通证的简单实现。取值器1function totalSupply() external view returns (uint256); 复制返回存在的通证数量。 此函数是一个取值器,不会修改合约的状态。 请记住,Solidity 中没有浮点数。 因此,大多数通证都会采用 18 位小数,并且会返回总供应量和其他结果,如下所示:1 个通证 100000000000000000。 您需要在处理通证时格外注意,并不是每个通证都有 18 位小数。1function balanceOf(address account) external view returns (uint256); 复制返回地址拥有的通证数量(account)。 此函数是一个取值器,不会修改合约的状态。1function allowance(address owner, address spender) external view returns (uint256); 复制ERC-20 标准使一个地址能够允许另一个地址从中检索通证。 此取值器返回允许spender代表owner花费的剩余通证数量。 此函数是一个取值器,不会修改合约的状态,并且默认应返回 0。函数1function transfer(address recipient, uint256 amount) external returns (bool); 复制将通证的amount从函数调用者地址(msg.sender) 移动到接收者地址。 此函数发出稍后定义的Transfer事件。 如果可进行转账,它将返回 true。1function approve(address spender, uint256 amount) external returns (bool); 复制设置允许spender从函数调用方(msg.sender)余额转账的allowance的数额。 此函数发出 Approval 事件。 此函数返回是否成功设置了余量。1function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 复制使用余量机制将通证的amount从sender移动到recipient。 然后从调用者的余量中扣除该数额。 此函数发出Transfer事件。事件1event Transfer(address indexed from, address indexed to, uint256 value); 复制将通证(值)的数量从from地址发送到to地址时会发出此事件。在铸造新代币时,转账通常会在 from 0x00..0000 地址进行,而在销毁代币时,转账会在 to 0x00..0000 地址进行。1event Approval(address indexed owner, address indexed spender, uint256 value); 复制当owner批准要由spender使用的通证数量(value)时,将发出此事件。ERC-20 通证的基本实现下面是 ERC-20 通证的最简单代码:1pragma solidity ^0.8.0;23interface IERC20 {45 function totalSupply() external view returns (uint256);6 function balanceOf(address account) external view returns (uint256);7 function allowance(address owner, address spender) external view returns (uint256);89 function transfer(address recipient, uint256 amount) external returns (bool);10 function approve(address spender, uint256 amount) external returns (bool);11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);121314 event Transfer(address indexed from, address indexed to, uint256 value);15 event Approval(address indexed owner, address indexed spender, uint256 value);16}171819contract ERC20Basic is IERC20 {2021 string public constant name = "ERC20Basic";22 string public constant symbol = "ERC";23 uint8 public constant decimals = 18;242526 mapping(address => uint256) balances;2728 mapping(address => mapping (address => uint256)) allowed;2930 uint256 totalSupply_ = 10 ether;313233 constructor() {34 balances[msg.sender] = totalSupply_;35 }3637 function totalSupply() public override view returns (uint256) {38 return totalSupply_;39 }4041 function balanceOf(address tokenOwner) public override view returns (uint256) {42 return balances[tokenOwner];43 }4445 function transfer(address receiver, uint256 numTokens) public override returns (bool) {46 require(numTokens <= balances[msg.sender]);47 balances[msg.sender] = balances[msg.sender]-numTokens;48 balances[receiver] = balances[receiver]+numTokens;49 emit Transfer(msg.sender, receiver, numTokens);50 return true;51 }5253 function approve(address delegate, uint256 numTokens) public override returns (bool) {54 allowed[msg.sender][delegate] = numTokens;55 emit Approval(msg.sender, delegate, numTokens);56 return true;57 }5859 function allowance(address owner, address delegate) public override view returns (uint) {60 return allowed[owner][delegate];61 }6263 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {64 require(numTokens <= balances[owner]);65 require(numTokens <= allowed[owner][msg.sender]);6667 balances[owner] = balances[owner]-numTokens;68 allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;69 balances[buyer] = balances[buyer]+numTokens;70 emit Transfer(owner, buyer, numTokens);71 return true;72 }73}显示全部 复制ERC-20 代币标准的另一个优秀实现是 OpenZepelin ERC-20 实现(opens in a new tab)。t上次修改时间: @tyevlag(opens in a new tab), Invalid DateTime查看贡献者本教程对你有帮助吗?是否编辑页面(opens in a new tab)在本页面取值器函数事件ERC-20 通证的基本实现网站最后更新: 2024年2月16日(opens in a new tab)(opens in a new tab)(opens in a new tab)使用以太坊查找钱包获取以太币Dapps - 去中心化应用二层网络运行节点稳定币质押ETH学习学习中心什么是以太坊?什么是以太币 (ETH)?以太坊钱包Gas fees以太坊安全和预防欺诈措施什么是 Web3?智能合约以太坊能源消耗以太坊路线图以太坊改进提案 (Eip)以太坊的历史以太坊白皮书以太坊词汇表以太坊治理区块链桥零知识证明测试中心开发者开始体验相关文档教程通过编码来学习设置本地环境生态系统社区中心以太坊基金会以太坊基金会的博客(opens in a new tab)生态系统支持方案(opens in a new tab)以太坊漏洞悬赏计划生态系统资助计划以太坊品牌资产Devcon(opens in a new tab)企业级应用主网以太坊私密以太坊企业级应用关于ethereum.org关于我们工作机会参与贡献语言支持隐私政策使用条款缓存政策联系我们(opens in a new tERC-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,但 这只意味着区块链上的其他合约无法读取它们。 区块链上 没有秘密,所有节点上的软件在每个区块上 都有每个合约的状态。 根据惯例,状态变量名称为 _ERC-20、ERC-721、ERC-1155、ERC-4626 和可组合性 · Ethereum Community Network
20、ERC-721、ERC-1155、ERC-4626 和可组合性 · Ethereum Community Network新闻资讯零时学院开发者门户生态漫游ΞSearch by ERC-20、ERC-721、ERC-1155、ERC-4626 和可组合性可组合性是以太坊的一个重要的功能,不同的代币标准怎么进一步增加可组合性?本文速览了 ERC20、721、1155、4626 代币标准HSHaym Salomon 2022-08-18来源 | @SalomonCrypto作者 | Haym Salomon
代币标准和可组合性*
ERC-20、ERC-721、ERC-1155、ERC-4626、ERC-之类的,不知道各种以太坊代币标准是什么?为什么这些标准很重要?有兴趣了解哪些代币标准都服务于什么目的?想要了解整体情况?这个长推为你解答!
以太坊 是一台世界计算机。它是由匿名和不受信任的节点组成的网络所维护的共享资源;通过共识达成一致,并且在经济上保障网络的安全。
以太坊网络提供可信的中立性,任何人都可以在上面独立和协作构建。
*应用程序编程接口(API)**是一种不同程序进行通信和开发者进行协调的机制。开发者会尽可能地隐藏他们程序的内部工作。通信被最大程度地简化和改进。
计算机科学基础: API 解释
从抽象(abstraction)的角度来说, API 是抽象在现实世界中的最常见的表现方式。一个 API 是一组定义好的规则,解释了程序/应用如何与彼此进行通信。
举个例子,我们设想一下,一个电商网站有一个价格机器人;用户向价格机器人给出水果的特质,而机器人会返回一个价格信息。
为了用价格机器人整合信息,你需要给它一个对象(水果)信息,并接受一个价格。因此,首先需要打包所有的对象信息:fruit_a = [apple, red, 200g, harvested 3 days ago]
现在,我们需要将这些信息喂给价格机器人。首先,我们调用(price_bot),接着通过让 price_bot 使用 calculate_price 的函数计算 fruit_a ,从而给我们一个价格,即 price_bot calculate_price(fruit_a)。
price_bot 将倾其所能计算出价格。作为用户,我们不知道也不关心屏幕背后发生的计算,我们只知道,最终 price_bot 会给我们一个的价格,即 price_bot.calculate_price(fruit_a) = price_fruit_a。
这就是价格机器人的 API:一个价格机器人支持的函数列表和如何使用他们的说明。这是一个示意图,由此开发者可以在无需掌握应用程序的情况下集成它。假设这个例子是真实的,那么这个 API 的文档应该是这样的:
从表面上看,API 开发工作可能不像编程;API 的开发和文档撰写工作更像写作而不是写代码。但不要被骗了,API 开发其实与写代码一样重要.......老实说,可能比写代码还要重要。
在世界计算机中,我们到处用得上 API:
集成协议
转移资产
构建可组合的投资
借入、借出和抵押资产
基本上,所有链上发生的事物不是 API 就是直接由 API 整合。
事实上,你可以将不同类型的代币标准视为符合某个 API 模板的一段代码。如果智能合约遵循了特定模板,那么它就是那种代币。
https://t.co/GoMlbfN9Vq
这是 ERC-20 的代币模板。为了生成一个 ERC-20 智能合约,开发者需要创建用来执行下面所有的方法和事件的代码。
所有 ERC-20 合约都支持这些函数;一位(不同的)开发者可以依靠下面这些来使用任何 ERC-20 合约。
ERC-20 是最为基础的代币标准,代表着当前绝大多数可用的代币。它包括了治理代币、ve-toke(投票托管代币)、稳定币等。
(ETH 不是 ERC-20 代币。)
ERC-721 代币一般被称为 NFT(非同质化代币)。这些代币(通常)代表着收藏品内独一无二或者可识别的物品,包括 PFP、艺术收藏品、财产等。
ERC-1155 代币标准结合了 ERC-20 和 ERC-721 代币标准的特性,提供了一个单一接口来管理这些代币类型的任何组合。这可以用作一个更现代化的 ERC-20 和 ERC-721 替代方案,并且具有服务于游戏的独特功能。
ERC-4626 是最新的代币标准,描述着有收益的金库。该标准为存入金库(或从金库赎回)的 ERC-20 代币提供了一个共同接口,以获得收益。这可以包括流动性挖矿和聚合,但还可以用到更多领域中。
ERC-777 是高度可配置却很少被使用的代币标准。它为 ERC-20 提供了升级,允许开发者附加在发送和/或接受代币时运行的代码。
尽管它被纳入在 https://ethereum.org,但我们在实践中很少看到 ERC-777。
快速回顾历史:
首先,互联网之前的时代,接着... 艾伦 图灵 → 机械计算 → 计算机 → 联网计算机 → 阿帕网 → 万维网(www)→ 互联网 → 比特币 → 以太坊大约在 2014 年到来,那时 @VitalikButerin 向我们介绍 ETH。
这是故事开始的地方。
以太坊只是基础设施,现在我们必须在上面构建。我们在此基础上设定的标准越丰富,我们就可以走得越远。
可以说,计算机科学是魔法,开发者是魔法师,而抽象(abtraction)就是咒语。可组合性则是目标。
抽象这一概念支撑着世界计算机展现其最重要的能力。
DeFi 之所以是一种更好的方式 —— 可组合性:是指让两件独立的事物的组合超过它们部分的总和的一种能力。
原生 ETH ..... ERC-20、721、777、1155、4626...... 随着每种 ERC 代币标准的增加,我们正在变得更加先进。每一种代币类型可以拥有更多的功能,每一个金钱 Lego 都将带来更多增值。
每个 ERC 标准的增加都将让我们更加靠近可编程的货币。
可编程的货币是全新的概念。如果货币是具体的、可编程的,就像乐高一样。
每一个协议会吸收塑料(即价值)并生产乐高积木(通常是钱)。这些积木可以和其他的积木结合在一起,创造某些定制的、全新的事物。
代币标准指的是可组合性如何在以太坊上展现(的一种方式)。
哎呀......我们都是构建者!不然你们觉得我们还会构建什么???
以太坊的杀手锏功能:可组合性。
我们之所以能拥有可组合性:抽象
抽象的目的:管理复杂性
管理复杂性有什么意义?—— 改变世界。
ECN的翻译工作旨在为中国以太坊社区传递优质资讯和学习资源,文章版权归原作者所有,转载须注明原文出处以及ethereum.cn,若需长期转载,请联系eth@ecn.co进行授权。Ethereum Community Network以太坊社区网络 订阅 Ethereum Community Network以太坊社区网络 订阅
【Ethereum】以太坊ERC20 Token标准完整说明 - 林泽归来 - 博客园
【Ethereum】以太坊ERC20 Token标准完整说明 - 林泽归来 - 博客园
会员
周边
新闻
博问
AI培训
云市场
所有博客
当前博客
我的博客
我的园子
账号设置
简洁模式 ...
退出登录
注册
登录
林泽归来
博客园
首页
新随笔
联系
管理
订阅
【Ethereum】以太坊ERC20 Token标准完整说明
什么是ERC20 token
市面上出现了大量的用ETH做的代币,他们都遵守REC20协议,那么我们需要知道什么是REC20协议。
概述
token代表数字资产,具有价值,但是并不是都符合特定的规范。
基于ERC20的货币更容易互换,并且能够在Dapps上相同的工作。
新的标准可以让token更兼容,允许其他功能,包括投票标记化。操作更像一个投票操作
Token的持有人可以完全控制资产,遵守ERC20的token可以跟踪任何人在任何时间拥有多少token.基于eth合约的子货币,所以容易实施。只能自己去转让。
标准化非常有利,也就意味着这些资产可以用于不同的平台和项目,否则只能用在特定的场合。
ERC20 Token标准(Github)
序言
EIP: 20 Title: ERC-20 Token Standard Author: Fabian Vogelsteller fabian@ethereum.org, Vitalik Buterin vitalik.buterin@ethereum.org Type: Standard Category: ERC Status: Accepted Created: 2015-11-19
总结
token的接口标准
抽象
以下标准允许在智能合约中实施标记的标记API。 该标准提供了转移token的基本功能,并允许token被批准,以便他们可以由另一个在线第三方使用。
动机
标准接口可以让Ethereum上的任何令牌被其他应用程序重新使用:从钱包到分散式交换。
规则
Token
方法
注意:调用者必须处理返回false的returns (bool success).调用者绝对不能假设返回false的情况不存在。
name
返回这个令牌的名字,比如"MyToken".
可选 - 这种方法可以用来提高可用性,但接口和其他契约不能指望这些值存在。
function name() constant returns (string name)
symbol
返回令牌的符号,比如HIX.
可选 - 这种方法可以用来提高可用性,但接口和其他契约不能指望这些值存在。
function symbol() constant returns (string symbol)
decimals
返回token使用的小数点后几位, 比如 8,表示分配token数量为100000000
可选 - 这种方法可以用来提高可用性,但接口和其他契约不能指望这些值存在。
function decimals() constant returns (uint8 decimals)
totalSupply
返回token的总供应量。
function totalSupply() constant returns (uint256 totalSupply)
balanceOf
返回地址是_owner的账户的账户余额。
function balanceOf(address _owner) constant returns (uint256 balance)
transfer
转移_value的token数量到的地址_to,并且必须触发Transfer事件。 如果_from帐户余额没有足够的令牌来支出,该函数应该被throw。
创建新令牌的令牌合同应该在创建令牌时将_from地址设置为0x0触发传输事件。
注意 0值的传输必须被视为正常传输并触发传输事件。
function transfer(address _to, uint256 _value) returns (bool success)
transferFrom
从地址_from发送数量为_value的token到地址_to,必须触发Transfer事件。
transferFrom方法用于提取工作流,允许合同代您转移token。这可以用于例如允许合约代您转让代币和/或以子货币收取费用。除了_from帐户已经通过某种机制故意地授权消息的发送者之外,该函数**应该**throw。
注意 0值的传输必须被视为正常传输并触发传输事件。
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
approve
允许_spender多次取回您的帐户,最高达_value金额。 如果再次调用此函数,它将以_value覆盖当前的余量。
注意:为了阻止向量攻击,客户端需要确认以这样的方式创建用户接口,即将它们设置为0,然后将其设置为同一个花费者的另一个值。虽然合同本身不应该强制执行,允许向后兼容以前部署的合同兼容性
function approve(address _spender, uint256 _value) returns (bool success)
allowance
返回_spender仍然被允许从_owner提取的金额。
function allowance(address _owner, address _spender) constant returns (uint256 remaining)
Events
Transfer
当token被转移(包括0值),必须被触发。
event Transfer(address indexed _from, address indexed _to, uint256 _value)
Approval
当任何成功调用approve(address _spender, uint256 _value)后,必须被触发。
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
实施
在Ethereum网络上部署了大量符合ERC20标准的令牌。 具有不同权衡的各种团队已经编写了不同的实施方案:从节省gas到提高安全性。
示例实现可在
https://github.com/ConsenSys/Tokens/blob/master/contracts/StandardToken.sol
https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol
在调用之前添加力0的实施“批准”了
https://github.com/Giveth/minime/blob/master/contracts/MiniMeToken.sol
ERC20 Token标准接口
以下是一个接口合同,声明所需的功能和事件以符合ERC20标准:
// https://github.com/ethereum/EIPs/issues/20
contract ERC20 {
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);
}
大部分Ethereum主要标记符合ERC20标准。
一些令牌包括描述令牌合同的进一步信息:
string public constant name = "Token Name";
string public constant symbol = "SYM";
uint8 public constant decimals = 18; // 大部分都是18
如何工作?
以下是令牌合约的一个片段,用于演示令牌合约如何维护Ethereum帐户的令牌余额
contract TokenContractFragment {
// Balances 保存地址的余额
mapping(address => uint256) balances;
// 帐户的所有者批准将金额转入另一个帐户
mapping(address => mapping (address => uint256)) allowed;
// 特定帐户的余额是多少?
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner]; //从数组中取值
}
// 将余额从所有者帐户转移到另一个帐户
function transfer(address _to, uint256 _amount) returns (bool success) {
//判断条件 发送者余额>=要发送的值 发送的值>0 接收者余额+发送的值>接收者的余额
if (balances[msg.sender] >= _amount
&& _amount > 0
&& balances[_to] + _amount > balances[_to]) {
balances[msg.sender] -= _amount; //发送者的余额减少
balances[_to] += _amount; //接收者的余额增加
return true;
} else {
return false;
}
}
// 发送 _value 数量的token从地址 _from 到 地址 _to
// transferFrom方法用于提取工作流程,允许合同以您的名义发送令牌,例如“存入”到合同地址和/或以子货币收取费用; 该命令应该失败,除非_from帐户通过某种机制故意地授权消息的发送者; 我们提出这些标准化的API来批准:
function transferFrom(
address _from,
address _to,
uint256 _amount
) returns (bool success) {
//和上面一样的校验规则
if (balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount
&& _amount > 0
&& balances[_to] + _amount > balances[_to]) {
balances[_from] -= _amount;
allowed[_from][msg.sender] -= _amount; //减少发送者的批准量
balances[_to] += _amount;
return true;
} else {
return false;
}
}
// 允许_spender多次退出您的帐户,直到_value金额。 如果再次调用此函数,它将以_value覆盖当前的余量。
function approve(address _spender, uint256 _amount) returns (bool success) {
allowed[msg.sender][_spender] = _amount; //覆盖当前余量
return true;
}
}
token余额
假设token合约内有两个持有者
0x1111111111111111111111111111111111111111有100个单位
0x2222222222222222222222222222222222222222有200个单位
那么这个合约的balances结构就会存储下面的内容
balances[0x1111111111111111111111111111111111111111] = 100
balances[0x2222222222222222222222222222222222222222] = 200
那么,balanceOf(...)就会返回下面的结果
tokenContract.balanceOf(0x1111111111111111111111111111111111111111) 将会返回 100
tokenContract.balanceOf(0x2222222222222222222222222222222222222222) 将会返回 200
转移token的余额
如果0x1111111111111111111111111111111111111111想要转移10个单位给0x2222222222222222222222222222222222222222,那么0x1111111111111111111111111111111111111111会执行下面的函数
tokenContract.transfer(0x2222222222222222222222222222222222222222, 10)
token合约的transfer(...)方法将会改变balances结构中的信息
balances[0x1111111111111111111111111111111111111111] = 90
balances[0x2222222222222222222222222222222222222222] = 210
balanceOf(...)调用就会返回下面的信息
tokenContract.balanceOf(0x1111111111111111111111111111111111111111) 将会返回 90
tokenContract.balanceOf(0x2222222222222222222222222222222222222222) 将会返回 210
从token余额批准和转移
如果0x1111111111111111111111111111111111111111想要批准0x2222222222222222222222222222222222222222传输一些token到0x2222222222222222222222222222222222222222,那么0x1111111111111111111111111111111111111111会执行下面的函数
tokenContract.approve(0x2222222222222222222222222222222222222222, 30)
然后allowed(这里官方文档写的是approve,很明显是错的)结构就会存储下面的内容
tokenContract.allowed[0x1111111111111111111111111111111111111111][0x2222222222222222222222222222222222222222] = 30
如果0x2222222222222222222222222222222222222222想要晚点转移token从0x1111111111111111111111111111111111111111到他自己,0x2222222222222222222222222222222222222222将要执行transferFrom(...)函数
tokenContract.transferFrom(0x1111111111111111111111111111111111111111, 20)
balances的信息就会变成下面的
tokenContract.balances[0x1111111111111111111111111111111111111111] = 70
tokenContract.balances[0x2222222222222222222222222222222222222222] = 230
然后allowed就会变成下面的内容
tokenContract.allowed[0x1111111111111111111111111111111111111111][0x2222222222222222222222222222222222222222] = 10
0x2222222222222222222222222222222222222222仍然可以从0x1111111111111111111111111111111111111111转移10个单位。
tokenContract.balanceOf(0x1111111111111111111111111111111111111111) will return 70
tokenContract.balanceOf(0x2222222222222222222222222222222222222222) will return 230
简单修复的token合约
以下是一个样本令牌合同,固定供应量为1000000单位,最初分配给合同所有者:
pragma solidity ^0.4.8;
// ----------------------------------------------------------------------------------------------
// Sample fixed supply token contract
// Enjoy. (c) BokkyPooBah 2017. The MIT Licence.
// ----------------------------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/issues/20
contract ERC20Interface {
// 获取总的支持量
function totalSupply() constant returns (uint256 totalSupply);
// 获取其他地址的余额
function balanceOf(address _owner) constant returns (uint256 balance);
// 向其他地址发送token
function transfer(address _to, uint256 _value) returns (bool success);
// 从一个地址想另一个地址发送余额
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
//允许_spender从你的账户转出_value的余额,调用多次会覆盖可用量。某些DEX功能需要此功能
function approve(address _spender, uint256 _value) returns (bool success);
// 返回_spender仍然允许从_owner退出的余额数量
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
// token转移完成后出发
event Transfer(address indexed _from, address indexed _to, uint256 _value);
// approve(address _spender, uint256 _value)调用后触发
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
//继承接口后的实例
contract FixedSupplyToken is ERC20Interface {
string public constant symbol = "FIXED"; //单位
string public constant name = "Example Fixed Supply Token"; //名称
uint8 public constant decimals = 18; //小数点后的位数
uint256 _totalSupply = 1000000; //发行总量
// 智能合约的所有者
address public owner;
// 每个账户的余额
mapping(address => uint256) balances;
// 帐户的所有者批准将金额转入另一个帐户。从上面的说明我们可以得知allowed[被转移的账户][转移钱的账户]
mapping(address => mapping (address => uint256)) allowed;
// 只能通过智能合约的所有者才能调用的方法
modifier onlyOwner() {
if (msg.sender != owner) {
throw;
}
_;
}
// 构造函数
function FixedSupplyToken() {
owner = msg.sender;
balances[owner] = _totalSupply;
}
function totalSupply() constant returns (uint256 totalSupply) {
totalSupply = _totalSupply;
}
// 特定账户的余额
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
// 转移余额到其他账户
function transfer(address _to, uint256 _amount) returns (bool success) {
if (balances[msg.sender] >= _amount
&& _amount > 0
&& balances[_to] + _amount > balances[_to]) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
}
//从一个账户转移到另一个账户,前提是需要有允许转移的余额
function transferFrom(
address _from,
address _to,
uint256 _amount
) returns (bool success) {
if (balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount
&& _amount > 0
&& balances[_to] + _amount > balances[_to]) {
balances[_from] -= _amount;
allowed[_from][msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(_from, _to, _amount);
return true;
} else {
return false;
}
}
//允许账户从当前用户转移余额到那个账户,多次调用会覆盖
function approve(address _spender, uint256 _amount) returns (bool success) {
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
//返回被允许转移的余额数量
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}
注意的是,最后的例子中allowed限定的第二维的参数是调用者的转移数量,而开始的例子是接收者的数量。
参考资料
http://themerkle.com/what-is-the-erc20-ethereum-token-standard/
https://github.com/ethereum/EIPs/pull/610
https://github.com/ethereum/EIPs/issues/20
https://theethereum.wiki/w/index.php/ERC20_Token_Standard
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#heading=h.m9fhqynw2xvt
posted @
2018-01-21 19:40
林泽归来
阅读(7819)
评论(0)
编辑
收藏
举报
会员力量,点亮园子希望
刷新页面返回顶部
公告
Copyright © 2024 林泽归来
Powered by .NET 8.0 on Kubernetes
什么是ERC-20?关于ERC代币你应该了解的知识点 - 知乎
什么是ERC-20?关于ERC代币你应该了解的知识点 - 知乎首发于AAX学院切换模式写文章登录/注册什么是ERC-20?关于ERC代币你应该了解的知识点AAX学院高流动,低点差——尽在aax.com你应该听说过ERC-20代币,特别是如果你关注过2017年ICO热潮期间的加密领域。然而,除了ERC-20之外,还有许多其他的以太坊代币标准,比如ERC-721和ERC-223,它们给代币提供了更多的用例。在这篇文章中,作为以太坊区块链之旅的一部分,我们主要探索最重要的ERC代币标准。“ERC”是什么意思?ERC是Ethereum Request for Comment的缩写,用于对代币和以太坊生态系统提出改进建议。提交ERC后,以太坊社区将对其进行评估,并决定是否接受或拒绝该建议。获得绿灯后,ERC将被正式确定为以太坊改进建议(EIP)。虽然ERC大多是初始和非正式的建议,但EIP总是由以太坊核心开发者进行审核和评估。说到这里,”ERC “这个词在加密货币社区中广为人知,它是以太坊网络上代币的标准。简而言之,代币标准是用来定义数据和实现它的每个代币的功能。代币的标准化使得创作者更容易发行币,并将其与应用程序集成。ERC-20范例: Tether (USDT), Chainlink (LINK), AAX Token (AAB)ERC-20是以太坊生态系统中最流行的代币标准,也是整个加密货币行业中最流行的代币标准。ERC-20是由以太坊联合创始人Vitalik Buterin在2015年6月提出的,它是一个简单的接口,允许开发者在以太坊区块链之上创建他们的代币,并将其与第三方应用程序(如钱包和交易所)集成。除了允许创建者使用简单的功能,比如限制他们的币的总供应量,ERC-20代币、去中心化应用(DApps)和智能合约之间也有直接的互动。需要强调的是,ERC-20代币是可以互换的资产。就像百元大钞或标准金条一样,可互换代币是具有等值单位的相同资产。由于创建ERC-20代币很容易,大多数加密项目在2017年的ICO热潮中使用该标准来发行他们的原生币,并将其出售给出资者。因此,ERC-20是加密行业最广泛接受的代币标准,大多数数字资产钱包、交易所(包括AAX)和其他服务都支持该标准。ERC223范例:暂无ERC-223是以太坊生态系统中的一个可互换代币标准,其主要目标是解决ERC-20的一些问题。虽然ERC-20在加密项目和用户中非常受欢迎,但它允许人们将加密货币发送到智能合约而不是钱包。因此,一些用户由于合约失败或其他原因而失去了他们的资金。为了解决这个问题,ERC-223有一个功能,在用户不小心将代币发送到智能合约的情况下,会自动提醒用户。这样的交易会被自动取消,让用户收回资金(但还是要支付矿工费)。虽然它向下兼容ERC-20币,但ERC-223的特点是比之更低廉的矿工费。然而,尽管ERC-223具有优势,但它未能被以太坊社区采用,也尚未有加密项目使用该代币标准。ERC-721范例: CryptoKitties, Sorare与ERC-20和ERC-223相反,ERC-721是一个不可替代的代币(NFT)标准。这里的每个代币不是相同的硬币,而是独一无二的,具有自己的标识符,便于通过区块链进行验证。虽然可互换代币具有类似于标准金条或同值美元钞票的功能,但ERC-721币更像是艺术品或其他(复杂的)手工制作的物品,每件物品都是独一无二的,在某些方面与其他物品不同。虽然它们有多种应用,但NFT最受欢迎的用例是在区块链游戏解决方案中。通过非同质的代币,区块链游戏玩家可以收集、拥有和交易独特的游戏物品,如武器、角色、衣服、坐骑和车辆。此外,ERC-721代币标准允许创作者在多个区块链游戏和应用中集成NFT,让游戏玩家无论在哪里玩都能使用他们的数字收藏品。ERC-1155范例:EnjinERC-1155是一种混合代币标准,允许开发人员在一个智能合约下创建无限的可替代代币和不可替代代币。开发者在使用ERC-721时必须为每个NFT创建一个新的智能合约,而在使用ERC-1155时,他们只需要为非可替代代币和可互替代代币部署一个智能合约,从而缩短了开发时间,并最大限度地减少了创建者使用的资源。在区块链游戏中,这使得加密货币项目可以使用单一的智能合约来发行他们的游戏内货币作为可替代的代币,同时让用户在参与游戏的过程中收集NFT项目。关于AAX学院AAX是由LSEG Technology公司提供技术支持的数字资产交易所。AAX学院是AAX打造的一档用户教育频道,旨在帮助更多用户学习新手教程和了解到关于区块链的基础知识。 发布于 2020-09-22 08:38首次代币发行(ICO)数字化资产token赞同 51 条评论分享喜欢收藏申请转载文章被以下专栏收录AAX学院带来最前沿的区块链资讯知识,探究区块链背后