AssemblyScript API
Reading time: 28 min
注意:如果您在 graph-cli
/graph-ts
版本 0.22.0
之前创建了子图,那么您正在使用较旧版本的 AssemblyScript,我们建议查看迁移指南
。
此页面记录了编写子图映射时可以使用的内置 API。有两种开箱即用的 API:
- Graph TypeScript库 (
graph-ts
) 和 - 通过
graph codegen
生成的子图文件中的代码。
也可以添加其他库作为依赖项,只要它们与AssemblyScript兼容即可。由于这是语言映射所写的,因此AssemblyScript wiki是语言和标准库特性的良好来源。
@graphprotocol/graph-ts 库提供以下 API:
- 用于处理以太坊智能合约、事件、区块、交易和以太坊价值的以太坊 API。
- 用于与图形节点交互,存储和加载实体的 存储 API。
- 用于将消息记录Graph节点输出和Graph浏览器的log API。
- 用于从 IPFS 加载文件的ipfs API。
- 用于解析 JSON 数据的json API。
- 使用加密功能的crypto API。
- 用于在不同类型系统(例如 Ethereum、JSON、GraphQL 和 AssemblyScript)之间进行转换的低级原语。
子图清单中的 apiVersion
指定了由 Graph Node 运行的特定子图的映射 API 版本。
版本 | Release 说明 |
---|---|
0.0.7 | 添加了 TransactionReceipt 和 Log 类到以太坊类型。已将 receipt 字段添加到Ethereum Event对象。 |
0.0.6 | 向Ethereum Transaction对象添加了 nonce 字段 向 Etherum Block对象添加 baseFeePerGas字段 |
0.0.5 | AssemblyScript 升级到版本 0.19.10(这包括重大更改,参阅 迁移指南)ethereum.transaction.gasUsed 重命名为 ethereum.transaction.gasLimit |
0.0.4 | 已向 Ethereum SmartContractCall对象添加了 functionSignature 字段。 |
0.0.3 | 已向Ethereum Call 对象添加了 from 字段。etherem.call.address 被重命名为 ethereum.call.to 。 |
0.0.2 | 已向Ethereum Transaction对象添加了 input 字段。 |
关于内置于 AssemblyScript 中的基本类型的文档可以在AssemblyScript wiki中找到。
以下额外的类型由 @graphprotocol/graph-ts
提供。
从'@graphprotocol/graph-ts'导入{ ByteArray }
ByteArray
表示一个 u8
类型的数组。
结构
fromI32(x: i32): ByteArray
- 将x
分解为字节。fromHexString(hex: string): ByteArray
- 输入长度必须是偶数。在十六进制字符串中添加0x
前缀是可选的。
类型转换
toHexString(): string
- 转换为以0x
前缀的十六进制字符串。toString(): string
- 将字节解释为 UTF-8 字符串。toBase58(): string
- 将字节编码为 base58 字符串。toU32(): u32
- 将字节解释为小端u32
。在溢出的情况下会抛出异常。toI32(): i32
- 将字节数组解释为小端i32
。在溢出的情况下会抛出异常。
操作符
equals(y: ByteArray): bool
– 可以写成x == y
。concat(other: ByteArray) : ByteArray
- 返回一个新的ByteArray
,由this
直接跟随other
构成。concatI32(other: i32) : ByteArray
- 返回一个新的ByteArray
,由this
直接跟随other
的字节表示构成。
从“@Graphprotocol/graph-ts”导入{ BigDecimal }
BigDecimal 用于表示任意精度的小数。
注意:内部 BigDecimal
存储在IEEE-754 十进制128位浮点格式中,支持34位十进制数字的有效位数。这使得 BigDecimal
不适合表示超过34位数字的固定点类型,比如 Solidity 中的 ufixed256x18
或相当类型。
结构
constructor(bigInt: BigInt)
– 从一个BigInt
创建一个BigDecimal
。static fromString(s: string): BigDecimal
– 从一个十进制字符串解析。
类型转换
- toString (): string - 打印为十进制字符串。
数学方法
plus(y: BigDecimal): BigDecimal
– 可以写成x + y
。minus(y: BigDecimal): BigDecimal
– 可以写成x - y
。times(y: BigDecimal): BigDecimal
– 可以写成x * y
。div(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
。
从'@graphprotocol/graph-ts'导入{ BigInt }
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
– 将 bytes 解释为无符号的小端整数。如果你的输入是大端的,请先调用.reverse()。 -
BigInt.fromSignedBytes(x: Bytes): BigInt
– 将 bytes 解释为有符号的小端整数。如果你的输入是大端的,请先调用.reverse()。类型转换
-
x.toHex(): string
– 将 BigInt 转换为十六进制字符的字符串。 -
x.toString(): string
– 将 BigInt 转换为十进制数字字符串。 -
x.toI32(): i32
– 将 BigInt 作为 i32 返回;如果值不适合 i32,则失败。最好先检查 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.div(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, bits: u8): BigInt
– 可以写成x << y
.rightShift(x: BigInt, bits: u8): BigInt
– 可以写成x >> y
.
从'@graphprotocol/graph-ts'导入{ TypedMap }
TypedMap
可用于存储键值对。请参阅此示例。
TypedMap 类具有以下 API:
new TypedMap<K, V>()
- 创建一个键类型为K
,值类型为V
的空映射。map.set(key: K, value: V): void
– 将key
的值设置为value
。map.getEntry(key: K): TypedMapEntry<K, V> | null
– 返回键为key
的键值对,如果映射中不存在该键,则返回null
。map.get(key: K): V | null
– 返回键为key
的值,如果映射中不存在该键,则返回null
。map.isSet(key: K): bool
– 如果映射中存在key
则返回true
,否则返回false
。
从 '@graphprotocol/graph-ts'导入{ Bytes }
字节用于表示任意长度的字节数组,包括字节类型的以太坊值、 bytes32等。
Bytes
类扩展了 AssemblyScript 的 Uint8Array,支持所有 Uint8Array
的功能,以及以下新方法:
结构
fromHexString(hex: string): Bytes
- 将字符串hex
转换为一个ByteArray
。字符串hex
必须由偶数个十六进制数字组成,并且可选地以0x
开头。fromI32(i: i32): Bytes
- 将i
转换为一个字节数组。
类型转换
b.toHex()
– 返回表示数组中字节的十六进制字符串。b.toString()
– 将数组中的字节转换为 Unicode 字符串。b.toBase58()
– 将以太坊的字节数值转换为 base58 编码(用于 IPFS 哈希)。
操作符
b.concat(other: Bytes): Bytes
- 返回一个新的Bytes
,由this
直接跟随other
组成。b.concatI32(other: i32): ByteArray
- 返回一个新的Bytes
,由this
直接跟随other
的字节表示组成。
从 '@graphprotocol/graph-ts'导入{ Address }
Address
扩展了 Bytes
,用于表示以太坊的 address
值。
除了 Bytes
API 之外,它还添加了以下方法:
Address.fromString(s: string): Address
– 从十六进制字符串创建一个Address
。Address.fromBytes(b: Bytes): Address
– 从b
创建一个Address
,b
必须恰好为 20 个字节长。传入长度不足或超过 20 字节的值将导致错误。
从 '@graphprotocol/graph-ts'导入 { store }
store
API 允许从和到 Graph Node 存储加载、保存和删除实体。
写入存储的实体与子图的 GraphQL 模式中定义的 @entity
类型一一对应。为了方便处理这些实体,由 Graph CLI 提供的 graph codegen
命令会生成实体类,这些类是内置 Entity
类的子类,具有模式中字段的属性 getter 和 setter,以及加载和保存这些实体的方法。
以下是从以太坊事件创建实体的常见模式。
/ Import the Transfer event class generated from the ERC20 ABIimport { Transfer as TransferEvent } from '../generated/ERC20/ERC20'// Import the Transfer entity type generated from the GraphQL schemaimport { Transfer } from '../generated/schema'// Transfer event handlerexport function handleTransfer(event: TransferEvent): void {// Create a Transfer entity, using the transaction hash as the entity IDlet id = event.transaction.hashlet transfer = new Transfer(id)// Set properties on the entity, using the event parameterstransfer.from = event.params.fromtransfer.to = event.params.totransfer.amount = event.params.amount// Save the entity to the storetransfer.save()}
如果在处理链时遇到 Transfer 事件,它会使用生成的 Transfer 类型(别名为 TransferEvent 以避免与实体类型的命名冲突) 传递给 handleTransfer 事件处理器。 此类型允许访问事件的母交易及其参数等数据。
每个实体都必须有一个唯一的 ID 以避免与其他实体发生冲突。 事件参数包含可以使用的唯一标识符是相当常见的。 注意:使用交易hash作为 ID 时, 假定同一交易中没有其他事件创建以该hash作为 ID 的实体。
如果实体已经存在,则可以使用以下内容从存储中加载它:
let id = event.transaction.hash // or however the ID is constructedlet transfer = Transfer.load(id)if (transfer == null) {transfer = new Transfer(id)}// Use the Transfer entity as before
由于实体可能尚未存在于存储中,因此 load
方法返回一个类型为 Transfer | null
的值。因此,在使用该值之前可能需要检查 null
情况。
注意: 只有在映射中的更改依赖于实体的先前数据时,加载实体才是必要的。请参阅下一节,了解更新现有实体的两种方法。
截至 graph-node
v0.31.0、@graphprotocol/graph-ts
v0.30.0 和 @graphprotocol/graph-cli
v0.49.0,所有实体类型上都提供了 loadInBlock
方法。
存储API有助于检索在当前区块中创建或更新的实体。这方面的一种典型情况是,一个处理程序从某个链上事件创建一个,之交易后的处理程序希望访问该交易(如果存在)。在交易不存在的情况下,子图必须去数据库才能发现实体不存在;如果子图作者已经知道实体必须是在同一个区块中创建的,那么使用loadInBlock可以避免这种数据库往返。对于某些子图,这些遗漏的查找可能会显著增加索引时间。
let id = event.transaction.hash // or however the ID is constructedlet transfer = Transfer.loadInBlock(id)if (transfer == null) {transfer = new Transfer(id)}// Use the Transfer entity as before
注意: 如果在给定的区块中没有创建实体,则 loadInBlock
将返回 null
,即使存储中存在具有给定 ID 的实体也是如此。
在 graph-node
v0.31.0、@graphprotocol/graph-ts
v0.31.0 和 @graphprotocol/graph-cli
v0.51.0 中引入了 loadRelated
方法。
这允许从事件处理程序中加载派生实体字段。例如,给定以下模式:
type Token @entity {id: ID!holder: Holder!color: String}type Holder @entity {id: ID!tokens: [Token!]! @derivedFrom(field: "holder")}
以下代码将加载Holder实体来源的Token实体:
let holder = Holder.load('test-id')// 加载与给定持有人相关联的 Token 实体。let tokens = holder.tokens.load()
有两种方法可以更新现有实体:
- 利用 Transfer.load(id)加载实体,在实体上设置属性,然后调用.save() 将其返回到存储。
- 使用 new Transfer(id)创建实体,在实体上设置属性,然后调用.save()将其保存到存储。 如果实体已经存在,则将更改合并到其中。
由于生成的属性设置器,在大多数情况下更改属性是直截了当的:
let transfer = new Transfer(id)transfer.from = ...transfer.to = ...transfer.amount = ...
也可以使用以下两条指令之一取消设置属性:
transfer.from.unset()transfer.from = null
这只适用于可选属性,即在 GraphQL 中声明时没有使用 !
的属性。两个例子是 owner: Bytes
或 amount: BigInt
。
更新数组属性稍微复杂一些,因为从实体获取数组会创建该数组的副本。这意味着在更改数组后,必须显式地重新设置数组属性。以下假设 entity
有一个 numbers: [BigInt!]!
字段。
// This won't workentity.numbers.push(BigInt.fromI32(1))entity.save()// This will worklet numbers = entity.numbersnumbers.push(BigInt.fromI32(1))entity.numbers = numbersentity.save()
目前无法通过生成的类型来删除实体。相反,要删除实体,需要将实体类型的名称和实体ID传递给 store.remove
方法:
import { store } from '@graphprotocol/graph-ts'...let id = event.transaction.hashstore.remove('Transfer', id)
以太坊 API 提供对智能合约、公共状态变量、合约函数、事件、交易、区块和编码/解码以太坊数据的访问。
与实体一样,graph codegen
为子图中使用的所有智能合约和事件生成类。为此,合约 ABI 需要作为子图清单中数据源的一部分。通常,ABI 文件存储在一个名为 abis/
的文件夹中。
通过生成的类,以太坊类型和内置类型之间的转换在幕后进行,这样子图作者就不必担心它们。
以下示例说明了这一点。 给定一个子图模式,如
type Transfer @entity {from: Bytes!to: Bytes!amount: BigInt!}
对于以太坊上的 Transfer(address,address,uint256)
事件签名,类型为 address
、address
和 uint256
的 from
、to
和 amount
值被转换为 Address
和 BigInt
,从而允许它们传递给 Transfer
实体的 Bytes!
和 BigInt!
属性:
let id = event.transaction.hash.toHex()let transfer = new Transfer(id)transfer.from = event.params.fromtransfer.to = event.params.totransfer.amount = event.params.amounttransfer.save()
传递给事件处理程序的以太坊事件(例如前面示例中的 Transfer
事件)不仅提供对事件参数的访问,还提供对其父事务和它们所在的区块的访问。以下数据可以从 event
实例中获取(这些类是 graph-ts
中的 ethereum
模块的一部分):
class Event {address: AddresslogIndex: BigInttransactionLogIndex: BigIntlogType: string | nullblock: Blocktransaction: Transactionparameters: Array<EventParam>receipt: TransactionReceipt | null}class Block {hash: BytesparentHash: BytesunclesHash: Bytesauthor: AddressstateRoot: BytestransactionsRoot: BytesreceiptsRoot: Bytesnumber: BigIntgasUsed: BigIntgasLimit: BigInttimestamp: BigIntdifficulty: BigInttotalDifficulty: BigIntsize: BigInt | nullbaseFeePerGas: BigInt | null}class Transaction {hash: Bytesindex: BigIntfrom: Addressto: Address | nullvalue: BigIntgasLimit: BigIntgasPrice: BigIntinput: Bytesnonce: BigInt}class TransactionReceipt {transactionHash: BytestransactionIndex: BigIntblockHash: BytesblockNumber: BigIntcumulativeGasUsed: BigIntgasUsed: BigIntcontractAddress: Addresslogs: Array<Log>status: BigIntroot: ByteslogsBloom: Bytes}class Log {address: Addresstopics: Array<Bytes>data: BytesblockHash: BytesblockNumber: BytestransactionHash: BytestransactionIndex: BigIntlogIndex: BigInttransactionLogIndex: BigIntlogType: stringremoved: bool | null}
由 graph codegen
生成的代码还包括用于子图中使用的智能合约的类。这些类可以用于访问智能合约在当前区块上的公共状态变量和调用函数。
一种常见的模式是访问事件起源的合约。 这是通过以下代码实现的:
// Import the generated contract class and generated Transfer event classimport { ERC20Contract, Transfer as TransferEvent } from '../generated/ERC20Contract/ERC20Contract'// Import the generated entity classimport { Transfer } from '../generated/schema'export function handleTransfer(event: TransferEvent) {// Bind the contract to the address that emitted the eventlet contract = ERC20Contract.bind(event.address)// Access state variables and functions by calling themlet erc20Symbol = contract.symbol()}
这里将 Transfer
别名为 TransferEvent
,以避免与实体类型产生命名冲突。
只要以太坊上的 ERC20Contract
有一个名为 symbol
的公共只读函数,就可以使用 .symbol()
来调用它。对于公共状态变量,将自动生成一个同名的方法。
作为子图一部分的任何其他合约都可以从生成的代码中导入,并且可以绑定到一个有效地址。
如果您的合约的只读方法可能回滚,则应通过在生成的合约方法前加上 try_
来处理。例如,Gravity 合约暴露了 gravatarToOwner
方法。下面的代码可以处理该方法中的回滚:
let gravity = Gravity.bind(event.address)let callResult = gravity.try_gravatarToOwner(gravatar)if (callResult.reverted) {log.info('getGravatar reverted', [])} else {let owner = callResult.value}
请注意,连接到 Geth 或 Infura 客户端的 Graph 节点可能无法检测到所有重复使用,如果您依赖于此,我们建议使用连接到 Parity 客户端的 Graph 节点。
数据可以按照以太坊的 ABI 编码格式使用 ethereum
模块中的 encode
和 decode
函数进行编码和解码。
import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'let tupleArray: Array<ethereum.Value> = [ethereum.Value.fromAddress(Address.fromString('0x0000000000000000000000000000000000000420')),ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(62)),]let tuple = tupleArray as ethereum.Tuplelet encoded = ethereum.encode(ethereum.Value.fromTuple(tuple))!let decoded = ethereum.decode('(address,uint256)', encoded)
查询更多的信息:
- ABI 规范
- 您可以使用Rust Ethereum ABI 库/CLI来进行编码和解码。
- 更复杂的示例可以在这里找到。
从 '@graphprotocol/graph-ts'导入 { log }
log
API 允许子图将信息记录到 Graph Node 的标准输出以及 Graph Explorer。可以使用不同的日志级别记录消息。提供了一种基本的格式字符串语法来从参数组成日志消息。
log
API 包括以下函数:
log.debug(fmt: string, args: Array<string>): void
- 记录调试消息。log.info(fmt: string, args: Array<string>): void
- 记录信息消息。log.warning(fmt: string, args: Array<string>): void
- 记录警告消息。log.error(fmt: string, args: Array<string>): void
- 记录错误消息。log.critical(fmt: string, args: Array<string>): void
– 记录关键消息并终止子图。
log
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)}
在日志消息字符串中,参数数组中的每个条目都需要自己的占位符 。下面的示例包含了日志消息中的三个占位符 。因此,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]])}
下面的例子记录了一个事件的区块号、区块hash和交易hash:
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..."])}
从 '@graphprotocol/graph-ts'导入{ ipfs }
智能合约偶尔会在链上固定 IPFS 文件。这允许映射从合约获取 IPFS 哈希并从 IPFS 读取相应的文件。文件数据将作为 Bytes
返回,通常需要进一步处理,例如使用稍后在本页面中记录的 json
API。
给定一个 IPFS hash或路径,从 IPFS 读取文件的过程如下:
// Put this inside an event handler in the mappinglet hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D'let data = ipfs.cat(hash)// Paths like `QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile`// that include files in directories are also supportedlet path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'let data = ipfs.cat(path)
注意: 目前 ipfs.cat
不是确定性的。如果在请求超时之前无法从 IPFS 网络检索到文件,则会返回 null
。因此,始终值得检查结果是否为 null
。
还可以使用 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 valueslet obj = value.toObject()let id = obj.get('id')let title = obj.get('title')if (!id || !title) {return}// Callbacks can also created entitieslet newItem = new Item(id)newItem.title = title.toString()newitem.parent = userData.toString() // Set parent to "parentId"newitem.save()}// Put this inside an event handler in the mappingipfs.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
的处理程序将被中止,并且子图被标记为失败。
从'@graphprotocol/graph-ts'导入{ crypto }
crypto
API 为映射中的使用提供了加密函数。目前,只有一个函数可用:
crypto.keccak256(input: ByteArray): ByteArray
从'@graphprotocol/graph-ts'导入{ json, JSONValueKind }
JSON 数据可以使用 json API 进行解析:
json.fromBytes(data: Bytes): JSONValue
– 从有效的 UTF-8 序列的Bytes
数组中解析 JSON 数据json.try_fromBytes(data: Bytes): Result<JSONValue, boolean>
–json.fromBytes
的安全版本,如果解析失败,则返回错误变体json.fromString(data: string): JSONValue
– 从有效的 UTF-8String
解析 JSON 数据json.try_fromString(data: string): Result<JSONValue, boolean>
–json.fromString
的安全版本,如果解析失败,则返回错误变体
JSONValue
类提供了一种从任意 JSON 文档中提取值的方法。由于 JSON 值可以是布尔值、数字、数组等,因此 JSONValue
带有一个 kind
属性用于检查值的类型:
let value = json.fromBytes(...)if (value.kind == JSONValueKind.BOOL) {...}
此外,还有一个方法用于检查值是否为 null
:
value.isNull(): boolean
当值的类型确定时,可以使用以下方法之一将其转换为内置类型:
value.toBool(): boolean
value.toI64(): i64
value.toF64(): f64
value.toBigInt(): BigInt
value.toString(): string
value.toArray(): Array<JSONValue>
- (然后使用上述 5 种方法之一将JSONValue
转换)
源类型 | 目标类型 | 转换函数 |
---|---|---|
Address | Bytes | none |
Address | String | s.toHexString() |
BigDecimal | String | s.toString() |
BigInt | BigDecimal | s.toBigDecimal() |
BigInt | String (hexadecimal) | s.toHexString() 或 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() 或 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.toU64() |
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) |
Bytes | Address | Address.fromBytes(s) |
String | BigInt | BigInt.fromString(s) |
String | BigDecimal | BigDecimal.fromString(s) |
String (hexadecimal) | Bytes | ByteArray.fromHexString(s) |
String (UTF-8) | Bytes | ByteArray.fromUTF8(s) |
您可以通过 dataSource
命名空间检查调用处理程序的数据源的合约地址、网络和上下文:
dataSource.address(): Address
dataSource.network(): string
dataSource.context(): DataSourceContext
基础的 Entity
类和子类 DataSourceContext
类都有助于动态设置和获取字段的帮助函数:
setString(key: string, value: string): void
setI32(key: string, value: i32): void
setI32(key: string, value: i32): 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
dataSources
内的 context
部分允许您定义在子图映射中可访问的键值对。可用的类型包括 Bool
、String
、Int
、Int8
、BigDecimal
、Bytes
、List
和 BigInt
。
以下是一个 YAML 示例,说明了在 context 部分使用各种类型的情况:
dataSources:- kind: ethereum/contractname: ContractNamenetwork: mainnetcontext:bool_example:type: Booldata: truestring_example:type: Stringdata: 'hello'int_example:type: Intdata: 42int8_example:type: Int8data: 127big_decimal_example:type: BigDecimaldata: '10.99'bytes_example:type: Bytesdata: '0x68656c6c6f'list_example:type: Listdata:- type: Intdata: 1- type: Intdata: 2- type: Intdata: 3big_int_example:type: BigIntdata: '1000000000000000000000000'
Bool
:指定一个布尔值(true
或false
)。String
:指定一个字符串值。Int
:指定一个32位整数。Int8
:指定一个8位整数。BigDecimal
:指定一个十进制数。必须用引号括起来。Bytes
:指定一个十六进制字符串。List
:指定一个项目列表。每个项目都需要指定其类型和数据。BigInt
:指定一个大整数值。由于其较大,必须用引号括起来。
该上下文可以在您的子图映射文件中访问,从而实现更加动态和可配置的子图。