subgraphs > Developing > Creating > AssemblyScript API > AssemblyScript API

AssemblyScript API

Reading time: 27 min

Note: If you created a subgraph prior to graph-cli/graph-ts version 0.22.0, then you're using an older version of AssemblyScript. It is recommended to review the Migration Guide.

Learn what built-in APIs can be used when writing subgraph mappings. There are two kinds of APIs available out of the box:

  • The Graph TypeScript library (graph-ts)
  • Code generated from subgraph files by graph codegen

You can also add other libraries as dependencies, as long as they are compatible with AssemblyScript.

Since language mappings are written in AssemblyScript, it is useful to review the language and standard library features from the AssemblyScript wiki.

API 参考

链到本节

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

  • 用于处理以太坊智能合约、事件、区块、交易和以太坊价值的以太坊 API。
  • 用于与图形节点交互,存储和加载实体的 存储 API。
  • A log API to log messages to the Graph Node output and Graph Explorer.
  • 用于从 IPFS 加载文件的ipfs API。
  • 用于解析 JSON 数据的json API。
  • 使用加密功能的crypto API。
  • 用于在不同类型系统(例如 Ethereum、JSON、GraphQL 和 AssemblyScript)之间进行转换的低级原语。

版本

链到本节

子图清单中的 apiVersion 指定了由 Graph Node 运行的特定子图的映射 API 版本。

版本Release 说明
0.0.9Adds new host functions eth_get_balance & hasCode
0.0.8Adds validation for existence of fields in the schema when saving an entity.
0.0.7添加了 TransactionReceiptLog 类到以太坊类型。
已将 receipt 字段添加到Ethereum Event对象。
0.0.6向Ethereum Transaction对象添加了 nonce 字段 向 Etherum Block对象添加
baseFeePerGas字段
0.0.5AssemblyScript 升级到版本 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 字段。

内置类型

链到本节

Documentation on the base types built into AssemblyScript can be found in the 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 的字节表示构成。

BigDecimal

链到本节
从“@Graphprotocol/graph-ts”导入{ BigDecimal }

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

Note: Internally BigDecimal is stored in IEEE-754 decimal128 floating-point format, which supports 34 decimal digits of significand. This makes BigDecimal unsuitable for representing fixed-point types that can span wider than 34 digits, such as a Solidity ufixed256x18 or equivalent.

结构

  • 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

BigInt

链到本节
'@graphprotocol/graph-ts'导入{ BigInt }

BigInt 用于表示大整数。这包括以太坊中的类型 uint32uint256int64int256 的数值。所有小于 uint32 的数值,比如 int32uint24int8 都被表示为 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 创建一个 Addressb 必须恰好为 20 个字节长。传入长度不足或超过 20 字节的值将导致错误。

商店API

链到本节
'@graphprotocol/graph-ts'导入 { store }

store API 允许从和到 Graph Node 存储加载、保存和删除实体。

Entities written to the store map one-to-one to the @entity types defined in the subgraph's GraphQL schema. To make working with these entities convenient, the graph codegen command provided by the Graph CLI generates entity classes, which are subclasses of the built-in Entity type, with property getters and setters for the fields in the schema as well as methods to load and save these entities.

创建实体

链到本节

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

/ 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 transaction hash as the entity ID
let id = event.transaction.hash
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 事件处理器。 此类型允许访问事件的母交易及其参数等数据。

Each entity must have a unique ID to avoid collisions with other entities. It is fairly common for event parameters to include a unique identifier that can be used.

Note: Using the transaction hash as the ID assumes that no other events in the same transaction create entities with this hash as the ID.

从存储中加载实体

链到本节

如果实体已经存在,则可以使用以下内容从存储中加载它:

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

As the entity may not exist in the store yet, the load method returns a value of type Transfer | null. It may be necessary to check for the null case before using the value.

Note: Loading entities is only necessary if the changes made in the mapping depend on the previous data of an entity. See the next section for the two ways of updating existing entities.

查找在区块中创建的实体

链到本节

截至 graph-node v0.31.0、@graphprotocol/graph-ts v0.30.0 和 @graphprotocol/graph-cli v0.49.0,所有实体类型上都提供了 loadInBlock 方法。

The store API facilitates the retrieval of entities that were created or updated in the current block. A typical situation for this is that one handler creates a transaction from some on-chain event, and a later handler wants to access this transaction if it exists.

  • In the case where the transaction does not exist, the subgraph will have to go to the database simply to find out that the entity does not exist. If the subgraph author already knows that the entity must have been created in the same block, using loadInBlock avoids this database roundtrip.
  • For some subgraphs, these missed lookups can contribute significantly to the indexing time.
let id = event.transaction.hash // or however the ID is constructed
let 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()

更新现有实体

链到本节

有两种方法可以更新现有实体:

  1. 利用 Transfer.load(id)加载实体,在实体上设置属性,然后调用.save() 将其返回到存储。
  2. 使用 new Transfer(id)创建实体,在实体上设置属性,然后调用.save()将其保存到存储。 如果实体已经存在,则将更改合并到其中。

由于生成的属性设置器,在大多数情况下更改属性是直截了当的:

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

也可以使用以下两条指令之一取消设置属性:

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

这只适用于可选属性,即在 GraphQL 中声明时没有使用 ! 的属性。两个例子是 owner: Bytesamount: BigInt

更新数组属性稍微复杂一些,因为从实体获取数组会创建该数组的副本。这意味着在更改数组后,必须显式地重新设置数组属性。以下假设 entity 有一个 numbers: [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
store.remove('Transfer', id)

以太坊 API

链到本节

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

对以太坊类型的支持

链到本节

与实体一样,graph codegen 为子图中使用的所有智能合约和事件生成类。为此,合约 ABI 需要作为子图清单中数据源的一部分。通常,ABI 文件存储在一个名为 abis/ 的文件夹中。

通过生成的类,以太坊类型和内置类型之间的转换在幕后进行,这样子图作者就不必担心它们。

以下示例说明了这一点。 给定一个子图模式,如

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

对于以太坊上的 Transfer(address,address,uint256) 事件签名,类型为 addressaddressuint256fromtoamount 值被转换为 AddressBigInt,从而允许它们传递给 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()

事件和区块/交易数据

链到本节

传递给事件处理程序的以太坊事件(例如前面示例中的 Transfer 事件)不仅提供对事件参数的访问,还提供对其父事务和它们所在的区块的访问。以下数据可以从 event 实例中获取(这些类是 graph-ts 中的 ethereum 模块的一部分):

class Event {
address: Address
logIndex: BigInt
transactionLogIndex: BigInt
logType: string | null
block: Block
transaction: Transaction
parameters: Array<EventParam>
receipt: TransactionReceipt | null
}
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
baseFeePerGas: BigInt | null
}
class Transaction {
hash: Bytes
index: BigInt
from: Address
to: Address | null
value: BigInt
gasLimit: BigInt
gasPrice: BigInt
input: Bytes
nonce: BigInt
}
class TransactionReceipt {
transactionHash: Bytes
transactionIndex: BigInt
blockHash: Bytes
blockNumber: BigInt
cumulativeGasUsed: BigInt
gasUsed: BigInt
contractAddress: Address
logs: Array<Log>
status: BigInt
root: Bytes
logsBloom: Bytes
}
class Log {
address: Address
topics: Array<Bytes>
data: Bytes
blockHash: Bytes
blockNumber: Bytes
transactionHash: Bytes
transactionIndex: BigInt
logIndex: BigInt
transactionLogIndex: BigInt
logType: string
removed: bool | null
}

访问智能合约状态

链到本节

graph codegen 生成的代码还包括用于子图中使用的智能合约的类。这些类可以用于访问智能合约在当前区块上的公共状态变量和调用函数。

一种常见的模式是访问事件起源的合约。 这是通过以下代码实现的:

// Import the generated contract class and generated Transfer event class
import { ERC20Contract, Transfer as TransferEvent } from '../generated/ERC20Contract/ERC20Contract'
// Import the generated entity class
import { Transfer } from '../generated/schema'
export function handleTransfer(event: TransferEvent) {
// 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()
}

这里将 Transfer 别名为 TransferEvent,以避免与实体类型产生命名冲突。

只要以太坊上的 ERC20Contract 有一个名为 symbol 的公共只读函数,就可以使用 .symbol() 来调用它。对于公共状态变量,将自动生成一个同名的方法。

作为子图一部分的任何其他合约都可以从生成的代码中导入,并且可以绑定到一个有效地址。

处理重复调用

链到本节

If the read-only methods of your contract may revert, then you should handle that by calling the generated contract method prefixed with try_.

  • For example, the Gravity contract exposes the gravatarToOwner method. This code would be able to handle a revert in that method:
let gravity = Gravity.bind(event.address)
let callResult = gravity.try_gravatarToOwner(gravatar)
if (callResult.reverted) {
log.info('getGravatar reverted', [])
} else {
let owner = callResult.value
}

Note: A Graph node connected to a Geth or Infura client may not detect all reverts. If you rely on this, we recommend using a Graph Node connected to a Parity client.

编码/解码 ABI

链到本节

数据可以按照以太坊的 ABI 编码格式使用 ethereum 模块中的 encodedecode 函数进行编码和解码。

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.Tuple
let encoded = ethereum.encode(ethereum.Value.fromTuple(tuple))!
let decoded = ethereum.decode('(address,uint256)', encoded)

查询更多的信息:

Balance of an Address

链到本节

The native token balance of an address can be retrieved using the ethereum module. This feature is available from apiVersion: 0.0.9 which is defined subgraph.yaml. The getBalance() retrieves the balance of the specified address as of the end of the block in which the event is triggered.

import { ethereum } from '@graphprotocol/graph-ts'
let address = Address.fromString('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
let balance = ethereum.getBalance(address) // returns balance in BigInt

Check if an Address is a Contract or EOA

链到本节

To check whether an address is a smart contract address or an externally owned address (EOA), use the hasCode() function from the ethereum module which will return boolean. This feature is available from apiVersion: 0.0.9 which is defined subgraph.yaml.

import { ethereum } from '@graphprotocol/graph-ts'
let contractAddr = Address.fromString('0x2E645469f354BB4F5c8a05B3b30A929361cf77eC')
let isContract = ethereum.hasCode(contractAddr).inner // returns true
let eoa = Address.fromString('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
let isContract = ethereum.hasCode(eoa).inner // returns false

日志记录 API

链到本节
'@graphprotocol/graph-ts'导入 { log }

The log API allows subgraphs to log information to the Graph Node standard output as well as Graph Explorer. Messages can be logged using different log levels. A basic format string syntax is provided to compose log messages from argument.

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..."
])
}

IPFS API

链到本节
'@graphprotocol/graph-ts'导入{ ipfs }

智能合约偶尔会在链上固定 IPFS 文件。这允许映射从合约获取 IPFS 哈希并从 IPFS 读取相应的文件。文件数据将作为 Bytes 返回,通常需要进一步处理,例如使用稍后在本页面中记录的 json API。

给定一个 IPFS hash或路径,从 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

还可以使用 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')
let title = obj.get('title')
if (!id || !title) {
return
}
// Callbacks can also created entities
let 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 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 的处理程序将被中止,并且子图被标记为失败。

Crypto API

链到本节
'@graphprotocol/graph-ts'导入{ crypto }

crypto API 为映射中的使用提供了加密函数。目前,只有一个函数可用:

  • crypto.keccak256(input: ByteArray): ByteArray

JSON API

链到本节
'@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-8 String 解析 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 转换)

类型转换参考

链到本节
源类型目标类型转换函数
AddressBytesnone
AddressStrings.toHexString()
BigDecimalStrings.toString()
BigIntBigDecimals.toBigDecimal()
BigIntString (hexadecimal)s.toHexString() 或 s.toHex()
BigIntString (unicode)s.toString()
BigInti32s.toI32()
BooleanBooleannone
Bytes (signed)BigIntBigInt.fromSignedBytes(s)
Bytes (unsigned)BigIntBigInt.fromUnsignedBytes(s)
BytesString (hexadecimal)s.toHexString() 或 s.toHex()
BytesString (unicode)s.toString()
BytesString (base58)s.toBase58()
Bytesi32s.toI32()
Bytesu32s.toU32()
BytesJSONjson.fromBytes(s)
int8i32none
int32i32none
int32BigIntBigInt.fromI32(s)
uint24i32none
int64 - int256BigIntnone
uint32 - uint256BigIntnone
JSONbooleans.toBool()
JSONi64s.toU64()
JSONu64s.toU64()
JSONf64s.toF64()
JSONBigInts.toBigInt()
JSONstrings.toString()
JSONArrays.toArray()
JSONObjects.toObject()
StringAddressAddress.fromString(s)
BytesAddressAddress.fromBytes(s)
StringBigIntBigInt.fromString(s)
StringBigDecimalBigDecimal.fromString(s)
String (hexadecimal)BytesByteArray.fromHexString(s)
String (UTF-8)BytesByteArray.fromUTF8(s)

数据源元数据

链到本节

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

  • dataSource.address(): Address
  • dataSource.network(): string
  • dataSource.context(): DataSourceContext

Entity 和 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

清单文件中的 DataSourceContext

链到本节

dataSources 内的 context 部分允许您定义在子图映射中可访问的键值对。可用的类型包括 BoolStringIntInt8BigDecimalBytesListBigInt

以下是一个 YAML 示例,说明了在 context 部分使用各种类型的情况:

dataSources:
- kind: ethereum/contract
name: ContractName
network: mainnet
context:
bool_example:
type: Bool
data: true
string_example:
type: String
data: 'hello'
int_example:
type: Int
data: 42
int8_example:
type: Int8
data: 127
big_decimal_example:
type: BigDecimal
data: '10.99'
bytes_example:
type: Bytes
data: '0x68656c6c6f'
list_example:
type: List
data:
- type: Int
data: 1
- type: Int
data: 2
- type: Int
data: 3
big_int_example:
type: BigInt
data: '1000000000000000000000000'
  • Bool:指定一个布尔值(truefalse)。
  • String:指定一个字符串值。
  • Int:指定一个32位整数。
  • Int8:指定一个8位整数。
  • BigDecimal:指定一个十进制数。必须用引号括起来。
  • Bytes:指定一个十六进制字符串。
  • List:指定一个项目列表。每个项目都需要指定其类型和数据。
  • BigInt:指定一个大整数值。由于其较大,必须用引号括起来。

该上下文可以在您的子图映射文件中访问,从而实现更加动态和可配置的子图。

编辑

上页
Advance Subgraph Features
下页
AssemblyScript的常见问题
编辑