Dapp开发及智能合约部署技术

发布于: 雪球转发:0回复:0喜欢:0

去中心化应用,或者叫dApp,是一种不依赖于中心化服务器的应用。相反,dApp使用了类似于区块链前置机这些Web3技术,来实现自己的逻辑和后台功能,具备不可篡改和安全的特性。

在这个技术教程中,你会学习如何开发一个端到端的 dApp。在 dApp 中,用户可以通过智能合约,获取并存储 ETH 的当前价格。飞机@aishutuyu

去中心化应用是什么?

与传统的 App 是在中心化服务器运行前端代码不同,dApp 的前端代码是运行在区块链上的。当然,dApp 的前端代码和 UI 可以使用任何语言开发,可以部署在任何服务器上与前端逻辑相交互。

由于将后端逻辑存储在高度安全、防篡改的智能合约中,dApp 享有许多传统 Web2 系统无法实现的优势:

因为 dApp 可以通过安全性且不易篡改的智能承载来承载逻辑,所以 dApp 有很多 Web2 系统中没有的优势:

不会停机

隐私性更强

抗舞蹈

在最小的信任环境下执行逻辑

然而,这些优势也带来了对应的缺点。由于代码是部署在区块链上,这些逻辑默认是无法修改的,所以 dApp 的维护负载比较高。除此之外,因为代码是在广泛的网络中运行另外,由于用户需要有Web3钱包并且通过有足够的加密资产来支付手续费,所以用户体验也会下降。

dApp 组件

dApp 的组件有三种不同的类型:智能合约、外围逻辑(UI)和数据存储。

智能合约

智能合约了 dApp 的业务逻辑和当前的状态,这是 dApp 和传统网络应用的最大区别,也正是这一点让 dApp 具备了上述提到的优势。

前端 / UI

尽管逻辑需要开发者完成智能合约代码,并将其部署在区块链上,在前端,开发者还是使用标准的网络技术,比如 HTML 和 javascript,因此开发者可以使用自己熟悉的工具,库和框架。客户端的UI通常通过Web3.jsEther.js与智能交互。像对信息进行签名和发送给智能合约这些操作,通常是通过浏览器的Web3钱包MetaMask完成。

数据存储

大多数应用需要存储数据,但是因为区块链存储的特点,在链上存储大量的数据效率很低,而且非常昂贵。这也是为什么许多 dApp 需要使用 IPFS 或者 Filecoin 这样的链服务存储数据,只让区块链存储重要的业务逻辑和状态。

当然你也可以选择传统的云存储服务,但是还是有很多开发者选择存储,因为区块链应用可以提供最小信任的特性。

以太坊 dApp 架构来源:The Architecture of a Web3 Application

现在我们知道了 dApp 的组件,让我们开发一个简单的 dApp。

第一步:创建智能合约

我们 dApp 中的智能合约是一个简单的例子,它可以查看数据以及区块链上的变化的反应。在这个例子中,我们会通过 Chainlink ETH/USD 喂价来查看 ETH/USD 的价格,然后将结果永久存储在智能合约上。

第一步是打开 Chainlink 的文档,然后导航到网页链接{Using Data Feeds}页面。从这里将源代码复制进你的 IDE 中的一个新的文件里(比如 Visual Code),或者你可以点击“Open In Remix”按钮,然后使用在线IDE Remix。

在这个例子中,我们将使用 Visual Studio Code 和Hardhat(一个 EVM 开发框架)。

首先,为我们的 dApp 创建一个新的文件夹,并在这个文件夹中创建一个文件夹文件夹,用于存储智能合约代码:

mkdir chainlink-dapp-示例 cd chainlink-dapp-示例 mkdir 后端 光盘后端

接下来,通过 VS Code 打开创建好的文件夹,然后安装 Hardhat

npm 初始化 -y npm install --save-dev 安全帽 NPX安全帽 (选择创建javascript项目,选择默认参数)

当安装完成之后,在“contracts”文件夹中删掉 Touch.sol ,然后在这个文件夹中创建一个名为 PriceConsumerV3.sol 的文件。在这个文件中将存储我们的合约,所以将 Chainlink 文档中的代码复制到这个文件中,然后保存。

在示例代码中,您会看到演示合约已经有一个名为 getLatestPrice 的功能来通过 Rinkeby 上的 ETH/USD 喂价来查看以太坊的当前价格。

函数 getLatestPrice() 公共视图返回 (int) { ( /*uint80 roundID*/, 国际价格, /*uint 开始时间*/, /*uint 时间戳*/, /*uint80 轮回回答*/ ) = PriceFeed.latestRoundData(); 退货价格;

创建一个新的变量和函数,在智能合约上存储这个值。

int 公共存储价格;

然后,创建一个新的函数,它会被 dApp 的前端调用。这个函数会通过 getLatestPrice 函数查看以太坊的最新价格,然后将该值存储在storedPrice这个参数中:

函数 storeLatestPrice() 外部 { 存储价格 = getLatestPrice(); }

你的新合约应该和下面的一样:

// SPDX 许可证标识符:MIT 杂注可靠性^0.8.7; 导入“@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol”; 合约 PriceConsumerV3 { AggregatorV3接口内部priceFeed; int 公共存储价格; /** * 网络:林克比 * 聚合器:ETH/USD * 地址:0x8A753747A1Fa494EC906cE90E9f37563A8AF630e */ 构造函数(){ 供给价格 = 聚合器V3接口(0x8A753747A1Fa494EC906cE90E9f37563A8AF630e); } /** * 返回最新价格 */ 函数 getLatestPrice() 公共视图返回 (int) { ( /*uint80 roundID*/, 国际价格, /*uint 开始时间*/, /*uint 时间戳*/, /*uint80 轮回回答*/ ) = PriceFeed.latestRoundData(); 退货价格; } 函数 storeLatestPrice() 外部 { 存储价格 = getLatestPrice(); } }

第二步:智能部署合约

现在您已经可以在 Rinkeby 测试网中编译并部署您的合约了,如果没有测试网的通证的话,可以在网页链接{Chainlink 水龙头}获得一些。

如果您使用的是 Remix 的话,您可以通过 Remix 编译并配置您的合约。如果您使用的是 Visual Studio Code 这样的 IDE 的话,我们推荐使用 Hardhat 来管理您的合约。

在部署合约之前,第一步是安装 Hardhat 工具包,Chainlink 合约库和 dotenv 库。dotenv 可以将存储密码和敏感信息存储在一个单独的 .env 文件中:

npm install --save-dev @nomicfoundation/hardhat-toolbox npm install @chainlink/contracts --save npm install dotenv

然后,将hardhat-config.js文件中的内容换成下面的内容:

要求(“@nomicfoundation/hardhat-toolbox”); //require(“@nomiclabs/hardhat-ethers”) require('dotenv').config() const RINKEBY_RPC_URL = process.env.RINKEBY_RPC_URL || “网页链接” const PRIVATE_KEY = process.env.PRIVATE_KEY || “abcdef” 模块. 导出 = { 默认网络:“rinkeby”, 网络:{ 安全帽: { // // 如果你想进行一些分叉,请取消注释 // 分叉: { // url: MAINNET_RPC_URL // } }, 本地主机:{ }, 林克比:{ 网址:RINKEBY_RPC_URL, 帐户:[PRIVATE_KEY], 保存部署:true, }, }, 坚固性:“0.8.9”, };

下一步是在后端文件夹中创建一个 .env 文件。然后你需要从网页链接{Web3 钱包中获取你的私钥},然后粘贴到 PRIVATE_KEY 这行。请再确定一下,为了安全你在这个例子中最好使用一个在主网上没有任何资产的新Web3钱包。

当这些完成以后,你需要一个 RPC 端点来接入 Rinkeby 网络。你可以将它粘贴到 .env 文件的 RINKEBY_RPC_URL 中的 RPC URL 中。我们推荐注册一个免费的 Infura 或者 Alchemy 账户来获取一个RPC URL

创建.env文件

下一步是修改“script”文件夹中deploy.js文件中的内容,使得它可以配置你的新合约。打开文件,然后将代码替换为下列代码。

// 我们在这里明确要求 Hardhat 运行时环境。这是可选的 // 但对于通过 `node <script>` 以独立方式运行脚本很有用。 // // 您还可以使用“npx Hardhat run <script>”运行脚本。如果你这样做,安全帽 // 将编译您的合约,将 Hardhat 运行时环境的成员添加到 // 全局范围,并执行脚本。 const hre = require("安全帽"); 异步函数 main() { const PriceConsumer =等待 hre.ethers.getContractFactory("PriceConsumerV3"); const PriceConsumer = 等待 PriceConsumer.deploy(); 等待 PriceConsumer.deployed(); console.log("合约部署到:",priceConsumer.address); } // 我们推荐这种模式,以便能够在任何地方使用 async/await // 并正确处理错误。 main().catch((错误) => { 控制台.错误(错误); 进程.exitCode = 1; });

现在您已经可以通过 Hardhat 来编译您的智能合约并将其部署在 Rinkeby 网络中:

npxhardhat编译 npxhardhat运行--network rinkeby脚本/deploy.js

您现在应该看到类似下面这行的信息,会显示您在 Rinkeby 网络上部署的智能合约地址。注意这个地址,我们在后面的步骤中需要使用它。

部署的智能合约

恭喜,您已经完成了 dApp 的合约部分!

第三步:创建前端应用

dApp的接入逻辑和UI可以通过各种框架完成。

React是最受欢迎的 Javascript 代码库之一,它可以用于开发功能丰富的网页,因此也被许多 Web3 dApp 所使用。除此之外,Ether.js 是一个 Javascript 库,它用于EVM区块链连接和交互的。当你把这二者结合在一起时,就可以开始开发你的 dApp 的接口了。

在这部分,我们将使用create-react-app创建一个新的 React 应用。然后我将介绍如何通过 Ether.js 来将 UI 和已经部署的智能合约连接起来,完成一个端到端的 dApp。

创建 React 应用

开发前端代码之前,需要先安装并初始化一个 cerate-react-app 项目,然后修改它相当于我们的 dApp。第一步将这个库安装到“frontend”文件夹:

cd .. npx create-react-app 前端

这一步完成后,你应该可以在“frontend”文件夹中看到所有相关的React代码。打开“frontend”文件夹然后执行以下操作:

删除/src/setupTests.js

删除 /src/ReportWebVitals.js

删除 /src/logo.svg

删除/src/App.test.js

删除/src/App.css

文件夹结构应该如下所示:

React前端文件夹结构

在修改 React 应用代码之前,我们需要先安装BootstrapEther.js。Bootstrap 是一个很流行的前端 CSS 框架,有很多 React 可以使用的 UI 小部件和 CSS 样式。Ether.js 可以将前端代码与区块链上已经部署的智能合约相连接。在“frontend”文件夹中输入以下命令:

cd 前端 npm 安装 bootstrap npm 安装 ethers

现在我们可以开始修改React应用的代码,在/src/文件夹中打开App.js文件,然后删掉这些内容。我们从0开始编写。

第一步是告诉应用程序我们想要使用 React(包括 useEffect 和 useState 库)和 Ether.js:

从 'react' 导入 React, { useEffect, useState }; 从“以太”导入{以太};

下一步,创建一个名为“App”的函数然后导出它:

函数应用程序(){ } 导出默认应用程序;

现在我们将开始完成“App”函数的代码。加入下面的代码,这些代码会做以下的操作:

创建 storePrice 和 setStoresPrice 的react hook。

连接你的 Metamask Web3 钱包。

设置已经部署的智能合约地址和 ABI。Ether.js 在与已经部署的智能合约交互的时候需要这两个信息。把智能合约地址这个值(可以在部署的时候获得)插入到REPLACE_WITH_DEPLOYED_CONTRACT_ADDRESS这里。智能合约的 ABI 可以从文件 /backend/artifacts/contracts/PriceConsumerV3.json 中获得,您还可以使用代码压缩器对它进行更好的格式化,在您的应用中。

const [storedPrice, setStoredPrice] = useState(''); const 提供者 = new ethers.providers.Web3Provider(window.ethereum) const 签名者=provider.getSigner() const ContractAddress = <REPLACE_WITH_DEPLOYED_CONTRACT_ADDRESS>''; 常量 ABI = '[{"inputs":[],"stateMutability":"nonpayable","type":"构造函数"},{"inputs":[],"name":"getLatestPrice","outputs":[{" InternalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[]," name":"storeLatestPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"storedPrice","outputs" :[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]' const 合约 = new ethers.Contract(contractAddress, ABI, 签名者);

现在我们在应用程序中创建两个函数:

getStoredPrice 会连接配置的合约,并且通过storedPrice() 获取当前价格。

setNewPrice 会调用已部署合约的 storeLatestPrice 函数,直到交易完成,然后调用 getStoredPrice 函数来获取存储在智能合约中的价格。

我们会在应用中加入 getStoredPrice 函数,它会在加载页面的时候调用 getter 函数:

const getStoredPrice = async () => { 尝试 { const ContractPrice =等待contract.storedPrice(); setStoredPrice(parseInt(contractPrice) / 100000000); } 捕获(错误){ console.log("getStoredPrice 错误:", error); } } 异步函数 updateNewPrice() { 尝试 { const transaction =等待contract.storeLatestPrice(); 等待事务.wait(); 等待 getStoredPrice(); } 捕获(错误){ console.log("更新新价格错误:", error); } } 获取存储价格() .catch(控制台.错误)

继承代码的最后一步是返回 JSX 代码以让浏览器渲染。将下面的代码复制进 App 的函数中,在 getStorePrice() 的下面。这些代码会做下面的操作:

返回一个简单的2列网格布局。

第一列包含智能合约中存储的 ETH/USD 价格。

第二列包含了一个按钮,用户可以使用这个按钮来与智能合约,更新交易存储的价格。点击按钮,然后调用下面的 setNewPrice 函数。

返回 ( <div className="容器"> <div className="row mt-5"> <div className="col"> <h3>存储价格</h3> <p>存储的 ETH/美元价格:{storedPrice}</p> </div> <div className="col"> <h3>更新价格</h3> <按钮类型=“提交”className=“btn btn-dark” onClick={updateNewPrice}>更新</button> </div> </div> </div> );

你的应用程序现在已经完成了。如果需要,你可以和这里的完整代码进行比较,保证你的代码中没有错误。你可以运行你的 dApp 了。

运行你的 dApp

在确认你所有的文件都已经存储以后,在前端文件夹中运行以下命令来启动你的 dApp:

npm 运行开始

在应用被加载以后,浏览器中会有一个新的窗口,显示 dApp 的 UI,你应该从 Metamask 看到一个弹出的通知,请求将钱包连接到这个应用上。

反应前端

在检查你在 Metamask 的账户中有一些 Rinkeby ETH 以后,点击“更新”按钮,就可以和你已经配置好的智能合约进行交易了。你应该会收到 Metamask 的通知,请求你确认交易。在你完成后这些以后,过几秒你的 dApp 会自动刷新,然后当前的以太坊会出现在“Stored Price”区域:

React前端展示Data Feed结果

恭喜,您已经成功创建、部署并且交互了一个简单的 dApp!在本教程中,您只需在您的电脑上运行了一个本地接口,同时您也可以将其部署在云服务器中,或者使用去中心化版本的前端,可以将其部署在IPFS中!你也可以修改应用的CSS来改变UI以使更符合你的使用场景。

总结

去中心化应用可以用区块链和智能合约这些Web3科技替代传统的头部服务器,带来传统应用没有安全性和抗集群的特点。

在这个演示中,我们创建了一个简单的 dApp,dApp 中包含了一个智能合约,这个智能合约可以从 Chainlink ETH/USD 喂价中获得最新的价格,然后存储在智能合约中。然后我们创建了一个简单的 UI,使用了 React 和 Ether.js 连接并且与部署良好的交互。