互联网技术日新月异,互联网不断渗透到人们的生活中;
Web3.0将是彻底改变人们生活的互联网形态;
Web3.0让所有在线公民不再受现有资源积累的限制;
更平等地获得财富和声誉。
web3.0将从哪里开始?
本集文章,授权转载,侵权必究。
3.0世界系列文章
来源:《代码与野兽》
[Web3系列文章]
NO.1 Meet Web3:在Web3的世界里写第一行HelloWorld。
第二,全面系统的Web3学习路线将帮助你成为Web3开发专家。
3号Web3世界:区块链、比特币、以太坊、智能合约
NO.4 Remix IDE用VSCode搭建Solidity开发环境。
第5期深入探讨Web3世界中的协议和硬盘:IPFS
第六篇讲扎实语法:帮你成为智能合约专家。
第7名Web3 World:用React ethers.js开发简单的加密钱包
第八期Web3世界:Web3为什么能赚钱?为什么不是全部在Web3中?
本文将解释令牌和ERC20的基本概念,并完成一个完整的DApp设计和实现,包括智能合约、前端、测试和部署。
非常适合Web3初学者学习。
本文中使用的一些主要工具、框架和技术:
Solidity:智能契约编程语言。元掩码:加密钱包。松露:智能合同开发工具包。加纳切:当地的区块链。React,nextjs:前端UI库/框架。Chakra,tailwindcss:组件库/CSS框架。Wagmi,ethersjs:JS: JS和智能合约交互SDK。注意:本文将不涉及这些工具、框架和技术的基本安装和使用。
完成后的效果如下:
基本概念什么是Token/令牌/通行证?
这里的令牌是指以太坊平台的令牌,其他平台的令牌在概念上可能略有不同。
以太坊平台除了token的概念,很多模仿以太坊的平台也有token的概念,比如BSC,polygon。
Token,英文是token,顾名思义,就是代表某种东西的货币。它可能意味着任何事情:
像人民币这样的法定货币。
黄金。石油。股票资产。游戏道具。积分。门票。和更多的东西.代币唯一不能代表的就是油费。
除了代币,代币还有一个名字,叫pass。所谓通用证书就是通用证书。通过持有这张通行证,你可以证明你拥有某种东西或利益。这和中国早期的粮票、布票是一样的。
现在我们明白了,它虽然有三个名字,但其实指的是一个东西,就是文中通常所说的token。
从代码上看,token是一个智能合约,负责提供审计、转账、记账等功能。没什么特别的。
最后,扩展一点知识。
比特币和以太坊是代币吗?可以说是,但和通常意义上的代币还是有一些区别的。我们一般把比特币和以太坊这种带有自己区块链的代币称为“币”。除了比特币,我们还会称之为“替代货币”。没有自己的区块链而依赖于其他区块链的货币叫做“代币”。这些名词应该是每个玩硬币的人都清楚的。
什么是ERC、EIP和ERC20?ERC是以太坊征求意见的缩写,是以太坊的改进建议。ERC提交后,以太坊社区将对草案进行评估,并最终接受或拒绝该提案。
如果被接受,ERC将被承认为EIP。
EIP是以太坊改进建议的缩写,即以太坊被接受的改进建议。
ERC按时间顺序从1开始递增,ERC 20是第20个建议。
在说ERC20之前,我们先来看看代币发行过程中存在的问题。
正如我们上面所说,令牌是智能合约,智能合约是代码。虽然代币契约主要用于查账、转账、记账,但是在缺乏规范约束的情况下,每个代币的实现可能是不同的。
比如猪币的转账函数是T,参数的顺序是余额和收款人;猫币的转账函数是tr,参数顺序是收款人和余额。虽然每个都可以,但是很多应用集成起来会很麻烦,会导致集成尽可能多的令牌。尤其是交易所、钱包等应用。
ERC20是一个关于代币的提案,由以太坊联合创始人Vitalik于2015年6月提出。这是一个简单的接口,允许开发者在以太坊区块链上发布他们自己的令牌,并且可以与第三方应用程序集成。
eips.ethereum.org/EIPS/eip-20 EIP 20号的地址
既然是接口,就是规范约束。每个人都应该遵循这个接口来实现他们的令牌契约。
如果你不按照这个规范来实现你的令牌契约,那么你的令牌集成到第三方应用的时候是不会被识别的,比如令牌名称,余额等。无法在MetaMask中正常显示。
代币的价值很大程度上取决于发行量。如果你的代币不能通用和流通,基本上就失去了代币的价值。
因此,要发行令牌,应该根据ERC20接口实现契约。
截至本文撰写时(2023年1月4日),以太坊有近74万个ERC20代币,BSC有近300万个ERC20代币。从这些数字可以看出,ERC20对代币的发展起到了重要的推动作用。
对了,BSC就是币安的智能链。因为以太坊交易的气费太贵,BSC模仿以太坊做自己的平台。但是和以太坊相比,气少了很多,所以吸引了很多用户,自然发展的比较晚。
ERC20接口简介ERC20接口指定了9个方法和2个事件。
方法:
函数名称()公共视图返回(字符串)函数符号()公共视图返回(字符串)函数小数()公共视图返回(uint8)函数totalSupply()公共视图返回(uint256)函数balanceOf(address _owner)公共视图返回(uint256 balance)函数transfer(address _to,uint256 _value)公共返回(bool success)函数transferFrom(address _from,address _to,uint256 _value)公共返回(bool success)函数approve(address _spender,Uint256 _ value
事件转移(address indexed _ from,address indexed _ to,uint256 _ value)事件审批(address indexed _ owner,address indexed _ spender,uint256 _ value)我们来详细解释一下它们的作用。
Name:返回令牌名称。例如,如果我创建一个诺亚硬币,它将返回'诺亚'Symbol:返回令牌符号。比如诺亚币的符号是NH,那么就返回‘NH’。也可以叫令牌码。Decimals:返回令牌使用的小数位数。将通过将令牌数除以该值来向用户显示令牌。也就是准确性。通常使用18。TotalSupply:返回颁发的令牌总数。举个例子,如果只发行了一万个诺亚币,那么就返还一万个。BalanceOf:返回指定帐户的余额。转移:将指定数量的令牌转移到指定的地址,需要触发转移事件。转移:将指定数量的令牌从一个指定地址转移到另一个指定地址。这通常叫取钱,但要看授权。批准:允许指定的地址从您的帐户中多次提取代币,最多不超过指定的金额。并且需要触发审批事件,也就是授权。允许:查询指定地址到另一个指定地址的授权令牌量。我们可以把它们分为三类,查询、转账和授权:
查询类方法有:名称、符号、小数、totalSupply和balanceOf。
其中,名称、符号和符号是可选的,因为它们没有特定的功能。但是建议是全部实现。
TotalSupply和balanceOf分别是发行总额和核对余额,很好理解。
转移方式有:转学。
它可以将令牌从您的帐户转移到另一个帐户,这很容易理解。
授权方式有:转出、审批、允许。
这三个功能可能很难理解。
我再举一个例子详细说说授权。
假设我是一个游戏平台(游戏平台也是一个地址,和用户没什么区别)。玩家张三完成了我的任务,我奖励他50个代币。但我不会直接转到他的账户上,而是记在授权的账本上。玩家张三可以用我的50代币。
第四,李是游戏商,卖游戏道具。如果张想在李四手里买一个价值30代币的道具,可以用平台的代币支付给李四。而且这个代币不一定会直接打入李四的账户。和上面的游戏一样,我也在授权的账本里写了下来,允许李四使用我的30个代币,同时把张三元那50个代币的账本改成20个代币。
这是授权的玩法,对应的实现是:
平台授予玩家一个令牌:批准。
查看玩家在游戏平台的授权代币余额:津贴。
使用玩家平台授权的代币进行交易:transferFrom。
当然,这只是我举的一个场景作为例子。授权的玩法可以应用在更多的场景中。
ERC20接口智能合约实现ERC20的代码实现是很多刚接触智能合约的小伙伴需要学习的内容。
你可能需要使用VSCode或者Remix作为编辑器来编写Solidity代码。这部分我就不说了。
由于一些特殊原因,我在这里选择VSCode。
我会用松露来创造项目。
它可以帮助我们编译和部署合同。
运行命令创建项目:
MK noth-token-contract CD noth-token-contract truffle init创建contracts/IERC20.sol文件并定义IERC20接口。
//spdx-license-identifier:MIT pragma solidity ^0.8.0;接口IERC20 {函数名()外部视图返回(字符串内存);函数符号()外部视图返回(字符串内存);函数小数()外部视图返回(uint 8);函数totalSupply()外部视图返回(uint 256);函数balanceOf(address _owner)外部视图返回(uint 256 balance);函数传递(address _to,uint256 _value)外部返回(bool成功);函数transferFrom( address _from,address _to,uint256 _value)外部返回(bool成功);函数approve(address _spender,uint256 _value)外部返回(bool成功);函数津贴(address _owner,address _spender)外部视图返回(uint256剩余);事件转移(address indexed _from,address indexed _to,uint 256 _ value);事件批准(address indexed _owner,address indexed _spender,uint 256 _ value);}然后创建contracts/NoahToken.sol文件实现IERC20接口。
//spdx-license-identifier:MIT pragma solidity ^0.8.0;\”导入\”。/ierc 20。sol '合同诺阿托肯是IERC20 { string private _ name//代币名称string private _ symbol//代币代号uint8 private _ decimals//代币精度uint256 private _ totalSupply//代币发行总量映射(地址=uint 256)private _ balances;//账本mapping(address=mapping(address=uint 256))private _ allow ance;//授权记录公共所有者地址;//合约发布者构造函数(string memory _initName,string memory _initSymbol,uint8 _initDecimals,uint256 _initTotalSupply ) { //发布合约时设置代币名称、代号、精度和发行总量_ name=_ init name _ symbol=_ init symbol _ decimals=_ init decimals _ total supply=_ initTotalSupplyowner=msg.sender//在合约部署时把所有的代币发行给合约发布者_ balances[owner]=_ initTotalSupply;}函数名()外部视图覆盖返回(字符串内存){ return _ name}函数符号()外部视图覆盖返回(字符串内存){ return _ signal }函数小数()外部视图覆盖returns(uint 8){ return _ decimals;}函数总供应量()外部视图覆盖returns(uint 256){ return _ total supply;}功能平衡(address _ owner)外部视图覆盖returns(uint 256 balance){ return _ balances[_ owner];}函数传递(地址_收件人,uint256 _值)外部覆盖返回(布尔成功){ //检查发送者余额是否足够要求(_余额[消息。发件人]=_ value,'余额不足');//扣除发送者余额_ balances[消息。发件人]-=_ value;//增加接收者余额_ balances[_ to]=_ value;//触发转账事件发出传送(msg.sender,_to,_ value);返回真实}函数transferFrom(地址发件人,地址收件人,uint256值)外部覆盖返回(布尔成功){ //检查发送者余额是否足够require(_ balances[_ from]=_ value,'余额不足');//检查授权额度是否足够要求(_余量[_from][msg.sender]=_value,'余量不足');//扣除发送者余额_ balances[_ from]-=_ value;//增加接收者余额_ balances[_ to]=_ value;//扣除授权额度_ allow ance[_ from][msg。发件人]-=_ value;//触发转账事件发出传送(_from,_to,_ value);返回真实}函数批准(address _spender,uint256 _value)外部覆盖返回(布尔成功){ //设置授权额度_允许ance[msg。sender][_ spender]=_ value;//触发授权事件发出批准(消息发送者,_花费者,_价值);返回真实}函数津贴(地址_所有者,地址_支出者)外部视图覆盖返回(uint256剩余){ return _ allow ance[_ owner][_ spender];}}具体代码的作用我都加到注释中了,就不再多赘述。
在合约编写完成之后,我们需要在本地进行测试、编译、部署。
使用松露测试智能合约松露支持通过代码对智能合约进行测试。目前支持Java脚本语言和固态两种语言,但Java脚本语言更灵活,也更流行。这里选择Java脚本语言进行测试。
创建测试/令牌。射流研究…文件,该文件是测试文件。
测试平衡关于与转移函数松露使用摩卡和柴这两个库作为断言库,但略有不同。
首先应该使用合同函数而不是形容函数。
合同函数会传递一个默认参数,它会提供一组可用的账户。
const Noah token=artifacts . require(' Noah token ');contract('Token '(accounts)={ const [alice,bob]=accounts;It('balanceOf 'async ()={//发行诺亚币,发行1024 const noahtokeninstance=await noahtoken . new('诺亚''诺亚'0,' 1024 '{ from:Alice });//检查alice的余额是否为1024 const result=awaitnoahtokeninstance . balance of(Alice);assert.equal(result.valueOf()。单词[0],1024,‘1024不在爱丽丝’);});It('transfer 'async ()={//发行诺亚币,发行1024 const noahtokeninstance=await noahtoken . new(' Noah '' Noah '0,' 1024 '{ from:Alice });//爱丽丝转账1枚诺亚币给鲍勃Await NoahTokenistance.transfer(鲍勃,1,{from:爱丽丝});//检查爱丽丝的余额是否为1023 let balance result=awaitnoahtokeninstance . balance of(爱丽丝);assert . equal(alicebalancesult . value of()。单词[0],1023,‘1023不在爱丽丝’);//检查bob的余额是否为1 let Bob balance result=awaitnoahtokeninstance . balance of(Bob);assert . equal(bobbalance result . value of()。单词[0],1,' 1不在bob中');//bob将1枚诺亚币转账给Alice Await noahtokenistance . transfer(Alice,1,{ from:Bob });//检查alice的余额是否为1024 alicebalancesult=awaitnohtokeninstance . balance of(Alice);assert . equal(alicebalancesult . value of()。单词[0],1024,‘1024不在爱丽丝’);//检查bob的余额是否为0 bobbalance result=awaitnoahtokeninstance . balance of(Bob);assert . equal(bobbalance result . value of()。单词[0],0,' 0不在bob中');});});代码里有详细的注释,这里就不赘述了。其他功能也可以用这种方式测试。
写入以下内容后运行命令:
松露测试。/test/token.js可以全部通过。
使用ganache在本地部署智能合约,除了代码测试之外,我们通常还需要将合约部署到开发环境中,集成调试前端代码。
我使用ganache部署智能合约,它将在本地运行区块链。
配置truffle-config.js和迁移文件。首先修改项目中的truffle-config.js文件,添加开发环境的相关配置。
{ ' network '{ development:{ host:' 127 . 0 . 0 . 1 '//Localhost(默认:无)port: 7545,//Standard Ethereum port(默认:无)network_id: '*,//anynetwork(默认:无)}}}同时创建一个migration/1 _ noahtoken _ migration . js文件进行部署。
内容如下:
const Noah token=artifacts . require(' Noah token ');module . exports=function(deployer){ deployer . deploy(NoahToken,' noah '' NOAH '18,' 102400000000000000 ');}deployer.deploy的第一个参数是契约,其余参数是部署契约传递的参数。
部署到ganache,最后运行truffle编译的部署脚本:
Truffle migrate-network development-f1 network参数是指定的网络环境,Truffle会将契约部署到指定的网络。
f参数是指定部署文件名的前缀,truffle将从这个文件开始迁移。
等一下,你可以在加纳切的合同里看到这个合同的地址。
点击查看合同的详细内容。
但是需要注意的是,ganache中的数字是以十六进制形式显示的,所以decimals和totalSupply与我们传入的十进制数不匹配。
另外注意:ganache中的贴图总是有显示问题,总是显示0个项目。这个Bug已经存在一年多了。记得我第一次用Ganache的时候,曾经怀疑自己的合同有问题,为此问题折腾了一整天,至今记忆犹新。可惜一年多过去了,ganache还没有修复这个Bug。
配置MetaMask网络在测试之前,我们需要先配置网络。
配置信息如下图所示:
在元掩码中添加令牌接下来,我们将在元掩码中添加令牌。
在这一步中,您可以看到代币余额。
但是本地链在MetaMask中无法正常显示,但是部署到链中时是正常的。
前端DApp使用了很多库。让我们先安装这些库。
创建Nextjs项目运行命令创建项目:
NPCREATE-NEXT-APP项目的名称取决于您的偏好;编程语言选择打字稿。
用于安装wagmi和etherjs以与智能合约交互的SDK使用wagmi和etherjs,安装依赖于:
M I wag miers安装chakraUI组件库,选择chakra,安装依赖于:
NPI @ chakra-ui/react @ emotion/react @ emotion/styledframemotion安装配置tailwindcss框架选择tailwindcss,安装依赖于:
m install-d tail wind CSS post CSS autoprefixer初始化配置。
Xtailwind CSS init-p修改tailwind.config.js的内容
/** @type {import('tailwindcss ')。config } */module . exports={ content:['/pages/**/*。{js,ts,jsx,tsx}“,”。/components/**/*。{js,ts,jsx,tsx} '],主题:{extend: {},},插件:[],}修改styles/globals.css的内容
@顺风基地;@tailwind组件;@ tailwind utilities这些配置相当麻烦。更多详细信息,请参考官方文档。
关闭React nextjs的严格模式会默认开启React的严格模式,但是我们无法使用,需要关闭。
/* * @ type {import ('next ')。nextconfig } */constnextconfig={ ReactTrictMode:false,} module . exports=nextconfig Create pages/Noah-token . tsx文件这是我们令牌的操作页面。
导出默认函数NoahToken() { return phello,NoahToken!/p}关闭服务器呈现。接下来需要配置wagmi的相关配置。但在此之前,我们需要关闭SSR。
JS的页面默认都是支持SSR的,这会导致下面的错误。
触发此错误是因为服务器的用户界面与客户端的用户界面不一致。
关闭服务器端渲染很简单。
从“下一个/动态”导入动态;导出默认动态(()=Promise.resolve(NoahToken),{ SSR:false });开发功能代码分为几个部分:
简介:个人信息。详细信息:令牌信息。BalanceOf:检查余额。转学:转学。允许:检查授权余额。批准:授权。转让来源:授权转让。代码很多,这里就不多做分析了。考虑在后续单独写一篇文章专门介绍wagmi。
在线部署将合同部署到GoerilGoeril是目前最流行的测试网络之一。接下来,我们将把诺亚币部署到这个网络中。
要部署到Goeril,首先需要在app.infura.io/.上创建一个项目
然后就可以得到API密钥了。
返回到合同项目。
安装两个软件包:
NPI @ truffle/HD wallet-provider dotenvdotenv用于读取环境变量。
创建一个。env文件,并编写以下内容:
private _ key=' XXX ' project _ id=' XXX '返回到truffle-config.js文件并添加goerli相关配置:
要求(' dotenv ')。config();const { PRIVATE_KEY,PROJECT _ ID }=process.envconst HDWalletProvider=require(@ truffle/HD wallet-provider));module.exports={ //.网络:{ //.goer Li:{ provider:()=new hdwallet provider(PRIVATE _ KEY,` https://goer Li . in fura . io/v3/$ { PROJECT _ ID } `),network_id: 5,//Goerli的ID确认:2,//#在部署之间等待的确认。(默认值:0) timeoutBlocks: 200,//-部署超时前的块数(最小值/默认值:50) skipDryRun: true //在迁移前跳过模拟运行?(对于公共网络,默认值为false)} } }最后,运行命令:
truffle migrate-network goer Li-f1稍等,部署成功。
将DApp部署到韦尔塞尔
在部署之前,需要在vercel的环境变量中配置契约地址。
由于我之前配置过Vercel,这部分不是重点,就不展开了。
当然,在实际工作中,我们并不是真的从零开始实现一个ERC20的代币合约,而是通常使用OpenZepplin的库一键发行硬币。本文的目的是关注学习。
知道如何发行代币是不够的。我们还需要知道如何推广硬币。推广硬币最简单的方法就是发布一个免费的收币网站,因为网络上最不可或缺的就是羊毛党。
后面我还会写一篇如何开发一个免费的钱币收藏网站,也就是龙头网站的文章。
Web3是未来世界的一大变数。我们想帮助更多的人了解并加入Web3。如果你对Web3感兴趣,记得关注我~
一起定居,一起成长,一起拥抱未来。
#标题创作挑战# #web3#