使用React、Ethers.js、Solidity和Hardhat构建全栈dApp。
在本教程中,您将学习一个web3技术堆栈,它允许您在几十个区块链网络上构建全栈应用程序,包括Ethereum、Polygon、Avalanche、Celo等。通过使用以太坊虚拟机(EVM)。
这个项目的代码位于这里[1]。本教程的视频课程位于此处[2]。另请参见定义web3堆栈[3]
自从我开始在区块链领域工作以来,我一直在深入研究Solidity和EVM的智能合同开发。我已经确定了技术堆栈,我认为是谁开始构建具有可靠性的全堆栈dApp:
客户端框架-反应
以太坊开发环境-安全帽[4]
以太坊Web客户端库-Ethers.js[5]
Api层-图形协议[6]
我在学习这个的过程中遇到的问题是,虽然这些东西中的每一个都有相当好的文档,但实际上没有任何关于如何将所有这些东西放在一起并理解它们如何一起工作的内容。有一些非常好的模板,比如scaffold-eth[7](包括Ethers、Hardhat和The Graph),但是对于初学者来说可能太多了。
我想要一个端到端的指南,告诉我如何使用最新的资源、库和工具来构建一个完整的以太坊应用程序。
我感兴趣的是:
1.如何创建、部署和测试以太坊智能合约到本地、测试和主网络2。如何在本地、测试和生产环境/网络之间切换3。如何使用React、Vue、Svelte或Angular等各种前端环境连接到契约并与之交互。在花了一些时间搞清楚了所有这些,开始使用我非常满意的栈之后,我觉得把如何使用这个栈来构建和测试一个完整的以太坊应用写出来会很好,不仅是给其他可能对这个栈感兴趣的人,也是给他们以后的参考。这是参考。
片段让我们回顾一下我们将使用的主要部分,以及它们如何适合堆栈。
1.在构建智能合约时,您需要一种方法来部署合约、运行测试和调试Solidity代码,而无需处理实时环境。
您还需要一种方法来将您的Solidity代码编译成可以在客户端应用程序中运行的代码。在我们的例子中,它是一个React应用程序。稍后我们将了解它是如何工作的。
Hardhat是一个专门为全栈开发设计的以太坊开发环境和框架,也是我在本教程中将用到的框架。
生态系统中其他类似的工具还有Ganache[8]、Truffle[9]和Foundry[10]。
2.以太坊Web客户端库在我们的React应用程序中,我们需要一种方法来与部署的智能合约进行交互。我们需要一种读取数据和发送新事务的方法。
Ethers.js[11]旨在成为一个完整而紧凑的库,用于通过客户端JavaScript应用程序(如React、Vue、Angular或Svelte)与以太坊区块链及其生态系统进行交互。这是我们将使用的图书馆。
生态系统中另一个流行的选择是web3.js[12]。
3.MetaMaskMetamask[13]帮助处理帐户管理并将当前用户连接到区块链。元掩码使用户能够以几种不同的方式管理他们的帐户和密钥,同时将他们与站点上下文隔离开来。
一旦用户连接了他们的MetaMask钱包,作为开发人员的你就可以与全球可用的以太坊API (window.ethereum)进行交互,它可以识别web3兼容浏览器的用户(例如MetaMask用户),每当你请求交易签名时,MetaMask都会提示你以尽可能简单易懂的方式向用户展示。
4.ReactReact是一个前端JavaScript库,用于构建Web应用程序、用户界面和UI组件。它由脸书和许多个人开发者和公司维护。
React及其庞大的元框架生态系统(如Next.js[14]、Gatsby[15]、Redwood[16]、Blitz.js[17]等)。)支持各种部署目标,包括传统SPA、静态站点生成器、服务器端渲染以及三者的结合。React似乎将继续主导前端领域,我认为在不久的将来,React将继续这样做。
5.图形对于以太坊等基于区块链构建的大多数应用来说,直接从链中读取数据既困难又耗时,所以你过去常常会看到个人和公司构建自己的集中式索引服务器,并从这些服务器中服务API请求。这需要大量的工程和硬件资源,并且破坏了去中心化所需的安全属性。
Graph是一个用于查询区块链数据的索引协议,它支持创建完全分散的应用程序,并解决了这个问题,公开了应用程序可以使用的丰富的GraphQL查询层。在本指南中,我们不会为我们的应用程序构建子图,但我们会在以后的教程中这样做。
要了解如何使用图形构建区块链API,请参见在以太坊上构建图形QL API[18]。
我们将构建什么在本教程中,我们将构建、部署并连接到几个基本的智能合约:
1.在以太坊区块链2上创建和更新消息契约。铸造代币的契约,然后允许契约的所有者将代币发送给其他人并读取代币的余额,新代币的所有者也可以发送给其他人。我们还将构建一个React前端,允许用户:
1.阅读部署到区块链2号的合同中的问候。更新问候语3。将新制造的令牌从它们的地址发送到另一个地址4。一旦有人收到令牌,允许他们发送给其他人。5.从部署到区块链的合同中读取令牌余额的先决条件1。本地机器上安装的Node.js2. MetaMask[19] Chrome扩展安装在您的浏览器中。对于本指南,您不需要拥有任何以太坊,因为我们会。
首先,我们将创建一个新的React应用程序:
Npx create-react-app react-dapp接下来,切换到新目录,使用NPM或Yarnethers.js[20]安装使用hardhat[21]:
NPM安装Ethers Hardhat @ nomi labs/hard hat-Waffle以太坊-Waffle Chai @ nomi labs/hard hat-Ethers安装并配置以太坊的开发环境接下来,用hard hat初始化一个新的以太坊开发环境:
npx安全帽?你想干嘛?创建一个JavaScript项目?Hard hat项目根目录:选择默认路径如果遇到有关README.md文件的错误,请删除README.md文件并重新运行该命令。
现在,您应该可以在根目录中看到为您创建的以下工件:
Hardhat . config . js——您的整个hard hat设置(即您的配置、插件和定制任务)都包含在这个文件中。scripts-包含名为sample-script.js的脚本的文件夹,该脚本将在执行时部署您的智能合约测试-包含示例测试脚本的文件夹-包含示例Solidity智能合约的文件夹。
由于MetaMask [22]的配置问题,我们需要将HardHat配置上的链ID更新为1337。我们还需要更新已编译契约的工件[23]的位置,以便它位于React应用程序的src目录中。
要进行这些更新,请打开hardhat.config.js并更新module.exports,如下所示:
module . exports={ solidity:' 0 . 8 . 9 '路径:{ artifacts:'/src/artifacts '},网络:{ hard hat:{ chainId:1337 } };我们的智能合同接下来,我们来看看contracts/Greeter.sol中提供给我们的合同样本:
//spdx-license-identifier:MIT pragma solidity ^0.8.9;导入“hard hat/console . sol”;合同问候语{字符串问候语;构造函数(string memory _ greeting){ console . log('部署带有问候语的欢迎器:'_ greeting);问候语=_问候语;}函数greet() public view returns(字符串内存){ return greeting}函数set Greeting(string memory _ greeting)public { console . log('将问候语从' %s '更改为' %s ' 'greeting,_ greeting);问候语=_问候语;}}这是一个很基础的智能合约。部署时,它设置一个问候变量并公开一个函数(Greeting ),可以调用该函数返回问候。
它还公开了一个允许用户更新setGreeting的函数。当部署到以太坊区块链时,这些方法将可供用户进行交互。
以太坊区块链的读写和与智能合约的交互有两种方式,读或写/交易。在我们的合同中,问候语可以被认为是阅读,而setGreeting可以被认为是写作/交易。
当写入或初始化交易时,您必须为要写入区块链的交易付款。为了让这个作品成功,你需要付出【气】(https://www.investopedia.com/terms/g/gas-ethereum.asp #:~:text=什么是气(以太坊)?以太坊区块链平台),这是在以太坊区块链上成功交易和执行合同所需的成本或价格。
只要你只是从区块链读取数据,而不改变或更新任何东西,你就不需要交易,也不会有汽油或成本。然后,你调用的函数只会被你连接的节点执行,你不用付任何气,阅读免费。
在我们的React应用程序中,我们与智能合约交互的方式是使用由Hardhat from contracts创建的库、合约地址和ABI[24]的组合。
什么是ABI?ABI代表应用程序二进制接口。您可以将其视为客户端应用程序和以太坊区块链之间的接口,以太坊部署了您将与之交互的智能合约。
ABI通常由HardHat等开发框架从Solidity smart contracts编译而来。你也可以经常在Etherscan上找到智能合约的ABI[25]。
编译ABI既然我们已经理解了基本的智能合同和ABI是什么,让我们为我们的项目编译一个ABI。
为此,请转到命令行并运行以下命令:
NPX安全帽编译如果你有任何依赖错误问题安全帽-工具箱,请检查[26]安装说明在这里。
现在,您应该在src目录中看到一个名为artifacts的新文件夹。工件/合同/greeter.json文件包含ABI作为属性之一。当我们需要使用ABI时,我们可以从JavaScript文件中导入它:
从'导入欢迎。/artifacts/contracts/greeter . sol/greeter . JSON '那么我们可以这样引用ABI的话:
Console.log ('greeter ABI:'greeter.abi)请注意,Ethers.js也支持人类可读的ABI[27],但这不会在本教程中涉及。
部署并使用本地网络/区块链链路,让我们将智能合约部署到本地区块链,以便我们可以测试它。
要部署到本地网络,您需要首先启动本地测试节点。为此,请打开CLI并运行以下命令:
Npx hardhat节点当我们运行这个命令时,您应该会看到一个地址和私钥列表。
这是为我们创建的20个测试帐户和地址,我们可以使用它们来部署和测试我们的智能合同。每个账户还包含10,000枚伪造的空灵硬币。稍后,我们将学习如何将测试帐户导入MetaMask,以便我们可以使用它。
接下来,使用以下代码更新scripts/deploy.js以部署Greeter协定:
const hre=require(' hard hat ');异步函数main(){ const Greeter=await hre . ethers . getcontractfactory(' Greeter ');const greeter=await greeter . deploy(' Hello World ');await greeter . deployed();console.log(`合同成功部署到$ { greeter . address } `);}main()。catch((错误)={ console.error(错误);process . exit code=1;});现在,我们可以运行部署脚本,并为要部署到本地网络的CLI提供一个标志:
NPX hard hat run scripts/deploy . js-Network localhost执行完这个脚本后,智能合约应该部署到本地测试网络,然后我们就应该能够开始与它进行交互了。
当我们部署合同时,它使用我们在启动本地网络时创建的第一个帐户。
如果您查看CLI的输出,您应该能够看到以下内容:
Greeter部署到:0x 9 Fe 46736679d 9 a 65 f 0992 f 2272 de 9 F3 C7 fa6e 0此地址是我们将用于在客户端应用程序中与智能合约对话的地址。保持该地址可用,因为我们在从客户端应用程序连接到它时需要它。
要向智能合约发送交易,我们需要使用运行npx hardhat node时创建的帐户之一连接到MetaMask wallet。在CLI取消的合同列表中,您应该会看到帐号和私钥:
react-dapp git:(main)npx hard hat node started HTTP and web socket JSON-RPC server at http://127 . 0 . 0 . 1:8545/Accounts=========Account # 0:0x f 39 FD 6 e 51 aaad 88 f 6 F4 ce 6 ab 8827279 cffb 922266(第10000个)私钥:0x AC 0974 be 39 a 17 e 36 ba 46 b4d 238 ff 944 bbacb 47.我们可以把这个账号导入MetaMask,开始使用那里的一些假货。
为此,首先打开MetaMask并启用测试网络:
接下来,将网络更新为Localhost 8545:
接下来,在元掩码的帐户菜单中单击导入帐户:
复制并粘贴一个由CLI取消的私钥,然后单击导入。导入帐户后,您应该看到Eth:
现在,我们已经部署了智能合约,并准备好使用帐户,我们可以开始从React应用程序与它进行交互。
连接React客户端在本教程中,我们不会担心使用CSS来构建一个漂亮的UI和这一切。我们100%专注于帮助您启动和运行的核心功能。从那里,你可以把它拿走,如果你想让它看起来很好。
说到这里,让我们回顾一下我们希望React应用程序实现的两个目标:
1.从智能合同2中获取问候语的当前值。允许用户更新问候语的值。知道了这些之后,我们该怎么做呢?为了实现这一目标,我们需要做以下工作:
1.创建一个输入字段和一些本地状态来管理输入值(更新问候)2。允许应用程序连接到用户的元掩码帐户以签署交易3。创建一个读写智能合同的函数。为此,使用以下代码打开src/App.js并更新它,并将greeterAddress的值设置为您的智能合约的地址:
\”导入\”。/app。CSS '从“做出反应”导入{使用状态};从“醚”导入{醚} '从“导入欢迎者”./工件/合同/迎宾员。索尔/迎宾员。JSON '//Update用部署时注销到硬币指示器(coin-levelindicator的缩写)命令行界面(Command Line Interface for batch scripting)的约定地址const greeter address=' your-contract-address '函数App(){//存储本地状态的问候语const [greeting,setGreetingValue]=useState() //请求访问用户的元掩码帐户异步函数请求帐户(){ await window。以太宇宙。请求({ method:' eth _ request accounts ' });} //调用智能合约,读取当前问候语值异步函数fetch greeting(){ if(窗口类型。以太eum!==' undefined '){ const provider=new ethers。提供商。web 3提供商(窗口。乙醚eum)const contract=新乙醚.Contract(greeterAddress,Greeter.abi,provider)try { const data=await contract。问候()控制台。log(' data:'data)} catch(err){ console。log(' Error:'err)} }//调用智能合约,发送更新异步函数setGreeting() { if(!问候语)返回if (typeof window.ethereum!==' undefined '){ await request account()const provider=new ethers。提供商。web 3提供商(窗口。以太eum);const signer=提供者。get signer()const contract=new ethers .Contract(greeterAddress,Greeter.abi,signer)const transaction=await契约。设置问候语(Greeting)等待交易。wait()Fetch Greeting()} } return(p class name=' App ' header class name=' App-header ' button onClick={ Fetch Greeting } Fetch Greeting/button onClick={ Set Greeting } Set Greeting/button input onChange={ e=Set Greeting value(e . target。value)} placeholder='设置问候语'//header/p);}导出默认应用要测试它,请启动反应服务器:
npm开始当应用程序加载时,您应该能够获取当前问候语并将其注销到控制台。您还应该能够通过使用您的元掩码钱包签署合同并花费假醚来更新问候语。
部署和使用实时测试网络我们还可以部署几个以太坊测试网络,如罗普斯滕、林克比或科万,以便在无需将其部署到主网的情况下获得可公开访问的合约版本。在本教程中,我们将部署到罗普斯滕测试网络。
首先,请先更新您的元掩码钱包以连接到罗普斯滕网络。
接下来,通过访问这个[28]或另一个测试水龙头,给自己发送一些测试以太币,以便在本教程的其余部分使用。
我们可以通过注册Infura[29]或炼金术[30](我在本教程中使用Infura)等服务来访问罗普斯滕(或任何其他测试网络) 。
在Infura或魔力中创建应用程序后,您将获得一个如下所示的端点:
https://ropsten.infura.io/v3/your-project-id请务必在Infura或魔力应用程序配置中设置允许以太坊地址列表,以包含您将从中进行部署的帐户的钱包地址。
要部署到测试网络,我们需要使用一些额外的网络信息更新我们的建筑工人配置。我们需要设置的一件事是我们将从中部署的钱包的私钥。
要获取私钥,您可以从元掩码导出它。
我建议不要在您的应用程序中对这个值进行硬编码,而是将其设置为环境变量。
接下来,添加具有以下配置的网络属性:
模块。exports={默认网络:'安全帽'路径:{项目:'/src/artifacts '},网络:{ hardhat: {},ropsten:{ URL:' https://ropsten。在弗拉。io/v3/your-project-id '账号:[`0x $ { your-private-key } ` }]} },实度:' 0.8.9 '};要部署,请运行以下脚本:
npx安全帽运行脚本/deploy.js -网络罗普斯滕部署合约后,您应该能够开始与其交互。您现在应该能够在醚能rops ten Testnet Explorer[31]上查看实时合约。
铸造代币智能合约最常见的用例之一是创建代币,让我们看看我们如何做到这一点。由于我们对所有这些工作原理了解得更多一些,所以我们会走得更快一些。
在主契约目录中创建一个名为令牌。溶胶的新文件。
接下来,使用以下智能合约更新Token.sol:
//spdx-license-identifier:MIT pragma solidity ^0.8.9;导入“安全帽/控制台。sol”;约定令牌{ string public name=' Nader Dabit Token 'string public symbol=' NDTuint公共总供给=1000000;映射(地址=uint)余额;构造函数(){ balances[msg。发送者]=总供应量;}功能转移(地址,单位金额)外部{要求(余额[消息。发件人]=金额,'没有足够的令牌');余额[消息发送者] -=金额;余额[到]=金额;}函数balanceOf(地址账户)外部查看返回(单位){返回余额[账户];}}请注意,此代币合约仅用于演示目的,不符合ERC20[32]标准。我们将在这里[33]介绍ERC20代币
该合约将创建一个名为“纳德达比特令牌\”的新代币,并将供应量设置为1000000。
接下来,编译这个合约:
npx硬件编译现在,更新脚本/部署。射流研究…中的部署脚本以包含这个新的代币合约:
const hre=require('安全帽');异步函数main(){ const[deployer]=await hre。醚类。get signers();console.log('使用帐户部署合同:'部署者。地址);const Greeter=await hre。醚类。getcontractfactory(' Greeter ');等待迎宾员。部署(‘你好,世界!’);const Token=await hre。醚类。getcontractfactory(' Token ');常量令牌=等待令牌。deploy();等待迎宾员。已部署();等待令牌。已部署();console.log('欢迎部署到:'迎宾员。地址);console.log('令牌部署到:'标记。地址);}main().然后(()=process.exit(0)).catch(错误={ console。错误(error));过程。出口(1);});现在,我们可以将这个新合约部署到本地或罗普斯滕网络:
npx安全帽运行脚本/deploy.js -网络本地主机部署合约后,您可以开始将这些代币发送到其他地址。
为此,让我们更新完成这项工作所需的客户端代码:
\”导入\”。/app。CSS '从“做出反应”导入{使用状态};从“醚”导入{醚} '从“导入欢迎者”./工件/合同/迎宾员。索尔/迎宾员。JSON \”导入令牌自\”。/工件/契约/令牌。溶胶/令牌。JSON ' const greeter address=' your-contract-address ' const token address=' your-contract-address ' function App(){ const[greeting,setGreetingValue]=use state()const[user account,setuser account]=use state()const[amount,setAmount]=useState()异步函数请求帐户(){ await window。以太宇宙。请求({ method:' eth _ request accounts ' });}异步函数fetch greeting(){ if(窗口类型。以太eum!==' undefined '){ const provider=new ethers。提供商。web 3提供商(窗口。以太eum)控制台。log({ provider })const contract=new ethers .Contract(greeterAddress,Greeter.abi,provider)try { const data=await contract。问候()控制台。log(' data:'data)} catch(err){ console。日志('错误:'err) } }异步函数get balance(){ if(窗口类型。以太eum!=='未定义'){ const[account]=await window。以太宇宙。request({ method:' eth _ request accounts ' })const provider=new ethers。提供商。web 3提供商(窗口。以太eum);常数合同=新醚合同(tokenAddress,Token.abi,provider)const balance=await合同。(账户)余额;console.log('Balance:'Balance。tostring());} }异步函数setGreeting() { if(!问候语)返回if (typeof window.ethereum!==' undefined '){ await request account()const provider=new ethers。提供商。web 3提供商(窗口。以太eum);控制台。log({ provider })常量签名者=提供者。get signer()const contract=new ethers .Contract(greeterAddress,Greeter.abi,signer)const transaction=await契约。设置问候语(greeting)等待交易。wait()获取问候语()} }异步函数send coins(){ if(窗口类型。以太eum!==' undefined '){ await request account()const provider=new ethers。提供商。web 3提供商(窗口。以太eum);const signer=提供者。获取签名者();常数合同=新醚。合同(tokenAddress,Token.abi签名人);const transaction=等待合同。转账(用户账号,金额);等待交易。wait();控制台。日志(` ${ amount }枚硬币已成功发送至${用户帐户} `);}}导出默认应用接下来,运行应用程序:
npm开始我们应该能够点击获得平衡并看到我们登录到控制台的帐户中有1,000,000 个代币。
您还应该能够通过单击导入令牌在元掩码中查看它们:
接下来单击自定义令牌并输入令牌合约地址,然后单击添加自定义令牌。(如果询问代币小数,请选择0)现在代币应该在您的钱包中可用:
接下来,让我们尝试将这些硬币发送到另一个地址。
为此,请复制另一个帐户的地址,并使用更新后的反应用户界面将它们发送到该地址。当您检查令牌数量时,它应该等于原始数量减去您发送到该地址的数量。
ERC20代币ERC20代币标准[34]定义了一套适用于所有ERC20代币的规则,使它们能够轻松地相互交互100 .ERC 20使得人们可以很容易地铸造自己的代币,这些代币将与以太坊区块链上的其他代币具有互操作性。
让我们看看如何使用ERC20标准构建我们自己的代币。
首先,安装openzeplin[35]智能契约库,我们将在其中导入基本的ERC20令牌:
npminstall @ open zeppelin/contracts接下来,我们将通过扩展(或继承)契约来创建令牌ERC20:
//spdx-license-identifier:MIT pragma solidity ^0.8.9;导入' @ open zeppelin/contracts/token/er C20/er C20 . sol '契约NDToken为ERC20 {构造函数(字符串内存名称,字符串内存符号)ERC20(名称,符号){ _mint(msg.sender,100000 *(10 * * 18));}}构造函数允许您设置令牌名称和符号,_mint函数允许您转换令牌并设置数量。
默认情况下,ERC20将小数位设置为18,因此在我们的_mint函数中,我们将100,000乘以10的18次方,以转换总共100,000个令牌,每个令牌有18个小数位(类似于1 Eth从10到18wei[36])。
为了进行部署,我们需要传入构造函数的值(名称和符号),因此我们可以在部署脚本中执行以下操作:
const nd token=await hre . ethers . getcontractfactory(' nd token ');const nd Token=await nd Token . deploy(' Nader Dabit Token '' NDT ');通过扩展原始ERC20令牌,您的令牌将继承以下所有功能和函数:
函数名称()公共视图返回(字符串)函数符号()公共视图返回(字符串)函数小数()公共视图返回(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之后有关ERC20令牌的另一个示例,请参见Solidity by example[37]。
结论嗯,我们在这里涵盖了很多,但对我来说,这是开始使用这个堆栈的面包和黄油/核心,也是我想要拥有的,不仅作为一个正在学习所有这些东西的人,而且作为我将来可能需要的任何东西,如果我需要引用它的话。我希望你学到了很多。
如果你想支持除MetaMask之外的多个钱包,请查看Web3Modal[38],它可以通过相当简单和可定制的配置,在你的应用程序中轻松支持多个提供者。
在我未来的教程和指南中,我将深入研究更复杂的智能合约开发,以及如何将它们部署为子图[39]以在其上公开GraphQL API,并实现分页和全文搜索。
我还将讨论如何使用IPFS和Web3数据库等技术以分散的方式存储数据。
原文:https://web3.career/learn-web3/web3-interview-questions
引用链接[1] 此处:https://github。com/dabi T3/全栈以太eum[2]此处:https://www.youtube.com/watch?v=a0osIaAOFSE[3]定义web3堆栈:https://edgeandnode。com/blog/defining-The-web 3-stack[4]安全帽:https://安全帽。[5]醚类。js:https://个文档。醚类。io/V5/[6]图协议:https://图表。com/[7]脚手架-eth:https://github。com/austingriffith/scaffold-eth[8]Ganache:https://www .松露套房。块菌在以太坊上构建图表QL API:https://dev。to/dabi T3/建筑图QL-API-on-ether eum-4 poa[19]元掩码:https://元掩码。io/[20]醚。js:https://个文档。醚类。io/V5/[21]安全帽:https://github。经济实验室/安全帽[22]元掩码配置问题:https://安全帽。组织/元掩码-发放。超文本标记语言我们还需要更新已编译合约的工件:https://安全帽。组织/指南/编译-合同。ABI:https://个文档。固体郎。org/en/v 0。5 .3/ABI规格。html[25]您还可以经常在以太网扫描:https://以太网扫描。io/[26]此处的:https://安全帽。org/安全帽-runner/plugins/nomic foundation-安全帽-工具箱[27]人类可读的ABI:https://博客。里穆。F4 d917[28]接下来,通过访问这个:https://faucet.egorfine.com/[29]我们可以通过注册在富拉:https://在富拉。io/dashboard/ether eum/cbdf 7 C5 eee 8 B4 e 2 b 91 e 76 b 77 ffd 34533/settings[30]alchemyapi:https://www .阿尔切米亚皮。io/[31]您现在应该能够在以太网浏览器:https://Ropsten。醚类可以。io/[32]ERC 20:https://eips。以太宇宙。org/EIPS/EIP-20[33]我们将在这里:https://dev。to/dabi T3/the-complete-guide-to-full-stack-ether eum-development-3j 13 # ERC 20-token[34]代币标准:https://以太博物馆。org/en/developers/docs/standards/tokens/ERC-20/[35]open zeplin:https://github。com/open zeppelin/open zeppelin-contracts[36]魏:https://www .investopedia。com/terms/w/Wei。ASP[
37] Solidity by example: https://solidity-by-example.org/app/erc20/[38] Web3Modal: https://github.com/Web3Modal/web3modal[39] subgraphs: https://thegraph.com/docs/define-a-subgraph