# 基础开发环境

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

### 1、用remix部署第一个合约

remix是一个以太坊官方的在线合约编辑器。 地址： <https://remix.ethereum.org/>

以太坊编写智能合约的语言一般是用solidity。

我们动手自己实现一个水龙头的合约，调用合约的withdraw方法可以向自己账号充币

在contracts文件夹下新建Faucet.sol文件

代码如下：

/`/ SPDX-License-Identifier: MIT`

`pragma solidity ^0.4.5;`

`contract Faucet{`

&#x20; `function withdraw(uint withdraw_amont) public {`

&#x20;     `require(withdraw_amont<0.1 ether);`

&#x20;     `msg.sender.transfer(withdraw_amont);`

&#x20; `}`

&#x20; `function() public payable{}`

`}`

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

点击![图片](/files/-M_C60UgGfPVifYDbXI-) 按钮进入编译界面。

![图片](/files/-M_C60UhhNPnsgF8-FnQ)

1处是选择编译器版本， solidity语言有很多版本，而且更新很快，新版本会出现很多不向下兼容版本的情况（以太坊官方说自己的开发文化是敢于创新也体现在此），所以这里选择编译器版本很关键， 如果你是在网上找到代码来调试，一定看看代码中声明适合什么版本的，这里编译器选择到对应的版本。

2处点击即可开始编译

3处可以复制编译好的bytecode和ABI， bytecode就是在创建合约时需要像以太坊传递的参数data中的内容， ABI是向机器指令层面编码和解密传送数据的主要方式， ABI有点类似类的反射，通过ABI知道合约有哪些方法和传参。

点击![图片](/files/-M_C60UikFCNYo6f-fWY) 按钮进入部署合约界面

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

1处选择编译环境， JavascriptVM 是Remix自带的虚拟机环境，用这个环境可以不用连接钱包就可以调试。 injected Web3 可以连接MetaMask钱包进行调试。 Web3 Provider是连接本地的Ganache测试环境。

点击Deploy按钮进行部署

2处是部署完成后返回的合约地址 ，点开合约地址可以调试合约的函数调用。 (PS：我们也可以在At Address处输入已知的合约地址，调试合约)

我们可以看见因为合约定义了withdraw函数， 所以点开合约地址后下面会有withdraw的调用的地方。

在withdraw旁边输入框输入数字，点击 withdraw按钮可以调试 withdraw函数。 此时调用withdraw会失败，因为这个合约上没有余额

增加余额的方式：

1，给合约地址充币

可以在remix编辑器控制台命令行输入：

web3.eth.sendTransaction({from:"账号地址",to:"合约地址",value:'1000000000000000000'});

上面命令为打1ETH到合约地址。

2，可以在部署合约时输入Value的值（PS：这需要合约的构造函数声明payable才可以接受支付，上面示例代码还没有支持， 后面的演示示例中演示怎么支持payable）

### 2、Ganache本地区块链测试网络安装

<https://www.trufflesuite.com/ganache> 在这里下载安装。

Ganache可视化界面用的非常方便。他是本地的以太坊区块链测试环境， 会自动建立十个账号，并每个账号有100ETH，供我们调试程序。 可以在本地测试链上部署合约。 注意每次Ganache重启后会恢复初始状态，合约需要重新部署， 反复的部署合约需要管理起来， 所以下面我们介绍truffle工具管理合约。

### 3、安装truffle

安装：

npm install -g truffle

初始化truffle项目：

truffle init

目录结构：

├── contracts //存放合约

│   └── Migrations.sol

├── migrations //存放迁移文件

│   └── 1\_initial\_migration.js

├── test //存放测试脚本

└── truffle-config.js //配置文件

编译合约：

truffle compile

部署合约：

truflle migrate

进入命令行：

truffle console

在有truffle配置文件的项目中运行这个命令

### 4、用truffle部署合约

contracts目录下建立合约， 我们还是拿水龙头合约来测试。 建立文件名为：Faucet.sol

代码：

// SPDX-License-Identifier: MIT

pragma solidity ^0.4.5;

contract Faucet{

&#x20;constructor() public payable {}

&#x20;  function withdraw(uint withdraw\_amont) public {

&#x20;     require(withdraw\_amont<0.1 ether);

&#x20;     msg.sender.transfer(withdraw\_amont);

&#x20; }

&#x20; function() public payable{}

truffle 支持的编译器的版本是 0.5.16 , 上面合约是0.4.5版本的， 需要编译器版本可以在 truffle-config.js 配置文件中配置项compilers->solc->version 进行配置，修改为0.4.26。

上面代码增加了contructor为payable属性，主要是让等会创建合约时就可以打以太坊。

在migration文件中建立迁移文件： 2\_Faucet.js

const Faucet = artifacts.require("Faucet");

module.exports = function (deployer) {

&#x20; deployer.deploy(Faucet);

};

1\_initial\_migration.js 是第一个初始化合约， 这个合约的作用是记录了迁移到哪步了，避免重复迁移。migration合约巧妙的把区块链环境当作了数据库。

编译：

truffle compile

编译生成的文件叫作artifacts是json格式文件， 会生成在build/contracts 文件夹下, 生成的json文件会包含编译的betycode，abi，以及在部署后网络合约地址也在生成的json中包含

部署：

truflle migrate

默认会部署到Ganache测试网络, Ganache默认会创建10个有私钥的账号， truflle能读取到Ganacache的私钥，默认会用第一个账户进行部署。

更改部署时的账户并向合约充值： 在2\_Faucet.js文件代码修改如下：

const Faucet = artifacts.require("Faucet");

module.exports = function (deployer,network,accounts) {

&#x20; deployer.deploy(Faucet,{from:accounts\[1],value:web3.utils.toWei('1', 'ether')});

};

或者代码写为：

const Faucet = artifacts.require("Faucet");

module.exports = function (deployer,network,accounts) {

&#x20; deployer.deploy(Faucet).then(function(instance){

//先部署，部署成功后充值

&#x20;web3.eth.sendTransaction({from:accounts\[1],to:instance.address,value:web3.utils.toWei('1', 'ether')});

&#x20; });

};

重新部署：

truffle migrate --reset

用truflle console命令行控制台也给合约账户充值：

truffle console

\>let accounts=await web3.eth.getAccounts()

\>let instance=await Faucet.deployed()

\>web3.eth.sendTransaction({from:accounts\[1],to:instance.address,value:web3.utils.toWei('1', 'ether')})

### 5、用VUE开发水龙头合约界面

安装vue命令行

npm install -g @vue/cli

用vue命令行创建一个应用

vue create myapp

安装依赖

cd myapp

yarn add web3

yarn add @truffle/contract

复制上面合约编译生成的artifacts文件Faucet.json 到 Vue项目src/components/文件夹下。

编辑HelloWorld.vue文件，在默认的界面上增加一个点击按钮

\<button @click="click">水龙头\</button>

在VUM的javascript代码部分使用如下代码

\<script>

import Web3 from "web3";

import contract from "@truffle/contract";

import FaucetJson from "./Faucet.json";

import { BigNumber } from '@ethersproject/bignumber';

export default {

&#x20; data(){

&#x20;   return {

&#x20;     web3:false,

&#x20;     contract\_instance:false,

&#x20;     accounts:\[]

&#x20;   }

&#x20; },

&#x20; async created(){

&#x20;    //初始化web3

&#x20;    // Modern dapp browsers...

&#x20;   let web3Provider ;

&#x20;   if (window\.ethereum) {

&#x20;     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;     }

&#x20;   }

&#x20;   // Legacy dapp browsers...

&#x20;   else if (window\.web3) {

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

&#x20;   }

&#x20;   // If no injected web3 instance is detected, fall back to Ganache

&#x20;   else {

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

&#x20;   }

&#x20;   this.web3 = new Web3(web3Provider);

&#x20;//初始化合约

&#x20;   const FaucetContract=contract(FaucetJson);

&#x20;   FaucetContract.setProvider(web3Provider);

&#x20;   this.contract\_instance=await FaucetContract.deployed();

&#x20;   this.accounts=await this.web3.eth.getAccounts();

&#x20; },

&#x20; methods:{

&#x20;    click(){

&#x20;//调用合约的withdraw函数     this.contract\_instance.withdraw(this.web3.utils.toWei('1','ether'),{from:this.accounts\[0]});

&#x20;    }

&#x20; },

&#x20; name: 'HelloWorld',

&#x20; props: {

&#x20;   msg: String

&#x20; }

}

\</script>

JS代码中一般调用的步骤是：初始化web3实例-> 初始化合约实例->调用合约

在调用withdraw，不用将值做BigNumber的转换， 因为truflle-contract 底层会做BigNumber转换

运行环境：

yarn serve

这时候在浏览器点击按钮可以试用水龙头功能。

注意，如果出现报错： Error: the tx doesn't have the correct nonce. account has nonce of: 14 tx has nonce of: 0 ， 是钱包的问题，不是代码的问题。 关闭浏览器重启一下MetaMask钱包。

### 6、结合火币链开发

MetaMask添加自定义RPC，添加火币生态链测试地址：

chainid 256

RPC  [https://http-testnet.hecochain.com](https://weibo.cn/sinaurl?u=https%253A%252F%252Fhttp-testnet.hecochain.com%252F)

区块浏览：<https://scan-testnet.hecochain.com/home/index> (PS: 火币生态的浏览器地址可以清晰看到合约的源码，这里是学习合约的一个好地方)

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

到水龙头下去领币：

<https://scan-testnet.hecochain.com/faucet>

火币链是基于EOS的，出块速度更快，也兼用以太坊的EVM，部署合约的操作步骤和以太坊没有区别。

* truffle配置火币链生态链

在truffle项目中安装依赖

yarn add @truffle/hdwallet-provider\@1.0.18

然后编辑配置文件truffle-config.js

去掉下面几行注释

const HDWalletProvider = require('@truffle/hdwallet-provider');

const fs = require('fs');

const mnemonic = fs.readFileSync(".secret").toString().trim();

在.secret 文件中添加账号的私钥， 私钥可以从metamask的账号详情导出。

在  networks下添加:

hecotest: {

&#x20;   provider: () => new HDWalletProvider(mnemonic, \`<https://http-testnet.hecochain.com\\`>),

&#x20;       network\_id: 256

&#x20;    },

&#x20;    hecomain: {

&#x20;       provider: () => new HDWalletProvider(mnemonic, "<https://http-mainnet.hecochain.com>"),

&#x20;       network\_id: 128

&#x20;    }

部署合约时指定网络名称：

truffle migrate --network=hecotest

hdwallet-provider一定要安装1.0.18版本的，不然会有报错：invalid sender , 可能是新版本用法不一样， truffle配置文件中的实例代码是老版本用户。


---

# 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/ji-chu-kai-fa-huan-jing.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.
