Skip to content

Commit 092a4ae

Browse files
committed
feat: 08 translate
1 parent 30f4fee commit 092a4ae

File tree

3 files changed

+654
-293
lines changed

3 files changed

+654
-293
lines changed

basic/02-web3js-transaction/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ const Web3 = require('web3');
22
const fs = require('fs');
33
const contractOfIncrementer = require('./compile');
44

5-
require('dotenv').config({path: __dirname + '/../.env'});
6-
console.log(process.env);
5+
require('dotenv').config();
76
const privatekey = process.env.PRIVATE_KEY;
87

98
/*
@@ -157,7 +156,7 @@ const Trans = async () => {
157156
// more details , please refer to https://medium.com/blockcentric/listening-for-smart-contract-events-on-public-blockchains-fdb5a8ac8b9a
158157
const web3Socket = new Web3(
159158
new Web3.providers.WebsocketProvider(
160-
'wss://ropsten.infura.io/ws/v3/' + process.env.INFURA_ID
159+
'wss://kovan.infura.io/ws/v3/' + process.env.INFURA_ID
161160
)
162161
);
163162
incrementer = new web3Socket.eth.Contract(abi, createReceipt.contractAddress);

basic/08-hardhat-graph/README-CN.md

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
## Graph 介绍
2+
3+
编写智能合约时,通常状态的变化是通过触发一个事件来表达,The Graph 则是捕捉区块链事件并提供一个查询事件的 GraphQL 接口,让我们可以方便的跟踪数据的变化。实际上很多 defi 协议都是 The Graph 来基于查询数据。
4+
5+
## 流程概述
6+
7+
- 在 Rinkeby 部署一个合约,并调用触发事件。
8+
- 创建定义数据索引的 Subgraph。
9+
- 部署 Subgraph 到 TheGraph,实现数据索引。
10+
- 在前端 DApp 中查询索引数据。
11+
12+
如果你有自己的私有链,这可以克隆 Graph 节点代码 https://github.com/graphprotocol/graph-node/ 自己运行 Graph 节点来完成数据的索引。
13+
14+
TheGraph 中定义如何为数据建立索引,称为 Subgraph,它包含三个组件:
15+
16+
- Manifest 清单(subgraph.yaml) - 定义配置项
17+
- Schema 模式(schema.graphql) - 定义数据 , 参考文档 https://graphql.cn/learn/
18+
- Mapping 映射(mapping.ts) - 定义事件到数据的转换
19+
20+
## 操作步骤
21+
22+
1. 安装相关依赖
23+
24+
```bash
25+
yarn install
26+
```
27+
28+
2. 配置私钥
29+
30+
为方便获取,在 .env 中放入的私钥,格式为 "PRIVATE_KEY=xxxx", 然后代码自动从中读取<br>
31+
另外需要设置你的 infura 节点 id,在 .env 中放入的私钥,格式为 "INFURA_ID=xxxx"
32+
33+
3. 部署合约(用于测试 graph 的简单合约)
34+
35+
```bash
36+
npx hardhat run ./scripts/deploy.js --network rinkeby
37+
```
38+
39+
输出信息类似如下:
40+
41+
```bash
42+
Deploying contracts with the account: xxxxxxxxxxxxxx
43+
Account balance: 10000000000000000000000
44+
Token address: 0x5FbDB2315678afecb367f032d93F642f64180aa3
45+
Transfer 50 to receiver 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
46+
Account balance of receiver is: 50
47+
```
48+
49+
4. TheGraph 创建一个 Subgraph 空间
50+
51+
因为需要借助 TheGraph 的节点来完成数据的索引,因此我们需要在 [TheGraph Studio](https://thegraph.com/studio/) 上创建一个 Subgraph。
52+
53+
如果没有 The Graph 的账户,可以直接连接钱包注册,账户名即为钱包地址,以下称之为 `<THEGRAPH_USERNAME>`
54+
55+
批准钱包签名之后,会跳转到 `My Subgraphs` 面板,点击 `Create a Subgraph` 按钮。
56+
<center><img src="https://github.com/Dapp-Learning-DAO/Dapp-Learning-Arsenal/blob/main/images/basic/08-hardhat-graph/create_subgraph_btn.png?raw=true" /></center>
57+
58+
输入你的项目名称(例如 TEST01),以下称之为 `<SUBGRAPH_NAME>`,点击 continue 按钮,之后会跳转到 subgraph 的项目主页
59+
60+
注:最新版的 Graph CLI 仅支持在 mainnet 和 rinkeby 上部署,若要在其他网络上使用,需要使用 Github 账户登录后在 Hosted Service 上创建和部署
61+
62+
5. 开发和部署 subgraph
63+
64+
先使用 yarn 在全局安装 Graph CLI
65+
66+
```bash
67+
yarn global add @graphprotocol/graph-cli
68+
```
69+
70+
6. 初始化配置:
71+
72+
```bash
73+
graph init --studio <SUBGRAPH_NAME>
74+
```
75+
76+
若使用 Hosted Service,则初始化命令如下:
77+
78+
```bash
79+
graph init --product hosted-service <GITHUB_USER>/<SUBGRAPH NAME>
80+
```
81+
82+
- 在 "Subgraph name" 和 "Directory to create the subgraph" 直接回车即可
83+
- Ethereum network 这里选择 rinkeby
84+
- "Contract address" 这里输入在步骤 3 中部署合约时生成的合约地址
85+
- 上面执行到 "fetch ABI from Etherscan" 时会报执行失败,然后出现 "ABI file (path)" 字样,提示输入本机中 abi 的文件路径,这里我们输入 SimpleToken.json 所在的路径即可(`./abis/SimpleToken.json`)
86+
- 如果 yarn install 失败(例如网络错误),可以进入新生成的项目目录,手动安装 npm 依赖
87+
88+
7. 修改定义模式
89+
90+
- 两个文件的修改范例在 `./scripts/schema.graphql``./scripts/mapping.ts`
91+
92+
- `<SUBGRAPH_NAME>/schema.graphql` 修改文件内容如下
93+
94+
```graphql
95+
type TransferEntity @entity {
96+
id: ID!
97+
from: Bytes! # address
98+
to: Bytes! # address
99+
value: BigInt!
100+
}
101+
102+
type ApprovalEntity @entity {
103+
id: ID!
104+
owner: Bytes! # address
105+
spender: Bytes! # address
106+
value: BigInt!
107+
}
108+
```
109+
110+
- `<SUBGRAPH_NAME>/src/mapping.ts` 修改文件内容如下
111+
112+
```ts
113+
import { BigInt } from '@graphprotocol/graph-ts';
114+
import { SimpleToken, Transfer, Approval } from '../generated/SimpleToken/SimpleToken';
115+
import { TransferEntity, ApprovalEntity } from '../generated/schema';
116+
117+
export function handleTransfer(event: Transfer): void {
118+
// Entities can be loaded from the store using a string ID; this ID
119+
// needs to be unique across all entities of the same type
120+
let entity = TransferEntity.load(event.transaction.from.toHex());
121+
122+
// Entities only exist after they have been saved to the store;
123+
// `null` checks allow to create entities on demand
124+
if (entity == null) {
125+
entity = new TransferEntity(event.transaction.from.toHex());
126+
}
127+
128+
// BigInt and BigDecimal math are supported
129+
entity.value = event.params.value;
130+
131+
// Entity fields can be set based on event parameters
132+
entity.from = event.params.from;
133+
entity.to = event.params.to;
134+
135+
// Entities can be written to the store with `.save()`
136+
entity.save();
137+
138+
// Note: If a handler doesn't require existing field values, it is faster
139+
// _not_ to load the entity from the store. Instead, create it fresh with
140+
// `new Entity(...)`, set the fields that should be updated and save the
141+
// entity back to the store. Fields that were not set or unset remain
142+
// unchanged, allowing for partial updates to be applied.
143+
144+
// It is also possible to access smart contracts from mappings. For
145+
// example, the contract that has emitted the event can be connected to
146+
// with:
147+
//
148+
// let contract = Contract.bind(event.address)
149+
//
150+
// The following functions can then be called on this contract to access
151+
// state variables and other data:
152+
//
153+
// - contract.approve(...)
154+
// - contract.totalSupply(...)
155+
// - contract.transferFrom(...)
156+
// - contract.increaseAllowance(...)
157+
// - contract.balanceOf(...)
158+
// - contract.decreaseAllowance(...)
159+
// - contract.transfer(...)
160+
// - contract.allowance(...)
161+
}
162+
163+
export function handleApproval(event: Approval): void {
164+
// Entities can be loaded from the store using a string ID; this ID
165+
// needs to be unique across all entities of the same type
166+
let entity = ApprovalEntity.load(event.transaction.from.toHex());
167+
168+
// Entities only exist after they have been saved to the store;
169+
// `null` checks allow to create entities on demand
170+
if (entity == null) {
171+
entity = new ApprovalEntity(event.transaction.from.toHex());
172+
}
173+
174+
// BigInt and BigDecimal math are supported
175+
entity.value = event.params.value;
176+
177+
// Entity fields can be set based on event parameters
178+
entity.owner = event.params.owner;
179+
entity.spender = event.params.spender;
180+
181+
// Entities can be written to the store with `.save()`
182+
entity.save();
183+
}
184+
```
185+
186+
8. 修改实体名字
187+
188+
- 进入 graphtest 目录
189+
- 修改 subgraph.yamlentities 定义如下
190+
191+
```yaml
192+
---
193+
entities:
194+
- TransferEntity
195+
- ApprovalEntity
196+
```
197+
198+
9. 授权和部署 Subgraph
199+
200+
首先获取你的 `<DEPLOY KEY>`,在你的 subgraph 项目主页可以找到:
201+
<center><img src="https://github.com/Dapp-Learning-DAO/Dapp-Learning-Arsenal/blob/main/images/basic/08-hardhat-graph/auth_deploy_key.png?raw=true" /></center>
202+
203+
- 授权
204+
205+
```bash
206+
graph auth --studio <DEPLOY KEY>
207+
```
208+
209+
若使用 Hosted Service,则初始化命令如下:
210+
211+
```bash
212+
graph auth --product hosted-service <ACCESS_TOKEN>
213+
```
214+
215+
- 进入 subgraph 的本地目录
216+
217+
```bash
218+
cd ./<SUBGRAPH_NAME>
219+
```
220+
221+
- BUILD SUBGRAPH
222+
223+
```bash
224+
graph codegen && graph build
225+
```
226+
227+
- DEPLOY SUBGRAPH
228+
229+
```bash
230+
graph deploy --studio <SUBGRAPH_NAME>
231+
```
232+
233+
若使用 Hosted Service,则初始化命令如下:
234+
235+
```bash
236+
graph deploy --product hosted-service <GITHUB_USER>/<SUBGRAPH NAME>
237+
```
238+
239+
- 这里必须输入 `Version Label` , 比如`0.0.1`, 否则会报错提示 `You must provide a version label.`
240+
241+
## 检验 subgraph 是否部署成功
242+
243+
从 subgraphs 面板进入你的 subgraph 项目主页, 查看索引进度,当进度 100%可以开始调用。
244+
245+
这里已经预生成了一个示例请求,点击播放按钮即可请求数据。至此 subgraph 部署成功
246+
247+
<center><img src="https://github.com/Dapp-Learning-DAO/Dapp-Learning-Arsenal/blob/main/images/basic/08-hardhat-graph/query_subgraph.png?raw=true" /></center>
248+
249+
## Graph Node 本地搭建
250+
251+
1. 搭建 graph-node
252+
出于便捷的考虑,我们使用官方提供的 docker compose 来进行节点、数据库、IPFS 的部署。
253+
254+
- 克隆 graph node( https://github.com/graphprotocol/graph-node/ )代码
255+
- 进入 docker 目录
256+
- 将 docker-compose.yml 中 ethereum 字段的值改为需要连接链的节点连接信息。
257+
258+
注意:如果是最新的 mac(big sur 系统),在安装 docker 的时候,不能使用 brew cask install docker 命令,具体原因参考链接:https://www.jianshu.com/p/50037be9c00d
259+
260+
```yaml
261+
graph-node:
262+
image: graphprotocol/graph-node
263+
ports:
264+
- '8000:8000'
265+
- '8001:8001'
266+
- '8020:8020'
267+
- '8030:8030'
268+
- '8040:8040'
269+
depends_on:
270+
- ipfs
271+
- postgres
272+
environment:
273+
postgres_host: postgres
274+
postgres_user: graph-node
275+
postgres_pass: let-me-in
276+
postgres_db: graph-node
277+
ipfs: 'ipfs:5001'
278+
ethereum: 'mainnet:http://127.0.0.1:8545' #此处的mainnet需要和subgraph.yml里network对应上
279+
# ethereum: 'dev:https://rinkeby.infura.io/v3/INFURA_ID' # 也可以连测试网络
280+
RUST_LOG: info
281+
```
282+
283+
> 注意: graph-node 连接的节点需要开启 archive 模式(启动节点时,添加 flag --syncmode full --gcmode archive)。
284+
285+
2. graph-node 启动
286+
287+
直接使用 docker compose 来进行启动
288+
289+
```bash
290+
docker-compose -f docker-compose.yml up -d
291+
```
292+
293+
3. 编译 subgraph
294+
进入 subgraph 的本地目录运行下列命令
295+
296+
由于在前一步骤执行过命令 npx hardhat run ./scripts/deploy.js --network rinkeby
297+
298+
因此,此处修改 subgraph.yaml,修改内容如下:
299+
300+
```bash
301+
dataSources:
302+
- kind: ethereum/contract
303+
name: SimpleToken
304+
network: rinkeby
305+
306+
```
307+
308+
```bash
309+
graph codegen --output-dir src/types/
310+
graph build
311+
```
312+
313+
4. 部署 subgraph
314+
315+
```bash
316+
graph create davekaj/SimpleToken --node http://127.0.0.1:8020
317+
318+
graph deploy davekaj/SimpleToken --debug --ipfs http://localhost:5001 --node http://127.0.0.1:8020
319+
```
320+
321+
5. 可以使用 GraphQL 来进行查询数据。
322+
323+
## subgraph
324+
325+
subgraph 定义了你希望通过 GraphQL API 提供的数据、数据源和数据访问模式。开发者可以选择直接使用别人已经部署[17]的 subgraph,或者自己定义并部署 subgraph。
326+
327+
1. GraphQL Schema
328+
GraphQL Schema 定义了你想保存和查询的数据类型/实体。也可定义如关系或全文搜索的配置项。
329+
2. subgraph 清单( yaml 配置)
330+
manifest 定义了 subgraph 索引的智能合约、合约的 ABI、关注这些合约的事件,以及如何将事件数据映射到 Graph 节点存储并允许查询。
331+
3. AssemblyScript 映射
332+
AssemblyScript 映射允许您使用 schema 中定义的实体类型保存要索引的数据。Graph CLI 还使用 schema 与智能合约的 ABI 的组合生成 AssemblyScript 类型。
333+
4. 通过@derivedFrom 建立关系
334+
通过@derivedFrom 字段在实体上定义反向查询,这样就在实体上创建了一个虚拟字段,使它可以被查询,但不能通过映射 API 手动设置。实际上,这是从另一个实体上定义的关系中衍生出来的。这样的关系,对存储关系的两者意义不大,如果只存储一方而派生另一方,则索引和查询性能都会更好。
335+
336+
## 参考文档
337+
338+
官方文档:
339+
340+
- https://thegraph.com/docs/developer/quick-start
341+
342+
本项目参考文档:
343+
344+
- https://mp.weixin.qq.com/s/DlC5jAS_CzXuOZFmmveNXA
345+
- https://mp.weixin.qq.com/s/LhdAREmhXSHxIaVfhcJQ_g
346+
- https://dev.to/dabit3/building-graphql-apis-on-ethereum-4poa
347+
- https://learnblockchain.cn/article/2566
348+
- https://blog.openzeppelin.com/subgraphs-announcement
349+
OpenZeppelin subgraphs 库: 为常用的 OpenZepplin 合约建立 subgraphs
350+
- https://github.com/graphprotocol/agora
351+
成本模型
352+
- Subgraph 选择指南(分析节点成本,收益以及应该索引哪些 Subgraph):
353+
<https://wavefive.notion.site/The-Graph-Protocol-Indexer-Subgraph-Selection-Guide-725f6e575f6e4024ad7e50f2f4e9bbad>
354+
355+
其他相关参考文档:
356+
357+
- https://thegraph.com/
358+
- https://graphql.cn/learn/
359+
- https://gql-guide.vercel.app/
360+
- https://thegraph.com/docs/graphql-api
361+
GraphGen——命令行工具,用于快速生成子图,由一些有 GraphGen 命令注释的 Solidity 接口文件组成。
362+
- https://medium.com/protean-labs/introducing-graphgen-a-subgraph-generator-for-the-graph-network-836fe0385336
363+
364+
- Matchstick ——是 Limechain 做一个开发的单元测试框架,一个 graph 模拟节点,用于在沙盒环境中测试子图部署的映射逻辑
365+
相关教程:https://limechain.tech/blog/matchstick-what-it-is-and-how-to-use-it/

0 commit comments

Comments
 (0)