# 欢迎了解 HyperGraph

## 在这里您会了解到什么

这里是 HyperGraph 的帮助文档页面，针对不同的人群我们提供了不同版块的帮助文档，希望对您了解HyperGraph 有用。

在这里，我们会和您分享：

A、HyperGraph 项目是针对何种需求产生，提供什么样的产品和服务。甚至还会介绍其底层的技术原理与流程。

B、会向您介绍 HyperGraph 产品的使用指南，无论是您作为普通用户、开发者还是矿工和项目方技术人员，您都可以在这里找您需要的内容。

C、会介绍 HGT Token 分配和锁仓相关细则，也会列出相关的合约地址、审计报告和白皮书的地址，供您查询

D、其他可能有关的站点、文档连接和合作伙伴链接

## 你可能想了解什么

根据不同的背景和需求，您可以选择不同的帮助文档进行了解。

如果您是矿工或者纯粹对挖矿感兴趣的朋友，请前往挖矿帮助专区

如果您是项目方技术或者开发区块链数据分析感兴趣的开发者，请前往产品帮助

如果想了解项目的背景、技术原理和通证分配情况，请前往项目介绍专区


# 了解挖矿

挖矿的基本介绍

在DeFi时代，挖矿变得非常流行，是一种让参与者支持，参与者获得Token的有效的Token分发手段。 挖矿由于项目质量参差不齐，存在巨大的风险，但是风险与收益对等，挖矿尤其是头矿，是获取超额收益的一个好的途径。

而今天的挖矿跟以往的公链挖矿有所不同。主要两个方面来说：

1、不需要像 POW 公链那样需要硬件&#x20;

2、也不是像 POS 公链那样大部分需要本币质押。

但既然是挖矿，就需要有铲子。这个铲子就是矿池所需要的币或者LP（流动性 Token），通过质押矿池中所设定需要的币， 就可以获得新的产出，一般是分发的 Token，这个过程就是挖矿。

并且在这种挖矿过程中，所质押的币可能没有损失，所分得的Token是白得的，当然如果是提供流动性，也有可能存在损失。 具体在什么样的矿池，大家根据承受风险的能力和持有数字资产情况而定。


# DeFi挖矿的本质

1、DeFi 挖矿的本质是社区用户提供代币兑换的流动性获得平台代币收益，其中平台代币流动性挖矿兴起之初，代币由于流通量少往往有高溢价，因而受到社区所欢迎。

&#x20;2、当前主流的挖矿形式是 LP （Liquidity Provider）挖矿，如果是交易平台挖矿，是社区用户通过将自己持有的代币抵押在流动性池，为交易者提供做市流动性获得挖矿奖励。 对于非交易平台类代币的 DeFi 挖矿，比如 HGT 的挖矿，也是用户在 MDX 等兑换平台提供了流动性，获得了流动性 Token，通过抵押流动性Token 来挖矿。

3\. DeFi 挖矿已经渐渐成为一个成熟的业务，和早先 Staking 类似。像 UniSwap，或者 Heco 网络上的 Mdex等去中心交易所，都有成熟的流动性挖矿机制，并锁仓了数十亿美元级别的资金。

4\. 由于数字资产自身的高波动性，理财的利率会比传统金融要高，同时置身于去中心化形态的DeFi ，给金融工具提供了一定的可信度和透明度，用户完全掌控自己的资产，所有过程和操作，链上均公开透明，所以也正在受到越来越多的人关注，未来还有很大的发展空间。


# 挖矿需要的准备工作

挖矿至少需要有以下准备工作要做：

1、需要有支持挖矿所在公链的去中心化钱包

所谓去中心化钱包，就是自己掌握私钥和助记词的钱包。对于以太坊、火币生态链和币安智能链而言，同一套助记词可以生成同一个地址。

2、地址上，需要有公链主币做手续费。比如以太坊是ETH，火币生态链HECO是 HT，币安智能链是 BNB。

如果没有手续费，则该账户只能在对区块链上的数据进行读取，而无法写入，因而无法转账资产，无法参加挖矿。

3、挖矿所需要的铲子，或者能兑换铲子的资产。

比如 HGT/HUSD 交易对的 LP Token，可以挖 MDEX，这个时候  HGT/HUSD 就是铲子，如果只有 HUSD 或者 USDT，就要先去兑换 HGT，然后USDT 也需要兑换成HUSD， 然后才能组建 LP Token


# DeFi挖矿与其他挖矿的异同

目前区块链挖矿分为很多种：

首先分为需要硬件和不需要硬件的两类。

需要硬件的，一般是要做一些特殊计算的挖矿，比如以比特币为代表的POW共识挖矿。也有POC，使用硬盘存储空间，而不是消耗计算性能的挖矿。也可以归为基于需要特殊硬件的挖矿之列。

不需要硬件的，如果挖矿是基于链上进行的，更多的是一种质押或者Staking。

如果是公链本身的挖矿，一般是质押公链本币，比如 EOS 的Staking，做超级节点，也可以获得 EOS。

如果不是公链本身的 Staking，就是 DeFi 挖矿所用的形式了。这种形式，有以下特点：

A、不是公链出块本身的奖励，公链本身奖励是主币，比如 以太坊是 ETH。但是随着所在公链出块，也伴随着新Token的分发。

B、矿池的所有操作，包括抵押、解压、收益计算、收矿等，全部基于智能合约来实现，矿池信息、用户资产信息也保存于链上

C、Staking 的币种可以多种，可以是单币，也可以是基于DEX的流动性LP，根据需要调整，包括各个矿池的权重也可以调整。

还有一些基于钱包的，但是不在区块链上的Staking 挖矿，这属于中心化的币理财了，虽然同样是抵押币种获得收益，这不应该属于挖矿的范围。请注意加以区分。


# 挖矿产出、轮次

挖矿的会随着所在公链主网出块，生成新的Token。

目前 HGT 在Heco上的产出是每个区块产出 10 个HGT，HECO 是 3 秒出块，一天产出28800 个块，也就是每天挖矿产出为 288000 个HGT。

HGT 的产出用的是轮次制，也就是每一轮挖矿设置起始区块和结束区块。

第一轮的起始区块是：3173966 也就是 2021年3月22日晚上20点18分18秒。

而结束区块是100天后的第 6053966 个区块。

第一轮结束后，挖矿终止。按需开启第二轮。

在每个轮次中间，可以增加和减少矿池，但是所有矿池一起分配全天的 288000HGT的产出。当然，每个矿池的分配也不是平均的，而是每个矿池都有一个权重系数，至于每个矿池产量多少，就是跟权重系统相关：

某矿池的日产出=288000HGT \* （当前矿池权重系数/矿池总权重系数之和）

也有的挖矿不设置轮次，可能会设置一些减产操作。这些操作都跟权重一样，都基于智能合约设置好。


# 矿池介绍

矿池指的是用户能抵押一类资产取得所生成Token的合约交互界面。

目前矿池一般分为两种，一种是单币池，就是抵押一种币就能够获得Token，一种是 LP 池，也就是说需要提供两种币的流动性才能取得 Token。

单币池也叫一池，一池抵押的币种可能是主币本身，比如 HGT 挖矿也有 HGT 池，这种池子是为了鼓励用户将资产锁定起来，取得更好的收益。也有可能是别的币，这种情况下，持有该币种的用户，相当于没有额外付出，就可以免费取到币。

‌

![](/files/-MYgI9bNEG-Tu_b-eOvz)

LP池也叫二池，二池抵押的币是一种流动性交易对，由用户在DEX 组建流动性来获得。如果组建的流动性交易对有HGT，则是为HGT提供了流动性，所以LP池挖矿也叫流动性奖励。如果所组建的流动性的交易对没有HGT，则也是一种免费获得币的情况。

‌

![](/files/-MYgI9bOWgvxRK60HlJc)

对于项目的发展来讲，免费取到币的这种池一般是合作的资源互换，或者像DEX，这种池子也是业务发展的需要，因为需要稳定币交易对或者主流交易对，但是不可避免会带来一些不好的影响。就是大量的低成本甚至无成本的Token被分发给在这些矿池参与挖矿的人。


# 钱包基本操作

挖矿需要在去中心化钱包中进行，所以挖矿之前请注册去中心化钱包。

常见的钱包有 火币钱包、TokenPocket、MetaMask 等，原则上每一个钱包都可以。但是无论使用哪个钱包，都要注意以下几点：

1、注册完成，请注意保存好助记词和私钥

2、在连接网络和接收资产时，请确保使用了正确的公链，如果本来是火币生态链的应用，选择了以太链，可能出现无法连接的情况，或者接收资产去了错误的地址，为找回带来麻烦


# 火币钱包注册Heco地址

火币生态链Heco现已接入火币钱包，Heco为已实现TPS500+、出块时间缩短至3秒，并兼具支持元交易功能、无缝对接以太坊智能合约及支持ETH、BTC等资产跨链映射等功能的高性能公链。Heco的接入，将进一步丰富火币钱包生态，为用户带来更加快捷、高效的操作体验。\
Heco钱包创建、钱包导入和链上转账、收款及交易详情查询流程如下：

**Heco钱包创建**\
1、尚未创建任何钱包，进入钱包首页，点击“创建”

![](/files/-MYgH1JfobQda0N5J0-N)

已创建钱包，可通过点击“我的资产”等页面钱包标示，选择Heco，“创建钱包”

![](/files/-MYgH1JgMmHWurVLSCWl)

2、如无特别需求，一般选择“标准钱包”，然后确认

![](/files/-MYgH1JhrQ9K1_qz9_m3)

![](/files/-MYgH1JiltIH4wHfprVe)

**钱包导入**\
1、进入“钱包管理”，选择“导入”

![](/files/-MYgH1Jj_7SZaSSaYbah)

2、进入“导入钱包”页面，输入安全密码

![](/files/-MYgH1JkTWKNyZCDiLX7)

3、选择Heco

![](/files/-MYgH1JlPPKBjGRX8ZBY)

4、输入助记词或私钥

![](/files/-MYgH1Jm6XIYTSnGxQ5z)

5、导入成功后可到钱包页面查看

![](/files/-MYgH1JnuoASw6JFfc5T)

注：目前HT已上线以太坊、波场和火币生态链Heco，如下，火币钱包已对不同类型HT作出标示，在操作过程中，需予以关注。

![](/files/-MYgH1Jonmj4JcTYBwJG)


# TokenPocket(Heco)

**1、下载使用TP钱包。**

扫码下载，按照指示步骤下载TP钱包。

![image](/files/-MYgBgpAzz_Rdcno9Q_C)

苹果用户支持App Store版本（需海外ID）和Testflight版本，教程以Testflight版为例：

![](/files/-MYgBgpBhAPZERCZKP1y)

**二、钱包如何创建**

1、下载TP钱包安装打开后，首次注册的新用户点击【我没有钱包】，选择【HECO（火币生态链）】。对于已经需要导入钱包的用户可以选择【我有钱包】，以下教程默认未注册过钱包。

![](/files/-MYgBgpC0JHwS7MBnXYV)

2、点击【创建钱包】进入创建界面。设置【钱包名】【密码】后点击创建钱包，进入备份钱包提示界面，认真阅读注意事项。

![](/files/-MYgBgpDUkdqJz30j44R)

3、【备份助记词】界面需要我们根据提供的助记词单词和顺序正确记录，确认记录好以后点击【备份完成 进行验证】按照正确顺序完成助记词验证。完成助记词验证后即可注册成功。![](/files/-MYgBgpE_IlZAZuVElBe)

4、只需要点击底部的【发现】菜单，即可使用后续上架的火币生态链的DApp。（一大波DApp在路上）为了您资产的安全，建议在选择DApp的时候尽量选择上架钱包的DApp，谨防遇到一些高风险的DApp项目。

![](/files/-MYgBgpFH1NuWl_MARtn)

**三、钱包如何转账**

1、选择需要操作的代币（例如HT），点击左下角【转账】，收款功能点击后可以获取收款二维码和复制收款地址，同使用TP钱包的用户可以直接扫码支付。（如遇到其他平台二维码，可能会有兼容性，此时最好可以使用复制黏贴功能操作）

![](/files/-MYgBgpG53v1IzMhhl_F)

2、转账方式分为【直接转账】【地址簿转账】【扫码转账】三种方式，我们根据自己习惯的方式选择即可。转界面请认真填入并核对收款地址和转出数量是否正确；矿工费区域可选三种资费的矿工费，也可自定义设置；【高级功能】可以输入【文本】或【十六进制】并发送上链。

![](/files/-MYgBgpHS1iPsGYbJhdI)

**四、助记词、私钥如何备份**

打开钱包，点击上部蓝色区域右上角【详情】功能进入钱包详情，可选【导出助记词】【导出私钥】【导出Keystore】，用户可根据自己的实际情况进行一种或者多种选择备份。（无论采用哪种备份方式，都要务必保存好不要丢失和泄露）

![](/files/-MYgBgpIwri_ew7SSpNZ)

**五、助记词、私钥导入钱包**

1、老用户使用TP钱包，可以在安装后打开钱包选择【我有钱包】选择币安智能链使用助记词、私钥等方式导入；已经使用TP钱包的用户可以通过打开钱包右上角第一项【添加钱包】选择导入钱包功能。

![](/files/-MYgBgpJzVq2gKqR9XVv)

2、选择适合自己的导入方式（如私钥导入），只需要填入自己的私钥，设置密码后即可点击【导入钱包】功能来导入和管理钱包。（去中心化钱包，助记词、私钥等是唯一导入和管理的凭证，所以请务必不要泄露。）

![](/files/-MYgBgpKNmG7IjmTxUm8)


# MetaMask 的网页版

安装方法

MetaMask是非常流行的以太坊网络钱包，尤其在浏览器上使用的版本，更是使用 DApp应用的必备神器。

1. 首先建议如果没有Chrome浏览器请先安装Chrome浏览器。下载地址为：

<https://www.google.cn/chrome/>

1. 如果你能顺利地浏览谷歌Chrome插件应用商店，可以直接走MetaMask官方推荐的安装方式，具体为：
   \*
   1. 、进入 <https://metamask.io/>
   2. 、点击Download 按钮

![](/files/-MYgAaSzYEbG1_JEoX6s)

* * 1. 、进入下载页面后，先点击选项按钮的Chrome，再点击下方 Install MetaMask for Chrome

![](/files/-MYgAaT-nsRHEaqXju0h)

（4）进入应用商店MetaMask页面，点击右上角的“添加至Chrome”，然后等待弹出对话框。

![](/files/-MYgAaT0bH2nCj1getFe)

（5）、在弹出来的对话框中，点击“添加扩展程序”，开始下载并安装。

![](/files/-MYgAaT11gftnkC91LzI)

1. 、下载成功，我们就可以看到在浏览器地址栏右侧出现了一个插件（扩展程序）按钮，同时MetaMask也弹出来了一个欢迎页面，我们就可以开始MetaMask的初步设置了。

![](/files/-MYgAaT2-rp987Zl0zrq)

这个时候我们点击下扩展程序按钮弹出来的小浮层，再点击MetaMask后边的小图钉按钮，这样MetaMask就可以长期固定在地址栏的右侧了。

如果我们不能访问谷歌应用商店怎么办呢，下面就介绍一下如何自行下载安装包，在Chrome浏览器上安装Metamask。

1. 、首先我们进入MetaMask 插件项目在Github上的源代码托管页面，链接为:

<https://github.com/MetaMask/metamask-extension>

1. 、点击右边的Releases，进入安装包下载地址：

![](/files/-MYgAaT3rIYnnFMcNc5N)

1. 、我们点击编译好的最新版本的MetaMask，下图为：metamask-chrome-8.0.10.zip ,直接下载完成。

![](/files/-MYgAaT4-VkpGn1Odhn_)

1. 、解压之后得到的目录像这个样子，注意不要使用解压到当前文件夹，要解压到独立的目录metamask-chrome-8.0.10，现在我们就可以打开Chrome浏览器来安装了。

![](/files/-MYgAaT52XWHyVK6nyzF)

（5）、点击Chrome浏览器地址栏右侧的下拉按钮，点击菜单，再点击“更多工具”，再点击子菜单中的“扩展程序”

![](/files/-MYgAaT6X-0MN7ZLl0G3)

1. 、点击菜单打开的扩展程序管理界面如下，再打开页面右上的“开发者模式”：

![](/files/-MYgAaT7Wt8AdSUi4enT)

1. 、点击加载已解压的扩展程序，然后选择到我们刚才解压的metamask-chrome-8.0.10，直接点击“选择文件夹”，点击确定即可。

![](/files/-MYgAaT8D0QxIcUFOYnf)

1. 、然后我们就看到了扩展程序面板上出现了刚刚安装好的 MetaMask，此时地址栏右侧也出现了扩展程序按钮。

![](/files/-MYgAaT9JglLmCsjru8c)

1. 、同时，MetaMask安装完成了，也弹出来了一个页面，这是MetaMask的初始配置页面。

![](/files/-MYgAaTAu2elyyX_sWPS)

下面我们就可以按步骤来配置或者生成自己的去中心化以太坊网络钱包了。

1. 下面我来做一个简单的配置说明，讲如何生成一个钱包地址并往里面转账。
2. 、在上图点击“开始使用”，然后接下来点击“创建钱包”

![](/files/-MYgAaTBBSSw3QYCnXn5)

1. 、在接下来的协议页面点击“I Agree”，然后进入了密码设置界面。这是我们使用MetaMask钱包的公共登录密码，一个MetaMask钱包可以管理多个钱包地址，但是这个登录密码是共用的，可以在具体的某一笔支付、或者退出了MetaMask重新打开MetaMask时，都会使用到这个密码。

![](/files/-MYgAaTCddhcdxIvMaUV)

1. 、输入完成，点击创建，就进入了助记词的抄写环节，注意不要复制保存成文件，也不建议拍照，最好的办法就是抄写在纸上，然后把纸张妥善地保管起来。
2. 然后再下一步检验助记词的抄写情况，无论是单词还是顺序都不能错误，一一确认过之后，最后一页点击“完成”，就创建好了账户。通过MetaMask 就可以复制地址，发送和接收ETH和以太坊网络上的其他资产了。

![](/files/-MYgAaTDFFqoG-PIgckt)

注意，目前为止，我们只是设置好了钱包，但是钱包还在以太网络上，如果要连接火币生态链，还有一步操作，就是添加Heco主网节点，下一节讲解。


# MetaMask 连接 Heco 主网

**添加Heco主网连接**

1. 找到添加RPC，点击MetaMask 网络选择下拉列表

![](/files/-MYgFlIcApm3TmXTwVB6)

在点击开始的下拉列表选择“添加自定义RPC”

![](/files/-MYgFlId-F-qDEQPbSvT)

在上图中，已经添加了Heco，新装的MetaMask是没有的。

2、

网络名称：Heco

链ID: 128

新增RPC URL: <https://http-mainnet-node.huobichain.com>

区块浏览器: [https://hecoinfo.com](https://hecoinfo.com/)

符号：HT

![](/files/-MYgFlIeuh6fJIIEH12d)


# BitKeep 钱包

**如何下载使用钱包**

如何下载？用浏览器打开网站 <https://bitkeep.com，点击下载即可。切记比对我们的官网同名域名，bitkeep.com，以免遭受钓鱼安全风险。> 苹果手机用户建议下载 TestFlight 版本（先在 AppStore 上搜索安装 TestFlight，然后用浏览器打开 bitkeep.com，选择 TestFlight 版本即可），安卓手机可直接选择APK 安装包安装，安卓较老机型可选择 HACK 版本下载安装。

![](/files/-MYgCJZArV5Sr-ECyD2U)

**如何创建钱包**

第一种:添加钱包 - 创建新钱包 , 备份好新创建钱包的助记词 - 验证助记词 -设置交易密码 - 创建成功（注：关于助记词需切记 a.一定要妥善备份好您的助记词，随时恢复您的数字钱包，找回您的钱包资产。b.助记词是 12 个英文单词组成，一定核对好顺序进行备份。c.BitKeep 不会在服务器上保存您的助记词，故一旦丢失，BitKeep 也无法帮您找回钱包。d.助记词或者私钥一定不要发给除了自己的第二个知道！

![](/files/-MYgCJZBqetJiXyBPAxi)

第二种：添加钱包 - 导入已有钱包 - 输入自己已有钱包的助记词或私钥 - 设置交易密码 - 创建成功。

![](/files/-MYgCJZCVfK0OsG_1qvK)

**如何在钱包添加HT(HECO)**

在钱包页面 - 我的资产 - 点击＋号搜索币种进行添加

![](/files/-MYgCJZDRv_NCc--X5ZI)

**如何进行转账收款**

转账：添加币种成功后，在钱包页面，点击进入币详情页面 - 点击转账 - 输入要转账的收款地址 - 输入要转账的币的数量 - 最后确认地址无误点击确认 - 输入交易密码发起转账。

![](/files/-MYgCJZEBx_tHlUlQCv3)

收款：添加币种成功后，在钱包页面，点击进入币详情页面 - 点击收款 - 复制钱包地址进行收币资产。

![](/files/-MYgCJZF7v1pvSHJhxpO)


# 挖矿资产准备


# 如何转入HT或者其他主流资产

## 1.如何获得钱包的地址

#### 如何在MetaMask获得HECO钱包地址

可以通过点击MetaMask，Account名称下方的地址，即可自动复制钱包地址

![](/files/-MYgJbEiKgeXSJLFtcLB)

#### 如何在TP钱包App获得你的HECO钱包地址

点击右上角的 详情，点击账户名称下面的钱包地址，随后钱包地址就复制到你的剪切板中了

![](/files/-MYgJbEj7tam-gCOhP8T)![](/files/-MYgJbEktz8DO-NN5psv)

## 2.获取HECO(HRC20)的资产

目前，从火币Global提取HECO火币生态链的HECO（HRC20）代币，是获取HRC20代币最主流的方法。

需要注册，登录火币账户进行资产的提取。

### 1）.登录火币

登录火币官网，点击右上角balances

或直接点击下方链接：

<https://www.huobi.com/zh-cn/finance-beta/>  （可能需要翻墙）

<https://www.huobi.be/zh-cn/finance-beta/>

![](/files/-MYgJbElSpQH62JJkW2q)

### 2）.资产选择![](/files/-MYgJbEmnxcaYuOfoUcw)

![](/files/-MYgJbEncbpedYL-L1-J)

### 3）.提币流程

选择想提取的资产，选择提币，在提币选项时，**链名称选择HECO**，即火币生态链的token标准。

选择提币数量，确认手续费。（手续费会比以太坊的提币费用低很多）

#### I.PC端提币教程

**链名称选择HRC20，否则无法正确接收你的资产**

![](/files/-MYgJbEoT4VCQF53tMDA)

**链名称选择HRC20，否则无法正确接收你的资产**

![](/files/-MYgJbEp8xCoBTtVa8Nb)

#### II.移动端提币教程：

1.登录火币Global APP

2.点击右下角 资产

3.选择HUSD，HT等资产

4.选择提币

5.在提币界面**选择HECO链**（注意，不要选错链，不要填错提币地址，否则**可能造成资产的永久性丢失**）

![](/files/-MYgJbEqdn0qhc-I00Ci)  ![](/files/-MYgJbErUQl7IotJebQH)   ![](/files/-MYgJbEsvC-bKBYrSkp_)

### 4）.确认提币

输入各种验证码后，提币成功。

### 5）.查询到账

火币Global确认提币后，可以在在钱包中查询到账情况。

除了提出HT之外的币，例如提取HUSD，HBTC等token，一般PC端的钱包不会默认显示，需要添加代币

**MetaMask添加资产方法：**

**不要通过搜索添加代币的名称，一定需要 通过添加合约才能正常显示**

**搜索到的代币不是HRC20标准的，是以太坊版本的token**

**添加错Token你的钱包中无法显示正确的数量，不要慌张，你的代币不会消失，按照下方正确添加即可看见**

1.点击添加代币

2.点击自定义代币

3.添加合约地址：以HUSD为例：0x0298c2b32eae4da002a15f36fdf7615bea3da047

4.完成添加代币

![](/files/-MYgJbEtsHGgZ5yPlTKl)![](/files/-MYgJbEu6ekjrmHK55OL)![](/files/-MYgJbEvTdwYxomxxv5z)

**TokenPocket添加资产方法**

![](/files/-MYgJbEwZXjO1A2LW_ES)![](/files/-MYgJbEx2UaBYfasgsP2)![](/files/-MYgJbEyykm5TYRNIP6F)

HECO火币生态链资产合约（HRC20）：

需要自行在HECO钱包中进行添加

HUSD：0x0298c2b32eae4da002a15f36fdf7615bea3da047

ETH：0x64ff637fb478863b7468bc97d30a5bf3a428a1fd

HBTC：0x66a79d23e58475d2738179ca52cd0b41d73f0bea

HLTC：0xecb56cf772b5c9a6907fb7d32387da2fcbfb63b4

HDOT：0xa2c49cee16a5e5bdefde931107dc1fae9f7773e3

HBCH：0xef3cebd77e0c52cb6f60875d9306397b5caca375

HBSV：0xc2cb6b5357ccce1b99cd22232942d9a225ea4eb1

HXTZ：0x45e97dad828ad735af1df0473fc2735f0fd5330c

HFIL：0xae3a768f9ab104c69a7cd6041fe16ffa235d1810

WHT（Wrapped HT）：0x5545153ccfca01fbd7dd11c0b23ba694d9509a6f

USDT：0xa71edc38d189767582c38a3145b5873052c3e47a

## 3.特别提示

**通过在Meta搜索 币的名称**

**你所添加的币是以太坊版本的，并非在HECO上**

**在HECO钱包里面将无法看见对应资产的数量**

![](/files/-MYgJbEzrcIGwPUtxUyR)


# 兑换所需币种

## **兑换HGT**

&#x20;**1. 进入Mdex**

&#x20;    打开火币钱包，搜索栏输入：Mdex

&#x20;  &#x20;

![图1、搜索Mdex](/files/-MXmkjGlS3gVgrrdspG3)

**2. 兑换HGT**

进入Mdex，选择兑换

![图2 HGT兑换准备](/files/-MXmlJ-3XR_X-1k4zfir)

&#x20;  在搜索框中输入HGT，币种列表出现HGT后点击进入

&#x20;&#x20;

![图3 选择通证HGT](/files/-MXmlpy8dT8LUf1vDOw3)

&#x20;  输入想要兑换的数量并确认，在上面的下拉币种列表选择用什么资产兑换，这里选择HT

&#x20; &#x20;

![图4、HGT确认兑换数量](/files/-MXmm7H-OLcvBi9Wvi3h)

若第一次使用提示授权，先同意授权兑换

![图5、HGT兑换成功](/files/-MXmmTaks1DXy2Xk_p7z)


# 添加流动性

**3. 加HGT-HT流动性**

进入资金池，选择【添加流动性】

![图1、HGT-HT添加流动性准备](/files/-MXmmvtbXDXo6ApaLmUh)

选择通证，搜索HGT，币种列表出现HGT后点击进入

![图2、选择通证HGT](/files/-MXmnCUQcrhLMAcx3UZt)

输入想要添加的数量并确认

![图3、HGT-HT确认添加数量](/files/-MXmnR4cUrWNB9oawsGC)

出现下图提示即添加流动性成功，奖励的LP通证会自动进入钱包

![图4、HGT-HT添加流动性成功](/files/-MXmne-SL0Einp9HYgeB)

##


# 质押挖矿

## **开始挖矿**

1. 流动性挖矿

&#x20;       成功添加了HGT-HT流动性矿池之后，在钱包首页直接搜索HyperGraph或输入挖矿网址：<https://www.hg.network/mine>

![图1、搜索HyperGraph](/files/-MXmo0sIbXJ36WkAdJBu)

进入HyperGraph，找到HGT-HT的矿池进入

![图2、找到HGT-HT矿池](/files/-MXmoGb8fGKETRcn_L0M)

点击抵押之后授权合约

![图3、HGT-HT LP使用授权](/files/-MXmoSqTwJdJPU5OIosF)

输入LP的数量确认就可以挖矿了

![图4、HGT-HT LP 抵押数量确认](/files/-MXmod7IE1TtNfU_fiVh)

抵押成功后，开始产生挖矿收益

![图5、HGT-HT LP挖矿](/files/-MXmowp5H1UofodumrHU)

2\.  **单币质押挖矿，HGT挖矿可以用单币质押挖矿**

找到HGT单币矿池进入

![图6、找到HGT单币池](/files/-MXmpHo1L3UOUKrotIlg)

点击抵押授权合约

![图7、HGT使用授权](/files/-MXmpRyZTiDYTLhv31kR)

![图8、HGT单币抵押](/files/-MXmpbSgSIV0K7H2Rqox)

输入抵押数量并确定

![图9、HGT 抵押数量确认](/files/-MXmplT2dDGGS7zY4sUA)

抵押成功就可以开始挖矿了，可实时查看挖矿收益

![图10、开始HGT挖矿](/files/-MXmpsQX_nQ1Z5TLRAjk)

以上就是HGT挖矿的详细教程了。

目前HGT流动性挖矿支持HGT-HT、HGT-HUSD、HGT-USDT，MDX-USDT，BAC-HGT

单币挖矿支持HGT、MDX、HBO、LHB，JT等，大家可以根据需求选择挖矿的池子。


# 常用术语

挖矿必备英文单词&#x20;

1\) Stake: 质押&#x20;

2\) Unstake: 解除质押

&#x20;3\) Harvest: 收割/丰收&#x20;

4\) Compound: 复投/混合&#x20;

5\) Deposit: 存入&#x20;

6\) Withdraw: 提现&#x20;

7\) Swap: 兑换&#x20;

8\) Liquidity: 流动性&#x20;

9\) Liquidity Provider: 流动性提供者&#x20;

10\) Gas Fee: 矿工费/网络费用&#x20;

11\) Gas Price: Gas 价格（油费，手续费）&#x20;

12\) Gas Limit: Gas 限制

&#x20;13\) Trading Fee: 交易手续费&#x20;

14\) Add: 增加&#x20;

15\) Remove: 减少&#x20;

16\) Auto-compound: 自动复投&#x20;

17\) Slippage: 滑点&#x20;

18\) Syrup Pool: 糖浆池&#x20;

19\) Farm: 农场&#x20;

20\) Staked only: 已质押的&#x20;

21\) Live: 进行中&#x20;

22\) Finished: 已结束


# 合约操作

我们所看到的挖矿界面，只是一个操作的入口。就像车子一样，我们看到的界面只是方向盘等操作工具，实际的挖矿的逻辑均在链上进行，所以在界面不可用的时候，我们就可以使用开发者工具，直接与智能合约进行交互，一样达成结果。包括进行挖、提、存等操作均可以。


# 合约操作介绍

敬请期待


# 合约操作环境准备

敬请期待


# 合约数据读取

敬请期待


# 合约写操作执行

敬请期待


# 产品使用篇

在本部分帮助文档将讲解如何使用 HyperGraph 产品来提交子图来进行数据索引与查询。

注意：

1、此部分产品仅向开发者和项目方，对于普通用户和矿工并无适用，也无必要，为了减少对资源的浪费，请不要提交无关的查询子图和测试用例。

2、建议使用电脑版登录


# HyperGraph 的产品业务

HyperGraph 致力于构建 DApp 相关项目的后端数据基础设施，让用户非常方便地提交对区块链数据的查询，并将查询结果方便地集成于自己的产品之中。

所以当前提供的产品主要是供项目使用提交查询子图（subgraph）的产品。通过该产品，项目或者开发者，可以方便地提交对于区块链数据的查询子图，提交子图的方式包括：上传代码压缩包、使用github连接以及项目自行通过API的方式来部署。

项目开发者部署完成子图，后端处理程序会自动进入后续处理环节：如果是上传代码压缩包，就是会自动解压代码包，如果是Github，也会自动获取源代码文件，然后检验基本文件的正确性与命令安全性，然后执行相关部署命令。如果是API方式部署，也会自动从部署日志里分析出相关的内容进行数据更新。

由于 HyperGraph 所做的是数据后端服务，目前没有直接面向用户的产品，所以很多用户并不是非常了解项目所做的事情，甚至也分不清楚HyperGraph 跟其他数据相关的基础设施产品比如预言机的区别。这里做一个简单的区分。

HyperGraph 目前所做的工作是根据开发者提交的subgraph查询指令，高性能地分析高性能公链区块数据，然后索引数据，并提供查询接口，是一种数据分析输出，以支持运营和业务。而预言机，是由于区块链程序，特指智能合约程序无法方便地取到链下的一些数据，尤其是报价数据，所以有一些预言机服务，以一种去中心化的方式，将这些数据写入链上，使得链上智能合约可以方便地读取到，是一种链下数据上链的服务。两者是有本质的不同的。

当然，对于HyperGraph而言，随着合作项目增多，分析数据增多，也将会产生更多有价值的数据，这些数据也将可以为链上使用，这时候，HyperGraph也会结合预言机服务，来将这些数据写入上链，提供给链上智能合约使用，这个时候就实现了HyperGraph所愿景的数据互通，甚至更进一步讲，不仅仅是对区块链数据的分析，更可以与传统互联网数据结合，将多种数据综合使用与提供链下查询、链上预言机服务，以发挥更大价值。

在下一节，将正式讲解产品的使用。


# 控制台注册与登录

1. 在[https](https://www.hg.network/)[://www.hg.network](https://www.hg.network/) 首页点击注册/登录

![](/files/-MYgRozx3OrzGLtrCDqY)

1. 可以在界面左上角选择语言，目前支持英文和简体中文

![](/files/-MYgRozywxx1q2hjlNYP)

1. 目前支持 Github和邮箱两种登录方式

如果选择Github 登录，会自动进入Github 登录或者已经登录就是授权界面

![](/files/-MYgRozzDBtFZAw0Xwbd)

授权：

![](/files/-MYgRp--v7xk8dQtMXbo)

这样自动完成了Github登录注册操作，以后使用Github 方式登录只需要点击登录框底部链接即可，一般情况下不再需要二次授权等操作。

![](/files/-MYgRp-0jxAmb6A6ry-p)

1. 邮箱注册

注册过程很简单，输入邮箱，发送验证码，邮箱就会收到验证码。

输入验证码和密码，就完成了注册的过程。

![](/files/-MYgRp-1S0NDeMSvGNhS)

1. 邮箱登录

输入邮箱账户和密码，就要有一个验证码验证的环节，验证成功，即可登录完成。

![](/files/-MYgRp-2Bj5JMZYkl7ik)

![](/files/-MYgRp-3zm3IrXtaC2Ms)

登录成功，就将进入控制台界面，登录失败，就会在页面右上角有错误提示。


# 添加子图

进入控制台之后，就可以看到已经添加的子图列表或者添加新项目

![](/files/-MYgq4sNcTxfD2JfuiOq)

目前HyperGraph已经支持火币生态链和币安智能链部署子图，可以根据左上角选择公链来进行子图的筛选。

![](/files/-MYgq4sOplq1frEq5O39)

点击右上角的添加项目按钮，进入添加子图的表单，按要求添加即可：

![](/files/-MYgq4sP2DwCJnkEY6TO)

其他的地方，都比较直接清楚，这里对两个地方进行一个比较详细的讲解。

一是公链的选择，请务必选择正确的公链，否则会部署到错误的节点网络，一方面没有结果数据，也是对资源的极大的浪费。

![](/files/-MYgq4sQBYG33w9RB8Iz)

当前已经支持火币生态链和币安智能链的子图部署，后续将支持更多基于EVM的公链。

二是部署方式，为了方便用户直接或者省心投入使用，目前HyperGraph节点支持三种部署方式，压缩包部署、Github部署和API部署，默认是 API 部署。

1.压缩包部署

将需要部署的子图程序，去掉node\_modules 打包，压缩成 zip 或者 tar.gz 格式上传，后端会进行压缩包解压，校验和部署。

这种方式适合不需要更改，直接部署即可使用的项目，特别是自建了节点已经成功运行，只是迁移至HyperGraph的项目，如果需要频繁更改的项目，不适用这种方式。

&#x20;2.Github部署

将需要部署的子图程序，去掉node\_modules 等后提交到能公开访问的git托管服务上，建议使用github，提交完成后，后端根据提交的Github URL进行子图代码部署，校验和部署。

注意，提交的 URL必须以 .git 结尾

这种方式适用于要做代码变更和后续更新的项目，但是目前不能自主更新Github就更新subgraph，需要和HyperGraph技术支持取得联系来更新部署子图。

3.API部署（推荐的方式）

API 的方式部署最为灵活，开发人员可以自己在本地开发和部署子图到远程HyperGraph节点，以AuthToken 授权的方式访问自己有权限的子图。可以随时部署生效。如果是处在频繁的开发阶段，建议可以用这种方式。

为了妥善对接和后续技术支持起见，请添加完子图，特别是第1、2种部署方式，请联系技术支持客服，联系方式：微信 camewiththewind

一个用户可以在多链和单链部署多个子图。

我们这里分别演示添加火币生态链和币安智能链的子图。

添加一个火币生态链的子图

![](/files/-MYgq4sR0NUX7cylg-JD)

添加一个币安链的子图：

![](/files/-MYgq4sS--AgxcuQfHlZ)

**节点功能已经上线，请在添加子图时选择要部署的节点。**

添加完成就会显示在列表里面，可以点击公链来进行切换

![](/files/-MYgq4sTj9a3CqVlbZ4C)

![](/files/-MYgq4sU4sW6NVCD4X79)


# 查看子图

进入子图列表页，默认是全部子图列表，

![](/files/-MYhHNMDC3K4YXCFGCvA)

也可以通过筛选公链，点击其中标题和Logo就可以进入相应的子图详情页

![](/files/-MYhHNMEXiW8-EVRo7kf)

在未部署之前，我们压缩包部署看到的是一些简单的基本信息：

![](/files/-MYhHNMF0rUhN6Lsb0PJ)

在部署并同步完成之后，我们在列表首页可以看到子图是可用状态：

![](/files/-MYhHNMGOyyXF6WB5Ktn)

在详情页，也有了更多的子图信息：

![](/files/-MYhHNMHUyxBgAn8b_sh)

这里对这些项目进行一个简单的说明：

子图名称

这是一个内部部署用的名字，可以用于做健康状态等查询

AuthToken

在API方式部署的时候有用，通过此Token来定位你的子图和进行授权操作，这样确保只有有这个AuthToken的用户能修改子图和重新部署

Subgraph 代码链接

指的是上传的代码，可以提供下载

Subgraph 标识

这是系统内部对子图的唯一编号，如果代码发生了更改，此编号会变化，如果代码无变化，多次部署并不会导致此编号变化，如果是API方式部署，更新了代码，此编号无变化，请跟技术支持取得联系。

HTTPS查询API

项目可以在产品中调用此API来查询数据，使用的是GraphQL语言来进行查询，此链接也可以在浏览器中打开就进入了实验台（Playground）

WebSocket 查询API，功能跟HTTPS 查询API一样，但是支持WebSocket的方式连接

实验台

用户可以使用此链接来进行一些查询调试

主合约

指的是从subgraph.yaml中分此出来的，此子较长所主要分析的合约

健康状态

这是全局使用的健康状态URL，可以用子图名称来检查此子图的同步情况

![](/files/-MYhHNMIaT4ihOvlovc0)

同时日志也可以查看了：

![](/files/-MYhHNMJrbnh7kkYxn1H)

日志还可以进行分类的筛选，这里不再详细讲述，统计功能将于后续继续开发完善，敬请期待。


# 程序开发

本章将讲述子图（ subgraph） 相关的开发流程与开发方法。

主要分为两部分：

&#x20;     第一部分是控制台的使用和部署开发流程。

&#x20;    首先从实际业务流程的角度讲解了 HyperGraph 的工作原理。然后就结合 HyperGraph 控制台以及 graph-cli 等工具，讲解了怎么添加子图项目、生成子图脚手架、添加子图代码，部署到远程服务器，进行数据索引查询的过程。

&#x20;    第二部分是子图开发、AssemblyScript开发、GraphQL 查询语言编写的参考文档。


# 业务交互流程

HyperGraph项目就是基于服务高性能公链，满足应用开发繁荣的数据需求，同时降低开发者门槛和自身维护后端服务的成本而产生。HyperGraph旨在构建一个高性能区块链的数据服务网络，这个高性能包括两个方面，一方面满足类似HECO等高性能区块链的需求，另一方面本身必须做到满足去中心化服务的同时，具有高效的服务能力。在此数据服务网络中，HyperGraph核心开发者团队构建基础设施与标准，提供开发、优化与维护方案，协调网络运转，索引节点依据标准建设网络节点，提供数据存储、索引查询、API服务等，参与网络共同建设，获得收益。开发者则根据自身业务定义数据获取需求，使用网络资源为自身和第三方有需求的业务服务，通证持有者，均可通过抵押通证，支持网络节点建设，获得自身数字资产增值收益，形成一个整体有效运转的数据服务生态。

## 2.1、云端基础设施

&#x20;为了提供高性能区块链数据服务，HyperGraph 制定标准，与各方参与者一起构建云端基础设施，云端基础设施包括两部分，一部分由各节点底层组成的数据索引网络，一部分是使用云端设施的工具、API和用户交互界面。示意如图1所示，这里需要注意的是，图1中各节点在网络中并不由某一个特定实体运营，而是HyperGraph网络中的去中心化节点成员。彼此之间的激励协调，也是由区块链上的合约相互协调，消息传送，真正让开发者应用HyperGraph服务做到全栈式去中心化。

![](/files/-MYh3Ih_gmLSXZSBj2qx)

图1、去中心化云端数据网络基础设施示意图

开发者通过界面交互提交自己有关数据查询与索引的需求指令，比如GraphQL查询语言，子图数据集定义等。使用工具进行便捷查询与节点构建，使用APIs查询数据或者将HyperGraph API和Web3 API结合发起向HyperGraph 网络的元交易签名等服务。

2.1.1、数据索引网络

&#x20;与传统数据库不同，区块链上存储的数据并没有字段概念，也没有关系型查询语言可用，而且所有的应用共用的是同一个存储库。所以数据的查询本身相较传统数据库变得异常困难，以DEX业务为例，查询某一个交易对在某一个时间段内的交易量、交易详情等，并没有快捷的查询方式，具体做法得扫描该时间段内的所有块的所有数据，将属于相关合约的交易全扫描出来，再匹配具体交易对，做数据合并计算，这样的计算方式非常低效。

&#x20;目前也有TheGraph这样的项目提供了开源的处理方式，但是有两个关键点，一是开源软件目前绝大多数只支持了以太坊网络，暂时并没有迅速支持其他高性能区块链网络,即使支持也有比较长的时间周期。二是那些服务本身是依托以太网络而设计，很多的设计尤其是性能等并没有对高性能区块链网络做优化。

&#x20;当然开发者也可以自己使用开源软件构建自己的数据分析节点，就像没有云计算的时代，用户也自己架设服务器到IDC。但是自建节点有以下几个成本和风险点：

1. DApp 项目专注于自身业务逻辑，智能合约等的开发，再增加服务器端节点部署，对人员提出了更高要求，必然增加人力成本
2. 由于区块链公链存储本身文件较大，全节点模式需要更大的存储空间和好的机器性能，为了自身的部分业务查询，同步全量数据，带来了硬件成本的浪费
3. 自身构建查询索引节点，是一个纯粹的投入，并且还一定程度上存在单点故障。性能等方面的优化经验的积累，也是一个较长期的过程。

综上所述，为了让开发者专注于自有业务，HyperGraph构建了数据索引网络。HyperGraph针对能支持数据索引的开源软件，选用匹配数据网络的软硬件搭配，专门针对高性能区块链，做了参数、存储等方面的优化，能够平行扩展，增加了一些特色功能。同时，索引节点不仅仅由HyperGraph开发者来提供，还使用HGT激励一起共建节点，一方面更加去中心化，更好地避免单点故障，由用户投票与激励提高服务质量。另一方面，也组成更大的数据索引网络，发挥数据价值。

## 2.2 业务交互流程

上一章介绍了HyperGraph的基本使用，在关于HyperGraph的章节中也讲述了HyperGraph是什么？所以本章开门见山来讲，如何来开发子图提交到HyperGraph

在传统的关系数据库中，为了提高查询的速度，我们需要对数据表的数据构建索引。在区块链的查询中，同样如此，我们要想获得一个稳定的查询结果，得先提前向链上去取得数据，索引数据。这个过程就需要开发子图，开发者开发完成子图，提供到HyperGraph，HyperGraph的数据引擎会自动运行所部署子图的数据索引，在索引完成之后，开发者可以使用一个Graph API 的链接来提交查询，取得想要的查询结果。

子图是一个特定的能部署在HyperGraph网络上的项目，就像部署在区块链上的智能合约项目可以在区块链上运行逻辑、存储数据类似，部署在HyperGraph 上的子图项目也可以让HyperGraph的数据引擎来索引高性能区块链的区块数据，索引存储后，提供查询接口。

子图项目通过yaml文件来描述或者定义，本子图查询针对哪个智能合约，需要分析智能合约的哪个事件的数据，并告诉HyperGraph如何将事件中的数据存储到数据库中，从而最终方便地实现查询。

当你开发完成子图应用，如果是以 API 方式的部署，可以使用 Graph CLI 命令行工具来部署子图，在HyperGraph 的Dashboard（控制台）里提供了比较详细的命令。通过命令首先会将子图的定义存储到IPFS，然后也通过权限认证口令来通知索引节点开始为子图索引数据。下图比较详细地展示了比较详细的数据流程，讲述子图部署后是如何处理区块链网络的交易与数据。

![](/files/-MYh3IhakpaXyXsinhiK)

图2、网络中数据形成和流转过程

图2 概要地描述了具体的数据和业务交互流程，这里以具体例子进行说明。以用户在DEX上Swap数字资产为例，说明数据是如何从用户端产生，然后存储在区块链网络上，再由索引节点分析存储，然后前端开发者取到数据进行展示的。

1. DApp 一般都是Serverless 应用，也就是说，在服务器端并没有数据库，也不存在动态脚本用于与用户直接相关的服务器端处理。程序由两部分组成，一部分是智能合约，负责路由、交易对生成、交易和流动性池逻辑处理等，部署在区块链上，另一部分是静态资源和脚本，包括图片、CSS、JavaScript等，部署在静态服务器上，通过CDN加速提供给用户，用户通过钱包对Web3 API的支持与DApp进行交互。
2. 用户使用DEX 由一种资产兑换另一种资产。比如使用HUSD兑换 WHT，用户在界面上选择交易对的币种，如图3所示。

![](/files/-MYh3IhbxPROXUSN54t6)

图3、用户在DEX 上进行资产兑换

由于第一次使用HUSD HRC20 Token，所以先要Approve，Approve是授权合约使用你的Token额度，然后再Swap，由于HUSD和HT并没有直接的流动性池或者是直接的流动池并没有理想的价格，而现在有流动性更好或者价格更理想的HUSD和HBTC以及HBTC和WHT（WHT可以理解为原生Gas资产HT的HRC20映射）的池子，所以增加了一层中间兑换，由合约自动将HUSD兑换成HBTC然后再兑换成为WHT，从而完成用户得到HT的过程。

1. 这样的一次操作，涉及到了相当多的操作与实体，包括用户（某一个地址）、路由合约（用于转发交易路由）、交易合约（处理多层兑换逻辑）、交易对合约（更新交易对库存）、所参与的各币种合约（检查权属，余额等等）。
2. 在这个过程中，除了明显的从一个地址到另一个地址的 transaction这类交易，还会有大量的event产生，有授权的Approval、有交换资产的Swap、有同步Balance的Sync等等，如图4所示。

![](/files/-MYh3Ihcl2h_rJCpOZTq)

图4、一个典型的Swap操作所产生的event

1. 正是由于这些event的产生与上链，不但有了数据分析的需要，也有了丰富的数据分析来源。HyperGraph 网络节点根据需求定义，持续地分析与扫描高性能区块链数据，分析出子图需求中定义的数据。由于HyperGraph 针对于高性能区块链而优化，所以相较于以太坊网络上的Graph Node，有更多的自定义优化手段和节点优化建议，以保证高效运行。
2. HyperGraph 节点根据定义的子图和事务处理程序处理数据。针对区块链网络中的事件，HyperGraph 内置程序在HyperGraph 的存储数据库中创建和更新实体。

DApp或者不支持Web3的页面，也可以获取远程查询数据。开发者使用GraphQL 向HyperGraph 远程节点进行查询。以JSON格式获得数据返回。然后开发者根据需要展示在界面上。

如此反复，就完成了HyperGraph 节点的使用过程。

在下面的章节中，我们将比较详细地讲解如何定义子图、部署子图以及如何查询子图。


# 快速入门

快速入门

本教程主要是引导您来通过示例和针对合约创建一个子图，以演示整个环境搭建的过程。

1. 首先去[https](https://dashboard.hg.network/)[://dashboard.hg.network](https://dashboard.hg.network/) 去添加一个子图，这个子图请选择部署方式为 API 方式，选择所部署的公链为火币生态链。

![](/files/-MZ3l0v_TuSkmt-Fd6NE)

1. 进入子图列表页，可以看到子图列表出现了刚加的子图，所给的提示也跟其他类型方式添加的子图不同，有一个提示按钮

![](/files/-MZ3l0vaqRanOggYI_qv)

1. 点击提示按钮，显示出来了详细的部署开发过程中的命令

![](/files/-MZ3ov3c8408DvWTlil4)

下面，我们就根据这些命令来开启子图开发。

1. 初始化一个新子图

初始化新子图要安装 graph-cli 开发包，以使用graph命令来初始化新子图。

可以使用 npm 或者 yarn 来进行全局安装，命令如下：

`# NPM`

`$ npm install -g @hgdotnetwork/graph-cli`

`# Yarn`

`$ yarn global add @hgdotnetwork/graph-cli`

在安装的过程中，可能会出错找不到libsecret 库的情况，可以另行安装，比如在Ubuntu 上，通过apt search libsecret ，找到，然后再使用命令 apt install libsecret-1-dev 安装即可。

安装完成，我们执行 graph --help 会得到如下所示的内容：

`graph version 0.20.2`

&#x20;`graph -`

&#x20;`build Builds a subgraph and (optionally) uploads it to IPFS`

&#x20;`codegen Generates AssemblyScript types for a subgraph`

&#x20;`create Registers a subgraph name`

&#x20;`auth Sets the access token to use when deploying to a Graph node`

&#x20;`init Creates a new subgraph with basic scaffolding`

&#x20;`remove Unregisters a subgraph name`

&#x20;`test Runs tests against a Graph Node environment (using Ganache by default)`

&#x20;`help (h) -`

&#x20;`version (v) Output the version number`

&#x20;`deploy Deploys the subgraph to a Graph node`

这些命令后面都有比较详细的说明，在后续的流程中，也会提到这些命令的用法，所以这里暂时不展开。

通过这些步骤，我们就安装好了graph 的命令行环境，就可以进行subgraph的开发和部署了。

首先我们通过graph init 创建一个示例项目来了解。

`graph init [options] [subgraph-name] [directory]`

`Options:`

&#x20;`--allow-simple-name Use a subgraph name without a prefix (default: false)`

&#x20;`-h, --help Show usage information`

`Choose mode with one of:`

&#x20;`--from-contract <address> Creates a scaffold based on an existing contract`

&#x20;`--from-example Creates a scaffold based on an example subgraph`

`Options for --from-contract:`

&#x20;`--abi <path> Path to the contract ABI (default: download from Etherscan)`

&#x20;`--network <mainnet|kovan|rinkeby|ropsten|goerli|poa-core|poa-sokol|xdai|matic|mumbai|fantom|bsc|heco|clover>`

&#x20;`Selects the network the contract is deployed to`

&#x20;`--index-events Index contract events as entities`

&#x20;`--contract-name Name of the contract (default: Contract)`

从上面的参数可以看到，可以从示例项目创建项目的脚手架

`$ graph init --from-example <SUBGRAPH_NAME> [<DIRECTORY>]`

也可以从合约创建项目

`$ graph init --from-contract <CONTRACT_ADDRESS> <SUBGRAPH_NAME> --network <NETWORK> [<DIRECTORY>]`

\<SUBGRAPH\_NAME>  参数在HyperGraph网络中，建议就是在创建的“子图名称/公链名称”构成的，也就是在子图详情页看到的子图名称，比如“subgraphdemo/heco”。

\<DIRECTORY> 就是项目的目录

\<CONTRACT\_ADDRESS> 就是合约地址，就是子图想要解析的合约地址

\<NETWORK> 即想合约所部署公链所在的网络名称，比如币安智能链就是bsc、火币生态链就是 Heco

下面演示使用一下：

`graph init --from-example subgraphdemo/heco --network heco`

我们就可以成功地基于示例项目创建一个脚手架项目。

执行输出如下图所示：

![](/files/-MZ3l0vc1gJ9QSLXsT5E)

如何基于合约创建也演示一下：

`graph init subgraphdemo/heco --network heco --from-contract 0x0bb480582ecae1d22bbaeaccfbb849b441450026`

如果正常运行，可以得到如下输出：

![](/files/-MZ3l0vdZpZdUmW2_1lb)

从上面的输出可以看到，指定合约和网络，生成一个子图项目，会连接相应的网络的公链浏览器，取回来相应的合约ABI 合约接口定义文件。

如果真的要部署此子图，请在HyperGraph控制台，即[https://dashboard.hg.network](https://dashboard.hg.network/) 也要提交此项目。

![](/files/-MZ3l0veNIdfj0Wys_At)

有了这个脚手架项目，我们就能正式进行子图开发，来在子图代码中，对合约的事情进行解析等，后续章节将继续进行讲解。


# 远程部署

在上一节中，我们基于graph init 命令

`graph init subgraphdemo/heco --network heco --from-contract 0x0bb480582ecae1d22bbaeaccfbb849b441450026`

成功地生成了项目的脚手架文件，整个执行命令输出如下：

`✔ Subgraph name · subgraphdemo/heco`

`✔ Directory to create the subgraph in · candy`

`✔ Ethereum network · heco`

`✔ Contract address · 0x0bb480582ecae1d22bbaeaccfbb849b441450026`

`✔ Fetching ABI from https://hecoinfo.com:https://api.hecoinfo.com/api?module=contract&action=getabi&address=0x0bb480582ecae1d22bbaeaccfbb849b441450026`

`✔ Contract Name · Contract`

`———`

&#x20;`Generate subgraph from ABI`

&#x20;`Write subgraph to directory`

`✔ Create subgraph scaffold`

`✔ Initialize subgraph repository`

`✔ Install dependencies with yarn`

`✔ Generate ABI and schema types with yarn codegen`

`Subgraph subgraphdemo/heco created in candy for network heco`

`Next steps:`

&#x20;`` 1. Run `graph auth https://deploy.hg.network <access-token>` ``

&#x20;`to authenticate with the hosted service. You can get the access token from`

&#x20;`https://dashboard.hg.network/.`

&#x20;``2. Type `cd candy` to enter the subgraph.``

&#x20;``3. Run `yarn deploy` to deploy the subgraph to``

&#x20;`https://e.hg.network/subgraph/subgraphdemo/heco.`

`Make sure to visit the documentation on https://docs.hg.network for further information.`

此示例代码，也已经提交到github，请见：

<https://github.com/HGDotNetwork/candy-subgraph>

下面对代码做一些简单的调整，然后进行部署测试和查询测试。

首先来了解一下代码的结构：

.`/abis`

`./abis/Contract.json 合约的接口定义文件，根据指定的合约地址、网络，graph 程序自动获得`

`./schema.graphql 示例的数据实体定义文件，在其中放置要操作的数据对象和属性定义`

`./subgraph.yaml 子图数据源定义，包括合约、起始区块（默认没有）、事件、处理程序等`

`./yarn.lock yarn 依赖更新文件`

`./package.json 项目依赖以及定义`

`./src AssemblyScript 目录，用于存放解析逻辑代码`

`./src/mapping.ts 事件处理程序文件，针对每一个合约事件，均可以在这里编写相应的处理程序，对数据进行统计`

下面我们调整代码：

1. abis 目录下的内容不需要调整，除非我们要新增合约解析，就将新合约的 abi 文件放置到这里。
2. 这里用的是一个线上发送红包的合约，脚手架程序已经自动为我们自动生成了一个示例实体，示例实体对应了第一个示例事件以及相应的处理程序。

我们找到该合约的事件定义，这个很容易找，根据合约地址去区块浏览器上找即可：

<https://hecoinfo.com/address/0x0bb480582ecae1d22bbaeaccfbb849b441450026#code>

`event Packetstarted(uint256 total, address tokenAddress);`

这个事件是每发一个红包会生成的事件，并且传入了两个参数，第一个参数是红包的总金额，第二个参数是红包的币种。

再对照 schema.graphql，已经为此事件生成了示例实体：

`type ExampleEntity @entity {`

&#x20;`id: ID!`

&#x20;`count: BigInt!`

&#x20;`total: BigInt! # uint256`

&#x20;`tokenAddress: Bytes! # address`

`}`

根据发红包的逻辑，我们做一个简单的命名上的调整，并且增加一个某一个币种发红包的统计，修改 schema.graphql 如下：

`type PackageEntity @entity {`

`id: ID!`

`count: BigInt!`

`total: BigInt! # uint256`

`tokenAddress: Bytes! # address`

`}`

`type PackageToken @entity {`

`id: ID!`

`total: BigInt! # uint256`

`}`

为了逻辑尽可能简单的，其他实体先不处理

修改了schema 定义，就得相应调整mapping.ts ,也特别简单，将发红包的发送记录，保存在PackageEntity 里，然后使用PackageToken 对数据数据进行统计，将handlePackagestarted 调整如下：

`export function handlePacketstarted(event: Packetstarted): 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 = PackageEntity.load(event.transaction.hash.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 PackageEntity(event.transaction.hash.toHex())`

`// Entity fields can be set using simple assignments`

`entity.count = BigInt.fromI32(0)`

`}`

`let tokenEntity = PackageToken.load(event.params.tokenAddress.toHex())`

`if(tokenEntity == null){`

`tokenEntity = new PackageToken(event.params.tokenAddress.toHex())`

`tokenEntity.total = BigInt.fromI32(0);`

`}`

`tokenEntity.total = tokenEntity.total.plus(event.params.total)`

`// BigInt and BigDecimal math are supported`

`entity.count = entity.count + BigInt.fromI32(1)`

`// Entity fields can be set based on event parameters`

`entity.total = event.params.total`

`entity.tokenAddress = event.params.tokenAddress`

`` // Entities can be written to the store with `.save()` ``

`entity.save()`

`tokenEntity.save()`

`}`

这样就实现发红包的保存与红包金额的简单统计，下面我们来测试一下部署，为了方便起见，这里不演示本地部署，如果对本地部署感兴趣的可以自动部署本地环境以进行测试。

部署过程分为三步：

1、首先要根据Abi生成相应的代码，以操作合约数据

2、根据HyperGraph 控制后台的提示，在线上生成子图

3、根据 HyperGraph 控制后台的提示，在远程部署子图

1. 进入示例项目目录（package.json所在目录)， 生成代码使用命令为：

`yarn codegen`

或者手工执行

`npx graph codegen`

或者安装了全局 graph ，可以直接执行&#x20;

`graph codegen`

输出如下：

`✔ Apply migrations`

`✔ Load subgraph from subgraph.yaml`

&#x20; `Load contract ABI from abis/Contract.json`

`✔ Load contract ABIs`

&#x20; `Generate types for contract ABI: Contract (abis/Contract.json)`

&#x20; `Write types to generated/Contract/Contract.ts`

`✔ Generate types for contract ABIs`

`✔ Generate types for data source templates`

`✔ Load data source template ABIs`

`✔ Generate types for data source template ABIs`

`✔ Load GraphQL schema from schema.graphql`

&#x20; `Write types to generated/schema.ts`

`✔ Generate types for GraphQL schema`

`Types generated successfully`

1. 在HyperGraph 控制后台找到API方式的部署提示，获得创建子图的命令，如下图：

![](/files/-MZ6oZKK6x52yARz1zav)

可以打开命令行操作提示：

![](/files/-MZ6oZKLpIH-dcI8kr-v)

使用上图红框中的命&#x4EE4;**（具体命令可能由于节点和网络不同而会不同，请以界面上的提示命令为准）**

`% graph create subgraphdemo/heco \`

`--node https://deploy.hg.network \`

`--access-token <AuthToken>`

`Created subgraph: subgraphdemo/heco`

请注意，创建子图一定要加 access-token 参数，否则创建不会成功。access-token 参数的值 AuthToken 在控制台的子图详情页可以看到。

如此就可以创建子图，从输出上看，子图创建成功。

1. 创建成功之后，就可以正式部署了。注意，部署也要带上 access-token 参数, 根据命令行提示，我们使用这个命令：**（具体命令可能由于节点和网络不同而会不同，请以界面上的提示命令为准）**

`graph deploy --debug \`

`--node https://deploy.hg.network \`

`--ipfs https://f.hg.network subgraphdemo/heco \`

`--access-token <AuthToken>`

`✔ Apply migrations`

`✔ Load subgraph from subgraph.yaml`

&#x20; `Compile data source: Contract => build/Contract/Contract.wasm`

`✔ Compile subgraph`

&#x20; `Copy schema file build/schema.graphql`

&#x20; `Write subgraph file build/Contract/abis/Contract.json`

&#x20; `Write subgraph manifest build/subgraph.yaml`

`✔ Write compiled subgraph to build/`

&#x20; `Add file to IPFS build/schema.graphql`

&#x20;               `.. QmPPWmHomaJ3ZBNvuAw5sjhPJhhxjwnQR1uw4b7WyJycs3`

&#x20; `Add file to IPFS build/Contract/abis/Contract.json`

&#x20;               `.. QmaHZdbi1ZTfMPq2rGhH3vgrsbF1o4HxfhQczfeYnccZQH`

&#x20; `Add file to IPFS build/Contract/Contract.wasm`

&#x20;               `.. QmcyaikiQnY2m9iP9VecLEqHZDs1sEMff7VNWsqi3cC4Fk`

`✔ Upload subgraph to IPFS`

`Build completed: QmSS3zRxoky8gpDNdTaUW1XJKtYeZeZZ1yb6qyEmegZ6vU`

`✖ Failed to deploy to Graph node https://deploy.hg.network/: Ethereum network not supported by registrar: heco`

这个时候，出了错误，这是由于部署节点，将 RPC 网络没有调整过来，在后续会逐步调整，现在我们修改一下 subgraph.yaml ，将 network 修改为：mainnet（**如果使用的是公开节点，不需要此步骤，分别为heco或者bsc**），同时为了高效索引起见，也加上 startBlock，subgraph.yaml 内容如下：

`specVersion: 0.0.2`

`schema:`

&#x20; `file: ./schema.graphql`

`dataSources:`

&#x20; `- kind: ethereum/contract`

&#x20;   `name: Contract`

&#x20;   `network: mainnet`

&#x20;   `source:`

&#x20;     `address: "0x0bb480582ecae1d22bbaeaccfbb849b441450026"`

&#x20;     `startBlock: 2095189`

&#x20;    `abi: Contract`

&#x20;    `mapping:`

&#x20;      `kind: ethereum/events`

&#x20;      `apiVersion: 0.0.4`

&#x20;      `language: wasm/assemblyscript`

&#x20;     `entities:`

&#x20;       `- Packetstarted`

&#x20;       `- PacketClaimed`

&#x20;       `- Packetended`

&#x20;       `- ClaimedTokens`

&#x20;       `- ClaimedPacketTokens`

&#x20;       `- OwnershipTransferred`

&#x20;     `abis:`

&#x20;       `- name: Contract`

&#x20;     `file: ./abis/Contract.json`

&#x20;       `eventHandlers:`

&#x20;         `- event: Packetstarted(uint256,address)`

&#x20;           `handler: handlePacketstarted`

&#x20;         `- event: PacketClaimed(uint256,address,uint32,address)`

&#x20;           `handler: handlePacketClaimed`

&#x20;         `- event: Packetended(uint256,address)`

&#x20;           `handler: handlePacketended`

&#x20;         `- event: ClaimedTokens(address,address,uint256)`

&#x20;           `handler: handleClaimedTokens`

&#x20;         `- event: ClaimedPacketTokens(uint32,address,address,uint256)`

&#x20;           `handler: handleClaimedPacketTokens`

&#x20;         `- event: OwnershipTransferred(address,address)`

&#x20;           `handler: handleOwnershipTransferred`

&#x20;       `file: ./src/mapping.ts`

然后我们再执行部署命令，此时已经部署成功：

`✔ Apply migrations`

`✔ Load subgraph from subgraph.yaml`

&#x20; `Compile data source: Contract => build/Contract/Contract.wasm`

`✔ Compile subgraph`

&#x20; `Copy schema file build/schema.graphql`

&#x20; `Write subgraph file build/Contract/abis/Contract.json`

&#x20; `Write subgraph manifest build/subgraph.yaml`

`✔ Write compiled subgraph to build/`

&#x20; `Add file to IPFS build/schema.graphql`

&#x20;               `.. QmPPWmHomaJ3ZBNvuAw5sjhPJhhxjwnQR1uw4b7WyJycs3`

&#x20; `Add file to IPFS build/Contract/abis/Contract.json`

&#x20;               `.. QmaHZdbi1ZTfMPq2rGhH3vgrsbF1o4HxfhQczfeYnccZQH`

&#x20; `Add file to IPFS build/Contract/Contract.wasm`

&#x20;               `.. QmcyaikiQnY2m9iP9VecLEqHZDs1sEMff7VNWsqi3cC4Fk`

`✔ Upload subgraph to IPFS`

`Build completed: QmfPj5bvz7q69oqTrimwisC8sXiGxDY54yJG5vCLug2Qhx`

`Deployed to https://e.hg.network/subgraph/subgraphdemo/heco`

`Subgraph endpoints:`

`Queries (HTTP):     https://q.hg.network/subgraphs/name/subgraphdemo/heco`

`Subscriptions (WS): wss://w.hg.network/subgraphs/name/subgraphdemo/heco`

通过HyperGraph 控制台，也可以看到已经更新的子图内容编号，在日志一栏中，也可以看到日志输出了。

![](/files/-MZ6oZKMx1OL5ul5p-xz)

可以的看到，上述的HTTP 查询链接是：

<https://q.hg.network/subgraphs/name/subgraphdemo/heco>

打开此链接输入一下简单的查询，就可以得到查询结果。右边文档区还可以看到Schema 的定义。

![](/files/-MZ6oZKN6vXwcPUxri_v)

至此，我们成功完成了一个子图从后端控制台添加，使用graph-cli 构建开发环境，从合约搭建脚手架，然后再一步步调整代码，直至部署成功的整个过程。


# 开发部署 FAQ

### 1、**子图创建命名对格式是有要求的吗？**

&#x20;     是的，强烈建议遵照HyperGraph 控制台页面上要求的格式命名您的子图。在添加子图时，只能填写小写字母，- 和数字 组成的名字，比如 subgraphdemo，dodoex-v2 等，而部署在HyperGraph 网络上的实际子图将为：“子图名称/公链名称”，也就是在控制台子图详情中显示的名字。如果所解析的合约在Heco网络上，子图名称为：“subgraphdemo/heco”, 如果是所解析的命约在BSC 网络上，而子图名称为：“subgraphdemo/bsc”。

![](/files/-MZ6AzsnHjFTAwb-8V7R)

### **2、现在支持在哪些网络创建子图？**

目前HyperGraph 支持在 Heco 和BSC 等高性能区块链网络上的合约创建子图，后续将支持更多的网络，包括 Heco、BSC 的测试网、其他基于 EVM 的高性能区块链网络，甚至以太坊网络。

### 3、在不同的网络是否支持同样的子图名称？

暂时HyperGraph 网络中的子图名称是全局唯一的。即使在不同的网络中，也不能有相同的名字。系统也会给出检测，请按提示操作。

### 4、是否可以更改部署类型，比如开始是Github 类型，调整成为API方式部署？

不支持自行调整部署方式，如有特殊需求，请跟技术支持联系调整

### 5、是否支持子图部署改名或者删除？

暂时不提供子图部署改名或者删除。

### 6、子图索引的数据源来自于哪里？

子图索引的数据一般来源于合约，在合约中定义了事件，索引程序会根据合约检索区块，分析事件进行分析存储，形成查询数据源。正像在web3.js 中调用合约需要ABI等信息一样，在子图开发中同样是如此。

### 7、要进行数据查询，对于合约编写有何建议？

对于需要查询的数据，建议在合约中，使用事件（events）来进行关联。这是索引子图数据最为快捷的方式。也是强烈推荐的方式。

如果合约不包含事件，子图可以使用合约调用以及区块处理器来触发索引，但是这样的话，速度会慢很多。

​另外，由于GraphQL会基于合约的事件生成查询实体，所以，在事件的参数中，参数名不要用id这样的定义，不然会跟实体自动生成的id字段名相冲突。

### 8、graph init 能支持多个合约创建子图吗？

graph init 命令用于创建一个初始项目的脚手架，所以功能并不是很复杂，所以不支持多个合约创建子图。如果想添加多个合约，可以后续在配置文件中加入更多的数据源。

### 9、我想获得数据索引的状态，有办法吗？

HyperGraph 在控制台提供了各个网络的健康状态查询功能。

Heco 网络是： <https://h.hg.network/graphql/playground>

BSC 网络是：<https://ph.hg.network/graphql/playground>

查询的典型 GraphQL 是：

`{`

&#x20;`indexingStatusesForSubgraphName(subgraphName:"pancakeswap/blocks") {`

&#x20;`subgraph`

&#x20;`health`

&#x20;`synced`

&#x20;`fatalError {`

&#x20;`handler`

&#x20;`message`

&#x20;`deterministic`

&#x20;`}`

&#x20;`nonFatalErrors {`

&#x20;`handler`

&#x20;`}`

&#x20;`chains {`

&#x20;`chainHeadBlock {`

&#x20;`number`

&#x20;`__typename`

&#x20;`}`

&#x20;`latestBlock {`

&#x20;`number`

&#x20;`__typename`

&#x20;`}`

&#x20;`}`

&#x20;`}`

`}`

你可以将上述代码中的“pancakeswap/blocks”换成你想要的子图进行查询。

如果有多个版本，也可以将上述查询中的 indexingStatusesForSubgraphName 替换成为： "indexingStatusForCurrentVersion" 或 "indexingStatusForPendingVersion" 进行有针对性的查询。

### 10、我能否使用其他项目的子图代码进行索引？

子图代码公开的情况下，可以基于其他项目的子图代码来进行数据查询与索引。

### 11、我能否在子图开发中使用 ethers.js 等开发程序库？

由于子图开发用 AssemblyScript 编写，所以并不能使用这类程序库，建议如果有其他的库需要调用数据，可以在数据存储之后，在查询端，使用你想要的库对数据进行调用。

### 12、子图中对于合约事件的处理顺序是什么样的？

在子图中，事件处理的顺序跟他们在区块中的顺序是一致的。跟所监听的合约个数、顺序等无关。

### 13、在代码中可以取得数据源的网络和合约地址等信息吗？

可以，通过引入 “graph-ts”，使用如下示例代码即可：

`import { dataSource } from '@graphprotocol/graph-ts'`

`dataSource.network()`

`dataSource.address()`

### 14、有什么提高子图索引性能的做法？

HyperGraph 的部署网络，已经进行了一定程度的部署优化，让用户可以快速添加子图和索引数据。对于用户自行添加的子图查询程序，强烈建议在 subgraph.yaml 中使用 startBlock ，以指定从某个区块开始进行索引。一般起始区块指定为合约创建所在的区块。

### 15、有没有对子图查询合并查询的计划？

确实在某些业务中，一个应用或者页面，需要大量地用到查询请求，已经在规划与开发查询子图查询合并的网关，以实现子图查询的缓存、连接复用等，以提高查询的效率。

### 16、查询时最多可以取回多少条数据？

默认每个查询集合返回100条数据，如果想要查询更多数据，可以用分页式的查询代码，比如

someCollection(first: 1000, skip: \<number>) { ... }

来最多一次查询1000条数据


# 子图开发

在前面的章节中，已经一步步地了解了子图项目的创建、构成和部署。子图部署成功之后，HyperGraph 后端节点就会根据子图索引数据。本章再基于上一节构建好的例子，比较详细地讲解子图的开发。

`/abis`

`./abis/Contract.json 合约的接口定义文件，根据指定的合约地址、网络，graph 程序自动获得，有了 abi 才可以知道有哪些事件可以处理，这是原始数据源定义`

`./schema.graphql 示例的数据实体定义文件，在其中放置要操作的数据对象和属性定义，当然也不仅仅是跟智能合约中的智能合约事件对象直接关联的实体，也可以有一些中间和结果实体和查询实现`

`./subgraph.yaml 子图的数据源、处理过程、方式定义，包括合约、起始区块（默认没有）、事件、处理程序等`

`./yarn.lock yarn yarn 工具的依赖更新文件`

`./package.json npm 和 yarn 所使用项目依赖以及定义`

`./src AssemblyScript 目录，用于存放解析逻辑代码，定义了将数据从事件转化成为能存储的实体的过程`

`./src/mapping.ts 事件处理程序文件，针对每一个合约事件，均可以在这里编写相应的处理程序，对数据进行统计`

### 一、ABI 文件

ABI 是Application Binary Interface的简写，以JSON文件格式定义了智能合约的接口，包括对智能合约公开函数的名称、参数、返回类型等的定义。一般会伴随着智能合约的部署而生成。可以通过以下方式获得一个智能合约的ABI 文件。

**1、使用 truffle compile**

如果是自有项目，在编译合约之后，在build/contracts 目录下就可以得到一个JSON文件，里面就有 ABI

**2、通过 solc或者 solcjs 生成**&#x20;

如果是有合约代码，可以用 Solidity Compiler 取得合约 ABI，使用 JavaScript 版本的 Compiler 为例。

安装solcjs：

`npm install solc -g`

或者安装solc-select

`pip3 install solc-select`

来安装 solc&#x20;

取得合约 ABI：

在取得ABI 之前，如果是复杂合约，可以先运行 truffle-flattener 将合约整合成一个文件，

执行：

`solcjs xxx.sol --abi`

`solc xxx.sol --abi`

就可以得到 ABI 文件。

**3、使用Remix 编译生成**

如果在Remix 中编译，在编译成功后，在artifacts 目录下，可以看到智能合约编译成功后，同步生成的JSON文件，打开文件，其中第一部分就是 ABI。

**4、通过已验证合约**

对于在区块链浏览器上已经验证的智能合约，可以直接使用智能合约获取ABI。比如

<https://hecoinfo.com/address/0x0bb480582ecae1d22bbaeaccfbb849b441450026#code>

**5、API 方式获取**

如果是在程序中获取ABI，也可以使用区块浏览器所提供的API获取方式。

比如 <https://hecoinfo.com/apis#contracts> graph-cli 中间的脚手架程序，根据合约地址自动获取ABI 就是用的这种方式。

注意请使用正确版本的ABI，或者在数据解析过程中，可能会失败。

### 二、子图声明文件 subgraph.yaml &#x20;

subgraph.yaml  是一个 YAML 格式的文件，使用 YAML 来声明子图的作用是方便读写，相应的支持库完善，数据也不冗余。

在 subgraph.yaml 中，定义了在当前这个子图项目中，需要索引哪些合约的数据、在相应的合约中，又需要重点分析哪些事件，并且建立了一个映射关系，将事件和相应的处理程序关联起来，以存到Graph Node 来存储，并提供查询。当然，存储与查询在远程的实现，子图开发者不用关心，但是子图开发者需要在子图映射程序中描述相应的逻辑关系。依据上一节的示例，subgraph.yaml  的内容如下：

`specVersion: 0.0.2`

`schema:`

&#x20; `file: ./schema.graphql`

`dataSources:`

&#x20; `- kind: ethereum/contract`

&#x20;   `name: Contract`

&#x20;   `network: mainnet`

&#x20;   `source:`

&#x20;     `address: "0x0bb480582ecae1d22bbaeaccfbb849b441450026"`

&#x20;     `startBlock: 2095189`

&#x20;    `abi: Contract`

&#x20;    `mapping:`

&#x20;      `kind: ethereum/events`

&#x20;      `apiVersion: 0.0.4`

&#x20;      `language: wasm/assemblyscript`

&#x20;     `entities:`

&#x20;       `- Packetstarted`

&#x20;       `- PacketClaimed`

&#x20;       `- Packetended`

&#x20;       `- ClaimedTokens`

&#x20;       `- ClaimedPacketTokens`

&#x20;       `- OwnershipTransferred`

&#x20;     `abis:`

&#x20;       `- name: Contract`

&#x20;     `file: ./abis/Contract.json`

&#x20;       `eventHandlers:`

&#x20;         `- event: Packetstarted(uint256,address)`

&#x20;           `handler: handlePacketstarted`

&#x20;         `- event: PacketClaimed(uint256,address,uint32,address)`

&#x20;           `handler: handlePacketClaimed`

&#x20;         `- event: Packetended(uint256,address)`

&#x20;           `handler: handlePacketended`

&#x20;         `- event: ClaimedTokens(address,address,uint256)`

&#x20;           `handler: handleClaimedTokens`

&#x20;         `- event: ClaimedPacketTokens(uint32,address,address,uint256)`

&#x20;           `handler: handleClaimedPacketTokens`

&#x20;         `- event: OwnershipTransferred(address,address)`

&#x20;           `handler: handleOwnershipTransferred`

&#x20;       `file: ./src/mapping.ts`

下面比较详情地讲解一下这个文件各个条目的构成：

description：子图项目的描述，如果子图和控制台添加的子图关联起来，此描述会保存起来，以展示在子图的详情页。

repository：子图所在的git 地址，通过这里可以找到子图代码，包括声明文件。也会展示在子图的详情页。

dataSources.source: 子图数据源的智能合约地址，以及智能合约对应的abi 定义。此合约地址不一定要写，如果没有指定合约地址，就有可能需要索引所有地址的所有事件。

dataSources.source.startBlock: 此数据也是可选填写。这是指合约数据分析的起始区块，一般建议采用合约创建所在区块作为开始分析的起始区块。

dataSources.mapping.entities: 在示例文件中，把合约中的事情自动分析出来列在这里，但是实际上应该在这里定义索引与查询中的对象实体。这些实体是可以存入到索引之后的数据库的，实体的定义也可以定在 schema.graphql 文件中。

dataSources.mapping.abis: 可以放置一个或者多个 ABI 文件，用于后续的接口和操作代码生成。以方便在映射代码与逻辑中，使得多个合约之间能进行调用交互。

dataSources.mapping.eventHandlers: 事件处理程序，列出子图中所分析的智能合约事件，本例中，相应的事件处理程序定义在 ./src/mapping.ts 中，这个文件就可以将这些事件进行分析，再将需要的内容或者直接或者计算后存入实体对象，最终存入数据库进行存储。

dataSources.mapping.callHandlers: 这是子图要分析智能合约函数的调用列表，同样在映射文件中也定义了处理程序，将函数的输入输出与要存入数据库的实体关联起来。

dataSources.mapping.blockHandlers: 列出了区块分析处理程序，当一个区块被加入到区块链中时，这些处理程序就会运行分析区块数据并依据区块分析处理程序保存分析结果。如果没有过滤机制的话，此区块处理程序，会分析每一个区块。过滤器能通过 call 的方式来提供，如果一个区块中数据源合约，包含了一个指定的调用，那么调用过滤器将运行相应的处理程序。&#x20;

区块中数据源触发顺序，是根据区块中的事务顺序而决定的。

### 三、Schema 文件

\
**GraphQL 数据实体定义**

子图项目的数据实体定义在了  chema.graphql 文件中。GraphQL 是一种用于API查询的语言，对 API 中的数据提供了一套易于理解的完整描述，使得客户端能够准确地获得它需要的数据。因而可以用于描述数据实体，也可以用于请求想要的数据，得到结果。

子图中的数据实体就是使用 GraphQL 接口定义语言（IDL）来描述和定义。如果您是GraphQL 新手，或者想了解更多GraphQL 开发的基本知识，可以参看GraphQL API 一节。

**定义实体**

正像传统数据库设计的数据库表，面向对象编译的对象设计一样，实体的设计也跟业务紧密相关，所以在定义实体之前，必须对DApp的业务和要分析的数据有一个整理和关联分析。

由于所有的查询都基于子图中定义的数据模型实体，而子图本身的索引也是基于实体。所以实体的定义是基于DApp的需求而出发的，所以我们在定义实体的时候，把实体认为是包含了数据的对象，而不仅是从事件和智能合约函数的角度来考虑。

当在schema.graphql中定义了各种实体类型，然后HyperGraph 将为查询某一个实体的一个实例或者集合，生成字段。在定义实体的时候，每一个应该是实体的类型，都必须用 @entity 修饰符去标注。

举两个实体定义的样例，还以上节中的示例项目为例，一个推荐的，一个不推荐的：

首先来看一下事件定义：

`{`

`"anonymous": false,`

`"inputs": [`

`{ "indexed": false, "name": "total", "type": "uint256" },`

`{ "indexed": false, "name": "tokenAddress", "type": "address" }`

`],`

`"name": "Packetstarted",`

`"type": "event"`

`}`

Packetstarted 事件是在红包（空投计划）成功设置之后记录到链上的，有两个参数，一个total 记录要发送的Token的数量，tokenAddress 是发送的Token。

好的做法是定义一个Packet，为了统计某一个Token发放的全部量，也定义了一下PacketToken

`type Packet @entity {`

`id: ID!`

`count: BigInt!`

`total: BigInt! # uint256`

`tokenAddress: Bytes! # address`

`}`

`type PacketToken @entity {`

`id: ID!`

`total: BigInt! # uint256`

`}`

不好的做法就是把事件，原封不动地定义为实体，如：

`type Packetstarted @entity {`

`id: ID!`

`count: BigInt!`

`total: BigInt! # uint256`

`tokenAddress: Bytes! # address`

`}`

要根据实际的业务需要，而不是将事件或者调用1:1 地在shema.graphql中定义为实体。


# GraphQL API

GraphQL API

在前面的章节讲到了使用GraphQL 进行实体的定义。

GraphQL 是一种用于API查询的语言，对 API 中的数据提供了一套易于理解的完整描述，使得客户端能够准确地获得它需要的数据。因而可以用于描述数据实体，也可以用于请求想要的数据，得到结果。子图中的数据实体就是使用 GraphQL 接口定义语言（IDL）来描述和定义。

本节来说明如何在HyperGraph 中使用GraphQL查询数据。

查询

在子图 schema.graphql 中，定义了称为实体的类型。对于每种实体类型，将在顶层查询类型上生成一个实体和实体关联的字段。

例子

查询您在实体定义文件中定义的单个Token实体：

&#x20;`{`

&#x20;`token(id: "1") {`

&#x20;`id`

&#x20;`owner`

&#x20;`}}`

注意：查询单个实体时，id字段是必填字段，并且必须是字符串，一般是地址或者Hash等具有唯一标识作用的值。

查询所有Token实体：

&#x20;`tokens {`

&#x20;`id`

&#x20;`owner`

&#x20;`}}`

排序

查询集合时，可以使用orderBy参数按特定属性进行排序。另外，orderDirection可用于指定排序方向，升序表示升序，降序表示降序。

例子

&#x20;`{`

&#x20;`tokens(orderBy: price, orderDirection: asc) {`

&#x20;`id`

&#x20;`owner`

&#x20;`}}`

分页

查询集合时，可以使用第一个参数从集合的开头进行分页。值得注意的是，默认排序顺序是按ID升序字母和数字顺序排序，而不是按创建时间。

此外，skip参数可用于跳过实体和分页。例如 first：100 显示前100个实体，first：100，skip：100 显示以第100个开始的下100个实体。这跟SQL查询中的 Limit start, number 很像。

查询应避免使用非常大的skip值，因为它们通常速度会很慢。对于检索大量数据，最好根据上一个示例中所示的属性来对实体进行分页。

例子

查询前10个Token：

&#x20;`tokens(first: 10) {`

&#x20;`id`

&#x20;`owner`

&#x20;`}}`

为了查询集合中间的一组实体，可以将skip参数与first参数结合使用，以从集合的开头开始跳过指定数量的实体。

例子

查询10个Token实体，从集合开始偏移10个位置：

&#x20;`tokens(first: 10, skip: 10) {`

&#x20;`id`

&#x20;`owner`

&#x20;`}}`

例子

如果需要检索大量实体，则将查询基于属性并按该属性进行过滤会更有效率。例如，使用以下查询检索大量Token实体的数据：

`{`

&#x20;`query manyTokens($lastID: String) {`

&#x20;`tokens(first: 1000, where: { id_gt: $lastID }) {`

&#x20;`id`

&#x20;`owner`

&#x20;`}`

&#x20;`}}`

第一次，它将发送带有 lastID =“” 的查询，并且对于后续请求，会将lastID 设置为上一个请求中最后一个实体的id属性。与使用增加的skip值相比，此方法的性能要好得多。

筛选

您可以在查询中使用where参数来筛选不同的属性。您可以过滤where参数中的多个值，也就是说在where中设置多个条件。

例子

查询失败的 challenge：

&#x20;`{`

&#x20;`challenges(where: { outcome: "failed" }) {`

&#x20;`challenger`

&#x20;`outcome`

&#x20;`application {`

&#x20;`id`

&#x20;`}`

&#x20;`}}`

您可以使用诸如\_gt，\_lte之类的后缀进行值比较：

例子

&#x20;`{`

&#x20;`applications(where: { deposit_gt: "10000000000" }) {`

&#x20;`id`

&#x20;`whitelisted`

&#x20;`deposit`

&#x20;`}}`

参数后缀的完整列表：

`_not`

`_gt`

`_lt`

`_gte`

`_lte`

`_in`

`_not_in`

`_contains`

`_not_contains`

`_starts_with`

`_ends_with`

`_not_starts_with`

`_not_ends_with`

请注意，某些后缀仅适用于特定类型。例如，布尔仅支持\_not，\_in和\_not\_in。

时间遍历查询

您不仅可以查询最新区块中实体的状态（默认情况下是查最新块），还可以查询过去的任意区块的状态。通过在查询的顶层字段中包含block参数，可以通过其块号或其块哈希来指定进行查询的块。

这样的查询结果不会随时间变化，即，无论执行什么时候，在特定的过去的块中查询都将返回相同的结果，但有一个例外，如果您在非常靠近以太坊开始的块中进行查询，如果该区块不在主链上并且链被重组，结果可能会改变。一旦一个块可以被认为是最终确认的，查询的结果将不会改变。

例子

&#x20;`{`

&#x20;`challenges(block: { number: 8000000 }) {`

&#x20;`challenger`

&#x20;`outcome`

&#x20;`application {`

&#x20;`id`

&#x20;`}`

&#x20;`}}`

该查询将返回challenge实体及其关联的应用程序实体，因为它们在8,000,000块后直接存在。

例子

&#x20;`{`

&#x20;`challenges(block: { hash: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c" }) {`

&#x20;`challenger`

&#x20;`outcome`

&#x20;`application {`

&#x20;`id`

&#x20;`}`

&#x20;`}}`

该查询将返回challenge实体及其关联的应用程序实体，因为它们是在使用给定哈希所对应的块之后直接存在的。


# AssemblyScript API（一）

\
AssemblyScript API

本节讲解在编写子图映射关系时可以使用哪些内置API。

开箱即用提供的API有两种:

TheGraph TypeScript库(graph-ts)和

graph codegen 命令从子图形文件生成的代码。

如果其他库与AssemblyScript兼容，也可以将其他库添加为依赖项。由于这编写的语言映射，因此可以在 AssemblyScript Wiki上找到语言和标准库功能的更多帮助和资源。因此，Web3 相关的库暂时不能在AssemblyScript 中使用。

安装

```
yarn install # Yarn
npm install  # NPM
```

使用graph init 创建的子图带有预先配置好的依赖项。安装这些依赖项所需的全部就是运行以下命令之一:

```
yarn add --dev @graphprotocol/graph-ts         # Yarn
npm install --save-dev @graphprotocol/graph-ts # NPM
```

如果子图是从头开始创建的，则以下两个命令之一将安装TheGraph TypeScript库作为依赖项:

API参考

@ graphprotocol / graph-ts 库提供以下API:

一个以太坊API，用于处理以太坊智能合约、事件、区块、交易和以太坊链上的各类值。

一个存储API，用于从HyperGraph节点存储中加载实体以及将实体保存到节点存储中。

一个日志API，用于将消息记录到HyperGraph节点输出和控制台浏览器上。

一个IPFS API，用于从IPFS加载文件。

一个用于解析JSON数据的JSON API。

一个使用加密功能的加密API。

基本类型可以在不同类型系统(例如以太坊，JSON，GraphQL和AssemblyScript)之间转换。

内置类型

可以在AssemblyScript Wiki中找到关于AssemblyScript内置的类型的文档。

为了实现对区块链数据的解析、存储等，@graphprotocol / graph-ts 提供了以下附加类型。

ByteArray 字节数组

```
import { ByteArray } from '@graphprotocol/graph-ts'
```

ByteArray代表u8(8位无符号整数)类型的数组。

构造:

fromI32(x:i32):ByteArray —— 将x转换为字节数组类型

fromHexString(hex:string):ByteArray——十六进制字符串转换为字节数组，输入长度必须为偶数。带0x前缀是可选的。

类型转换

toHexString():string——将字节数组类型转换为以0x为前缀的十六进制字符串。

toString():string——将字节数组转换为UTF-8字符串。

toBase58():string——将字节数组转换为base58字符串。

toU32():u32——将字节转换为小尾数u32(32位无符号整数)。在溢出的情况下抛出异常。

toI32():i32——将字节数组转换为小端 i32(32位有符号整数)。在溢出的情况下抛出异常。

操作符

equals(y:ByteArray):bool —— 可以写成x == y。

BigDecimal

```
import { BigDecimal } from '@graphprotocol/graph-ts'
```

BigDecimal 用于表示任意精度的小数。

构造

constructor(bigInt:BigInt) —— 从 BigInt 创建一个BigDecimal。

static fromString(s:string):BigDecimal——从十进制字符串解析成 BigDecimal

类型转换

toString():string—— 打印为十进制字符串。

Math

plus(y:​​BigDecimal):BigDecimal——可以写成x + y。

minus(y:​​BigDecimal):BigDecimal——可以写成x-y。

times(y:​​BigDecimal):BigDecimal——可以写成x \* y。

splitBy(y:​​BigDecimal):BigDecimal——可以写为x / y。

equals(y:​​BigDecimal):bool——可以写成x == y。

notEqual(y:​​BigDecimal):bool——可以写成x!= y。

lt(y:​​BigDecimal):bool——可以写成x \<y。

le(y:​​BigDecimal):bool——可以写成x <= y。

gt(y:​​BigDecimal):bool——可以写成x> y。

ge(y:​​BigDecimal):bool——可以写成x> = y。

neg():BigDecimal——可以写为-x。

BigInt

```
import { BigInt } from '@graphprotocol/graph-ts'
```

BigInt用于表示大整数。这包括 uint32 到 uint256 以及 int64 到 int256的以太坊值。少于 uint32以下的所有值，例如int32，uint24或int8都表示为i32。

BigInt类具有以下API:

构造

BigInt.fromI32(x:i32):BigInt ——从i32创建一个BigInt。

BigInt.fromString(s:string):BigInt ——从字符串中解析一个BigInt。

BigInt.fromUnsignedBytes(x:Bytes):BigInt——将字节解释为无符号，小尾数的整数。如果您输入的是大端整数，请首先调用.reverse()。

BigInt.fromSignedBytes(x:Bytes):BigInt——将字节解释为有符号的小端整数。如果您输入的是大端整数，请首先调用.reverse()。

类型转换

x.toHex():字符串——将BigInt转换为十六进制字符的字符串。

x.toString():字符串——将BigInt转换为十进制数字字符串。

x.toI32():i32——将BigInt作为i32返回；如果该值不是i32（有符号32位整数），则失败。建议首先检查x.isI32()。

x.toBigDecimal():BigDecimal——转换为无小数位数的小数。

数学运算

x.plus(y:BigInt):BigInt——可以写成x + y。

x.minus(y:BigInt):BigInt ——可以写成x-y。

x.times(y:BigInt):BigInt——可以写成x \* y。

x.dividedBy(y:BigInt):BigInt——可以写成x / y。

x.mod(y:BigInt):BigInt ——可以写为x％y。

x.equals(y:BigInt):bool ——可以写成x == y。

x.notEqual(y:BigInt):bool——可以写成x！= y。

x.lt(y:BigInt):bool——可以写成x \<y。

x.le(y:BigInt):bool——可以写成x <= y。

x.gt(y:BigInt):bool——可以写成x> y。

x.ge(y:BigInt):bool——可以写成x> = y。

x.neg():BigInt ——可以写为-x。

x.divDecimal(y:BigDecimal):BigDecimal——除以小数，得到小数类型的结果。

x.isZero():bool——检查数字是否为零的便捷方法。

x.isI32():bool——检查数字是否是i32。

x.abs():BigInt——绝对值

x.pow(exp:u8):BigInt——求幂

bitOr(x:BigInt,y:BigInt):BigInt ——可以写为x | y。

bitAnd(x:BigInt,y:BigInt):BigInt——可以写为x＆y。

leftShift(x:BigInt,位:u8):BigInt——可以写成x << y。

rightShift(x:BigInt,位:u8):BigInt ——可以写成x >> y。

TypedMap

```
import { TypedMap } from '@graphprotocol/graph-ts'
```

TypedMap可用于存储键值对。请参阅本示例。 TypedMap类具有以下API： new TypedMap ()——创建一个空映射，其键类型为K，值类型为T map.set(key:K,value:V):void——将key的值设置为value map.getEntry(key:K):TypedMapEntry |null——返回键的键/值对；如果映射中不存在键，则返回null map.get(key:K):V | null——返回键的值；如果映射中不存在键，则返回null map.isSet(key:K):bool——如果映射中存在键值，则返回true;否则返回false

Bytes 字节类型

```
import { Bytes } from '@graphprotocol/graph-ts'
```

Bytes 字节类型用于表示任意长度的字节数组。这包括类型为 byte，bytes32 等的以太坊值。 Bytes 类扩展了 AssemblyScript 的Uint8Array，它支持所有Uint8Array功能，以及以下新方法：

b.toHex()—— 返回一个十六进制字符串，表示数组中的字节 b.toString()—— 将数组中的字节转换为一串 unicode 字符 b.toBase58()—— 将以太坊字节值转换为base58编码（用于IPFS哈希）

Address

```
import { Address } from '@graphprotocol/graph-ts'
```

Address 类型扩展 Bytes 以表示以太坊地址值。 它在 Bytes API之上添加了以下方法： Address.fromString(s:string):Address——从一个十六进制字符串创建一个Address


# AssemblyScript API（二）

### 存储 API

```
import { store } from '@graphprotocol/graph-ts'
```

存储 API 允许从 HyperGraph 节点存储中加载、保存和删除实体。

写入存储映射表的实体与子图的 schema.graphql 文件中定义的@entity 类型是一一对应的。为了方便使用这些实体，Graph CLI （HyperGraph 请使用 @hgdotnetwork/graph-cli ）提供的graph codegen命令生成实体类，它们是内置Entity类型的子类，具有Schema 中字段的属性 getter和setter以及load(加载)和save(保存)方法来操作这些实体。

### 创建实体

以下是基于以太坊事件创建实体的常见模式。

```
// Import the Transfer event class generated from the ERC20 ABI
import { Transfer as TransferEvent } from '../generated/ERC20/ERC20'

// Import the Transfer entity type generated from the GraphQL schema
import { Transfer } from '../generated/schema'

// Transfer event handler
export function handleTransfer(event: TransferEvent): void {
  // Create a Transfer entity, using the hexadecimal string representation
  // of the transaction hash as the entity ID
  let id = event.transaction.hash.toHex()
  let transfer = new Transfer(id)

  // Set properties on the entity, using the event parameters
  transfer.from = event.params.from
  transfer.to = event.params.to
  transfer.amount = event.params.amount

  // Save the entity to the store
  transfer.save()
}
```

在处理区块链数据遇到 Transfer 事件时，它将使用生成的 Transfer 类型（实为 TransferEvent 的别名，以避免与实体类型的命名冲突）传递给handleTransfer事件处理程序。此类型允许访问数据，例如事件的父事务及其参数。

每个实体必须具有唯一的ID，以避免与其他实体发生冲突。事件参数包含可以使用的唯一标识符是相当普遍的。 注意：使用事务哈希作为ID假定同一事务中没有其他事件创建使用该哈希作为ID的实体。

从存储加载实体 如果实体已经存在，则可以使用以下方法从存储中加载它：

```
let id = event.transaction.hash.toHex() // or however the ID is constructed
let transfer = Transfer.load(id)
if (transfer == null) {
  transfer = new Transfer(id)
}

// Use the Transfer entity as before
```

由于实体可能尚不存在于存储中，因此load方法返回的类型为Transfer 或者null。因此可能需要在使用该值之前检查是否为null。

注意：只有在映射实现时所做的更改取决于实体之前的数据时，才需要加载实体。有关更新现有实体的两种方式，请参见下一部分。

更新现有实体 有两种更新现有实体的方法：

加载实体，例如Transfer.load(id)，在实体上设置属性，然后 .save() 将更新后的实体保存到存储。

只需使用new Transfer(id) 创建实体，在实体上设置属性，然后使用 .save() 将实体保存到存储中。如果实体已经存在，则更改将合并到其中。 在大多数情况下，由于生成了属性设置器（setter方法），因此更改属性很简单：

```
let transfer = new Transfer(id)
transfer.from = ...
transfer.to = ...
transfer.amount = ...
```

也可以使用以下两个指令之一来取消设置属性：

```
transfer.from.unset()
transfer.from = null
```

这仅适用于可选属性，即声明的属性中不带!的属性。

这仅适用于可选属性，即在 GraphQL 的声明的属性中不带!的属性。 这种属性的两个例子是：&#x20;

owner:Bytes 或 amount:BigInt

更新数组属性要多花点精力，因为从实体获取数组会创建该数组的副本。这意味着在更改数组后必须再次显式设置数组属性。以下假设实体有一个数字数组字段：\[BigInt!]! 字段。

```
// This won't work
entity.numbers.push(BigInt.fromI32(1))
entity.save()

// This will work
let numbers = entity.numbers
numbers.push(BigInt.fromI32(1))
entity.numbers = numbers
entity.save()
```

从存储中删除实体 当前无法通过生成的类型删除实体。相反，删除实体需要将实体类型的名称和实体ID传递给 store.remove来进行删除：

```
import { store } from '@graphprotocol/graph-ts'
...
let id = event.transaction.hash.toHex()
store.remove('Transfer', id)
```

以太坊API 以太坊API提供对智能合约、公共状态变量、合约函数、事件、交易和区块的访问。

支持以太坊类型 与实体一样，graph codegen 命令为子图中使用的所有智能合约和事件生成对应的类。为此，合同ABI必须成为子图声明清单中数据源的一部分。

通常，ABI 文件存储在 abis /文件夹中。 使用生成的类，以太坊类型和内置类型之间的转换在底层机制中进行，因此子图开发者不必关心。

以下示例说明了这一点。给定一个子图的schema定义，如

```
type Transfer @entity {
  from: Bytes!
  to: Bytes!
  amount: BigInt!
}
```

然后在以太坊上有一个 Transfer(address,address,uint256) 事件签名，三个参数： from 、to 和Amount ，类型分别为address、address和uint256类型。在数据处理中，address 和 uint256 ，会被转换为Address和BigInt，从而可以将它们传递给Transfer 实体的 Bytes! 和 BigInt! 属性：

```
let id = event.transaction.hash.toHex()
let transfer = new Transfer(id)
transfer.from = event.params.from
transfer.to = event.params.to
transfer.amount = event.params.amount
transfer.save()
```

### 事件、区块/交易数据&#x20;

传递给事件处理程序的以太坊事件，例如前面示例中的 Transfer 事件，不仅提供了对事件参数的访问，还提供对其父事务及其所属的块的访问。可以从事件实例获得以下数据（这些类是graph-ts中以太坊模块的一部分）：

```
class Event {
  address: Address
  logIndex: BigInt
  transactionLogIndex: BigInt
  logType: string | null
  block: Block
  transaction: Transaction
  parameters: Array<EventParam>
}

class Block {
  hash: Bytes
  parentHash: Bytes
  unclesHash: Bytes
  author: Address
  stateRoot: Bytes
  transactionsRoot: Bytes
  receiptsRoot: Bytes
  number: BigInt
  gasUsed: BigInt
  gasLimit: BigInt
  timestamp: BigInt
  difficulty: BigInt
  totalDifficulty: BigInt
  size: BigInt | null
}

class Transaction {
  hash: Bytes
  index: BigInt
  from: Address
  to: Address | null
  value: BigInt
  gasUsed: BigInt
  gasPrice: BigInt
  input: Bytes
}
```

访问智能合约状态 graph codegen 命令生成的代码还包括子图中使用的智能合约的类。这些可用于访问公共状态变量和在当前区块中调用智能合约其他方法的功能。 一种常见的模式是访问事件起源的智能合约。这可以通过以下代码实现：

```
// Import the generated contract class
import { ERC20Contract } from '../generated/ERC20Contract/ERC20Contract'
// Import the generated entity class
import { Transfer } from '../generated/schema'

export function handleTransfer(event: Transfer) {
  // Bind the contract to the address that emitted the event
  let contract = ERC20Contract.bind(event.address)

  // Access state variables and functions by calling them
  let erc20Symbol = contract.symbol()
}
```

以太坊上的 ERC20 智能合约具有一个叫 symbol 的公开的只读函数，就可以使用.symbol（）进行调用。对于公共状态变量，将自动创建一个具有相同名称的方法。 子图的任何其他协定都可以从生成的代码中导入，并且可以绑定到有效地址。

### 记录和调试

```
import { log } from '@graphprotocol/graph-ts'
```

日志 API 允许子图将信息记录到 HyperGraph 节点的标准输出以及Graph 浏览器上。 可以使用不同的日志级别记录消息。提供了一种基本的格式字符串语法，以根据参数变量组成日志消息。

日志API包含以下功能： log.debug(fmt: string, args: Array): void——记录调试消息。 log.info(fmt: string, args: Array): void——记录提示类消息。 log.warning(fmt: string, args: Array): void——记录警告 log.error(fmt: string, args: Array): void——记录错误消息。 log.critical(fmt: string, args: Array): void——记录重要消息并终止子图。 日志 API 接受格式字符串和字符串值数组。然后，它将占位符替换为数组中的字符串值。第一个{}占位符被替换为数组中的第一个值，第二个{}占位符被替换为第二个值，依此类推。

```
log.info('Message to be displayed: {}, {}, {}', [
  value.toString(),
  anotherValue.toString(),
  'already a string',
])
```

记录一个或多个值 记录单个值

在下面的示例中，字符串值“ A”在被记录之前被传递到一个数组中成为\['A']：

```
let myValue = 'A'

export function handleSomeEvent(event: SomeEvent): void {
  // Displays : "My value is: A"
  log.info('My value is: {}', [myValue])
}
```

从现有数组记录单个条目 在下面的示例中，尽管数组包含三个值，但仅记录了该参数数组的第一个值。

```
let myArray = ['A', 'B', 'C']

export function handleSomeEvent(event: SomeEvent): void {
  // Displays : "My value is: A"  (Even though three values are passed to `log.info`)
  log.info('My value is: {}', myArray)
}
```

从现有数组记录多个条目 arguments数组中的每个条目在日志消息字符串中都需要有自己的占位符{}。以下示例在日志消息中包含三个占位符{}。因此，将记录myArray中的所有三个值。

```
let myArray = ['A', 'B', 'C']

export function handleSomeEvent(event: SomeEvent): void {
  // Displays : "My first value is: A, second value is: B, third value is: C"
  log.info(
    'My first value is: {}, second value is: {}, third value is: {}',
    myArray,
  )
}
```

从现有数组记录特定条目 要在数组中显示特定值，必须提供索引值。

```
export function handleSomeEvent(event: SomeEvent): void {
  // Displays : "My third value is C"
  log.info('My third value is: {}', [myArray[2]])
}
```

记录事件信息 以下示例记录了事件的区块编号、区块哈希和事务哈希：

```
import { log } from '@graphprotocol/graph-ts'

export function handleSomeEvent(event: SomeEvent): void {
  log.debug('Block number: {}, block hash: {}, transaction hash: {}', [
    event.block.number.toString(), // "47596000"
    event.block.hash.toHexString(), // "0x..."
    event.transaction.hash.toHexString(), // "0x..."
  ])
}
```

### IPFS API

```
import { ipfs } from '@graphprotocol/graph-ts'
```

智能合约有时会在区块链上锚定 IPFS 文件。这允许映射从智能合约中获取IPFS哈希，并从IPFS中读取相应的文件。文件数据将以 Bytes 数据格式的形式返回，通常需要进一步处理，例如使用本节稍后提到的JSON API。

给定一个IPFS哈希或路径，可以按照以下步骤从IPFS读取文件：

```
// Put this inside an event handler in the mapping
let hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D'
let data = ipfs.cat(hash)

// Paths like `QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile`
// that include files in directories are also supported
let path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'
let data = ipfs.cat(path)
```

注意：ipfs.cat 目前尚未确定。如果在请求超时之前无法通过IPFS网络检索到文件，它将返回空值（null）。因此，始终检查结果是否为空（null）是很必要的。为了确保可以检索到文件，必须将它们关联到HyperGraph节点所对应到的IPFS节点。如果使用托管服务上，Heco 网络使用 <https://f.hg.netwoprk/，> BSC 网络使用 <https://pf.hg.network。>

也可以使用ipfs.map以流方式处理较大的文件。该函数需要IPFS文件的哈希或路径、回调的名称以及用于修改其行为的标志：

```
import { JSONValue, Value } from '@graphprotocol/graph-ts'

export function processItem(value: JSONValue, userData: Value): void {
  // See the JSONValue documentation for details on dealing
  // with JSON values
  let obj = value.toObject()
  let id = obj.get('id').toString()
  let title = obj.get('title').toString()

  // Callbacks can also created entities
  let newItem = new Item(id)
  item.title = title
  item.parent = userData.toString() // Set parent to "parentId"
  item.save()
}

// Put this inside an event handler in the mapping
ipfs.map('Qm...', 'processItem', Value.fromString('parentId'), ['json'])

// Alternatively, use `ipfs.mapJSON`
ipfs.mapJSON('Qm...', 'processItem', Value.fromString('parentId'))
```

当前唯一支持的标志是json，必须将此标志传递给ipfs.map。使用json标志，IPFS文件必须包含一系列JSON值，每行一个值。调用ipfs.map将读取文件中的每一行，将其反序列化为JSONValue并为它们中的每一个值调用回调函数。然后，回调可以使用实体操作来存储来自JSONValue的数据。仅当调用ipfs.map的处理程序成功完成时才存储实体更改的内容。 同时，它们被保存在内存中，因此ipfs.map可以处理的文件大小受到限制。

成功后，ipfs.map将返回void。如果回调的任何调用导致错误，则调用ipfs.map的处理程序将中止，并将子图标记为失败。

### 加密API

```
import { crypto } from '@graphprotocol/graph-ts'
```

加密API使加密算法相关的函数可用于映射。目前只有一个：

* `crypto.keccak256(input: ByteArray): ByteArray`

### JSON API

```
import { json, JSONValueKind } from '@graphprotocol/graph-ts'
```

JSON数据可以使用 json API进行解析：

&#x20;json.fromBytes(data:Bytes):JSONValue——解析来自Bytes数组的JSON数据 JSONValue 类提供了一种将值从任意JSON文档中提取出的方法。由于JSON值可以是布尔值，数字，数组等，因此JSONValue具有一种检查值类型的属性：

```
let value = json.fromBytes(...)
if (value.kind == JSONValueKind.BOOL) {
  ...
}
```

此外，还有一种方法可以检查该值是否为空：

&#x20;value.isNull():boolean&#x20;

当值的类型确定时，可以使用以下方法之一将其转换为内置类型：&#x20;

value.toBool():boolean

value.toI64():i64&#x20;

value.toF64():f64&#x20;

value.toBigInt():BigInt&#x20;

value.toString():string&#x20;

value.toArray():Array ——（然后使用上述5种方法之一转换JSONValue）

类型转换参考

| Source (s)           | Destination          | Conversion function          |
| -------------------- | -------------------- | ---------------------------- |
| Address              | Bytes                | none                         |
| Address              | ID                   | s.toHexString()              |
| Address              | String               | s.toHexString()              |
| BigDecimal           | String               | s.toString()                 |
| BigInt               | BigDecimal           | s.toBigDecimal()             |
| BigInt               | String (hexadecimal) | s.toHexString() or s.toHex() |
| BigInt               | String (unicode)     | s.toString()                 |
| BigInt               | i32                  | s.toI32()                    |
| Boolean              | Boolean              | none                         |
| Bytes (signed)       | BigInt               | BigInt.fromSignedBytes(s)    |
| Bytes (unsigned)     | BigInt               | BigInt.fromUnsignedBytes(s)  |
| Bytes                | String (hexadecimal) | s.toHexString() or s.toHex() |
| Bytes                | String (unicode)     | s.toString()                 |
| Bytes                | String (base58)      | s.toBase58()                 |
| Bytes                | i32                  | s.toI32()                    |
| Bytes                | u32                  | s.toU32()                    |
| Bytes                | JSON                 | json.fromBytes(s)            |
| int8                 | i32                  | none                         |
| int32                | i32                  | none                         |
| int32                | BigInt               | Bigint.fromI32(s)            |
| uint24               | i32                  | none                         |
| int64 - int256       | BigInt               | none                         |
| uint32 - uint256     | BigInt               | none                         |
| JSON                 | boolean              | s.toBool()                   |
| JSON                 | i64                  | s.toI64()                    |
| JSON                 | u64                  | s.toU64()                    |
| JSON                 | f64                  | s.toF64()                    |
| JSON                 | BigInt               | s.toBigInt()                 |
| JSON                 | string               | s.toString()                 |
| JSON                 | Array                | s.toArray()                  |
| JSON                 | Object               | s.toObject()                 |
| String               | Address              | Address.fromString(s)        |
| String               | BigDecimal           | BigDecimal.fromString(s)     |
| String (hexadecimal) | Bytes                | ByteArray.fromHexString(s)   |
| String (UTF-8)       | Bytes                | ByteArray.fromUTF8(s)        |

数据源元数据&#x20;

您可以通过dataSource命名空间检查调用处理程序的数据源的智能合约地址，网络和上下文：

* `dataSource.address(): Address`
* `dataSource.network(): string`
* `dataSource.context(): DataSourceContext`

实体和DataSourceContext 基础Entity类和子DataSourceContext类具有工具方法来动态设置和获取字段的能力：

* `setString(key: string, value: string): void`
* `setI32(key: string, value: i32): void`
* `setBigInt(key: string, value: BigInt): void`
* `setBytes(key: string, value: Bytes): void`
* `setBoolean(key: string, value: bool): void`
* `setBigDecimal(key, value: BigDecimal): void`
* `getString(key: string): string`
* `getI32(key: string): i32`
* `getBigInt(key: string): BigInt`
* `getBytes(key: string): Bytes`
* `getBoolean(key: string): boolean`
* `getBigDecimal(key: string): BigDecimal`


# 项目范例

有很多用户都是基于Uniswap的subgraph 和info的源码来修改成自己所需要的行情查询应用。

这里就提供了示例应用。


# Uniswap subgraph 范例

1、Uniswap info 如果要用在自己的基于Uniswap V2合约的Swap上，简单来讲要做以下调整：

A、subgraph.yaml&#x20;

修改数据源：

source:&#x20;

address: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'&#x20;

abi: Factory&#x20;

startBlock: 10000834

这 里的address 和 startBlock 请根据实际的合约进行调整。startBlock一般以合约创建的区块作为起始区块。

network 目前在 HyperGraph中，Heco和BSC请写为mainnet， HSC的请写为hsc

B、修改代码src/mappings/helpers.ts 中的 Factory 合约地址

export const FACTORY\_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'

C、修改稳定币和跟踪流动性的白名单资产

修改的地方在: src/mappings/pricing.ts 注意，地址请务必用**小写**。

&#x20;**`const`**` ``WETH_ADDRESS = '0x5545153ccfca01fbd7dd11c0b23ba694d9509a6f'`

`// New Stablecoin pair needed!`

`// TODO: HUSD to HUSDT`

**`const`**` ``WHT_HUSD_PAIR = '0xf07b1e4a87794293f781373fd1f0cfa65e7592a4'`

`export function`` `**`getHtPriceInUSD`**`():`` `**`BigDecimal`** **`{`**

&#x20; `// fetch eth prices for each stablecoin`

&#x20; **`let`**` ``husdPair = Pair.load(WHT_HUSD_PAIR) // usdt is token0`

&#x20; `if (husdPair !== null)`` `**`{`**

&#x20;   `return husdPair.token0Price`

&#x20; **`}`**` ``else`` `**`{`**

&#x20;   `return ZERO_BD`

&#x20; **`}`**

**`}`**

`// token where amounts should contribute to tracked volume and liquidity`

**`let`**` ``WHITELIST: string[] =`` `**`[`**

&#x20; `'0x5545153ccfca01fbd7dd11c0b23ba694d9509a6f', // WHT`

&#x20; `'0x0298c2b32eae4da002a15f36fdf7615bea3da047', // HUSD`

&#x20; `'0x64ff637fb478863b7468bc97d30a5bf3a428a1fd', // ETH`

&#x20; `'0x66a79d23e58475d2738179ca52cd0b41d73f0bea', // HBTC`

&#x20; `'0xa71edc38d189767582c38a3145b5873052c3e47a'  // HUSDT`

**`]`**

Subgraph 示例下载地址：

{% embed url="<https://github.com/HGDotNetwork/Uniswap-v2-subgraph>" %}


# Uniswap-info 范例

在部署好subgraph，同步好数据之后，就需要修改前端代码来支持。

修改的地方有几处：

1、src/constants/index.js&#x20;

`export const FACTORY_ADDRESS = '0xb0f0a809b898b91db7d862819dbff83d3539bf82'`

2、src/apollo/client.js

子图查询代码：

`export const client = new ApolloClient({ link: new HttpLink({ uri: 'https://q.hg.network/subgraphs/name/rrex/heco', }), cache: new InMemoryCache(), shouldBatch: true, })`

健康检查：

`export const healthClient = new ApolloClient({ link: new HttpLink({ uri: 'https://h.hg.network/graphql', }), cache: new InMemoryCache(), shouldBatch: true, })`

区块信息：

`export const blockClient = new ApolloClient({ link: new HttpLink({ uri: 'https://q.hg.network/subgraphs/name/kdex-heco-blocks', }), cache: new InMemoryCache(), })`

Info 代码示例地址：

{% embed url="<https://github.com/HGDotNetwork/Uniswap-info>" %}


# 常用子图

常用子图

以下常用子图请使用公共子图，请不要重复部署，否则会被移除：

区块信息子图：

BSC(56):

区块信息：

<https://pq.hg.network/subgraphs/name/bscblocks/bsc>

健康检查：

对于部署在节点上的查询子图，请以实际的节点健康检查链接为准。

<https://ph.hg.network/graphql>

Heco(128):

区块信息：

<https://q.hg.network/subgraphs/name/hecoblocks/heco>

健康检查：

对于部署在节点上的查询子图，请以实际的节点健康检查链接为准。

<https://ph.hg.network/graphql>

HSC(70):

区块信息：

<https://hq.hg.network/subgraphs/name/hscblocks/hsc>

健康检查：

对于部署在节点上的查询子图，请以实际的节点健康检查链接为准。

<https://hh.hg.network/graphql>

Matic(137):

区块信息：

<https://n18.hg.network/subgraphs/name/hgt-matic-blocks/matic>

健康检查：

请以实际的节点健康检查链接为准

OKExChain(66):

区块信息：

<https://n19.hg.network/subgraphs/name/okexchain-blocks/oec>

健康检查：

请以实际的节点健康检查链接为准

Ethereum(1):

区块信息：

<https://n23.hg.network/subgraphs/name/hgt-mainnet-blocks/mainnet>

健康检查：

请以实际的节点健康检查链接为准


# 服务用户

以下项目和产品的由 HyperGraph 提供技术和数据服务支持（目前已公开，排名不分先后）：

1、[Complus.exchange](https://Complus.exchange)

2、[Mdex.com](https://Mdex.com)

3、[Dodoex.io](https://Dodoex.io)

4、[OpenNFT.io](https://OpenNFT.io)

5、[Pippi.Finance](https://Pippi.Finance)

6、[LavaSWAP.com](https://LavaSWAP.com)

7、[LambSwap.fi](https://LambSwap.fi)


# HyperBridge

HyperBridge 是HyperGraph 团队完全自主开发的去中心化跨链桥。

## 一、背景

最近两年以来，区块链正式走入应用落地的阶段，DeFi、NFT、GameFi、MetaVerse、Web3.0 等概念走进现实，产生应用，真实地承载了相当的资金和价值，成为行业蓬勃发展的动力。但这也让当下区块链所存在的性能问题更加凸显，以太坊变得不堪重负。但同时以太坊又已经成为事实上的标准，拥有着最庞大的开发者和用户群体，所以各类以太坊的侧链和扩容技术也如雨后春笋，从BSC到Heco，从Polygon到Exchain等，各领风骚，都形成了一定的影响力。

层出不穷的公链和技术解决方案，也带来了一定的问题，那就是每一条公链，都是数据和资产的孤岛，各自为政。有的项目在多条公链上提供服务，但Token不能便利互通，而像USDT也是在各条公链上独立发行，映射发行的ETH等就更是各公链或者交易所自主控制。

当下互通有两种方式，一种是借助于中心化的交易所来支持一币多链，交易所接收到各链的资产，统一管理，然后根据用户需要，提供目标链的资产提取。这种方式弊端很明显，就是首先要交易所首先支持相应的公链，其次资产要交易所上架，第三交易所提币要注册账户甚至KYC等。这些都相对比较费时费力。

第二种方式是使用跨链桥，目前现存的跨链桥也存在如下问题，1、资产上架比较麻烦，2、跨链速度慢，至少几分钟，甚至更长时间。3、支持公链少。

基于团队在区块链数据分析、存储和网络方面的积累，HyperGraph 推出了HyperBridge 跨链桥。

## 二、特点

HyperBridge 做到了以下几点：

1、灵活支持多链

已经支持HECO、BSC、HSC、Polygon、ETH、ExChain

2、开放支持资产上架

项目可以自行维护资产上架，并且跨链项目的资产只需要在跨链上提供链上手续费，不会有本币手续费，保证了良好用户体验

3、支持主流跨链

采用跨链资产流动性激励机制来支持主流跨链，手续费80%分配给流动性提供者，20%用于平台回购并销毁HGT

4、支持跨链购买Gas

可以使用主流资产，购买目标链Gas，完全一站式实现资产跨链，可以迅速在目标链开启挖矿

5、跨链速度快

目前跨链的速度在30-60S 之前，跨链速度可以远胜当前任何的跨链手段

6、跨链操作简洁

整个跨链操作，跟链上转账和存币、挖矿操作一样，一次操作，轻松完成

7、跨链过程严谨安全

在源链和目标链上，均通过智能合约控制和管理过程，链上可追溯。跨链网关重用HyperGraph 节点网络，完全去中心化，全部技术自主研发

##


# Token 跨链

选择要跨链的源链，比如想从BSC 跨链到 Heco，就选择BSC链的钱包，进入跨链 DApp，

<https://www.hg.network/bridge/>

得到如下图：

![](/files/-Mg-rJ3EpKSEMMOBAb7-)

选择好要跨链的资产，选择源链与目标链。

收款地址默认是当前钱包地址，因为作为链上钱包，不同EVM的公链，私钥是一样的。所以在收款地址默认不变的情况下，可以跨到目标链上的同一个地址。如果换成别的地址也可以的，就相当于一次跨链转账。

输入数量，进入下一步：

![](/files/-Mg-rJ3FnQ-2sIqISgKU)

在这一页，相当于对操作信息进行提示，以让用户确认。由于跨链涉及到网关上的转账等操作，所以收取了一定的手续费。

确认无误，点击转账，就在钱包弹出了交易确认，确认之后，进入交易记录页面。等待链上确认成功，几秒钟之后，跨链网关就会扫描到链上记录，并在记录列表中显示出来，显示成等待处理。网关节点间会竞争，并由其中一个节点开始处理，在处理过程中，可以看到源链的链上操作，可以通过“查看哈希”在区块链浏览器上查看源链智能合约的处理情况。而处理过程中，目标链的操作还没有完成，所以需要等待。

![](/files/-Mg-rJ3G_YLsJT5jrxqQ)

网关处理完成，扫描到转出记录之后，就会更新跨链记录，将状态变更成已完成，同时目标链合约相关的交易哈希也已经取到，可以点击查看。这就完成了整个跨链过程。

![](/files/-Mg-rJ3HbAfBbt_b5sP5)

根据本链的处理情况，从BSC 跨链至Heco，全部过程不超过20 S。

## 项目Token跨链

项目方可以通过表单将所能提供流动性的Token信息提交，由HyperBridge跨链桥来添加白名单到资产列表，实现跨链。申请的入口，在跨链首页的右上角，如下图：

![](/files/-Mg-rJ3IVvLcP2J6FHst)

在获得认可和配置之后，所提交的项目地址，被认为是项目管理员地址，可以自行维护项目流动性。项目管理员地址钱包登录跨链桥，就可以看到管理员存币与管理员提币按钮。注意，项目管理员只是Token维护流动性的角色概念，并不能管理除了自己账户之外其他任何人的Token资产。

![](/files/-Mg-rJ3J3Z8KFnftD7zu)

实现对项目资产流动性的提供，同时也可以从单链或者多链提取出相应的资产。


# 主流跨链

为了方便用户在多链间流通，HyperBridge 跨链桥2.0版支持主流资产跨链，用户可以将USDT 跨链到别的公链，同时也支持用户在跨链桥上存入 USDT ，提供流动性，以赚取跨链手续费，用户存入的流动性，也可以在多链上提取出来。

主流资产跨链和Token跨链是一样的界面，在跨链时资产选择USDT即可。

![](/files/-MgjUasAWFhnO7mQ9n96)

在下面的输入框，选择要跨链的数目，我们可以看到，当前账户余额有188.93981USDT，而目标链的流动性额度有450.1797USDT。当前我最多只能输入188.93981，始果当前账户余额有1000USDT，则也最多只能跨450.1797USDT。我们这里输入20，点击下一步就可以开始跨链。

![](/files/-MgjUasBYVTzAw5vW3aw)

据界面提示，实际到账是19.9 USDT ，因为有千分之五的跨链手续费，其中80%奖励给流动性提供者。

0.2HOO的Gas手续费。

确认消息无误，点击转账，先授权合约花费 USDT，然后弹出二次确认。

第一次要授权确认。

稍后，网关开始工作，我们就能看跨链记录显示出来了。

![](/files/-MgjUasCkox-YD-p8NeE)

正在处理时，状态也会发生变化：

![](/files/-MgjUasD1gHU9K_DE2bT)

会显示是第多少号节点在处理跨链。

然后跨链成功，会看到成功后的记录：

![](/files/-MgjUasEOdxmOXa3c-zZ)

通过查看哈希，就可以看到链上处理的过程，目标地址成功接到了19.9USDT。

![](/files/-MgjUasF2rwpnNsAKSsL)


# 主流流动性提供

为了让用户积极参与主流跨链深度的构建，HyperBridge 提供了流动性奖励。每一笔主流跨链，都有千分之五需要做为手续费，其中千分之四提供给流动性提供者，千分之一平台用于回购HGT并销毁。

下面介绍一下流动性相关的操作，第一个是添加流动性，在当前链存入 USDT 做为流动性。

![](/files/-MgkCxD-o7EOWb-Fdank)

比如当前链是Heco链，你存入流动性之后，别人从其他链跨入Heco链，每提走的一笔USDT，流动性提供者均可以分享收益。

这里举一个例子。比如 Heco 跨链流动性池总共有 10000 USDT，张三提供的留动性占了 3000 USDT，占池子的 30%。有用户从 BSC 跨链到 Heco，跨链 1000 USDT。用户在 Heco 上可以收到 995 USDT。5USDT中的 1USDT 由平台收取，4USDT 分享给留动性提供者，张三可以分到其中的 30%，即 1.2USDT。

添加流动性和一般的抵押存入没有区别，这里不多演示，重点介绍一下“我的流动性”的操作。

![](/files/-MgkCxD0fgyOb223xCgP)

我的流动性界面，可以看到比较多的信息，包括：

1. 当前用户在当前链的流动性余额。
2. 当前用户当前链的流动性收益
3. 可用额度，是目标链的可提额度
4. 提取收益，是将收益提取到账户
5. 减少流动性是将流动性减少，比如本例中，可以由500USDT减少到400USDT。

这里值得一提的是HyperBridge支持从多个链去提取自己的流动性。

比如你在BSC 公链存入了500USDT流动性，可以在BSC 公链上发起减少流动性，目标链可以选其他多个链，直到把自己的额度提取光。


# 主流购买Gas

购买 Gas 是本次跨链桥升级的重要功能之一。可以直接通过跨链桥跨链购买Gas，当然也可以购买当前主链Gas。

![](/files/-MgoclQQ5xUsY2AemjJU)

下面演示一下目标链购买Gas。

当前处于Heco网络上，我们想为OKExChain上的当前账户购买Gas。

输入20，点击购买。

进入授权界面

![image](/files/-MgoclQRt42lKVDq1UPs)

授权成功，即可以提交交易。

提交完成交易，进入记录页面，就可以跟踪整个过程：

![](/files/-MgoclQSjAYDdQ16lRgQ)

共分成三个状态：

1、待处理，就是网关已经扫描到跨链记录，等待处理。

2、处理中，表示正在校验和转账。

3、已完成，就是网关扫描到了成功的记录。给予展示。

![](/files/-MgoclQTb3U4vb6q5G7J)

购买记录目前请在相应链的区块浏览器上直接查看。

这是目标链和当前链不同的情况，目标链和当前链相同，操作流程一样，也能实现Gas购买，就相当于一个简单的兑换操作。

值得一提的有两点：

1. 所有的兑换操作，都是通过去中心化交易所的路由实时购买的，HyperBridge本身不维护交易流动性。
2. 需要收取跨链手续费，比如20 USDT，实际上用于购买Gas的 USDT 只有19.9 USDT, 0.1 USDT 被用做了跨链手续费。如下图所示：

![](/files/-MgoclQUQ0tr0ptbTUnO)


# 总体介绍

### &#x20;HyperGraph 介绍

HyperGraph 是一个高性能数据网络，为所有高性能公链及其DApp提供数据索引与查询服务，是高性能区块链时代重要的数据服务基础设施。

\*目前已基于Heco、BSC、HSC等公链服务于 30+项目，包括Mdex、Dodoex等

\*HyperGraph具有核心技术优势，远超同类产品索引能力

\*开发团队拥有平均10年以上技术水平，数亿级用户架构经验

### HyperGraph节点

为了进一步满足业务量的暴增，快速承载处理巨大的数据量，HyperGraph 将节点网络公开，外部开发者可按规则接入成为节点，共同为需求方提供数据索引与查询服务并实现收益的分享。

\*收益真正通过业务直接奖励给Token持有者

\*服务器节点所有权去中心化

\*维护节点和服务器分布式管理

### HyperGraph节点重要性及其要求

索引节点跟前端的部署网关和后端公链RPC节点一起，组成了HyperGraph整个数据网络，节点是执行用户数据存储和查询的核心实体，是整个数据网络最直接承担业务压力的核心组成部分。参加节点相当于做了HyperGraph 数据网络的加盟商，可以共同分享高性能区块链时代的数据红利，同时承担以下职责：

\*维护互联网服务的重要性和高可靠性（如自行维护节点，须保证7x24小时响应）

\*自觉维护HyperGraph品牌和知识产权，不能自行将节点与技术分享给第三方

\*看中HyperGraph所从事业务的长期价值，并且积极发展与认真对待项目与客户

### 节点启动时间

2021.4月下旬开始Heco节点预备DAO池

2021.5月中旬开启节点报名

2021.5月中旬开始BSC节点预备DAO池

2021.5月下旬开启节点相关的准备与培训

2021.5月下旬最终确定第一期节点名单

2021.6月初进行节点网络部署与测试

2021.6月上旬开启用户服务迁移与并开放服务

2021.6月中旬完成节点网络完全上线

### 节点启动流程

A、节点报名

B、节点选型（选公链、选性能级别、可维护级别）

C、节点筹备（技术团队组建、服务器采购、账户分配、程序安装以及文档手册）

D、节点抵押（正式抵押节点池、矿工参与抵押到节点池）

E、产品上线与服务开放

### 节点报名条件

与HyperGraph目标一致，发展理念契合，且持币100,000 HGT起

\*持币包括节点预备池中存入的 HGT及BSC或Heco链地址上非抵押HGT

\*持有的HGT不足10万枚，也可以在节点开启后抵押给节点来获取收益

### 节点报名方式

Heco公链和BSC公链会同步开启节点报名

登陆HG.network即可参与报名


# 网络建设

## 1、进入服务网络

&#x20;各种角色根据不同的资源条件、技术能力和持币份额，进入HyperGraph网络为整体网络建设做贡献。

每个索引节点通过自身稳定的服务可靠性、开发者评价，再加上有不同的费用策略来吸引用户使用节点，节点正式进入服务网络，开始索引和提供查询服务可能基于这些情况。

1. 应用开发者通过部署特定的子图来发信号给索引节点，索引节点开始工作。
2. 某个节点或者子图的历史查询量等，也预示着了未来的服务需求。
3. 某个节点的HGT抵押量，也为网络的自动选择提供了重要参考。更高的抵押量意味着更大的重视和服务提供信心。

## 2、获取服务支持

核心开发者是整个HyperGraph网络的发起和维护成员，负责为网络成员提供技术支持等方面的服务，包括以下环节：

1. 高性能区块链网络对现有的技术架构带来了挑战, HyperGraph 在Graph Node等开源软件的基础上，构建基础设施，以适应高性能区块链网络。
2. 负责开发底层服务之外的交互界面，负责HyperGraph网络基本运营规则与服务标准制定。
3. 协助解决节点运营中具体到实际问题，包括软硬件配置、选型、优化等方面。
4. 组织社群成员，协调社区治理，奖励分发以及节点评估，奖惩等具体网络健康运营相关事宜。


# 节点角色

索引节点网络尚未开始，本文用于简单介绍项目流程

## 1、网络角色

HyperGraph 开发者团队提供网络构建的基础工具和产品。而网络生态根据不同的参与者有不同的角色，以下说明五种角色。

&#x20;**A、核心开发者**

&#x20;核心开发者负责基础软件的开发维护，节点建设标准的指导以及性能优化的建议。同时还负责协调HyperGraph社区治理以及一些公共资源的搭建，并免费提供给社区

&#x20;**B、索引节点**

HyperGraph数据网络由一系列索引节点联结而成。索引节点抵押HyperGraph 通证（HGT）来提供索引和查询服务，至少抵押100K HGT通证成为索引节点。索引节点的收益包括查询费和服务索引奖励。同时还可以分享节点奖励池的奖励。

索引节点抵押对节点起到监督的作用，节点必须正确地索引数据和提供服务的可靠性，节点的HGT不仅仅是来自于节点运营方，还可以来自于持币者的抵押。

节点选择子图定义来对数据进行索引，开发者对索引节点的质量进行评估，选择更优质的节点。用户也可以指定由哪个节点处理查询和供给费用。

**C、应用开发者**

&#x20;开发者是指根据需求，开发子图和相应处理程序的个人或者团队。开发者满足应用的数据查询需求，做一定开发，将开发的子图提交给索引节点，完成数据索引，查询并展示在用户界面上。开发者除了通过抵押HGT部署子图，也可以通过质押HGT标志子图质量，以获得索引优先级，同时开发者也根据自身专业经验和以普通用户的使用体验，实现对节点和子图的评估评价。

&#x20;**D、矿工**

&#x20;矿工指的是HGT持币者，由于索引节点需要HGT抵押来开启节点。除了初始的100K之外，其他的份额可以由矿工参与抵押自己的HGT额度给索引节点，以增加索引节点的竞争优势，同时可以分享索引节点的收益

**E、数据用户**

整个网络的存在和价值因能为最终用户产生价值而实现。DApp项目或者个人，均可以通过使用HGT支付来实现对索引网络中的数据查询，来完成自己的需求，甚至对接API，开发专门的统计等展示界面。

各角色关系如图6所示。

![](/files/-MYh5woe5kQCeyIMjtKX)

图6、HyperGraph 网络中各角色示意

##


# 节点设备

为了理解索引节点在节点网络中处于什么样的位置和重要性，先来看一下 HyperGraph 业务数据处理流程图：

![](/files/-MaYVhpxN_oMVhCwRyWP)

在这张图中，中间到右下角的部分，HyperGraph 网络解析智能合约事件，进行数据处理与存储，就是索引节点要完成的工作。所以索引节点是核心的核心。由于索引和存储是一个既需要大量计算，也需要大量存储的操作，所以索引节点需要有比较好的硬件计算和存储资源，以及安装相应的软件设施来对数据进行索引，并提供查询服务。

硬件根据服务量的不同，可以采用不同的硬件设备。下面分为三种规模来分别予以介绍。

**A、小型节点**，适合个人开发者或者小型业务团队作为业余职业来参与建设。提供小于20个子图的索引，或者每区块数据量在<10事务处理（以3s为出块时间算）这个量级，并不需要自建区块链RPC 归档节点，而使用核心开发者提供的免费RPC资源，建议硬件配置如下：

| **CPU** | **内存** | **硬盘**    | **说明**      |
| ------- | ------ | --------- | ----------- |
| 8核      | 16G    | 200G（SSD） | 社区免费提供RPC资源 |

**此机型成本在阿里云上如下：**

![](/files/-MaYVhpy2iLvSEMyvQc3)

但是由于HyperGraph节点可以得到集体采购的优惠价格，最终如下：

![](/files/-MaYVhpzzdExaWzzdyvF)

**B、中型节点**，适合中型应用应用团队使用或者中型应用团队贡献自己的节点参与建设，提供<50个子图的索引，或者每区块数据量在100个事务以内的数据量，每秒响应200个请求。中型节点可以自建区块链RPC 节点，也可以使用核心开发者提供的RPC资源，但是要为RPC资源增加额外的HGT支付。

| **CPU** | **内存** | **硬盘**    | **说明**      |
| ------- | ------ | --------- | ----------- |
| 16核     | 32G    | 500G（SSD） | 社区可选提供RPC资源 |

此设备优惠参考成本如下：

![](/files/-MaYVhq-fxjicXnIsl4I)

**C、大型节点**，适合大型团队，或者专业合作商来参与节点建设。可以存储100个以上的子图索引，每个区块可以索引的数据量在200个事务量级，每秒可以提供1000个以上的查询请求，大型节点需要自建RPC 归档节点，同时支持索引节点的垂直切分。

RPC节点

| **CPU** | **内存** | **硬盘**     | **说明**                |
| ------- | ------ | ---------- | --------------------- |
| 16核     | 32G    | 6000G（SSD） | 需要支持空间随时扩容，可以开放给第三方使用 |

RPC 节点的费用是比较贵的，主要贵的成本在存储空间上，参考成本如下：

![](/files/-MaYVhq0EjTBpcWVyjS1)

索引节点

| **CPU** | **内存** | **硬盘**     | **说明** |
| ------- | ------ | ---------- | ------ |
| 32核     | 64G    | 1000G（SSD） |        |

![](/files/-MaYVhq1Hh66d2pVfkLR)

**说明：以上硬件价格均是参考价格，实际价格以实际成交时为准，实际成交为实际花费，无其他额外支出。**

除了索引节点之外，软件上面也可以支持拆分。可以将后端软件设施支持拆分部署。

软件方面，大型节点，需要具体以下软件构建、编译和运行等的环境，以及相应环境的基本部署维护能力。

1. Linux 操作系统
2. Docker 容器或Rust语言编译环境
3. Nodejs开发编译环境
4. Postgres数据库
5. IPFS
6. HyperGraph 节点核心程序
7. HyperGraph 索引节点程序

具体服务和实际过程需要的支持由核心开发者提供相应帮助、程序和脚本等来实施。


# 节点查看与管理

每一个托管节点都可以获得阿里云子账户权限，可以自行登录阿里云子账户，查看子账户信息。但是为了服务安全稳定考虑，托管节点不能提供服务器登录和节点关机，启动等权限。仅可以查看配置信息和监控等。

RAM（Resource Access Management）用户会在支付成功后发给节点管理员。请妥善保管。登录查看资源过程如下：

1、进入阿里云首页：

<https://account.aliyun.com/login/login.htm>

2、使用RAM 用户登录：

![](/files/-MbAXUx-FQfuweWig4Mk)

输入用户名：

![](/files/-MbAXUx0ucVUqSE6Kv0k)

输入密码：

![](/files/-MbAXUx1sRZ0tR67TSkl)

登录成功后进入控制台：

![](/files/-MbAXUx2MujuFKjs43yt)

左上角点击：

![](/files/-MbAXUx3QzQniGu1DRyQ)

进入ECS：

![](/files/-MbAXUx4vyJrSYQRXgqd)

选择地域：

![](/files/-MbAXUx5jbwrPAZnN4Im)

在实例检索那里，输入实例的ID，点击检索，就可以看到实例了。

![](/files/-MbAXUx6Hm3hTEBUqumG)


# 节点托管类型

虽然开发团队会逐步和尽量让节点的软件安装、监控更为自动化，但是作为互联网设备，不可避免会存在问题需要处理，所以每个节点存在一定的运维管理工作。

而不同节点的技术储备也各不相同，比如有的节点可能本身就提供过互联网服务，有服务器和技术人力，有的节点可能根本不懂技术。但是为了保证HyperGraph网络的整体稳定性并给HyperGraph用户提供一致的服务，对服务的响应速度和质量，以及标准化程度都有相当的要求，所以针对这种情况，对节点的托管以及服务等级做出界定。

## 节点托管类型

#### 1、全托管

全托管是节点报名之后，协商采购完成服务器，除了硬件升级需要继续参与之外，对于软件的安装维护、服务的稳定性监控，完全不需要参与管理，甚至都不需要登录服务器。

但节点仍可以通过节点的后台查看节点的统计，也可以可选获得云平台子账户，通过分配的子账户在云服务器后台来获得服务器的配置以及运行状况，为了避免对服务造成不稳定因素和留下安全隐患，不能登录服务器和管理服务器。

在这种托管类型下，节点只需要关注自己的统计与业务量，而不需要关心服务器的运行情况，因此也不需要技术人员，节点发起人也不需要懂技术。

目前对于服务器全托管，开发团队不收取额外技术支持费用。

#### 2、半托管

半托管是有一定云平台使用经验的节点，自行在指定的机构区域采购节点，所以加入网络的方式，也可以统一采购，通过分配子账户的方式得到服务器。因为涉及到同RPC节点大量的数据交互，所以必须在RPC节点相近的位置采购节点，否则节点将无法运转。采购完成后， 就由开发团队接手，对软件进行安装，对运维进行管理。双方均可以登录和管理节点服务器，节点可以自行对设备进行扩容，可以自行重启和停止服务器。

节点通过节点的后台查看节点的统计，也可以获得云平台子账户或者自行通过云平台，在云服务器后台来获得服务器的配置以及运行状况，但为了避免对服务造成不稳定因素和留下安全隐患，不能随便动服务器的设置，更不能随意重启服务器，哪怕是扩容，也要有开发团队的参与和支持。

在这种托管类型下，节点既可以关注自己的统计与业务量，也可以了解服务器的运行情况，服务配置情况，因此节点发起方需要有人需要对Linux的运维有一定的了解，了解云平台的操作，懂重互联网服务稳定的重要性，并保证该联络技术人员24小时电话能畅通，以联合处理问题，当然，常规的设备情况都会加入自动监控，一般情况下不会有什么问题。

#### 3、全自助管理

全自助管理是指节点服务器从采购到提供服务，全程自助，开发者团队只提供安装程序与脚本，提供软件升级和必要的监控等服务，但是不需要开发者团队有账户，来登录服务器和管理程序，这类操作由节点方技术配合开发方进行。

节点通过节点的后台查看节点的统计，自行了解服务器的配置以及运行状况，但为了避免对服务造成不稳定因素和留下安全隐患，一旦提供线上服务，不要随便动服务器的设置，更不能随意重启服务器，哪怕是扩容，也要有开发团队的参与和支持。

在这种类型下，开发方没有权限登录和管理节点服务器，所以节点全权负责配置升级、扩容和服务管理。因此需要节点方有技术人员能够熟练地操作Linux数据库、Postgres数据库、Nodejs系列开发工具等软件，也了解云平台的操作和配置、扩容等操作，更懂得互联网服务稳定的重要性，节点方必须24小时有人可以接电话来处理问题。

因此为了保证服务质量的稳定性，除非是有经验的节点，否则原则不要全自助管理。

## 服务质量要求

提供互联网服务，7\*24小时，遇到问题，难以避免，但是遇到问题，要能快速地恢复，或者让用户不可察觉，或者有问题影响小，都是处理互联网问题的原则。所以在HyperGraph 服务上，包括但不限于做到以下几点：

1. 所有服务器核心资源，包括CPU、负载、磁盘空间，超过阈值，每5分钟邮件报警。
2. 所以核心的服务进程，包括ipfs、graph-node、geth等进程，每分钟监控进程运行情况，如果进程丢失，则自动启动并邮件和短信报警
3. 对于重点的用户，建议做备份查询部署，对于子图部署在两个以上的节点上，做部署和数据冗余，一旦一个出现问题，建议可以立即切换上线
4. 对于所有节点的网络连接通，子图查询，以及RPC和子图健康状况，做监控和每分钟邮件和短信报警

做到这些以满足以下服务要求，第一步做到99.9%可靠性的标准，并朝着99.99%的可靠性而努力。这里解释一下这两个数据是什么意思。

在互联网服务领域，有一个词叫SLA，英文是 Service Level Assurance，可以翻译为服务级别。也可以理解为服务的可靠性，一般用百分数来描述这种可靠性。

99.9%的意思是：在99.9%的情况下是可以用的，这是什么概念呢，一年有365天，那么1/1000的情况不可以用，也就是1/3天将不可以用，一天只允许出现8个小时不可以用，算到一天的话，一天86400秒，一天只允许有86.4秒，也就是1分半钟不可以用，其他时间都要求能正常提供服务。这是一个不高的标准，但是也不容易达成。99.99%则属于比较高的标准了，一年只允许不到一个小时的宕机时间。


# 定价方案第二版

为了保障用户所支付价值的稳定性以及创建HGT作为实用化Token的流通与使用场景，HyperGraph 采用的是USDT 计价，HGT 支付，支付完成之后即计价稳定为USDT的方式进行项目子图索引用查询费用的充值。第一版方案推出以来，得到了项目用户的很多建议，并考虑到初始项目的实际情况，根据不同用户的使用级别，调整制订了如下的价格方案，当前版本为第二版，以下价格方案会在节点上线前予以正式确定并实施：

## 免费方案

1、免费注册

2、免费获取SDK、添加子图

3、免费获得前期帮助（包括文档与前期技术支持、子图、DApp开发指导，公共资源支持）

## 收费基础标准

1. 已成功部署并同步数据的子图需要支付HGT，并根据当时 HGT 价格转计为 USDT 存入账户
2. 部署新子图活期账户不能低于 500 USDT
3. 每新部署一个子图需要 500 USDT 抵押，子图抵押费用将于子图移除后返还至子图账户，如不移除，将被永久抵押
4. 子图抵押的500USDT，在子图创建的前20天，可以随时解锁，20天之后的子图抵押需要7天以后才能解锁
5. 运行期低于  500 USDT 将会被通知充值，连续4周活期账户低于 500 USDT，子图将会被移除
6. 每日（开始为每周）进行数据统计与费用扣除，执行标准按初始标准或者上月的标准执行
7. 用户方案的查询和索引量以全账户查询和索引量汇总之和为统计依据
8. 以索引量级别为基准，索引量与查询量分别统计级别，如果该统计周期无新数据索引，则无需支付费用。如果只有索引量，无查询量，查询级别以起点用户计算，最终费用为索引级别与查询级别的平均费用。

## A、起点用户

1. 月基础使用费 500USDT/月（以HGT支付时价格转换计算）
2. 服务计价（免费）
   1. 索引每区块<=0.1事务
   2. 月索引事务量 <= 86400 事务
   3. 查询频率 <=0.2 QPS
   4. 月查询量<= 518400 次

## B、基础用户

1. 月基础使用费 1000USDT/月（以HGT支付时价格转换计算）
2. 服务计价（免费）
   1. 索引每区块<=0.5事务
   2. 月索引事务量 <= 432000 事务
   3. 查询频率 <=0.5 QPS
   4. 月查询量<=1296000 次

## C、初级用户

1. 月基础使用费 2000 USDT/月（以HGT 支付时价格转换计算）
2. 具体服务价格（索引或查询指标超出基础用户标准，不能低于2000USDT/月）
   1. 索引每区块 <= 1事务
   2. 月索引事务量 <= 864000 事务 0.002USDT/索引
   3. 查询频率 <=2 QPS
   4. 月查询量 <= 5184000 次 0.0002 USDT/查询

## D、中级用户

1、月使用费 4000 USDT/月（以HGT 支付时价格转换计算）

2、具体服务价格（索引或查询指标超出初级用户标准，不能低于4000USDT/月）

a) 索引每区块 <= 5事务

b) 月索引事务量 <= 4320000事务 0.001USDT/索引

c) 查询频率 <=10 QPS

d) 月查询量 <= 25920000次 0.0001 USDT/查询

## E、高级用户

1、月使用费 8000 USDT/月（以HGT 支付时价格转换计算）

2、具体服务价格（索引或查询指标超出中级用户标准，不能低于8000USDT/月）

a) 索引每区块 <= 20事务

b) 月索引事务量 <= 17280000事务 0.0005USDT/索引

c) 查询频率 <=50 QPS

d) 月查询量 <= 129600000次 0.00005 USDT/查询

## F、企业用户

1、月使用费 16000 USDT/月（以HGT 支付时价格转换计算）

2、具体服务标准 （索引或查询指标超出高级用户标准，不能低于16000USDT/月）

a) 索引每区块 > 20事务   0.0003 USDT/索引

b) 查询频率 >50 QPS     0.00003 USDT/查询

c) 独立RPC节点/可以提供RPC节点访问

d) 独立索引节点

e) 一定程度定制服务


# 节点网络 FAQ

### 1、节点抵押 10 万HGT就足够了吗？

答：DAO 节点预备池、活期账户的HGT和XHGT 不能少于10万，才能开启报名。这是做节点的最低限制。同时也是正常使用和启动节点的基本要求。有了10万HGT且能正常能提供服务的节点，就可以列入被部署节点行列。但是并不是说10万HGT就够了，节点账户本身可以为节点增加抵押，外部用户也可以为节点增加抵押。抵押量的增加一定程度代表了节点的实力，也是用户部署服务的一个重要考量。如果不足10万HGT，可以作为矿工直接抵押给有实力的节点，分享收益。

### 2、使用Heco的HGT抵押是否可以申请给BSC提供服务？

答：由于HyperGraph 给Heco、BSC、HSC，甚至其他兼容EVM的公链提供服务，而HGT又不能每条公链都发行Token，所以在HGT的消耗与抵押上做了多链服务的兼容。使用Heco的HGT，可以用于申请给BSC公链提供服务，也可以用于支付在BSC上的数据检索与查询服务。

### 3、使用Heco的HGT是否可以抵押给服务BSC的节点？

答：节点由节点创建者发起，由自身的抵押加上用户的抵押一起得到总抵押量，获得节点的资质。目前仅支持与节点创建者同样的公链来进行抵押。也就是说，如果发起者，是在Heco上发起了初始的节点抵押，对于普通用户的抵押同样也只支持Heco的HGT，在这种情况下，节点池只存在Heco公链上，BSC公链上的用户是无法获得节点池数据的，所以无法使用BSC上的HGT参与抵押。在BSC公链上亦然。

### 4、一个节点是否可以同时服务多链呢？

答：由于索引与查询节点是一个相对比较费资源的操作，为了标准化管理，相关的进程与端口也是相对固定的。多链的服务不但对于服务器资源是是一个挑战，对于多端口管理和标准化服务也带来了麻烦，甚至为运维带来了复杂度。所以不建议在同一节点上提供多链的服务。如果一个用户想要提供多链服务，就可以申请多个节点，每个节点为不同链上的DApp提供数据索引与查询服务，每个节点对应节点池进行初始抵押和矿工抵押。

### 5、一个地址是否可以开通多个节点？

答：一条公链的一个地址，在报名阶段，可以以10万HGT（包括Heco DAO 1池以及活期）为依据，报名Heco和BSC的节点，但是在上线阶段，一条公链的一个地址只可以部署一条公链的节点池。但是对于相同的地址，Heco和BSC两个公链的同一个地址，是可以开通两个节点的，但是要分别抵押，同样也有限制，一个公链的一个地址，只可以部署一个节点。

### 6、是否可以开通BSC、Heco之外网络的节点？

答：别的公链由于需求还比较小，所以暂时没有开通对其他公链的公共节点报名，相应公链的业务仍然暂时部署在开发团队的节点上。等相应的公链业务发展起来，会陆续开通。

### 7、是否有计划支持以太网络的节点？

答：对于所有基于EVM的公链，HyperGraph都可以支持。并且可以做到快速支持一条新公链。如果数据量在一天以内可以同步完成的话，HyperGraph的网络也可以在一天内支持该公链。所以以太网络的节点也在计划之内，不过暂时还没有支持，将来会支持的。

### 8、成为节点必须要采购和管理服务器吗？

答：由于HyperGraph 是提供数据索引和查询服务，数据索引与查询服务都是基于服务器而进行。所以成为节点必须要采购和管理服务。但是开发团队考虑到节点不一定有技术维护能力、同时也要重点考虑到服务的稳定性与可靠性，所以提供了自行采购和购买之外的其他选择。你可以选择自助管理，按文档自行部署节点。也可以选择完全托管。具体请见相关的帮助文档。

### 9、成为节点自己需要具备多少技术力量？

答：首先不用太担心，维护一个节点并不是一个很费时间和高门槛的事情。其次，节点成本、维护人员成本，也是影响节点收益的重点考虑量。所以开发团队在节点本身的安装、运维、监控等方面，尽量做到自动化和规范化。因此，除非将来节点规模比较大，否则可以使用可靠的兼职技术人员即可以对节点进行维护的管理。有什么问题，开发团队也会率先知悉并告知处理。

### 10、成为节点是否需要自行拓展客户？

答：HyperGraph以统一的品牌形象对外和发展项目使用服务，原则上不需要节点自行拓展客户。但是节点积极地发展客户，部署在自己的节点上也会自己增加收益，也是受到支持的，但是不允许产生返点，抢客等行为。

### 11、节点是否能独立于HyperGraph网络之外提供服务？

答：节点是HyperGraph重要的组成部分，但是离开网络，节点无法独立提供服务。因为索引节点本身也需要后端RPC归档节点提供数据源支持，也需要前端节点提供部署数据源和权限验证支持。另外，也建议索引节点做到服务器专用，不要再部署其他无关服务，影响服务稳定性，进而影响节点后续服务部署，也影响收益。

### 12、节点的收益是固定的吗？是否有保证？

答：节点的收益有固定的部分，就是作为节点，可以获得节点固定的奖励。但是主要的收益还是来自于为网络上的索引与查询提供服务。所以，并没有什么收益上的保证。请自行根据对业务的了解和风险承受能力来参与节点网络。

### 13、节点与矿工的收益是怎么划分的，有何不同？

答：节点的费用收入包括三部分：一部分是节点抵押的固定收益费用，在项目专门有节点激励为支出。一部分是索引与查询服务收费，这部分又分为两部分。70%的部分，节点没有支配权，按抵押量平均分给用户和节点。30%的部分，节点可以自行调整奖励比例。分多少给抵押用户，多少自行留下。所以矿工收入分为两部分，一部分是根据抵押量获得的收入。一部分是节点分到的奖励。

根据社区用户的意见和节点的沟通，矿工也参与固定收益部分的分配，分配比例跟节点设置的抵押奖励作为分配依据。比如设置的抵押奖励是20%（30%是上限），那么，固定收入部分，节点只保留80%，20%会按抵押比例分配给矿工。同样，在索引和查询收入部分，70%节点和用户按抵押比例分配，20%只给矿工按抵押比例分配，10%，完全留给矿工自己。

### 14、是否可以随时加入节点？初期启动需要多少个节点？

答：虽然新增和调整节点在技术上是一个常规工作，但是为了保证现有节点的收益和一定程序的负荷运转，节点网络不是随时开放报名的。初期启动的第一批节点，加上开发者团队的初始节点，应该不会超过20个。

### 15、节点是否需要备份节点，怎么保证单点故障的问题？

答：当前的节点网络设计，没有做到自动备份多份。为了解决单点故障问题，对于数据同步较慢的项目，我们建议对同一个子图，部署在不同节点上，做成人工冗余。对于数据同步慢的项目，可以随时恢复重新生成。所以为了降低参加节点网络的成本，并不需要对服务器进行备份。

### 16、HyperGraph 节点跟公链节点有何异同？

答：公链节点的存在是为了保证公链共识的达成与交易确认。大家是一起在保证同一件事情的正确性。而HyperGraph 虽然整体上也是一个网络，也是为了用户提供共同的服务，但是本身对于某一个具体子图的索引与查询是独立的，节点之间并无相关性，甚至可以是不同网络的查询，彼此之间也不需要互相确认，所以比公链节点网络更加松散。但是前面说了，这并不意味着节点可以独立地提供服务，缺乏了基础设施节点的支持，光索引节点是无源之水，是无法工作的。

### 17、项目是否有必要加入节点？

答：项目服务使用节点。但是是否加入节点不是必要的。因为不是每一个团队都有后端技术。项目应该更多地关注自己的业务。所以也不建议项目加入节点。

### 18、项目支付服务费用的机制是什么样的？

答：预付费机制。如果要部署子图，并能成功提供服务。需要在账户中有HGT余额，同时对每个正常运行的子图提供HGT抵押，在子图移除后可以退回。HGT 会定时，根据服务使用量，从预付费中扣除。如果不再使用服务，余下的费用可以退回。

### 19、项目支付的费用包括哪些，怎么构成？

答：项目支付的费用包括月使用基础方案费。超过基础方案的索引服务费和查询服务费。子图抵押费用不算是收费，只是处于抵押状态。

### 20、子图部署分配可以分配到指定节点吗？

答：可以，但是要满足公链的要求。比如不能跨链部置，也就是说，有的节点专门为Heco公链提供服务，只接受来自Heco 公链的部署请求。

### 21、如果不想做节点了怎么退出？

答：由于正在在线提供服务，如果要退出节点，请和开发团队协商，以转移用户的服务。同时矿工的抵押也要通知转移抵押。节点和矿工，转移和撤出部分抵押，有一定的冷却期，如果是节点本身减少抵押，为了保证节点正常运行，最换的抵押量也不能低于10万HGT并且要保证节点本身抵押量不能少于矿工抵押量的1/15。

### 22、如果要转移或者撤出抵押，有什么需要注意的？

答：首先有一定的冷却期，现在是28天，在冷却期是没有收益的。但是冷却期可以随时再转为抵押，不需要重新扣除抵押费。如果转移到新的节点重新抵押，是需要重新扣抵押费的。

### 23、节点接收抵押HGT有没有限制？

答：节点接收抵押HGT 至少有两个限制，一是公链限制，就是如果节点发起人在Heco链上开启，也只能接收Heco链的HGT作为抵押。二是数量限制，节点所承载的矿工抵押量不建议高于节点本身抵押量的15倍，高于15倍的部分将不计入节点的收益计算，从而降低抵押收益率。

### 24、HGT的抵押数量多少有什么不同？

答：节点接收的抵押量和总抵押量，一定程度代表了节点的实力和可靠性。所以抵押数量越高，在分配子图和服务会有更高的权重。

### 25、DAO池的HGT可以直接自动转入节点抵押吗？

答：由于HyperGraph秉持的理念是用户持有自己的资产，不能为用户自行转移资产。可以DAO池到期之后，再自行转入节点抵押


# Heco 网络公开归档节点

&#x20;        在Heco 官方的大力支持之下，HyperGraph 架设了两个公开使用的归档节点，以供大家使用。此节点支持 RPC 与 WS 方式使用，但是鉴于是公共免费资源，请不要过度使用，或者用于长期和大规模的数据服务。

具体配置与测试方式如下：

节点1：

http 方式：

URL：

[`https://pub001.hg.network/rpc`](https://pub001.hg.network/rpc)

WS 方式:

URL:&#x20;

`wss://pub001.hg.network/ws`

在MetaMask 中连接配置如下图：

![](/files/-Mevr4Nu2lu9fJiKZpMT)

可以使用 RPC 方式对1号节点进行测试，分别获取chain ID 和最新区块号，结果如下：

`# curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' -H "Content-Type: application/json" https://pub001.hg.network/rpc`

`{"jsonrpc":"2.0","id":1,"result":"0x80"}`

`# curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' -H "Content-Type: application/json" https://pub001.hg.network/rpc`

`{"jsonrpc":"2.0","id":1,"result":"0x6479e9"}`

你可以编写如下代码，测试Websocket 协议的连通情况：

`var Web3 = require('web3');`

`var web3 = new Web3('wss://pub001.hg.network/ws');`

`subscription = web3.eth.subscribe('pendingTransactions', function (error, result) {})`

&#x20;   `.on("data", function (transactionHash) {`

&#x20;       `web3.eth.getTransaction(transactionHash)`

&#x20;       `.then(function (transaction) {`

&#x20;         `console.log(transaction)`

&#x20;       `});`

`})`

如果正确，将输出如下图

![](/files/-Mevr4Nv4iJDGrOO17EI)

节点2：

http 方式：

URL：

`https://pub002.hg.network/rpc`

WS 方式:

URL:&#x20;

`wss://pub002.hg.network/ws`

在MetaMask 中连接配置如下图：

![](/files/-Mevr4NwPQ60leRtqd0H)

可以使用 RPC 方式对2号节点进行测试，分别获取chain ID 和最新区块号，结果如下：

`# curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' -H "Content-Type: application/json" https://pub002.hg.network/rpc`

`{"jsonrpc":"2.0","id":1,"result":"0x80"}`

`# curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' -H "Content-Type: application/json" https://pub002.hg.network/rpc`

`{"jsonrpc":"2.0","id":1,"result":"0x6479ea"}`

你可以编写如下代码，测试Websocket 协议的连通情况：

`var Web3 = require('web3');`

`var web3 = new Web3('wss://pub002.hg.network/ws');`

`subscription = web3.eth.subscribe('pendingTransactions', function (error, result) {})`

&#x20;   `.on("data", function (transactionHash) {`

&#x20;       `web3.eth.getTransaction(transactionHash)`

&#x20;       `.then(function (transaction) {`

&#x20;         `console.log(transaction)`

&#x20;       `});`

`})`

如果正确，将输出如下图

![](/files/-Mevr4Nxv7apm82HFVFh)


# HyperGraph 简介

&#x20;      区块链伴随着数字资产而诞生，早期仅仅是价值在互联网上点对点转移的底层承载，但随着技术与应用的发展，现在已经成为各类应用尤其是去中心化金融（DeFi）应用的基础设施。

&#x20;      应用的丰盛，越来越多的服务商和开发者加入到了区块链技术与应用的开发中来，同时应用的需求，也推动了公链技术的发展，高性能公链以其快速的确认和低廉的手续费，更引发了应用开发商的涌入。以火币生态链（HECO）为例，3 秒的出块速度，低廉的手续费让区块链 应用开发有了更多的发挥空间，也有了很多近似于传统互联网的产品体验， 如果再加上元交易的支持，用户零门槛使用各类 DApp 产品，必将带来区块链应用与开发的整体繁荣。&#x20;

&#x20;      尽管现在区块链应用的开发基础设施也相对完备，尤其是以太坊或者与以太坊完全兼容的网络，从 IDE 到开发者开发调试套件 、API 调用服务等都已经相对成熟与完善。 除了上面这些属于开发者端的工具和产品，由于应用上链和开发者的增多，带来了更多开发甚至是运营支撑基础设施的需求，尤其是数据处理与分析需求。&#x20;

&#x20;     在传统的关系数据库中，数据比较容易获得、查询与展示，但是区块链做一个公共的链上存储数据库，转账数据、多App同一时间的操作数据混杂，那怕是一个简单的查询也不能用传统的方法实现，需要分析区块，自行实现对数据的分析查询，不但是在人力、时间的投入上，还是硬件的投入上，有需要有相当的花费。

&#x20;     HyperGraph 项目就是基于以上现象和需求，构建一个高性能区块链的数据服务网络， 在数据服务网络中，HyperGraph 构建基础设施与标准，节点运营者根据标准建设网络节点， 参与网络共同建设。开发者则根据自身业务定义数据获取需求，通证持有者，支持网络节点获得收益，形成一个整体生态。 HyperGraph 数据网络不但索引与查询智能合约数据，也是智能合约数据与传统互联网数据交互的桥梁，HyperGraph 的愿景是，建立一个数据索引网络，最终将全世界所有的智能合约数据索引起来，并与传统互联网数据交互集成，提供给需要的开发者，以便随时搜索查 找相关数据。最终达成智能合约数据应用输入与输出的完全去中心化，并实现智能合约的无数据库运行。&#x20;


# HyperGraph 优势

对于区块链数据分析，现在有比较多的方法，包括自己使用 Web3 的接口自行编写脚本分析区块、使用 Ethereum-ETL 命令行程序对区块库高效批量分析等。而 TheGraphProtocal 开发的 GraphNode 是一整套更能批量和全面的区块链数据分析解决方案，HyperGraph也基于此套方案演进而来，但又具有以下特点和优势：

1、首先是性能，当下市场上用户量比较大的类似服务，比如 GraphNode 服务，主要是针对以太坊的，而以太坊平均14秒左右一个区块，对性能的要求并不高，但是这些服务一旦移植到Heco或者币安链这种3秒一个块的高性能的公链上面的时候，就没有办法满足需求了，目前以我们所知道的，HyperGraph是市面上唯一可以满足高性能公链做业务数据索引与查询分析的服务。

举个例子，Heco每三秒一个块，高峰期每个区块有400多个事件要分析，如果你不能在3秒内把这400个事件都处理完，下一个区块又来了，你就分析不过来了，这就是为什么，用户在一些流量比较大的Swap的行情数据展示上会看到，很多数据都有数个小时以上的延迟。但是在使用HyperGraph技术支持的项目里看到的都是数据实时更新。

2、另一个优势是跨链，虽然现在也有很多数据服务支持跨链，但是他们的跨链都只是支持不同的主网而已，HyperGraph 的跨链支持不但是针对链提供服务，而且将支持同一个项目的跨链数据聚合、不同项目、不同链的数据整合，举个例子，一个项目同时在以太坊和币安链上都有服务，传统的数据服务，去查询这个项目，要分别查询太坊和币安链，但是HyperGraph可以在有需要的项目下，将实现把不同主网的数据聚合起来，以方便查询分析，真正实现业务整合的数据目标。

3、产品与应用上的创新，HyperGraph 将针对从索引到查询的整个流程，提供更为全面的数据统计分析，发挥数据更大的价值，也提供更为友好的操作体验。比如以太链上的数据服务商，搭建他们的索引节点，还是用比较原生的办法，需要索引节点创建者本身通过 Remix 去手工执行合约。对技术人员的要求也比较高，体验不便捷，HyperGraph可以直接用SDK、API DApp的方式提供服务，无论有无技术背景，均可以使用自己合适的方式实现。


# 跨链支持

HyperGraph 全面升级，已正式开放接受 HECO 和 BSC 公链的项目合作。

项目可以根据官网HG.network的产品使用帮助文档，自主提交子图进行索引与数据查询。据悉 HyperGraph 的数据处理效率是同类产品的四倍，并且也将在技术研发方面，推进索引节点网络的同时，支持更多基于 EVM 的公链。目前，HyperGraph已服务于HECO、BSC公链的Mdex、Dodoex 等项目。


# 常用合约地址

### 一、Heco

1、HyperGraph Token Token 合约：[0xfD6cE15009D46c6327649218431E8643F82f6D64](https://hecoinfo.com/address/0xfD6cE15009D46c6327649218431E8643F82f6D64)

2、HyperGraph Miner 挖矿合约地址：[0xcdb573643ae82607981bf3ab4ac22fe8c0916440](https://hecoinfo.com/address/0xcdb573643ae82607981bf3ab4ac22fe8c0916440)

3、市场运营份额时间锁合约地址：[0x4480a77c33a20e1df907539a5245a5e1f4624099](https://hecoinfo.com/address/0x4480a77c33a20e1df907539a5245a5e1f4624099)

4、MDEX.com HGT-HUSD 矿池合约： [0x2d13e46d212d6aeb0c92ced4fb3d63f022132dcc](https://hecoinfo.com/address/0x2d13e46d212d6aeb0c92ced4fb3d63f022132dcc)

5、MDEX.com HGT-HT 矿池合约： [0x3d4ee5cea06a3db84300ed09eea5aac54f60523b](https://hecoinfo.com/address/0x3d4ee5cea06a3db84300ed09eea5aac54f60523b)

6、MDEX.com HGT-USDT 矿池合约： [0x48498be1bc4d3253334a375402311d364beba032](https://hecoinfo.com/address/0x48498be1bc4d3253334a375402311d364beba032)

### 二、BSC

1、HyperGraph Token Token 合约：[0x680052792714e10e1ef7cda551abca8667862053](https://bscscan.com/address/0x680052792714e10e1ef7cda551abca8667862053)

2、HyperGraph Miner 挖矿合约地址：[0x508f8b9a8d39592c84fa0c22a77dc6c61202938b](https://bscscan.com/address/0x508f8b9a8d39592c84fa0c22a77dc6c61202938b)

3、市场运营份额时间锁合约地址：[0x1f3d1e513476a950210db0f2986bdf2f4c67b78a](https://bscscan.com/address/0x1f3d1e513476a950210db0f2986bdf2f4c67b78a)

4、MDEX.com HGT-USDT  矿池合约： [0x01718ba7146645118895972eb7f4fa951a5a8fb0](https://bscscan.com/address/0x01718ba7146645118895972eb7f4fa951a5a8fb0)

5、MDEX.com HGT-BNB 矿池合约： [0xbd89f446a05bc7cb886e7ecbd3860bc8f3d6f9b9](https://bscscan.com/address/0xbd89f446a05bc7cb886e7ecbd3860bc8f3d6f9b9)

6、MDEX.com HGT-BTCB 矿池合约： [0xfcd78cd53db6d3e2fdb18c7d482c5377ba3f15b0](https://bscscan.com/address/0xfcd78cd53db6d3e2fdb18c7d482c5377ba3f15b0)

7、DodoEx HGT-BUSD 矿池合约： [0x256b502d4d5503ad57f6d4a5dd09cc239251c420](https://bscscan.com/address/0x256b502d4d5503ad57f6d4a5dd09cc239251c420)

8、DodoEx.io HGT-ETH 矿池合约： [0x9d70e383ff5a1afbb58428fc999bf2bc5eb78112](https://bscscan.com/address/0x9d70e383ff5a1afbb58428fc999bf2bc5eb78112)


# 通证分配

## 1、通证应用

HyperGraph治理通证 HGT，发行在火币生态链上，总量上限10亿，实际流通不超过5亿。HyperGraph服务高性能区块链数据索引与后端服务，HGT则用于服务网络中的节点抵押、服务使用、平台激励等方面，以确保整个网络的资源分配、服务质量、数据完整性、参与者积极性等。

## 2、通证分配

**A、零预挖**

HGT 通证没有预挖，从零开始流通。分配比例如图7所示：

![](/files/-MYh8GcfSfLIz4cnFRqI)

图7、通证分配比例

1. **市场推广与社区运营（5000万）**

初始发行5000万枚，初始流通50万枚，其中40万用于初始流动性，余下10万枚HGT用作社区推广空投奖励之用，持有HT和MDX的前5000名，各获得10 HGT 空投。

余下线性解锁的4950万枚锁仓于智能合约，990天线性解锁完成，用于HyperGraph网络建设质押奖励、社区活动、市场推广与运营等。

C、**挖矿发行（2.5亿）**

2.5亿枚不做初始发行，均为分期挖矿产出，首期挖矿100天，每区块10枚，总产出28800000枚。

**D、机构节点（5亿）**

5亿HGT初始发行后销毁，同时发行5亿XHGT，使用智能合约锁定，只作为机构节点锁仓抵押之用，不参与流通。机构节点是知名机构和可以为HyperGraph做出重要贡献的社区节点。

**E、早期投资人（1亿）**

1亿枚为早期投资人份额，不做初始发行，伴随挖矿活动同比例发行，首期100天挖矿解锁11520000枚。为了保证社区的信心，早期投资人在挖矿期间不解锁，每期挖矿结束之后，将随挖矿解锁的额度再注入1000天时间锁线性解锁。

**F、开发者团队（1亿）**

1亿枚为开发者团队激励份额，不做初始发行，伴随挖矿活动同比例发行，首期100天挖矿解锁11520000枚。为了保证社区的信心，开发者团队在挖矿期间不解锁，每期挖矿结束之后，将随挖矿解锁的额度再注入1000天时间锁线性解锁。

## 3、销毁与通缩

索引节点、矿工均需要质押HGT保证整个网络运行和获得收益，每次质押额的0.5%将永久销毁。数据用户需要支付HGT以用于数据查询消费，消费流水额度的1%将永久销毁。

## 4、用量预估

每个索引节点需要初始抵押10万HGT，要想获得优先使用推荐，抵押额、历史查询量等都是重要的参考指标，假设：

平均自有抵押额度为100万HGT，共100个节点，则总量为1亿HGT。

假设矿工参与押的平均额度为2万枚，5000用户参与，总量共需1亿HGT。

每年质押流水为4亿HGT，对应销毁量为200万。

每年查询流水为20亿枚HGT，对应销毁量为2000万。


# HyperGraph 审计报告

[HyperGraph Token 及币发行解锁审计报告](https://hgt.static.kingco.tech/HGraphToken-AuditReport-ChainsGuard-CN-%20V20210321.pdf)（中文）

[HyperGraph Miner 挖矿合约审计报告](https://hgt.static.kingco.tech/HGTMiner-AuditReport-ChainsGuard-CN-%20V20210321.pdf)（中文）

[HyperGraph Token Security Audit Report](https://hgt.static.kingco.tech/HGraphToken-AuditReport-ChainsGuard-EN-%20V20210321.pdf)（English）

[HyperGraph Miner Security Audit Report](https://hgt.static.kingco.tech/HGTMiner-AuditReport-ChainsGuard-EN-%20V20210321.pdf) （English）


# DApp开发基础认识

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

### 0. 基础认识

* 以太坊是什么？

以太坊被称为“世界计算机”， 全世界上千个节点， 具备“图灵完备”的特性，可以永久运行下去。 以太坊可以看作是“全球共享的**不可篡改**的**单线程**的**事务性**数据库” 。

* 不可篡改性

* 基于区块链特性，上千个节点共同确认，被记录到链上的信息将不可篡改，使得价值可以在互联网上传播。

* 单线程性

* 不会出现双花，在同时发出的交易中，必然会有一个交易会失败， 每次交易会有个nonce参数来避免重复交流。

* 事务性

* 每次交易出现异常，会回滚到初始状态， 即使一次交易执行了多个合约，前面的合约执行没有异常，后面合约有异常也会让前面的合约操作回滚。

* 钱包是什么？

* 钱包是管理私钥的，并没有存数字货币，数字货币是存在区块链上的， 私钥是最重要的， 私钥可以生成公钥，公钥可以生产账号地址。 Dapp开发会和钱包交互，Dapp并不会自己拿用户的私钥做加密操作，而是Dapp调用钱包，钱包加密后返回给Dapp。

* 智能合约的机制

* 智能合约也是一个以太坊账号，这个账号只有账户地址，没有私钥。

* 创建智能合约实际是向地址为0的账号发起一次交易。 交易中data参数是合约的二进制代码数据。 交易完成后会返回智能合约地址。

* 调用智能合约的方法实际是向智能合约地址发起交易。交易中data参数告诉了以太坊EVM要执行什么函数和函数的传参。

* 交易过程传参。

* nonce： 一个序列号编码，以账号的交易数作为这个值，是为了防止重放攻击。 以太坊是用交易随机数nonce按顺序确认的， nonce是交易账号的交易量，每次唯一，递增。

* gas price ： gas 是交易的燃料，燃料必须用以太坊购买，gas price定义了愿意支付的gas单价， 价格越高会执行越快，平均价格是节点决定的， 他的单位是wei， 1ETH=10\*\*18wei 。 之所以有gas是为了防止DDOS攻击。让每次交易都是有成本的。

* gas limit： 交易发起者最多支付多少gas， 如果到达这个数没有完成交易，会回滚，但消耗的gas不会返回。 汇款交易的gas是固定的21000个， 但是智能合约执行不是固定的。

* value ： 往交易地址发送的以太坊数量。 如果给0地址发送带value不带data的数据时，实际是摧毁币。

* data ： 附在交易的可编程的数据， 智能合约的创建和调用会用到这个data参数。

* v,r,s ： 签名相关的三个字段。 签名中会将链ID(chain\_id)作为带入到签名，为了防止跨链重放攻击。 以太主网链ID是1 ， Ropsten测试网链ID是3 ， 火币正式链ID是128， 火币测试链ID是256，币安ID是56， 本地测试网ID是1337


# 开发前的准备

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

**安装MetaMask浏览器钱包**

Chrome浏览器上的钱包插件 <https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=zh-CN>

MetaMask是浏览器钱包， 用它可以进行开发测试。 在网页需要钱包签名时，MetaMask可以弹出进行签名。 MetaMask是开发以太坊必备的。

安装好的界面：

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

点击中间下拉列表，可以切换网络， 点击头像可以切换账号。

**切换到以太坊测试链**

Rosten是一个以太坊的测试链， 在测试链是使用测试币进行合约部署，测试币有免费领取的地方，不会产生真实的费用。

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

**水龙头下领取测试币**

<https://faucet.ropsten.be/> 访问这个地址输入你MetaMask钱包的账户地址。 即可提取1ETH的测试币。

MetaMask钱包界面上也可以直接领取ropsten的测试币。

路径：&#x20;

资产 -> ETH > 购买 -> 从水龙头领取测试币


# 基础开发环境

***本教程是技术大牛 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配置文件中的实例代码是老版本用户。


# Web3与Solidity基础

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

### 1、web3的基础使用

web3.js 是以太坊官方发布的与以太坊交互的js库。

上面示例中已经有初步接触， 我们可以在VUE中使用web3 也可以在truffle控制台使用web3进行代码调试。

下面说下web3的常用方法：

* 获得账户

&#x20;web3.eth.getAccounts()

* 查看余额

web3.eth.getBalance("accountAddress")

* 账户转账

web3.eth.sendTransaction({from:"fromaddress",to:"toaddress",value:1000})

还有跟交易相关的gas , nonce等参数， 都会自动生成或者也可以指定覆盖。

* 单位转换

web3.utils.toWei("1","ether"); //将1ETH转换为wei单位

web3.utils.fromWei("20000000000","ether");//将wei单位转换为ETH

web3.utils.toBN("123");

* 获得协议版本

web3.eth.getProtocolVersion()

* 获得当前gas价格

web3.eth.getGasPrice()

* 获得交易数量

web3.eth.getTransactionCount("address")

* 预估执行合约要的gas数量

instance.functionName.estimateGas(args)

这里instance是truffle的合约对象。传参args 是functionName的传参。

### 2、solidity的基础使用

solidity是编写智能合约的编程语言，solidity代码通过编译器编译为EVM字节码， 以太坊区块上有个EVM虚拟机机制可以执行EVM的字节码。

上面在部署水龙头合约时已经初步接触了solidity，这一小节详细讲解一下solidity。

#### 2.1合约结构

定义一个简单的合约

// SPDX-License-Identifier: GPL-3.0

pragma solidity >0.7.0 <0.8.0;

contract Mytest {

&#x20;   uint storednumber=0;&#x20;

&#x20;   address payable owner;

&#x20;   event LogNumber(uint storednumber);

&#x20;   constructor(){

&#x20;       owner=msg.sender;

&#x20;   }

&#x20;   function test(uint number) public payable {

&#x20;       storednumber=helper(number);

&#x20;       emit LogNumber(storednumber);

&#x20;   }

&#x20;   function destory() public {

&#x20;       require(msg.sender == owner);

&#x20;       selfdestruct(owner);

&#x20;   }

}

function helper(uint x) pure returns (uint) {

&#x20;   return x \* 2;

}

第一行是声明开源协议

第二行声明代码适合的编译器版本

第三行contract关键词定义合约

合约中可以包括：状态变量， 函数， 事件。

#### 2.2状态变量

状态变量是永久地存储在合约存储中的值， 我们可以把合约理解成为一个单例的程序，constructor 构造函数只会在第一次合约创建时调用，所以合约中定义的变量就像单例对象的属于一样，值会全局一直保存。一般在构造函数中存储合约的创建者地址，方便合约后期做一些只能创建者操作的权限判断。

变量的数据类型有：

* 布尔值bool，值为true或false
* 整数型int， uint（无符合），声明长度，以8比特为单位， int8到uint256 ,如果没有定义长度，默认是256
* 浮点数fixed ，ufixed , 定义方式(ufixedMxN), M是整数的比特位数，N是小数位数
* 地址address， address有成员函数balance，transfer等 ， 地址类型要能支付需要在定义时用payable修饰或者在使用时用payable函数转换
* 字节数组（固定）， bytes1 到 bytes32， 一个英文字母会占一个byte
* 字节数组（动态） bytes， string , 字符串没有直接支持中文。 中文要utf8编码后才能赋值给变量。
  * 字符串拼接， 没有直接拼接的方法， 需要封装一个函数：

function  strConcat(string memory \_a, string memory \_b) internal pure returns (string memory){

&#x20;       bytes memory \_ba = bytes(\_a);

&#x20;       bytes memory \_bb = bytes(\_b);

&#x20;       string memory ret = new string(\_ba.length + \_bb.length);

&#x20;       bytes memory bret = bytes(ret);

&#x20;       uint k = 0;

&#x20;       for (uint i = 0; i < \_ba.length; i++) bret\[k++] = \_ba\[i];

&#x20;       for (uint i = 0; i < \_bb.length; i++) bret\[k++] = \_bb\[i];

&#x20;       return string(ret);

}

* 枚举类型 enum Name {Labe1,labe2}
* 数组 ，如unit32\[]\[5]
  * 数组的添加
    * arrayName.push() ; 添加数组
  * 数组的删除
    * delete arrayName\[1]; ,这个是清空值: 数字为变为0，地址会变为0地址，位置还存在，需要手动移动位置，如：

uint\[] array = \[1,2,3,4,5];

uint index=3;

delete array\[index];

for (uint i = index; i\<array.length-1; i++){

&#x20;array\[i] = array\[i+1];

}

array.pop();//删除最后一个函数

网上有文章讲array.length--改变长度的，0.6后不支持array.length-- 改变长度，需要array.pop 删除最后一个元素。

注意和js语言的pop函数不同的是，这里不会返回最后一个元素，也不能传参制定索引。

* * 数组的遍历

for(uint i=0;i\<arr.length;i++){

&#x20;arr\[i]; //获得数组的值

}

arr.length是属于uint类型的。

数组中的值只能是标量，不能为复杂的struct结构， 可以结合映射实现复杂的例子，这个例子可以学习一下： <https://ethereum.stackexchange.com/questions/12611/solidity-filling-a-struct-array-containing-itself-an-array/12614>

* 结构：struct NAME{TYPE1 NAME1; TYPE2 NAME2}
* 映射： mapping(KEYTYPE => VALUETYPE) NAME;
* 变量修饰符 memory、storage、calldata。

&#x20;状态变量会强制为storage类型， 外部传参的参数默认会为calldata类型。 calldata类型只能只读。 memory类型是内存临时变量，执行完后就会被释放， 一般函数类定义的变量会为memory类型的。

#### 2.3函数

形式： function FunctionName(\[parameters]) {public|external|private|internal} \[pure|constant|view|playable] \[modifiers] \[returns (return types)]

下面对各部分说明一下。

* 可见性说明

solidity函数的可见性定义在函数名之后，且是必须定义的。

* * public 内部外部都可以调用
  * external 外部可调用，内部要用this调用 , external比public更省gas
  * internal 只能合约内部调用，子类也可以调用
  * private 只能合约内部调用，子类不能调用
* 函数行为声明
  * view , 声明不会改变区块链状态（修改状态变量），只会读取状态变量，可以return 返回数据
  * prue， 声明不会改变区块链状态，也不读取状态变量，只处理计算就返回结果。
  * payable， 接受支付以太坊。
  * 不声明，表示non-payable 类型，表示会改变区块链状态但不支持支付。

注：view 和 prue 是不会产生gas费用的，因为他不用旷工确认，多声明view或prue，这是在省钱。

* 函数修饰符modifier

contract Mytest {

&#x20;event printString(string s);

&#x20;modifier onlyOwner{

&#x20;        require(msg.sender == owner);

&#x20;        \_;

&#x20;        emit printString("runing");

&#x20;    }

&#x20; function testmodifer() public onlyOwner{

&#x20;       emit printString("body");

&#x20; }

}

函数修饰符常用于验证条件的封装，下划线"\_" 表示要替换代码的body部分。

#### 2.4事件

用event声明，用emit触发，会记录到区块链的交易日志中，参数可以添加indexed关键词作为索引查询web3可以查询

event Withdrawal(adress indexed to,uint amount);

....

emit Withdrawal(msg.sender,123);

我们经常也会用事件来调试， 事件日志在合约调用也是会显示在remix控制台的。

#### 2.5错误处理

* require , 不符合条件就会抛出异常， 第二个参数可以写错误原因

require(msg.sender==owner,"Only the contract owner can call this function");

* revert ,支持抛出异常和输出错误信息

if(msg.sender!=owner){

&#x20;revert("Only the contract owner can call this function");

}

#### 2.6全局变量

* msg对象
  * msg.sender 调用者地址，可以是外部账户也可以是合约账户（合约之间可以互相调用）
  * msg.value 以太坊数量，单位wei
  * msg.gas 新版是用gasleft()函数获得要剩余的gas。
  * msg.data 传入的数据 bytes类型
  * msg.sig 签名, 类型是bytes4，其实是函数选择器的字符，EVM通过这个知道执行那个函数。
* tx对象， 交易相关信息
  * tx.gasprice 交易价格。
  * tx.origin 交易发起的外部账户。
* block区块对象
  * blockhash(blockNumber)函数，指定区块ID返回区块hash，类型是bytes32;
  * block.coinbase 矿工地址
  * block.difficulty 当前区块正明难度
  * block.gaslimit ， 当前区块花费的最大gas
  * block.number , 当前区块编号
  * block.timestamp , 当前区块写入的时间戳
* address，地址对象
  * address.balance 余额
  * address.transfter(number) 向这个地址转账
  * address.send(number) 与transfter 类似， 出错是不会抛出异常，会返回false
  * call/callcode/delegatecall 调用合约

&#x20;这几个方法都是比较旧的方式， 新方式可以把合约对象作为传参，然后显性调用， 如：

contract Mybase{

&#x20;   function run() public pure returns(string memory){

&#x20;       return "test";

&#x20;   }

}

contract Mytest {

&#x20;event printString(string  s);

&#x20;function testcall(Mybase my) public {

&#x20;       emit printString("run start");

&#x20;       string memory s = my.run();

&#x20;       emit printString(s);

&#x20;       emit printString("run end");

&#x20;   }

}

这my这个参数在调用的时候传递合约地址。 其实这个合约地址下只要有run方法就行。EVM是无法识别合约是不是属于Mybase的。

#### 2.7接口和库

接口

interface InterfaceBase {

&#x20;   //抽象方法

&#x20;   function brand() external  returns (bytes32);

}

contract MyContract is InterfaceBase{

&#x20;   function brand()  external override pure  returns (bytes32){

&#x20;       return '123';

&#x20;   }

}

接口定义的方法要用external不能用public

实现接口的方法要用override修饰

solidity 是用is实现继承的， is可以跟多个类来继承

库：

library  Lib {

&#x20;   function test(string memory s) external pure returns(string memory){

&#x20;       return s;

&#x20;   }

}

contract MyContract {

&#x20;   function run()  external pure{

&#x20;       Lib.test("xxx"); //调用库的方法

&#x20;   }

}

#### 2.8导入文件

父类或库独立成单独的文件方便代码管理，然后可以用import导入。

比如独立 lib.sol 文件

导入：

import "./lib.sol";

这样导入文件中所有类会被导入， 为了防止有名称冲突可以：

import \* as lib from "./lib.sol"

也可以自定导入文件中的几个对象

import {Lib,InterfaceBase} from "./lib.sol"

solidity的导入语法是遵循ES6规范的。

#### 2.9让合约可以接受支付

合约中加入如下代码：

event Received(address, uint);

receive() external payable {

&#x20;emit Received(msg.sender, msg.value);

}

#### 2.10合约被调用到不存在的方法的处理

fallback() external {

&#x20;//处理代码

}

可以接受calldata直接调用：

#### 2.11合约摧毁

调用函数 selfdestrunct 可以摧毁合约， 摧毁时会把合约的余额打入到函数指定的地址，并奖励gas， 这个机制是激励开发回收不用的合约，虽然合约摧毁了，但是交易记录依然永久存在区块链上。

如：

// SPDX-License-Identifier: GPL-3.0

pragma solidity >0.7.0 <0.8.0;

contract Mytest {

&#x20;address payable owner;

&#x20;constructor(){

&#x20;owner=msg.sender;

&#x20;}

&#x20;function destory() public {

&#x20;require(msg.sender == owner);

&#x20;selfdestruct(owner);

&#x20;}

}

调用合约的destory方法就可以摧毁合约。 摧毁的是合约的代码的并不会摧毁合约地址。 所以看见的现象会是，合约还能调用，而且还能往合约地址打以太坊， 合约地址成为了黑户，如果往里面打以太坊将取不回。 所以摧毁合同是危险的，还是不要轻易摧毁。

更多学习，看文档： <https://learnblockchain.cn/docs/solidity/index.html>


# ERC720 开发实例

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

**ERC20代币**

ERC20是以太坊流行的代币协议，ERC20名称的由来是：以太坊有个需求提案的地方叫ERC，GitHub自动分配20的编号，所以大家习惯叫ERC20

协议结构：

// ----------------------------------------------------------------------------

// ERC Token Standard #20 Interface

// <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md>

// ----------------------------------------------------------------------------

contract ERC20Interface {

&#x20;//总发行量

&#x20;function totalSupply() public constant returns (uint);

&#x20;//账户余额

&#x20;function balanceOf(address tokenOwner) public constant returns (uint balance);

&#x20;//配额带支付， 一般是设置合约地址待支付的权限

&#x20;function allowance(address tokenOwner, address spender) public constant returns (uint remaining);

&#x20;//转账

&#x20;function transfer(address to, uint tokens) public returns (bool success);

&#x20;//审批， 设置合约地址的allowance配额数量

&#x20;function approve(address spender, uint tokens) public returns (bool success);

&#x20;//从其他账户转账，通常与approve一起用

&#x20;function transferFrom(address from, address to, uint tokens) public returns (bool success);

&#x20;//转账事件

&#x20;event Transfer(address indexed from, address indexed to, uint tokens);

&#x20;//审批事件

&#x20;event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

}

合约中实际是有两个mapping来记录余额和配合的

mapping(adress => uint256) balances; //记录地址有多少代币余额

mapping(address => mapping(address => unit256)) public allowed;//记录配额

转账有两个方法

* transfer， 是当前用户（msg.sender） 转账给指定地址， 改变的是balances的状态结构。
* transferFrom，是from参数地址向to参数地址转账， from不一定是msg.sender ，所以需要from地址向授权给合约地址配额， 合约地址才能实现转账。 设置配额改变的是allowed状态，这个是个二级结构，第一级的address是对应了转出账号地址（from） ， 第二级的address对应的是智能合约地址，被授权的智能合约才能转账，等会儿会做个水龙头的合约作为演示。

实现合约可以借助 openzeppelin ， 它已经封装好了父类， 子类继承它即可

新建一个项目：

truffle init

安装依赖：

yarn add  @openzeppelin/contracts

创建合约： contracts/MTK.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MTK is ERC20 {

&#x20;//发行一个币的名称叫MyToken， 简称MTK

&#x20;constructor() ERC20("MyToken", "MTK") {

&#x20;\_mint(msg.sender, 1000);//发现总量,TODO还没有找到怎么设置小数位数

&#x20;}

}

先用remix调试， 这时候因为import导入多文件， 不方便把代码复制到remix上调试。 所以要建立remix的本地服务，让remix调试本地文件

安装remixd

npm install -g @remix-project/remixd

在项目根目录下启动服务：

sudo remixd -s \`pwd\` --remix-ide <https://remix.ethereum.org>

此时在remix文件的wordspaces选择为localhost即可。

编译和部署好合约后，可以用remix界面调试合约函数：

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

下面重点说一下用truflle console 命令行调试合约。

在migrate文件夹下建立2\_MTK.js文件：

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

module.exports = function (deployer) {

&#x20; deployer.deploy(MTK);

};

编辑truffle-config.js 修改编译器版本为 0.8.4

编译：truffle compile , 并部署合约 truffle migrate

进入命令行：

truflle console

\>MTK.address //获得部署合约地址

\>let instance=await MTK.deployed() //获得合约实例

\>let accounts = await web3.eth.getAccounts() //获得账户

\>instance.totalSupply() //获得总发行量

\>instance.balanceOf(accounts\[0]) //获得账户余额

\>instance.transfer(accounts\[1],web3.utils.toBN(100)) //向第二个账户打100MTK

\>instance.balanceOf(accounts\[0]) //获得第二个账户余额

下面在说下建立MTK的水龙头合约，演示approve和transferFrom的使用。

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./MTK.sol";

contract MTKFaucet {

&#x20;   MTK public MTKInstance;

&#x20;   address public MTKOwner;

&#x20;   constructor(MTK \_MTKInstance, address \_MTKOwner)  {

&#x20;       MTKInstance=\_MTKInstance;

&#x20;       MTKOwner=\_MTKOwner;

&#x20;   }

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

&#x20;       require(withdraw\_amount<=1000);

&#x20;       MTKInstance.transferFrom(MTKOwner,msg.sender,withdraw\_amount);

&#x20;   }

}

创建上面合约时需要传递已经部署好的MTK合约地址和部署账户的地址。

建立migrate/3\_MTKFaucet.js文件

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

const MTK = artifacts.require("MTK");//前一步MTK已经部署好，这里可以用MTK.address获得部署地址

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

&#x20; deployer.deploy(MTKFaucet,MTK.address,accounts\[0]);

};

调试MTKFaucet合约：

truffle console

\>let instance=await MTKFaucet.deployed()

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

\>instance.withdraw(1,{from:accounts\[1]}) //这会报错 revert ERC20: transfer amount exceeds allowance ， 是因为没有分配限额

\>let MTKInstance=await MTK.deployed()

\>MTKInstance.approve(MTKFaucet.address,10) //对合约分配限额为10

\>instance.withdraw(1,{from:accounts\[1]}) //这时候管用了

\>MTKFaucetInstances.withdraw(11,{from:accounts\[1]}) //超过限额还会报错

代币的转账和以太坊的转账是有区别的， 太坊的转账是改变的目标地址的状态。 而代币的转账是改变的合约的状态。

大多数交易所的账号地址是合约地址， 要判断交易所合约是否支持代币，如果向不支持代币的合约转账代币， 这个代币将永远卡住取不出来。

PS: ERC721就是NFT的协议。<https://docs.openzeppelin.com/contracts/4.x/erc721>


# 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钱包创建账号时选择导入私钥。


