应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

全栈以太坊和EVM开发的完整指南

  使用React、Ethers。js、Solidity和Hardhat构建全栈dApp
  在本教程中,您将学习一个web3技术栈,它允许您利用以太坊虚拟机(EVM)在包括以太坊、Polygon、Avalanche、Celo等在内的数十个区块链网络上构建全栈应用程序。
  该项目的代码位于此处〔1〕。本教程的视频课程位于此处〔2〕。另请查看定义web3堆栈〔3〕
  自从我开始在区块链领域工作以来,我一直在深入研究Solidity和EVM的智能合约开发。我已经确定了我认为是开始使用Solidity构建全栈dApp的技术栈:
  客户端框架React
  以太坊开发环境Hardhat〔4〕
  以太坊Web客户端库Ethers。js〔5〕
  API层TheGraphProtocol〔6〕
  我在学习这个的过程中遇到的问题是,虽然对于这些东西中的每一个都有相当好的文档,但实际上没有关于如何将所有这些东西放在一起并理解它们如何相互工作的东西。有一些非常好的样板,例如scaffoldeth〔7〕(其中还包括Ethers、Hardhat和TheGraph),但对于刚入门的人来说可能太多了。
  我想要一个端到端的指南来向我展示如何使用最新的资源、库和工具构建完整的以太坊应用程序。
  我感兴趣的是:1。如何创建、部署和测试以太坊智能合约到本地、测试和主网2。如何在本地、测试和生产环境网络之间切换3。如何使用React、Vue、Svelte或Angular等前端的各种环境连接到合约并与之交互
  在花了一些时间弄清楚所有这些并开始使用我感到非常满意的堆栈之后,我认为写出如何使用这个堆栈构建和测试一个完整的以太坊应用程序会很好,而不仅仅是为了其他人还有谁可能对这个栈感兴趣,也供自己以后参考。这就是那个参考。碎片
  让我们回顾一下我们将使用的主要部分以及它们如何适应堆栈。一、以太坊开发环境
  在构建智能合约时,您需要一种无需处理实时环境即可部署合约、运行测试和调试Solidity代码的方法。
  您还需要一种方法将您的Solidity代码编译成可以在客户端应用程序中运行的代码在我们的例子中,是一个React应用程序。稍后我们将详细了解其工作原理。
  Hardhat是专为全栈开发而设计的以太坊开发环境和框架,也是我将在本教程中使用的框架。
  生态系统中的其他类似工具是Ganache〔8〕、Truffle〔9〕和Foundry〔10〕。2。以太坊Web客户端库
  在我们的React应用程序中,我们需要一种方法来与已部署的智能合约进行交互。我们将需要一种方法来读取数据以及发送新交易。
  ethers。js〔11〕旨在成为一个完整而紧凑的库,用于从React、Vue、Angular或Svelte等客户端JavaScript应用程序与以太坊区块链及其生态系统进行交互。这是我们将要使用的库。
  生态系统中另一个流行的选择是web3。js〔12〕3。MetaMask
  Metamask〔13〕有助于处理帐户管理并将当前用户连接到区块链。MetaMask使用户能够以几种不同的方式管理他们的帐户和密钥,同时将他们与站点上下文隔离开来。
  一旦用户连接了他们的MetaMask钱包,您作为开发人员就可以与全球可用的以太坊API(window。ethereum)交互,该API可以识别web3兼容浏览器的用户(例如MetaMask用户),并且每当您请求交易签名时,MetaMask都会提示以尽可能易于理解的方式向用户展示。4。React
  React是一个前端JavaScript库,用于构建Web应用程序、用户界面和UI组件。它由Facebook和许多个人开发人员和公司维护。
  React及其庞大的元框架生态系统(如Next。js〔14〕、Gatsby〔15〕、Redwood〔16〕、Blitz。js〔17〕等)支持所有类型的部署目标,包括传统SPA、静态站点生成器、服务器端渲染以及这三者的组合。React似乎继续在前端领域占据主导地位,我认为至少在不久的将来会继续这样做。5。Graph
  对于大多数构建在以太坊等区块链上的应用程序,直接从链上读取数据既困难又费时,因此您过去经常看到人们和公司构建自己的集中式索引服务器并为来自这些服务器的API请求提供服务。这需要大量的工程和硬件资源,并破坏了去中心化所需的安全属性。
  Graph是一种用于查询区块链数据的索引协议,它支持创建完全去中心化的应用程序并解决了这个问题,暴露了应用程序可以使用的丰富的GraphQL查询层。在本指南中,我们不会为我们的应用程序构建子图,但会在以后的教程中这样做。
  要了解如何使用TheGraph构建区块链API,请查看在以太坊上构建GraphQLAPI〔18〕。我们将建造什么
  在本教程中,我们将构建、部署和连接到几个基本的智能合约:1。在以太坊区块链上创建和更新消息的合约2。铸造代币的合同,然后允许合同的所有者将代币发送给其他人并读取代币余额,并且新代币的所有者也可以将它们发送给其他人。
  我们还将构建一个React前端,允许用户:1。从部署到区块链的合约中读取问候语2。更新问候语3。将新铸造的代币从他们的地址发送到另一个地址4。一旦有人收到代币,允许他们也将代币发送给其他人5。从部署到区块链的合约中读取代币余额先决条件1。本地机器上安装的Node。js2。MetaMask〔19〕Chrome扩展安装在您的浏览器中
  您不需要为本指南拥有任何以太坊,因为我们将在整个教程的测试网络上使用假测试以太币。入门
  首先,我们将创建一个新的React应用程序:npxcreatereactappreactdapp
  接下来,切换到新目录并使用NPM或Yarnethers。js〔20〕安装和hardhat〔21〕使用:npminstallethershardhatnomiclabshardhatwaffleethereumwafflechainomiclabshardhatethers安装和配置以太坊开发环境
  接下来,使用Hardhat初始化一个新的以太坊开发环境:npxhardhat?Whatdoyouwanttodo?CreateaJavaScriptproject?Hardhatprojectroot:Choosedefaultpath
  如果您遇到有关README。md文件的错误,请删除README。md文件并重新运行该命令。
  现在您应该会在根目录中看到为您创建的以下工件:
  hardhat。config。js您的整个Hardhat设置(即您的配置、插件和自定义任务)都包含在此文件中。scripts一个包含名为samplescript。js的脚本的文件夹,该脚本将在执行时部署你的智能合约test一个包含示例测试脚本的文件夹contracts一个包含示例Solidity智能合约的文件夹
  由于MetaMask配置问题〔22〕,我们需要将HardHat配置上的链ID更新为1337。我们还需要更新已编译合约的工件〔23〕位置,使其位于React应用程序的src目录中。
  要进行这些更新,请打开hardhat。config。js并将module。exports更新为如下所示:module。exports{solidity:0。8。9,paths:{artifacts:。srcartifacts,},networks:{hardhat:{chainId:1337}}};我们的智能合约
  接下来,让我们看一下在contractsGreeter。sol中提供给我们的示例合约:SPDXLicenseIdentifier:MITpragmasolidity0。8。9;importhardhatconsole。sol;contractGreeter{stringgreeting;constructor(stringmemorygreeting){console。log(DeployingaGreeterwithgreeting:,greeting);greetinggreeting;}functiongreet()publicviewreturns(stringmemory){returngreeting;}functionsetGreeting(stringmemorygreeting)public{console。log(Changinggreetingfromstos,greeting,greeting);greetinggreeting;}}
  这是一个非常基本的智能合约。部署时,它会设置一个Greeting变量并公开一个可以调用以返回问候语的函数(greet)。
  它还公开了一个允许用户更新问候语(setGreeting)的函数。当部署到以太坊区块链时,这些方法将可供用户进行交互。读写以太坊区块链
  与智能合约交互的方式有两种,读取或写入交易。在我们的合约中,greet可以认为是读,而setGreeting可以认为是写交易。
  在写入或初始化交易时,您必须为要写入区块链的交易付费。为了使这项工作成功,您需要支付〔gas〕(https:www。investopedia。comtermsggasethereum。asp::textWhatIsGas(Ethereum)3F,ontheEthereumblockchainplatform),这是在以太坊区块链上成功进行交易和执行合同所需的费用或价格。
  只要您只是从区块链中读取数据而不更改或更新任何内容,您就不需要进行交易,也不会产生任何gas或成本。然后,您调用的函数将仅由您连接的节点执行,因此您无需支付任何气体,并且读取是免费的。
  ethers。js在我们的React应用程序中,我们与智能合约交互的方式是使用库、合约地址和Hardhat从合约创建的ABI〔24〕的组合。
  什么是ABI?ABI代表应用程序二进制接口。您可以将其视为您的客户端应用程序与部署您将与之交互的智能合约的以太坊区块链之间的接口。
  ABI通常由HardHat等开发框架从Solidity智能合约编译而成。您还可以经常在Etherscan〔25〕上找到智能合约的ABI编译ABI
  现在我们已经了解了基本的智能合约并了解了ABI是什么,让我们为我们的项目编译一个ABI。
  为此,请转到命令行并运行以下命令:npxhardhatcompile
  如果您有任何依赖性错误问题hardhattoolbox,请查看此处的〔26〕安装说明。
  现在,您应该会在src目录中看到一个名为artifacts的新文件夹。artifactscontractsGreeter。json文件包含ABI作为属性之一。当我们需要使用ABI时,我们可以从我们的JavaScript文件中导入它:importGreeterfrom。artifactscontractsGreeter。solGreeter。json
  然后我们可以像这样引用ABI:console。log(GreeterABI:,Greeter。abi)
  请注意,Ethers。js还支持人类可读的ABI〔27〕,但在本教程中不会涉及到这一点。部署和使用本地网络区块链
  接下来,让我们将智能合约部署到本地区块链,以便我们对其进行测试。
  要部署到本地网络,首先需要启动本地测试节点。为此,请打开CLI并运行以下命令:npxhardhatnode
  当我们运行此命令时,您应该会看到一个地址和私钥列表。
  这些是为我们创建的20个测试帐户和地址,我们可以使用它们来部署和测试我们的智能合约。每个账户还装有10,000个假以太币。稍后,我们将学习如何将测试帐户导入MetaMask,以便我们使用它。
  接下来,使用以下代码更新scriptsdeploy。js以部署Greeter合约:consthrerequire(hardhat);asyncfunctionmain(){constGreeterawaithre。ethers。getContractFactory(Greeter);constgreeterawaitGreeter。deploy(HelloWorld);awaitgreeter。deployed();console。log(contractsuccessfullydeployedto{greeter。address});}main()。catch((error){console。error(error);process。exitCode1;});
  现在我们可以运行部署脚本并为我们想要部署到本地网络的CLI提供一个标志:npxhardhatrunscriptsdeploy。jsnetworklocalhost
  执行此脚本后,智能合约应部署到本地测试网络,然后我们应该能够开始与其交互。
  部署合约时,它使用了我们启动本地网络时创建的第一个帐户。
  如果您查看CLI的输出,您应该能够看到如下内容:Greeterdeployedto:0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
  这个地址是我们将在我们的客户端应用程序中用来与智能合约对话的地址。保持此地址可用,因为我们在从客户端应用程序连接到它时需要使用它。
  要将交易发送到智能合约,我们需要使用运行npxhardhatnode时创建的帐户之一连接我们的MetaMask钱包。在CLI注销的合约列表中,您应该会看到帐号和私钥:reactdappgit:(main)npxhardhatnodeStartedHTTPandWebSocketJSONRPCserverathttp:127。0。0。1:8545AccountsAccount0:0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266(10000ETH)PrivateKey:0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80。。。
  我们可以将此帐户导入MetaMask,以便开始使用那里可用的一些假Eth。
  为此,首先打开MetaMask并启用测试网络:
  接下来,将网络更新为Localhost8545:
  接下来,在MetaMask中点击账户菜单中的导入账户:
  复制然后粘贴由CLI注销的私钥之一,然后单击导入。导入帐户后,您应该会在帐户中看到Eth:
  现在我们已经部署了智能合约并准备好使用帐户,我们可以开始从React应用程序与其交互。连接React客户端
  在本教程中,我们不会担心使用CSS构建漂亮的UI以及所有这些,我们100专注于核心功能,以帮助您启动和运行。从那里,你可以把它拿走,如果你愿意的话,让它看起来不错。
  话虽如此,让我们回顾一下我们希望从React应用程序中实现的两个目标:1。从智能合约中获取greeting当前值2。允许用户更新greeting的值
  了解了这些事情后,我们如何做到这一点?以下是我们需要做的事情来实现这一点:1。创建一个输入字段和一些本地状态来管理输入的值(更新greeting)2。允许应用程序连接到用户的MetaMask帐户以签署交易3。创建用于读取和写入智能合约的函数
  为此,使用以下代码打开srcApp。js并更新它,将greeterAddress的值设置为您的智能合约的地址:import。App。css;import{useState}fromreact;import{ethers}fromethersimportGreeterfrom。artifactscontractsGreeter。solGreeter。jsonUpdatewiththecontractaddressloggedouttotheCLIwhenitwasdeployedconstgreeterAddressyourcontractaddressfunctionApp(){storegreetinginlocalstateconst〔greeting,setGreetingValue〕useState()requestaccesstotheusersMetaMaskaccountasyncfunctionrequestAccount(){awaitwindow。ethereum。request({method:ethrequestAccounts});}callthesmartcontract,readthecurrentgreetingvalueasyncfunctionfetchGreeting(){if(typeofwindow。ethereum!undefined){constprovidernewethers。providers。Web3Provider(window。ethereum)constcontractnewethers。Contract(greeterAddress,Greeter。abi,provider)try{constdataawaitcontract。greet()console。log(data:,data)}catch(err){console。log(Error:,err)}}}callthesmartcontract,sendanupdateasyncfunctionsetGreeting(){if(!greeting)returnif(typeofwindow。ethereum!undefined){awaitrequestAccount()constprovidernewethers。providers。Web3Provider(window。ethereum);constsignerprovider。getSigner()constcontractnewethers。Contract(greeterAddress,Greeter。abi,signer)consttransactionawaitcontract。setGreeting(greeting)awaittransaction。wait()fetchGreeting()}}return(headerclassNameAppheaderbuttononClick{fetchGreeting}FetchGreetingbuttonbuttononClick{setGreeting}SetGreetingbuttoninputonChange{esetGreetingValue(e。target。value)}placeholderSetgreetingheader);}exportdefaultApp;
  要测试它,请启动React服务器:npmstart
  当应用程序加载时,您应该能够获取当前问候语并将其注销到控制台。您还应该能够通过使用您的MetaMask钱包签署合同并花费假Ether来更新问候语。
  部署和使用实时测试网络
  我们还可以部署几个以太坊测试网络,如Ropsten、Rinkeby或Kovan,以便在无需将其部署到主网的情况下获得可公开访问的合约版本。在本教程中,我们将部署到Ropsten测试网络。
  首先,请先更新您的MetaMask钱包以连接到Ropsten网络。
  接下来,通过访问这个〔28〕或另一个测试水龙头,给自己发送一些测试以太币,以便在本教程的其余部分使用。
  我们可以通过注册Infura〔29〕或Alchemy〔30〕(我在本教程中使用Infura)等服务来访问Ropsten(或任何其他测试网络)。
  在Infura或Alchemy中创建应用程序后,您将获得一个如下所示的端点:https:ropsten。infura。iov3yourprojectid
  请务必在Infura或Alchemy应用程序配置中设置ALLOWLISTETHEREUMADDRESSES,以包含您将从中进行部署的帐户的钱包地址。
  要部署到测试网络,我们需要使用一些额外的网络信息更新我们的hardhat配置。我们需要设置的一件事是我们将从中部署的钱包的私钥。
  要获取私钥,您可以从MetaMask导出它。
  我建议不要在您的应用程序中对这个值进行硬编码,而是将其设置为环境变量。
  接下来,添加具有以下配置的networks属性:module。exports{defaultNetwork:hardhat,paths:{artifacts:。srcartifacts,},networks:{hardhat:{},ropsten:{url:https:ropsten。infura。iov3yourprojectid,accounts:〔0x{yourprivatekey}〕}},solidity:0。8。9,};
  要部署,请运行以下脚本:npxhardhatrunscriptsdeploy。jsnetworkropsten
  部署合约后,您应该能够开始与其交互。您现在应该能够在EtherscanRopstenTestnetExplorer〔31〕上查看实时合约。铸造代币
  智能合约最常见的用例之一是创建代币,让我们看看我们如何做到这一点。由于我们对所有这些工作原理了解得更多一些,所以我们会走得更快一些。
  在主contracts目录中创建一个名为Token。sol的新文件。
  接下来,使用以下智能合约更新Token。sol:SPDXLicenseIdentifier:MITpragmasolidity0。8。9;importhardhatconsole。sol;contractToken{stringpublicnameNaderDabitToken;stringpublicsymbolNDT;uintpublictotalSupply1000000;mapping(addressuint)balances;constructor(){balances〔msg。sender〕totalSupply;}functiontransfer(addressto,uintamount)external{require(balances〔msg。sender〕amount,Notenoughtokens);balances〔msg。sender〕amount;balances〔to〕amount;}functionbalanceOf(addressaccount)externalviewreturns(uint){returnbalances〔account〕;}}
  请注意,此代币合约仅用于演示目的,不符合ERC20〔32〕标准。我们将在这里〔33〕介绍ERC20代币
  该合约将创建一个名为NaderDabitToken的新代币,并将供应量设置为1000000。
  接下来,编译这个合约:npxhardhatcompile
  现在,更新scriptsdeploy。js中的部署脚本以包含这个新的Token合约:consthrerequire(hardhat);asyncfunctionmain(){const〔deployer〕awaithre。ethers。getSigners();console。log(Deployingcontractswiththeaccount:,deployer。address);constGreeterawaithre。ethers。getContractFactory(Greeter);constgreeterawaitGreeter。deploy(Hello,World!);constTokenawaithre。ethers。getContractFactory(Token);consttokenawaitToken。deploy();awaitgreeter。deployed();awaittoken。deployed();console。log(Greeterdeployedto:,greeter。address);console。log(Tokendeployedto:,token。address);}main()。then(()process。exit(0))。catch(error{console。error(error);process。exit(1);});
  现在,我们可以将这个新合约部署到本地或Ropsten网络:npxhardhatrunscriptsdeploy。jsnetworklocalhost
  部署合约后,您可以开始将这些代币发送到其他地址。
  为此,让我们更新完成这项工作所需的客户端代码:import。App。css;import{useState}fromreact;import{ethers}fromethersimportGreeterfrom。artifactscontractsGreeter。solGreeter。jsonimportTokenfrom。artifactscontractsToken。solToken。jsonconstgreeterAddressyourcontractaddressconsttokenAddressyourcontractaddressfunctionApp(){const〔greeting,setGreetingValue〕useState()const〔userAccount,setUserAccount〕useState()const〔amount,setAmount〕useState()asyncfunctionrequestAccount(){awaitwindow。ethereum。request({method:ethrequestAccounts});}asyncfunctionfetchGreeting(){if(typeofwindow。ethereum!undefined){constprovidernewethers。providers。Web3Provider(window。ethereum)console。log({provider})constcontractnewethers。Contract(greeterAddress,Greeter。abi,provider)try{constdataawaitcontract。greet()console。log(data:,data)}catch(err){console。log(Error:,err)}}}asyncfunctiongetBalance(){if(typeofwindow。ethereum!undefined){const〔account〕awaitwindow。ethereum。request({method:ethrequestAccounts})constprovidernewethers。providers。Web3Provider(window。ethereum);constcontractnewethers。Contract(tokenAddress,Token。abi,provider)constbalanceawaitcontract。balanceOf(account);console。log(Balance:,balance。toString());}}asyncfunctionsetGreeting(){if(!greeting)returnif(typeofwindow。ethereum!undefined){awaitrequestAccount()constprovidernewethers。providers。Web3Provider(window。ethereum);console。log({provider})constsignerprovider。getSigner()constcontractnewethers。Contract(greeterAddress,Greeter。abi,signer)consttransactionawaitcontract。setGreeting(greeting)awaittransaction。wait()fetchGreeting()}}asyncfunctionsendCoins(){if(typeofwindow。ethereum!undefined){awaitrequestAccount()constprovidernewethers。providers。Web3Provider(window。ethereum);constsignerprovider。getSigner();constcontractnewethers。Contract(tokenAddress,Token。abi,signer);consttransationawaitcontract。transfer(userAccount,amount);awaittransation。wait();console。log({amount}Coinssuccessfullysentto{userAccount});}}return(headerclassNameAppheaderbuttononClick{fetchGreeting}FetchGreetingbuttonbuttononClick{setGreeting}SetGreetingbuttoninputonChange{esetGreetingValue(e。target。value)}placeholderSetgreetingbrbuttononClick{getBalance}GetBalancebuttonbuttononClick{sendCoins}SendCoinsbuttoninputonChange{esetUserAccount(e。target。value)}placeholderAccountIDinputonChange{esetAmount(e。target。value)}placeholderAmountheader);}exportdefaultApp;
  接下来,运行应用程序:npmstart
  我们应该能够点击GetBalance并看到我们登录到控制台的帐户中有1,000,000个代币。
  您还应该能够通过单击导入令牌在MetaMask中查看它们:
  接下来单击CustomToken并输入令牌合约地址,然后单击AddCustomToken。(如果询问代币小数,请选择0)现在代币应该在您的钱包中可用:
  接下来,让我们尝试将这些硬币发送到另一个地址。
  为此,请复制另一个帐户的地址,并使用更新后的ReactUI将它们发送到该地址。当您检查令牌数量时,它应该等于原始数量减去您发送到该地址的数量。ERC20代币
  ERC20代币标准〔34〕定义了一套适用于所有ERC20代币的规则,使它们能够轻松地相互交互。ERC20使得人们可以很容易地铸造自己的代币,这些代币将与以太坊区块链上的其他代币具有互操作性。
  让我们看看如何使用ERC20标准构建我们自己的代币。
  首先,安装OpenZepplin〔35〕智能合约库,我们将在其中导入基础ERC20令牌:npminstallopenzeppelincontracts
  接下来,我们将通过扩展(或继承)合约来创建我们的代币ERC20:SPDXLicenseIdentifier:MITpragmasolidity0。8。9;importopenzeppelincontractstokenERC20ERC20。sol;contractNDTokenisERC20{constructor(stringmemoryname,stringmemorysymbol)ERC20(name,symbol){mint(msg。sender,100000(1018));}}
  构造函数允许您设置代币名称和符号,mint函数允许您铸造代币并设置数量。
  默认情况下,ERC20将小数位数设置为18,因此在我们的mint函数中,我们将100,000乘以10的18次方来铸造总共100,000个代币,每个代币有18个小数位(类似于1Eth由10到18wei〔36〕。
  要部署,我们需要传入构造函数值(name和symbol),因此我们可能会在部署脚本中执行如下操作:constNDTokenawaithre。ethers。getContractFactory(NDToken);constndTokenawaitNDToken。deploy(NaderDabitToken,NDT);
  通过扩展原始的ERC20代币,您的代币将继承以下所有功能和功能:functionname()publicviewreturns(string)functionsymbol()publicviewreturns(string)functiondecimals()publicviewreturns(uint8)functiontotalSupply()publicviewreturns(uint256)functionbalanceOf(addressowner)publicviewreturns(uint256balance)functiontransfer(addressto,uint256value)publicreturns(boolsuccess)functiontransferFrom(addressfrom,addressto,uint256value)publicreturns(boolsuccess)functionapprove(addressspender,uint256value)publicreturns(boolsuccess)functionallowance(addressowner,addressspender)publicviewreturns(uint256remaining)
  部署后,您可以使用这些功能中的任何一个与新的智能合约进行交互。有关ERC20代币的另一个示例,请查看Soliditybyexample〔37〕结论
  好吧,我们在这里涵盖了很多,但对我来说,这是开始使用这个堆栈的面包和黄油核心,也是我想要拥有的东西,不仅是作为一个正在学习所有这些东西的人,而且也是未来如果我需要参考我将来可能需要的任何东西。我希望你学到了很多。
  如果除了MetaMask之外你还想支持多个钱包,请查看Web3Modal〔38〕,它可以通过相当简单和可自定义的配置轻松地在你的应用程序中实现对多个提供商的支持。
  在我未来的教程和指南中,我将深入研究更复杂的智能合约开发,以及如何将它们部署为subgraphs〔39〕以在它们之上公开GraphQLAPI并实现分页和全文搜索等功能。
  我还将探讨如何使用IPFS和Web3数据库等技术以分散的方式存储数据。
  原文:https:web3。careerlearnweb3web3interviewquestions
  引用链接
  〔1〕此处:https:github。comdabit3fullstackethereum
  〔2〕此处:https:www。youtube。comwatch?va0osIaAOFSE
  〔3〕定义web3堆栈:https:edgeandnode。comblogdefiningtheweb3stack
  〔4〕Hardhat:https:hardhat。org
  〔5〕Ethers。js:https:docs。ethers。iov5
  〔6〕TheGraphProtocol:https:thegraph。com
  〔7〕scaffoldeth:https:github。comaustintgriffithscaffoldeth
  〔8〕Ganache:https:www。trufflesuite。comganache
  〔9〕Truffle:https:www。trufflesuite。com
  〔10〕Foundry:https:www。paradigm。xyz202112introducingthefoundryethereumdevelopmenttoolbox
  〔11〕ethers。js:https:docs。ethers。iov5
  〔12〕web3。js:https:web3js。readthedocs。ioenv1。3。4
  〔13〕Metamask:https:metamask。iodownload。html
  〔14〕Next。js:https:nextjs。org
  〔15〕Gatsby:https:www。gatsbyjs。com
  〔16〕Redwood:https:redwoodjs。com
  〔17〕Blitz。js:https:blitzjs。com
  〔18〕在以太坊上构建GraphQLAPI:https:dev。todabit3buildinggraphqlapisonethereum4poa
  〔19〕MetaMask:https:metamask。io
  〔20〕ethers。js:https:docs。ethers。iov5
  〔21〕hardhat:https:github。comnomiclabshardhat
  〔22〕MetaMask配置问题:https:hardhat。orgmetamaskissue。html
  〔23〕我们还需要更新已编译合约的工件:https:hardhat。orgguidescompilecontracts。htmlartifacts
  〔24〕ABI:https:docs。soliditylang。orgenv0。5。3abispec。html
  〔25〕您还可以经常在Etherscan:https:etherscan。io
  〔26〕此处的:https:hardhat。orghardhatrunnerpluginsnomicfoundationhardhattoolbox
  〔27〕人类可读的ABI:https:blog。ricmoo。comhumanreadablecontractabisinethersjs141902f4d917
  〔28〕接下来,通过访问这个:https:faucet。egorfine。com
  〔29〕我们可以通过注册Infura:https:infura。iodashboardethereumcbdf7c5eee8b4e2b91e76b77ffd34533settings
  〔30〕Alchemy:https:www。alchemyapi。io
  〔31〕您现在应该能够在EtherscanRopstenTestnetExplorer:https:ropsten。etherscan。io
  〔32〕ERC20:https:eips。ethereum。orgEIPSeip20
  〔33〕我们将在这里:https:dev。todabit3thecompleteguidetofullstackethereumdevelopment3j13erc20token
  〔34〕代币标准:https:ethereum。orgendevelopersdocsstandardstokenserc20
  〔35〕OpenZepplin:https:github。comOpenZeppelinopenzeppelincontracts
  〔36〕wei:https:www。investopedia。comtermswwei。asp
  〔37〕Soliditybyexample:https:soliditybyexample。orgapperc20
  〔38〕Web3Modal:https:github。comWeb3Modalweb3modal
  〔39〕subgraphs:https:thegraph。comdocsdefineasubgraph

心中有一支经久不息的歌,那就是和谐的向善而歌全文心中有一支歌(原创:诗一首)心中有一支经久不息的歌,那是我引以自豪的向美而歌,爱美是每个人的追求,向美是热血在激荡着心窝。心中有一支经久不息的歌,……恐龙并没有灭绝,全球大约有190亿只恐龙,这是怎么回事?恐龙生活在中生代,并于6500万年前灭绝,关于恐龙灭绝的主因存在很多说法,但比较让人信服的是一颗巨大的陨石与地球相撞,而后改变了地球的基本气候环境。大部分恐龙在灾难中死亡……高下立判!小球迷追星梅西被保安打翻手机,梅球王扶起小胖拥抱合8月1日消息,1日凌晨举行的法国超级杯,巴黎圣日耳曼40击败南特夺冠,梅西本场比赛打入一球。赛后退场时,一位小球迷冲过来找梅西合影被保安打翻了手机,结果梅西走过来主动和这个小男……败家之眼再度来袭?华硕ROG6详细规格遭曝光,网友实用性大增现在的手机功能越来越多,越来越强大,像一些复杂的游戏也可以玩了,然而以前的手机产品几乎只能发短信,聊视频,可以说现在的改变幅度真的很大。而且有很多手机厂商为了让用户更好玩……特雷杨12投仅1中老鹰惨败热火,巴特勒21分邓罗三分9中8季后赛首场比赛,热火就拿出惊人的防守强度,打得老鹰落花流水。比赛在半场结束时就已基本失去悬念,最终比分为11591,主场作战的热火轻松取得大比分10的领先。面对热火的强硬……狼人杀经典对局全场预言家,就我一个民?狼人杀玩多了,难免会出现一些经典对局:超神预言家裸点4狼、霸气女巫盲毒狼王、果敢猎人一枪带走狼人、4狼上警干翻神民这些精彩的对局总是会给人留下深刻的印象!狼人杀场上出现的……走不了鹊桥?那来古猗园走走缘分的桥今天是我国传统节日七夕节,也是中国的情人节。牛郎织女鹊桥相会的传说最早可追溯到南北朝时期的《述异记》,这一天,银河横跨天际,牛郎和织女在喜鹊的帮助下跨过银河,享受一年一度的假期……中国运动品牌集体遇到小麻烦危机无法避免,但可预防,品牌运营无小事。过去的10多天,儿童节和端午节带来了久违的复苏、休憩和快乐,但对于国内运动品牌的公关而言,可能不是什么轻松的日子。他们或主动……每天学味中药之知母知母,味苦、辛,气大寒,沉而降。入足少阴、阳明,又入手太阴。最善泻胃、肾二经之火,解渴除热。知母能清胃热,如果属胃中火盛,消烁津液,则可用石膏配伍知母进行清热治疗。另外,……2022目前销量最高的两款75寸电视机,海信排第二,榜首月销随着科技的发展,人们对电视机的要求越来越高,尺寸越大越好,以大为美,毕竟电视机只有够大才能带来沉浸式的观影效果,而且电视机不仅仅只是电器,还是家中必备的一个装饰品,大气就尤为重……超详细的网络抓包神器tcpdump使用指南tcpdump是一款强大的网络抓包工具,它使用libpcap库来抓取网络数据包,这个库在几乎在所有的LinuxUnix中都有。熟悉tcpdump的使用能够帮助你分析调试网络数据……睿思芯科创始人兼CEO谭章熹RISCEDGE睿思芯科创始人兼CEO谭章熹当芯片半导体遇上元宇宙,会碰撞出怎样的火花?12月9日下午,在钛媒体集团联合大兴产促中心、国家新媒体产业基地共同主办的2021TEDGE……
极易投研道篇投资要做少数派投资市场中一直有少数派原则,即少数人赚钱原则,A股也常有十人投资一赚二平七亏损的说法。为什么会出现这种现象呢?我们先了解一个经济学现象帕累托法则(即二八法则)19世……诺基亚新E71渲染图全尺寸键盘回归,操控体验依然领先iPho每个手机的设计都有着自己独特的优势,也就是主要的卖点。比如有的手机主打影像拍照,有的手机主打性能游戏,同时还有的手机主打操控体验。虽然现在手机的主流设计是全面屏,通过触控进行操……硅光子迎爆发机遇!产业链龙头强者恒强硅光技术是后摩尔时代核心技术之一,是半导体技术和光学技术的结合,并且对于通信行业的影响将是颠覆性的。硅光硅光技术已进入大规模集成阶段:资料来源:中国通信学会,Yol……ampampquot后悔莫及ampampquot杨颖踹掉黄晓仔细看,画面中吞云吐雾的杨颖正和一群小哥哥正在玩剧本杀,而她熟练的模样简直是道行高深的老烟枪,视频一出立马引起了轩然大波。网友们的观点也是两极分化,一方认为杨颖是公众人物……怀孕影像日记41岁,我当妈妈了万万没想到,我会在41岁高龄当上了妈妈。我和老公同岁,是大学校友。我们19岁相识,20岁恋爱,27岁结婚,一切都是水到渠成,除了生孩子这件事。我们并非不喜欢孩子,朋……国民育儿大V梁启超,教育孩子的六不秘诀五岁学习儒家经典,八岁能诗文,十二岁中秀才,十七岁中举人,一时名动四方,自己厉害也就算了,教育出来的孩子,也是个个顶呱呱。他培养出了一个真正的全精英家庭,创造了一门三院士……红米捡漏款手机确定!5000mAh120Hz67W!不到13相信大家都注意到了,这几年手机的价格整体上涨,当年的千元机主要是指10001800元左右的产品,如今更多的实质17002300元价位的产品了,而在1500元以内的新机更是少之又……世锦赛冠军03惨败,国乒5将遭淘汰,陈梦递补者掀翻德乒名将7月15日,WTT布达佩斯球星赛继续进行,在已经快结束的比赛中,男双世锦赛冠军惨败出局,国乒折损5将,得益于陈梦的因病退赛,递补者韩乒李时温胜德名将晋级。1、世锦赛男双冠……并非不尊重科比,但96年魔术若不逼走奥尼尔,搭档哈达威保底596年魔术把奥尼尔逼走的操作真是匪夷所思,给了他一个7年6900万的报价。奥尼尔那数据和球场上的统治力是毋庸置疑的,奥尼尔当年的模版可是张伯伦。奥尼尔当时还是最有商业价值的大个……每日一味抗癌中药金银花,清热解毒凉散风热,夏季首选茶饮金银花忍冬科植物忍冬、红腺忍冬、山银花或毛花柱忍冬的干燥花蕾或带初开的花。在我国大部地区均产,而以山东产量最大,河南产的质量较佳。五六月夏初花开放前采收,金银花采后应立即……顶级旗舰也能成性价比?2679拿下OPPOFindX5卷疯了在双十一大幅度促销情况下,不少普通机型的性价比都明显提升,但是大部分顶级旗舰和性价比这词完全没有关系。然而,OPPOFindX5标准版在双十一种叠加京东PLUS会员优惠后,价格……网友集体送别谷爱凌真的舍不得你!我们在中国等你回来北京时间4月27日,谷爱凌发文感谢中国。根据安排,谷爱凌将去美国参加活动,而且将准备进入大学。所以,谷爱凌将暂时告别中国。很多网友都集体送别谷爱凌,感谢她这几个月带来的喜悦。……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网