# ERC721 DApp 开发实例

***本教程是技术大牛 luofei614 的DApp开发学习笔记，编成教程分享给开发者。***

DAPP例子：领取宠物

* 拉群官方pet-shop的项目模板：

truffle unbox pet-shop

truffle unbox 可以下载一些项目模板代码。 更多查看： <https://www.trufflesuite.com/boxes>

* 目录结构：

contracts/: 存放合约文件夹

migrations/: 部署迁移改变文件夹

test/: 测试文件

truffle-config.js: 配置文件

* 安装node模块依赖

yarn install

* 运行项目

yarn dev

浏览器看见界面如下：

![图片](/files/-M_C8RQKD0_eNhfH2SeK)

此项目只显示了前端， 还没实现合约和交互。 我们继续添加代码让他可以实现区块链领宠物。

原始教程地址：<https://www.trufflesuite.com/tutorial>

* 下面来创建智能合约：

在contracts目录下添加文件Adoption.sol文件：

pragma solidity ^0.5.0;

contract Adoption {

&#x20; address\[16] public adopters;

&#x20; function adopt(uint petId) public returns(uint){

&#x20;      require(petId>=0&\&petId<=15);

&#x20;      adopters\[petId]=msg.sender;

&#x20;      return petId;

&#x20; }

&#x20; function getAdopters() public view returns(address\[16] memory){

&#x20;     return adopters;

&#x20; }

}

编译合约，在项目根目录运行命令

truffle compile

编译的结果是会在build/contracts 生成合约的json文件。 json文件中包含了合约的abi信息和bytecode编码。 这个json中还有一个networks字段，是合约部署完成后会显示出区块链网络内容。

* 创建迁移文件

在migrations目录下创建2\_deploy\_contracts.js文件：

var Adoption = artifacts.require("Adoption");

module.exports = function(deployer) {

&#x20; deployer.deploy(Adoption);

};

* 部署合约

本地打卡Ganache， 默认监听的端口是7545

truffle-config.js 中以及设置了开发环境的测试区块链RPC地址，默认就是为本地测试网络7545的

Ganache，默认有创建十个以太坊账号，并都充了100ETH

部署合约运行命令：

truffle migrate

部署成功后，可以在Ganache界面中看见区块增多，并且第一个账户的以太坊减少， 默认会以第一个账户作为部署账户， 减少的以太坊是部署合约是gas花费。

当 truffle migrate 运行多少时，已经部署过的合约不会再部署，需要重新部署需要在运行时加上参数 --reset

* 编写js代码：

在/src/js/app.js文件中的initWeb3函数中添加如下代码：

初始化Web3，链接钱包：

// Modern dapp browsers...

if (window\.ethereum) {

&#x20;App.web3Provider = window\.ethereum;

&#x20;try {

&#x20;// Request account access

&#x20;await window\.ethereum.enable();

&#x20;} catch (error) {

&#x20;// User denied account access...

&#x20;console.error("User denied account access")

&#x20;}

}

// Legacy dapp browsers...

else if (window\.web3) {

&#x20;App.web3Provider = window\.web3.currentProvider;

}

// If no injected web3 instance is detected, fall back to Ganache

else {

&#x20;App.web3Provider = new Web3.providers.HttpProvider('<http://localhost:7545>');

}

web3 = new Web3(App.web3Provider);

window\.ethereum 是MetaMask插件的对象， window\.ethereum.enable() 可以弹出MetaMask选择钱包。

初始化合约实例，设置Provider：

在initContract方法中添加代码：

&#x20;$.getJSON('Adoption.json', function(data) {

&#x20;     // Get the necessary contract artifact file and instantiate it with @truffle/contract

&#x20;     var AdoptionArtifact = data;

&#x20;     App.contracts.Adoption = TruffleContract(AdoptionArtifact);

&#x20;     // Set the provider for our contract

&#x20;     App.contracts.Adoption.setProvider(App.web3Provider);

&#x20;     // Use our contract to retrieve and mark the adopted pets

&#x20;     return App.markAdopted();

&#x20; });

这个为什么Adoption.json可以直接获得数据， 是因为根目录下bs-config.json中配置了baseDir中有 build/contracts

在markAdopted函数中添加如下代码：

var adoptionInstance;

App.contracts.Adoption.deployed().then(function(instance) {

&#x20; adoptionInstance = instance;

&#x20; return adoptionInstance.getAdopters.call();

}).then(function(adopters) {

&#x20; for (i = 0; i < adopters.length; i++) {

&#x20;   if (adopters\[i] !== '0x0000000000000000000000000000000000000000') {

&#x20;     $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);

&#x20;   }

&#x20; }

}).catch(function(err) {

&#x20; console.log(err.message);

});

此代码获取合约中已经被领取的代码，标记为已领取，其他人不能再领取。

handleAdopt 添加如下代码：

var adoptionInstance;

web3.eth.getAccounts(function(error, accounts) {

&#x20;if (error) {

&#x20;console.log(error);

&#x20;}

&#x20;var account = accounts\[0];

&#x20;App.contracts.Adoption.deployed().then(function(instance) {

&#x20;adoptionInstance = instance;

&#x20;// Execute adopt as a transaction by sending account

&#x20;return adoptionInstance.adopt(petId, {from: account});

&#x20;}).then(function(result) {

&#x20;return App.markAdopted();

&#x20;}).catch(function(err) {

&#x20;console.log(err.message);

&#x20;});

});

将上面代码替换注释 replace me

现在这个例子可以完整跑了。 注意在使用时，将自己MetaMask钱包地址切换为测试网络。 并添加一个有余额的账号。 可以Ganache界面上选一个有余额的账号，复制私钥， 在MetaMask钱包创建账号时选择导入私钥。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hg.network/dapp-kai-fa-jiao-cheng/erc721-dapp-kai-fa-shi-li.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
