diff --git a/basic/04-web3js-truffle/README.md b/basic/04-web3js-truffle/README.md index f7eaaf8ea..f6a7bc38d 100644 --- a/basic/04-web3js-truffle/README.md +++ b/basic/04-web3js-truffle/README.md @@ -1,87 +1,103 @@ ## Truffle 介绍 -Truffle是基于Solidity语言的一套开发框架,它简化了去中心化应用(Dapp)的构建和管理流程。本身是采用Javascript编写,支持智能合约的编译、部署和测试。 -- [Truffle 官网](https://www.trufflesuite.com/docs/truffle/quickstart) -truffle开发框架提供了很多功能,简化了我们的开发、编译、部署与调试过程: +Truffle 是基于 Solidity 语言的一套开发框架,它简化了去中心化应用(Dapp)的构建和管理流程。本身是采用 Javascript 编写,支持智能合约的编译、部署和测试。 + +- [Truffle 官网](https://www.trufflesuite.com/docs/truffle/quickstart) - - 内置了智能合约编译、链接、部署和二进制文件的管理 - - 方便快速开发的合约自动化测试 - - 方便扩展的、脚本化的部署与发布框架 - - 方便的网络管理功能。不论是公有网络还是私有网络 - - 基于erc190标准,使用EthPM & NPM进行依赖包管理 - - 内置控制台功能。项目构建后,可以直接在命令行调用输出结果,方便了开发调试 - - 可配的构建流程,支持持续集成。 - - 支持外部脚本的执行 +truffle 开发框架提供了很多功能,简化了我们的开发、编译、部署与调试过程: +- 内置了智能合约编译、链接、部署和二进制文件的管理 +- 方便快速开发的合约自动化测试 +- 方便扩展的、脚本化的部署与发布框架 +- 方便的网络管理功能。不论是公有网络还是私有网络 +- 基于 erc190 标准,使用 EthPM & NPM 进行依赖包管理 +- 内置控制台功能。项目构建后,可以直接在命令行调用输出结果,方便了开发调试 +- 可配的构建流程,支持持续集成。 +- 支持外部脚本的执行 ## 文件说明 + ### 目录结构 - - contracts/: Solidity合约目录 - - migrations/: 部署脚本文件目录 +- contracts/: Solidity 合约目录 + +- migrations/: 部署脚本文件目录 - - test/: 测试脚本目录,参考 如何测试应用? +- test/: 测试脚本目录,参考 如何测试应用? - - truffle-config.js: Truffle 配置文件 +- truffle-config.js: Truffle 配置文件 ### 各文件作用 + 1. contracts/SimpleToken.sol: 这是一个用 Solidity 编写的 erc20 代币 智能合约. 2. migrations/1_initial_migration.js: 这是一个部署脚本,用来部署 Migrations 合约,对应 Migrations.sol 文件。 -3. truffle-config.js (之前是 truffle.js): Truffle 配置文件, 用来设置网络信息,和其他项目相关的设置。当我们使用内建的默认的Truffle命令时,这个文件留空也是可以的。 +3. truffle-config.js (之前是 truffle.js): Truffle 配置文件, 用来设置网络信息,和其他项目相关的设置。当我们使用内建的默认的 Truffle 命令时,这个文件留空也是可以的。 ## 测试流程 -1) 安装 truffle -``` + +1. 安装 truffle + +```bash npm install -g truffle ``` -2) 测试合约 -``` +2. 测试合约 + +```bash truffle test ``` + 这里,使用 "truffle test" 后,truffle 会启动内置的 test 网络,同时执行 测试 test 目录下的所有脚本,如果想单独测试某个脚本,可以 执行 "truffle test ./test/simpletoken.js" -3) 编译合约 -``` -truffle compile +3. 编译合约 + +```bash +truffle compile ``` 执行成功后,会输出类似如下信息。从输出信息可以看到, truffle 会把 contracts 目录下的所有合约进行编译 -``` + +```bash Compiling .\contracts\SimpleToken.sol... Writing artifacts to .\build\contracts ``` -4) 部署合约 +4. 部署合约 在 truffle-config.js 里面,可以配置 truffle 使用的以太网络,其中就包括 truffle test 使用的 "test" 网络。 这里,直接执行 truffle migrate 报没有找到 test 网络,因为 truffle 不会启动内置的 test 网络。所以这里我们使用 kovan 进行 truffle 合约部署 -``` + +```bash truffle migrate --network kovan ``` 当多次执行 truffle migrate 的时候,可能会出 "Network update to date", 然后不执行合约部署的情况,这个时候需要执行如下的 truffle 命令 -``` + +```bash truffle migrate --network kovan --reset ``` ## 在 infura 测试合约 + 在 test 目录下存在 sol 和 js 类型的文件,truffle 支持这两种类型的测试文件。但目前测试发现,如果连接的测试网络为 infura ,则执行 sol 的测试文件会报失败。所以,这里我们连接到 infura 进行测试时,只能使用 js 的测试文件。 -- 修改 simpletoke.js +- 修改 simpletoke.js 修改 simpletoken.js 文件,把其中的 accounts[1] 修改为 "0x5DF22be367b95788Cd51C7dbdf7c7aB70fE856EE" ( 为例 ), 然后执行 如下命令。执行过程可能比较慢,需要耐心等待一下。 -``` + +```bash truffle test ./test/simpletoken.js --network kovan ``` ## 在本地测试合约 -运行truffle develop,系统会给出10个测试账号,包括钱包地址和私钥。 -``` + +运行 truffle develop,系统会给出 10 个测试账号,包括钱包地址和私钥。 + +```bash $ truffle develop Truffle Develop started at http://127.0.0.1:9545/ @@ -110,25 +126,31 @@ Private Keys: (9) 040cdda01e0b34c00c39877078af2015bd16125fb4fabf1d7153b679e209409f ``` -选择任意一个私钥,将其放置在truffle-config.js中mnemonic变量中。 + +选择任意一个私钥,将其放置在 truffle-config.js 中 mnemonic 变量中。 例如,原代码是 + - const mnemonic = fs.readFileSync('./sk.txt').toString().trim() 修改后的代码是 + - const mnemonic = "0a8d9e2a470aedfabe279f16f629c5054a47d69b7d66d17ba65cdd7ca99876e1" -接下来配置本地网络参数,将下面network属性中development注释打开,host配置成本地,port配置成truffle develop给出的端口地址,如本例中端口是9545。network_id保留原状。 -``` +接下来配置本地网络参数,将下面 network 属性中 development 注释打开,host 配置成本地,port 配置成 truffle develop 给出的端口地址,如本例中端口是 9545。network_id 保留原状。 + +```js development: { host: "127.0.0.1", port: 9545, network_id: "*" }, ``` -配置好以后即可运行truffle compile进行编译,truffle migrate进行部署,truffle test进行测试。 + +配置好以后即可运行 truffle compile 进行编译,truffle migrate 进行部署,truffle test 进行测试。 测试成功后可以看到 -``` + +```bash > Artifacts written to C:\Users\Highland\AppData\Local\Temp\test--33840-ApHyOzehxOdp > Compiled successfully using: - solc: 0.8.0+commit.c7dfd78e.Emscripten.clang @@ -149,6 +171,7 @@ Private Keys: ``` ## 参考资料 -> https://learnblockchain.cn/docs/solidity/contracts.html -> https://solidity-cn.readthedocs.io/zh/develop/ +- + +- diff --git a/basic/06-ethersjs-waffle/README.md b/basic/06-ethersjs-waffle/README.md index ffd9841a2..4d90d61a4 100644 --- a/basic/06-ethersjs-waffle/README.md +++ b/basic/06-ethersjs-waffle/README.md @@ -1,48 +1,55 @@ ## 前言 -Waffle 是一款适配 ehterjs 的智能合约测试库。本样例演示了使用 Waffle 进行测试的基本流程及使用方法. -Waffle 详细使用方法可以参考 [Waffle 官网](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html) , -对于不熟悉 Waffle 测试框架的开发者, 可以根据本样例进行基础的操作, 阅读样例代码, 形成初步的流程概念, 之后再参考官网进行更加深入的了解. -## 合约介绍 + +Waffle 是一款适配 ehter.js 的智能合约测试库。本样例演示了使用 Waffle 进行测试的基本流程及使用方法. +Waffle 详细使用方法可以参考 [Waffle 官网](https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html) , 对于不熟悉 Waffle 测试框架的开发者, 可以根据本样例进行基础的操作, 阅读样例代码, 形成初步的流程概念, 之后再参考官网进行更加深入的了解. + +## 合约介绍 + - contract/SimpleToken.sol -一个标准的 ERC20 合约, 实现了 ERC20 的所有接口, 用户可以使用这个合约进行 ERC20 代币的发放 - -## 脚本介绍 + 一个标准的 ERC20 合约, 实现了 ERC20 的所有接口, 用户可以使用这个合约进行 ERC20 代币的发放 +  + +## 脚本介绍 + - test/simpleTokenTest.js -SimpleToken.sol 合约的单元测试代码. 这里只写了一个测试脚本, 实际开发中, 可以在 test 目录下, 针对不同的合约, 编写多个单元测试脚本, 之后使用 yarn test 命令即可执行 test 目录下所有的单元测试脚本. -在 simpleTokenTest.js 脚本中, 对 SimpleToken.sol 合约的各个接口进行简单的测试, 可以参考此样例编写其他合约的单元测试代码. + SimpleToken.sol 合约的单元测试代码. 这里只写了一个测试脚本, 实际开发中, 可以在 test 目录下, 针对不同的合约, 编写多个单元测试脚本, 之后使用 yarn test 命令即可执行 test 目录下所有的单元测试脚本. + 在 simpleTokenTest.js 脚本中, 对 SimpleToken.sol 合约的各个接口进行简单的测试, 可以参考此样例编写其他合约的单元测试代码. - index.js -外部合约, 需要单独进行调用. 对应实际生产环境中, 当单元测试通过后, 就可以调用此脚本进行实际的生成操作. -此脚本名字自行进行定义, 这里是使用 index.js 进行指定 + 外部合约, 需要单独进行调用. 对应实际生产环境中, 当单元测试通过后, 就可以调用此脚本进行实际的生成操作. + 此脚本名字自行进行定义, 这里是使用 index.js 进行指定 + +## 操作步骤 -## 操作步骤 - 1 安装依赖 -``` + +```bash yarn install ``` - 2 编译合约: -``` + +```bash yarn build ``` -- 3 执行测试 -``` -yarn test -``` +- 3 执行测试 -- 4 测试 index.js +```bash +yarn test ``` + +- 4 测试 index.js + +```bash node index.js ``` ## 参考文档 -waffle 官方文档: -https://ethereum-waffle.readthedocs.io/en/latest/getting-started.html -ehterjs 官方文档: -https://docs.ethers.io/v4/api-providers.html -https://docs.ethers.io/v5/getting-started/#getting-started--contracts +- waffle 官方文档: + +- ehterjs 官方文档: + -中文文档: -https://learnblockchain.cn/docs/ethers.js/api-providers.html \ No newline at end of file +- 中文文档: diff --git a/basic/07-hardhat/README.md b/basic/07-hardhat/README.md index 6c1b3f8a5..948935dbd 100644 --- a/basic/07-hardhat/README.md +++ b/basic/07-hardhat/README.md @@ -117,13 +117,13 @@ require('@nomiclabs/hardhat-waffle'); // hardhat waffle 插件 windows: - ``` + ```bash copy .env.example .env ``` - / linux: + linux: - ``` + ```bash cp .env.example .env ``` @@ -210,13 +210,13 @@ npx hardhat accounts ### console -hardhat的控制台模式,实时与链上交互。默认会启动hardhat内置网络。 +hardhat 的控制台模式,实时与链上交互。默认会启动 hardhat 内置网络。 ```sh npx hardhat console ``` -控制内置ethers和web3库,可以直接使用,无须引入。 +控制内置 ethers 和 web3 库,可以直接使用,无须引入。 ```js // hardhat console mode: @@ -226,7 +226,7 @@ npx hardhat console ### console.log debug -hardhat 提供了一个 `console.log()` 方法,可以在合约运行时打印日志,方便调试和测试。**此方法仅在hardhat内置网络中运行有效。** +hardhat 提供了一个 `console.log()` 方法,可以在合约运行时打印日志,方便调试和测试。**此方法仅在 hardhat 内置网络中运行有效。** 在合约中引入 `hardhat/console.sol` 即可使用: @@ -256,19 +256,19 @@ Changing greeting from 'Hello, world!' to 'hello Dapp-Learning!' 1. 编译合约 - ``` + ```bash npx hardhat compile ``` 2. 批量运行测试脚本 - ``` + ```bash npx hardhat test ``` 3. 部署到测试网: - ``` + ```bash npx hardhat run scripts/deploy.js --network ``` @@ -276,7 +276,7 @@ Changing greeting from 'Hello, world!' to 'hello Dapp-Learning!' ## 参考文档 -- hardhat 官方文档: https://hardhat.org/guides/project-setup.html -- hardhat 中文文档: https://learnblockchain.cn/docs/hardhat/getting-started/ -- ethers.js 和 hardhat 基础使用讲解: (https://www.bilibili.com/video/BV1Pv411s7Nb) -- https://rahulsethuram.medium.com/the-new-solidity-dev-stack-buidler-ethers-waffle-typescript-tutorial-f07917de48ae +- hardhat 官方文档: +- hardhat 中文文档: +- ethers.js 和 hardhat 基础使用讲解: +- diff --git a/basic/07-hardhat/hardhat.config.js b/basic/07-hardhat/hardhat.config.js index 0cae7ac8f..4e2deb1d7 100644 --- a/basic/07-hardhat/hardhat.config.js +++ b/basic/07-hardhat/hardhat.config.js @@ -11,11 +11,8 @@ task('accounts', 'Prints the list of accounts', async () => { } }); - function mnemonic() { - - return process.env.PRIVATE_KEY; - + return process.env.PRIVATE_KEY; } /** @@ -26,35 +23,27 @@ module.exports = { networks: { localhost: { url: 'http://localhost:8545', - //gasPrice: 125000000000,//you can adjust gasPrice locally to see how much it will cost on production + //gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production /* notice no mnemonic here? it will just use account 0 of the hardhat node to deploy (you can put in a mnemonic here to set the deployer locally) */ }, rinkeby: { - url: "https://rinkeby.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://rinkeby.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, kovan: { - url: "https://kovan.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://kovan.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, mainnet: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://mainnet.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, ropsten: { - url: "https://ropsten.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://ropsten.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, }, }; diff --git a/basic/07-hardhat/package.json b/basic/07-hardhat/package.json index 66c3a8831..dfcfe5eab 100644 --- a/basic/07-hardhat/package.json +++ b/basic/07-hardhat/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "npx hardhat test" }, "keywords": [], "author": "", diff --git a/basic/08-hardhat-graph/README.md b/basic/08-hardhat-graph/README.md index 935071a32..26bd2cb83 100644 --- a/basic/08-hardhat-graph/README.md +++ b/basic/08-hardhat-graph/README.md @@ -15,14 +15,13 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 - Manifest 清单(subgraph.yaml) - 定义配置项 - Schema 模式(schema.graphql) - 定义数据 , 参考文档 https://graphql.cn/learn/ -- Mapping 映射(mapping.ts) - 定义事件到数据的转换 - +- Mapping 映射(mapping.ts) - 定义事件到数据的转换 ## 操作步骤 -1. 安装相关依赖 +1. 安装相关依赖 - ``` + ```bash yarn install ``` @@ -31,15 +30,15 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 为方便获取,在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取
另外需要设置你的 infura 节点 id,在 .env 中放入的私钥,格式为 "INFURA_ID=xxxx" -3. 部署合约(用于测试graph的简单合约) +3. 部署合约(用于测试 graph 的简单合约) - ``` + ```bash npx hardhat run ./scripts/deploy.js --network ropsten ``` 输出信息类似如下: - ``` + ```bash Deploying contracts with the account: xxxxxxxxxxxxxx Account balance: 10000000000000000000000 Token address: 0x5FbDB2315678afecb367f032d93F642f64180aa3 @@ -48,20 +47,19 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 ``` 4. TheGraph 创建一个 Subgraph 空间 - + 因为需要借助 TheGraph 的节点来完成数据的索引,因此我们需要在 [TheGraph Studio](https://thegraph.com/studio/) 上创建一个 Subgraph。 - 如果没有 The Graph 的账户,可以直接连接钱包注册,账户名即为钱包地址,以下称之为``。 - + 如果没有 The Graph 的账户,可以直接连接钱包注册,账户名即为钱包地址,以下称之为 ``。 + 批准钱包签名之后,会跳转到 `My Subgraphs` 面板,点击 `Create a Subgraph` 按钮。 ![create_subgraph_btn](./imgs/create_subgraph_btn.png) - 输入你的项目名称(例如TEST01),以下称之为 ``,点击 continue 按钮,之后会跳转到subgraph的项目主页 + 输入你的项目名称(例如 TEST01),以下称之为 ``,点击 continue 按钮,之后会跳转到 subgraph 的项目主页 +5. 开发和部署 subgraph -5. 开发和部署 subgraph - - 先使用 yarn 在全局安装 Graph CLI(注意,此处需安装0.21.0版本,最新版0.22.0无法部署在测试网上) + 先使用 yarn 在全局安装 Graph CLI(注意,此处需安装 0.21.0 版本,最新版 0.22.0 无法部署在测试网上) ```bash yarn global add @graphprotocol/graph-cli@0.21.0 @@ -77,116 +75,105 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 - Ethereum network 这里选择 ropsten - "Contract address" 这里输入在步骤 3 中部署合约时生成的合约地址 - 上面执行到 "fetch ABI from Etherscan" 时会报执行失败,然后出现 "ABI file (path)" 字样,提示输入本机中 abi 的文件路径,这里我们输入 SimpleToken.json 所在的路径即可(`./abis/SimpleToken.json`) - - 如果yarn install 失败(例如网络错误),可以进入新生成的项目目录,手动安装npm依赖 - -
- + - 如果 yarn install 失败(例如网络错误),可以进入新生成的项目目录,手动安装 npm 依赖 7. 修改定义模式 - 两个文件的修改范例在 `./scripts/schema.graphql` 和 `./scripts/mapping.ts` - - `/schema.graphql` 修改文件内容如下 - - ```graphql - type TransferEntity @entity { - id: ID! - from: Bytes! # address - to: Bytes! # address - value: BigInt! - } - - - type ApprovalEntity @entity { - id: ID! - owner: Bytes! # address - spender: Bytes! # address - value: BigInt! - } - ``` + - `/schema.graphql` 修改文件内容如下 + + ```graphql + type TransferEntity @entity { + id: ID! + from: Bytes! # address + to: Bytes! # address + value: BigInt! + } + + type ApprovalEntity @entity { + id: ID! + owner: Bytes! # address + spender: Bytes! # address + value: BigInt! + } + ``` - `/src/mapping.ts` 修改文件内容如下 - ```ts - import { BigInt } from "@graphprotocol/graph-ts" - import { - SimpleToken, - Transfer, - Approval - } from "../generated/SimpleToken/SimpleToken" - import { TransferEntity,ApprovalEntity } from "../generated/schema" - - export function handleTransfer(event: Transfer): void { - // Entities can be loaded from the store using a string ID; this ID - // needs to be unique across all entities of the same type - let entity = TransferEntity.load(event.transaction.from.toHex()) - - // Entities only exist after they have been saved to the store; - // `null` checks allow to create entities on demand - if (entity == null) { - entity = new TransferEntity(event.transaction.from.toHex()) - - } - - // BigInt and BigDecimal math are supported - entity.value = event.params.value - - // Entity fields can be set based on event parameters - entity.from = event.params.from - entity.to = event.params.to - - // Entities can be written to the store with `.save()` - entity.save() - - // Note: If a handler doesn't require existing field values, it is faster - // _not_ to load the entity from the store. Instead, create it fresh with - // `new Entity(...)`, set the fields that should be updated and save the - // entity back to the store. Fields that were not set or unset remain - // unchanged, allowing for partial updates to be applied. - - // It is also possible to access smart contracts from mappings. For - // example, the contract that has emitted the event can be connected to - // with: - // - // let contract = Contract.bind(event.address) - // - // The following functions can then be called on this contract to access - // state variables and other data: - // - // - contract.approve(...) - // - contract.totalSupply(...) - // - contract.transferFrom(...) - // - contract.increaseAllowance(...) - // - contract.balanceOf(...) - // - contract.decreaseAllowance(...) - // - contract.transfer(...) - // - contract.allowance(...) - } + ```ts + import { BigInt } from '@graphprotocol/graph-ts'; + import { SimpleToken, Transfer, Approval } from '../generated/SimpleToken/SimpleToken'; + import { TransferEntity, ApprovalEntity } from '../generated/schema'; - export function handleApproval(event: Approval): void { - // Entities can be loaded from the store using a string ID; this ID - // needs to be unique across all entities of the same type - let entity = ApprovalEntity.load(event.transaction.from.toHex()) + export function handleTransfer(event: Transfer): void { + // Entities can be loaded from the store using a string ID; this ID + // needs to be unique across all entities of the same type + let entity = TransferEntity.load(event.transaction.from.toHex()); - // Entities only exist after they have been saved to the store; - // `null` checks allow to create entities on demand - if (entity == null) { - entity = new ApprovalEntity(event.transaction.from.toHex()) - - } + // Entities only exist after they have been saved to the store; + // `null` checks allow to create entities on demand + if (entity == null) { + entity = new TransferEntity(event.transaction.from.toHex()); + } - // BigInt and BigDecimal math are supported - entity.value = event.params.value + // BigInt and BigDecimal math are supported + entity.value = event.params.value; + + // Entity fields can be set based on event parameters + entity.from = event.params.from; + entity.to = event.params.to; + + // Entities can be written to the store with `.save()` + entity.save(); + + // Note: If a handler doesn't require existing field values, it is faster + // _not_ to load the entity from the store. Instead, create it fresh with + // `new Entity(...)`, set the fields that should be updated and save the + // entity back to the store. Fields that were not set or unset remain + // unchanged, allowing for partial updates to be applied. + + // It is also possible to access smart contracts from mappings. For + // example, the contract that has emitted the event can be connected to + // with: + // + // let contract = Contract.bind(event.address) + // + // The following functions can then be called on this contract to access + // state variables and other data: + // + // - contract.approve(...) + // - contract.totalSupply(...) + // - contract.transferFrom(...) + // - contract.increaseAllowance(...) + // - contract.balanceOf(...) + // - contract.decreaseAllowance(...) + // - contract.transfer(...) + // - contract.allowance(...) + } + + export function handleApproval(event: Approval): void { + // Entities can be loaded from the store using a string ID; this ID + // needs to be unique across all entities of the same type + let entity = ApprovalEntity.load(event.transaction.from.toHex()); + + // Entities only exist after they have been saved to the store; + // `null` checks allow to create entities on demand + if (entity == null) { + entity = new ApprovalEntity(event.transaction.from.toHex()); + } - // Entity fields can be set based on event parameters - entity.owner = event.params.owner - entity.spender = event.params.spender + // BigInt and BigDecimal math are supported + entity.value = event.params.value; - // Entities can be written to the store with `.save()` - entity.save() - } + // Entity fields can be set based on event parameters + entity.owner = event.params.owner; + entity.spender = event.params.spender; - ``` + // Entities can be written to the store with `.save()` + entity.save(); + } + ``` 8. 修改实体名字 @@ -194,16 +181,16 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 - 修改 subgraph.yaml 中 entities 定义如下 ```yaml - ... + + --- entities: - TransferEntity - ApprovalEntity - ... ``` 9. 授权和部署 Subgraph - 首先获取你的``,在你的subgraph项目主页可以找到: + 首先获取你的 ``,在你的 subgraph 项目主页可以找到: ![auth_deploy_key](./imgs/auth_deploy_key.png) - 授权 @@ -212,12 +199,12 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 graph auth --studio ``` - - 进入subgraph的本地目录 + - 进入 subgraph 的本地目录 ```bash cd ./ ``` - + - BUILD SUBGRAPH ```bash @@ -232,71 +219,72 @@ TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三 - 这里必须输入 `Version Label` , 比如`0.0.1`, 否则会报错提示 `You must provide a version label.` +## 检验 subgraph 是否部署成功 +从 subgraphs 面板进入你的 subgraph 项目主页, 查看索引进度,当进度 100%可以开始调用。 -## 检验subgraph是否部署成功 - -从subgraphs面板进入你的subgraph项目主页, 查看索引进度,当进度100%可以开始调用。 - -这里已经预生成了一个示例请求,点击播放按钮即可请求数据。至此subgraph部署成功 +这里已经预生成了一个示例请求,点击播放按钮即可请求数据。至此 subgraph 部署成功 ![query_subgraph](./imgs/query_subgraph.png) -## Graph Node本地搭建 -1) 搭建graph-node -出于便捷的考虑,我们使用官方提供的docker compose来进行节点、数据库、IPFS的部署。 - - - 克隆 graph node( https://github.com/graphprotocol/graph-node/ )代码 - - 进入 docker 目录 - - 将 docker-compose.yml 中 ethereum 字段的值改为需要连接链的节点连接信息。 - ``` - graph-node: - image: graphprotocol/graph-node - ports: - - '8000:8000' - - '8001:8001' - - '8020:8020' - - '8030:8030' - - '8040:8040' - depends_on: - - ipfs - - postgres - environment: - postgres_host: postgres - postgres_user: graph-node - postgres_pass: let-me-in - postgres_db: graph-node - ipfs: 'ipfs:5001' - ethereum: 'mainnet:http://127.0.0.1:8545' #此处需修改 - RUST_LOG: info - ``` - >> 注意: graph-node连接的节点需要开启archive模式(启动节点时,添加flag --syncmode full --gcmode archive)。 - -2) graph-node启动 - -直接使用docker compose来进行启动 +## Graph Node 本地搭建 + +1. 搭建 graph-node +出于便捷的考虑,我们使用官方提供的 docker compose 来进行节点、数据库、IPFS 的部署。 + +- 克隆 graph node( https://github.com/graphprotocol/graph-node/ )代码 +- 进入 docker 目录 +- 将 docker-compose.yml 中 ethereum 字段的值改为需要连接链的节点连接信息。 + +```yaml +graph-node: + image: graphprotocol/graph-node + ports: + - '8000:8000' + - '8001:8001' + - '8020:8020' + - '8030:8030' + - '8040:8040' + depends_on: + - ipfs + - postgres + environment: + postgres_host: postgres + postgres_user: graph-node + postgres_pass: let-me-in + postgres_db: graph-node + ipfs: 'ipfs:5001' + ethereum: 'mainnet:http://127.0.0.1:8545' #此处需修改 + RUST_LOG: info ``` + +> > 注意: graph-node 连接的节点需要开启 archive 模式(启动节点时,添加 flag --syncmode full --gcmode archive)。 + +2. graph-node 启动 + +直接使用 docker compose 来进行启动 + +```bash docker-compose -f docker-compose.yml up -d ``` -3) 编译subgraph -进入subgraph的本地目录运行下列命令 -``` +3. 编译 subgraph + 进入 subgraph 的本地目录运行下列命令 + +```bash graph codegen --output-dir src/types/ graph build ``` -4) 部署subgraph -``` +4. 部署 subgraph + +```bash graph create davekaj/SimpleToken --node http://127.0.0.1:8020 graph deploy davekaj/SimpleToken --debug --ipfs http://localhost:5001 --node http://127.0.0.1:8020 ``` - -5) 可以使用GraphQL来进行查询数据。 - - +5. 可以使用 GraphQL 来进行查询数据。 ## subgraph @@ -313,29 +301,31 @@ subgraph 定义了你希望通过 GraphQL API 提供的数据、数据源和数 ## 参考链接 -官方文档: -https://thegraph.com/docs/developer/quick-start - -本项目参考文档: -https://mp.weixin.qq.com/s/DlC5jAS_CzXuOZFmmveNXA -https://mp.weixin.qq.com/s/LhdAREmhXSHxIaVfhcJQ_g -https://dev.to/dabit3/building-graphql-apis-on-ethereum-4poa -https://learnblockchain.cn/article/2566 -https://blog.openzeppelin.com/subgraphs-announcement -OpenZeppelin subgraphs 库:为常用的 OpenZepplin 合约建立 subgraphs -https://github.com/graphprotocol/agora -成本模型 - -Subgraph 选择指南(分析节点成本,收益以及应该索引哪些 Subgraph): -https://wavefive.notion.site/The-Graph-Protocol-Indexer-Subgraph-Selection-Guide-725f6e575f6e4024ad7e50f2f4e9bbad - -## 参考文档 -https://thegraph.com/ -https://graphql.cn/learn/ -https://gql-guide.vercel.app/ -https://thegraph.com/docs/graphql-api +官方文档: + +- https://thegraph.com/docs/developer/quick-start + +本项目参考文档: + +- https://mp.weixin.qq.com/s/DlC5jAS_CzXuOZFmmveNXA +- https://mp.weixin.qq.com/s/LhdAREmhXSHxIaVfhcJQ_g +- https://dev.to/dabit3/building-graphql-apis-on-ethereum-4poa +- https://learnblockchain.cn/article/2566 +- https://blog.openzeppelin.com/subgraphs-announcement + OpenZeppelin subgraphs 库: 为常用的 OpenZepplin 合约建立 subgraphs +- https://github.com/graphprotocol/agora + 成本模型 +- Subgraph 选择指南(分析节点成本,收益以及应该索引哪些 Subgraph): + + +## 参考文档 + +- https://thegraph.com/ +- https://graphql.cn/learn/ +- https://gql-guide.vercel.app/ +- https://thegraph.com/docs/graphql-api GraphGen——命令行工具,用于快速生成子图,由一些有 GraphGen 命令注释的 Solidity 接口文件组成。 -https://medium.com/protean-labs/introducing-graphgen-a-subgraph-generator-for-the-graph-network-836fe0385336 +- https://medium.com/protean-labs/introducing-graphgen-a-subgraph-generator-for-the-graph-network-836fe0385336 -Matchstick ——是 Limechain 做一个开发的单元测试框架,一个graph模拟节点,用于在沙盒环境中测试子图部署的映射逻辑 -相关教程:https://limechain.tech/blog/matchstick-what-it-is-and-how-to-use-it/ +- Matchstick ——是 Limechain 做一个开发的单元测试框架,一个 graph 模拟节点,用于在沙盒环境中测试子图部署的映射逻辑 +相关教程:https://limechain.tech/blog/matchstick-what-it-is-and-how-to-use-it/ diff --git a/basic/08-hardhat-graph/hardhat.config.js b/basic/08-hardhat-graph/hardhat.config.js index e6292ab6d..d144ad9e1 100644 --- a/basic/08-hardhat-graph/hardhat.config.js +++ b/basic/08-hardhat-graph/hardhat.config.js @@ -1,10 +1,10 @@ -require("@nomiclabs/hardhat-waffle"); -const fs = require("fs"); -require('dotenv').config() +require('@nomiclabs/hardhat-waffle'); +const fs = require('fs'); +require('dotenv').config(); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async () => { +task('accounts', 'Prints the list of accounts', async () => { const accounts = await ethers.getSigners(); for (const account of accounts) { @@ -16,49 +16,38 @@ task("accounts", "Prints the list of accounts", async () => { // Go to https://hardhat.org/config/ to learn more function mnemonic() { - - return process.env.PRIVATE_KEY; - + return process.env.PRIVATE_KEY; } /** * @type import('hardhat/config').HardhatUserConfig */ module.exports = { - solidity: "0.8.0", + solidity: '0.8.0', networks: { localhost: { - url: "http://localhost:8545", - //gasPrice: 125000000000,//you can adjust gasPrice locally to see how much it will cost on production + url: 'http://localhost:8545', + //gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production /* notice no mnemonic here? it will just use account 0 of the hardhat node to deploy (you can put in a mnemonic here to set the deployer locally) */ }, rinkeby: { - url: "https://rinkeby.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://rinkeby.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, kovan: { - url: "https://kovan.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://kovan.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, mainnet: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://mainnet.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, ropsten: { - url: "https://ropsten.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://ropsten.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, - } + }, }; - diff --git a/basic/09-hardhat-react/README.md b/basic/09-hardhat-react/README.md index 613a888f3..16f5bf1eb 100644 --- a/basic/09-hardhat-react/README.md +++ b/basic/09-hardhat-react/README.md @@ -1,30 +1,34 @@ -## 前言 -Dapp 开发中很重要的部分便是前端展示,本样例代码使用 hardhat 结合 react 和 MetaMask,演示如何开发 Dapp 前端页面,以及开发的基本流程及接口调用。 -开发者需要具备 react 框架开发能力才能很好的理解样例代码. +## 前言 + +Dapp 开发中很重要的部分便是前端展示,本样例代码使用 hardhat 结合 react 和 MetaMask,演示如何开发 Dapp 前端页面,以及开发的基本流程及接口调用。开发者需要具备 react 框架开发能力才能很好的理解样例代码. 为方便获取,在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 -## 操作步骤 -1) 安装依赖 +## 操作步骤 + +1. 安装依赖 + ```sh npm install ``` -2) 部署合约 +2. 部署合约 + ```sh npx hardhat run scripts/deploy.js --network kovan ``` -3) 启动 react +3. 启动 react + ```sh cd frontend npm install npm start ``` -## 参考文档 -https://github.com/Fankouzu/smart-contract/tree/master/Solidity%20Lesson%2005 -https://create-react-app.dev/docs/getting-started/ -https://github.com/nomiclabs/hardhat-hackathon-boilerplate -https://www.nextjs.cn/ next.js - \ No newline at end of file +## 参考文档 + +- https://github.com/Fankouzu/smart-contract/tree/master/Solidity%20Lesson%2005 +- https://create-react-app.dev/docs/getting-started/ +- https://github.com/nomiclabs/hardhat-hackathon-boilerplate +- https://www.nextjs.cn/ next.js diff --git a/basic/09-hardhat-react/hardhat.config.js b/basic/09-hardhat-react/hardhat.config.js index 1d38a728c..494655daa 100644 --- a/basic/09-hardhat-react/hardhat.config.js +++ b/basic/09-hardhat-react/hardhat.config.js @@ -1,52 +1,42 @@ -require("@nomiclabs/hardhat-waffle"); +require('@nomiclabs/hardhat-waffle'); // The next line is part of the sample project, you don't need it in your // project. It imports a Hardhat task definition, that can be used for // testing the frontend. -require("./tasks/faucet"); -const fs = require("fs"); -require('dotenv').config() +require('./tasks/faucet'); +const fs = require('fs'); +require('dotenv').config(); function mnemonic() { - return process.env.PRIVATE_KEY; - } module.exports = { - solidity: "0.8.0", + solidity: '0.8.0', networks: { localhost: { - url: "http://localhost:8545", - //gasPrice: 125000000000,//you can adjust gasPrice locally to see how much it will cost on production + url: 'http://localhost:8545', + //gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production /* notice no mnemonic here? it will just use account 0 of the hardhat node to deploy (you can put in a mnemonic here to set the deployer locally) */ }, rinkeby: { - url: "https://rinkeby.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://rinkeby.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, kovan: { - url: "https://kovan.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://kovan.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, mainnet: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://mainnet.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, ropsten: { - url: "https://ropsten.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://ropsten.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, - } + }, }; diff --git a/basic/09-hardhat-react/package.json b/basic/09-hardhat-react/package.json index a996f7f5d..1204f607a 100644 --- a/basic/09-hardhat-react/package.json +++ b/basic/09-hardhat-react/package.json @@ -6,7 +6,7 @@ "test": "test" }, "scripts": { - "test": "hardhat test" + "test": "npx hardhat test" }, "repository": { "type": "git", diff --git a/basic/10-hardhat-ipfs-erc721/README.md b/basic/10-hardhat-ipfs-erc721/README.md index 5f47e7be7..0a4283b2f 100644 --- a/basic/10-hardhat-ipfs-erc721/README.md +++ b/basic/10-hardhat-ipfs-erc721/README.md @@ -1,27 +1,32 @@ -## IPFS 介绍 -是一个旨在创建持久且分布式存储和共享文件的网络传输协议。它是一种内容可寻址的对等超媒体分发协议。 +## IPFS 介绍 -在IPFS网络中的节点将构成一个分布式文件系统。它是一个开放源代码项目,自2014年开始由协议实验室在开源社区的帮助下发展。其最初由Juan Benet设计 -IPFS是一个对等的分布式文件系统,它尝试为所有计算设备连接同一个文件系统。在某些方面,IPFS类似于万维网,也可以被视作一个独立的BitTorrent群、在同一个Git仓库中交换对象。 换种说法,IPFS提供了一个高吞吐量、按内容寻址的块存储模型,及与内容相关超链接。这形成了一个广义的Merkle有向无环图(DAG)。 +是一个旨在创建持久且分布式存储和共享文件的网络传输协议。它是一种内容可寻址的对等超媒体分发协议。 -IPFS结合了分布式散列表、鼓励块交换和一个自我认证的名字空间。IPFS没有单点故障,并且节点不需要相互信任。分布式内容传递可以节约带宽,和防止HTTP方案可能遇到的DDoS攻击。 +在 IPFS 网络中的节点将构成一个分布式文件系统。它是一个开放源代码项目,自 2014 年开始由协议实验室在开源社区的帮助下发展。其最初由 Juan Benet 设计 +IPFS 是一个对等的分布式文件系统,它尝试为所有计算设备连接同一个文件系统。在某些方面,IPFS 类似于万维网,也可以被视作一个独立的 BitTorrent 群、在同一个 Git 仓库中交换对象。 换种说法,IPFS 提供了一个高吞吐量、按内容寻址的块存储模型,及与内容相关超链接。这形成了一个广义的 Merkle 有向无环图(DAG)。 -该文件系统可以通过多种方式访问,包括FUSE与HTTP。将本地文件添加到IPFS文件系统可使其面向全世界可用。文件表示基于其哈希,因此有利于缓存。文件的分发采用一个基于BitTorrent的协议。其他查看内容的用户也有助于将内容提供给网络上的其他人。 -IPFS有一个称为IPNS的名称服务,它是一个基于PKI的全局名字空间,用于构筑信任链,这与其他NS兼容,并可以映射DNS、.onion、.bit等到IPNS。 +IPFS 结合了分布式散列表、鼓励块交换和一个自我认证的名字空间。IPFS 没有单点故障,并且节点不需要相互信任。分布式内容传递可以节约带宽,和防止 HTTP 方案可能遇到的 DDoS 攻击。 + +该文件系统可以通过多种方式访问,包括 FUSE 与 HTTP。将本地文件添加到 IPFS 文件系统可使其面向全世界可用。文件表示基于其哈希,因此有利于缓存。文件的分发采用一个基于 BitTorrent 的协议。其他查看内容的用户也有助于将内容提供给网络上的其他人。 +IPFS 有一个称为 IPNS 的名称服务,它是一个基于 PKI 的全局名字空间,用于构筑信任链,这与其他 NS 兼容,并可以映射 DNS、.onion、.bit 等到 IPNS。 todo 1155 left -## IPFS 安装 -IPFS 有多种方式: +## IPFS 安装 + +IPFS 有多种方式: + - IPFS Desktop: 直接运行的应用程序,适合所有人 - Command-line: 命令行方式安装, 这我们选择这中安装方式, 下面以 mac 下这种安装方式为例进行讲解,其他系统安装方式参考文档 - -1) 下载文件 -``` + +1. 下载文件 + +```bash wget https://dist.ipfs.io/go-ipfs/v0.8.0/go-ipfs_v0.8.0_darwin-amd64.tar.gz ``` -2) 解压缩 +2. 解压缩 + ```angular2html tar -xvzf go-ipfs_v0.8.0_darwin-amd64.tar.gz @@ -33,7 +38,8 @@ tar -xvzf go-ipfs_v0.8.0_darwin-amd64.tar.gz > x go-ipfs/README.md ``` -3) 执行安装 +3. 执行安装 + ```angular2html cd go-ipfs bash install.sh @@ -41,15 +47,18 @@ bash install.sh > Moved ./ipfs to /usr/local/bin ``` -4) 检查安装结果 +4. 检查安装结果 + ```angular2html ipfs --version > ipfs version 0.8.0 ``` -## IPFS 初始化及启动 -1) 初始化 ipfs +## IPFS 初始化及启动 + +1. 初始化 ipfs + ```angular2html ipfs init @@ -63,7 +72,8 @@ ipfs init - peer identity : 每个 ipfs 节点都有一个独有的 id -2) 启动 +2. 启动 + ```angular2html ipfs daemon > Initializing daemon... @@ -71,41 +81,48 @@ ipfs daemon > Gateway server listening on /ip4/127.0.0.1/tcp/8080 ``` -3) IPFS Web console -在浏览器中输入地址 localhost:5001/webui 查看 IPFS 控制台 +3. IPFS Web console + 在浏览器中输入地址 localhost:5001/webui 查看 IPFS 控制台 + +## 测试 IPFS 和 ERC721 + +1. 配置私钥 + 在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 -## 测试 IPFS 和 ERC721 -1) 配置私钥 -在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 +2. 执行如下命令 -2) 执行如下命令 ```angular2html npx hardhat run scripts/deploy-ipfs.js --network kovan ``` + 运行结束后,在 console 输出的日志中,最后一行打印出了你上传文件独有的 hash + ```bash > ... > IPFS URL of art.jpg is : /ipfs/${FILE_HASH}$ ``` -3) 对比文件 -在当前目录下执行如下命令,其中 *${FILE_HASH}$* 在第二步中获得 + +3. 对比文件 + 在当前目录下执行如下命令,其中 _${FILE_HASH}$_ 在第二步中获得 + ```bash ipfs cat /ipfs/${FILE_HASH}$ > art2.jpg ``` 之后,可以对比下 art.jpg 和 art2.jpg 文件显示的内容是否一致 - ## 合约 -合约参考open-zeppelin: -修改项目: -mintWithTokenURI新增方法,任何人可以发发行nft。 -合约拍平 +合约参考 open-zeppelin +修改项目: mintWithTokenURI 新增方法,任何人可以发发行 nft。 + +合约拍平 +```bash npx hardhat flatten ./contracts/MYERC721.sol > MYERC721.sol +``` +## 参考文档 -## 参考文档 -- https://docs.ipfs.io/install/command-line/#official-distributions +- https://docs.ipfs.io/install/command-line/#official-distributions - https://mp.weixin.qq.com/s/3DshdSAzifyP9-CQZ-ORfw diff --git a/basic/10-hardhat-ipfs-erc721/hardhat.config.js b/basic/10-hardhat-ipfs-erc721/hardhat.config.js index ca8f1479f..d144ad9e1 100644 --- a/basic/10-hardhat-ipfs-erc721/hardhat.config.js +++ b/basic/10-hardhat-ipfs-erc721/hardhat.config.js @@ -1,10 +1,10 @@ -require("@nomiclabs/hardhat-waffle"); -const fs = require("fs"); -require('dotenv').config() +require('@nomiclabs/hardhat-waffle'); +const fs = require('fs'); +require('dotenv').config(); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async () => { +task('accounts', 'Prints the list of accounts', async () => { const accounts = await ethers.getSigners(); for (const account of accounts) { @@ -16,48 +16,38 @@ task("accounts", "Prints the list of accounts", async () => { // Go to https://hardhat.org/config/ to learn more function mnemonic() { - return process.env.PRIVATE_KEY; - } /** * @type import('hardhat/config').HardhatUserConfig */ module.exports = { - solidity: "0.8.0", + solidity: '0.8.0', networks: { localhost: { - url: "http://localhost:8545", - //gasPrice: 125000000000,//you can adjust gasPrice locally to see how much it will cost on production + url: 'http://localhost:8545', + //gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production /* notice no mnemonic here? it will just use account 0 of the hardhat node to deploy (you can put in a mnemonic here to set the deployer locally) */ }, rinkeby: { - url: "https://rinkeby.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://rinkeby.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, kovan: { - url: "https://kovan.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://kovan.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, mainnet: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://mainnet.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, ropsten: { - url: "https://ropsten.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://ropsten.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, - } -}; \ No newline at end of file + }, +}; diff --git a/basic/11-react-express-hardhat/README.md b/basic/11-react-express-hardhat/README.md index eea2d5438..396444d3a 100644 --- a/basic/11-react-express-hardhat/README.md +++ b/basic/11-react-express-hardhat/README.md @@ -1,7 +1,7 @@ ## Express 结合 hardhat - 配置私钥 -在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 + 在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 - 安装依赖 @@ -36,14 +36,13 @@ node app.js ```shell cd frontend -yarn +yarn yarn start ``` +## 参考文档 -## 参考文档 -https://github.com/dzzzzzy/Nestjs-Learning -https://docs.nestjs.cn/8/firststeps -https://github.com/HeyiMaster/nest-starter nestjs -https://www.bilibili.com/video/BV1bQ4y1A77L?p=4 netstjs Bilibili - \ No newline at end of file +- https://github.com/dzzzzzy/Nestjs-Learning +- https://docs.nestjs.cn/8/firststeps +- https://github.com/HeyiMaster/nest-starter nestjs +- https://www.bilibili.com/video/BV1bQ4y1A77L?p=4 netstjs Bilibili diff --git a/basic/11-react-express-hardhat/hardhat.config.js b/basic/11-react-express-hardhat/hardhat.config.js index c14922a0f..b41fe4154 100644 --- a/basic/11-react-express-hardhat/hardhat.config.js +++ b/basic/11-react-express-hardhat/hardhat.config.js @@ -1,19 +1,19 @@ -require('@nomiclabs/hardhat-waffle') -const fs = require('fs') -require('dotenv').config() +require('@nomiclabs/hardhat-waffle'); +const fs = require('fs'); +require('dotenv').config(); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html task('accounts', 'Prints the list of accounts', async () => { - const accounts = await ethers.getSigners() + const accounts = await ethers.getSigners(); for (const account of accounts) { - console.log(account.address) + console.log(account.address); } -}) +}); function mnemonic() { - return process.env.PRIVATE_KEY + return process.env.PRIVATE_KEY; } // You need to export an object to set up your config @@ -27,7 +27,7 @@ module.exports = { networks: { localhost: { url: 'http://localhost:8545', - //gasPrice: 125000000000,//you can adjust gasPrice locally to see how much it will cost on production + //gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production /* notice no mnemonic here? it will just use account 0 of the hardhat node to deploy (you can put in a mnemonic here to set the deployer locally) @@ -50,4 +50,4 @@ module.exports = { accounts: [mnemonic()], }, }, -} +}; diff --git a/basic/12-token-crowdfund/README.md b/basic/12-token-crowdfund/README.md index 2d2c2e7db..c7f41fb91 100644 --- a/basic/12-token-crowdfund/README.md +++ b/basic/12-token-crowdfund/README.md @@ -1,44 +1,52 @@ ## 众筹合约 + 本样例演示众筹合约的基本流程,包括部署合约,合约,启动众筹项目, ## 操作流程 + - 配置私钥 -在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 + 在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取 - 安装依赖 -``` + +```bash yarn ``` - 编译合约 -``` + +```bash npx hardhat compile ``` - 测试合约 -``` + +```bash npx hardhat test ``` - 部署合约 -``` + +```bash npx hardhat run scripts/deploy_crowdfunding.js --network rinkeby ``` -## Crowdsale类型 - - - CappedCrowdsale - - IndividuallyCappedCrowdsale - - TimedCrowdsale - - WhitelistedCrowdsale - - FinalizableCrowdsale - - PostDeliveryCrowdsale - - RefundableCrowdsale - - AllowanceCrowdsale - - MintedCrowdsale - - IncreasingPriceCrowdsale - + +## Crowdsale 类型 + +- CappedCrowdsale +- IndividuallyCappedCrowdsale +- TimedCrowdsale +- WhitelistedCrowdsale +- FinalizableCrowdsale +- PostDeliveryCrowdsale +- RefundableCrowdsale +- AllowanceCrowdsale +- MintedCrowdsale +- IncreasingPriceCrowdsale + ## 参考链接 -https://medium.com/openberry/creating-a-simple-crowdfunding-dapp-with-ethereum-solidity-and-vue-js-69ddb8e132dd -https://medium.com/extropy-io/crowdsales-on-ethereum-with-openzeppelin-57bbdea95390 -https://www.programmersought.com/article/1396206575/ -https://github.com/OpenZeppelin/openzeppelin-contracts/tree/release-v2.3.0/contracts/crowdsale + +- https://medium.com/openberry/creating-a-simple-crowdfunding-dapp-with-ethereum-solidity-and-vue-js-69ddb8e132dd +- https://medium.com/extropy-io/crowdsales-on-ethereum-with-openzeppelin-57bbdea95390 +- https://www.programmersought.com/article/1396206575/ +- https://github.com/OpenZeppelin/openzeppelin-contracts/tree/release-v2.3.0/contracts/crowdsale diff --git a/basic/12-token-crowdfund/hardhat.config.js b/basic/12-token-crowdfund/hardhat.config.js index 03b1d1667..9ce10eec6 100644 --- a/basic/12-token-crowdfund/hardhat.config.js +++ b/basic/12-token-crowdfund/hardhat.config.js @@ -1,10 +1,10 @@ -require("@nomiclabs/hardhat-waffle"); -const fs = require("fs"); -require('dotenv').config() +require('@nomiclabs/hardhat-waffle'); +const fs = require('fs'); +require('dotenv').config(); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async () => { +task('accounts', 'Prints the list of accounts', async () => { const accounts = await ethers.getSigners(); for (const account of accounts) { @@ -13,9 +13,7 @@ task("accounts", "Prints the list of accounts", async () => { }); function mnemonic() { - - return process.env.PRIVATE_KEY - + return process.env.PRIVATE_KEY; } /** @@ -25,50 +23,42 @@ module.exports = { solidity: { compilers: [ { - version: "0.5.4" + version: '0.5.4', }, { - version: "0.4.18", - settings: {} + version: '0.4.18', + settings: {}, }, { - version: "0.8.0", - settings: {} + version: '0.8.0', + settings: {}, }, - ] + ], }, networks: { localhost: { - url: "http://localhost:8545", - //gasPrice: 125000000000,//you can adjust gasPrice locally to see how much it will cost on production + url: 'http://localhost:8545', + //gasPrice: 125000000000, // you can adjust gasPrice locally to see how much it will cost on production /* notice no mnemonic here? it will just use account 0 of the hardhat node to deploy (you can put in a mnemonic here to set the deployer locally) */ }, rinkeby: { - url: "https://rinkeby.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://rinkeby.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, kovan: { - url: "https://kovan.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://kovan.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, mainnet: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://mainnet.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, ropsten: { - url: "https://ropsten.infura.io/v3/" + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) - accounts: [ - mnemonic() - ], + url: 'https://ropsten.infura.io/v3/' + process.env.INFURA_ID, //<---- YOUR INFURA ID! (or it won't work) + accounts: [mnemonic()], }, - } + }, }; diff --git a/basic/12-token-crowdfund/package.json b/basic/12-token-crowdfund/package.json index c59f611f6..b8e593b7e 100644 --- a/basic/12-token-crowdfund/package.json +++ b/basic/12-token-crowdfund/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "npx hardhat test" }, "keywords": [], "author": "",