29 分
AssemblyScript API
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 を提供しています:
- Ethereum スマートコントラクト、イベント、ブロック、トランザクション、Ethereum の値を扱うためのethereumAPI
- エンティティをグラフノードのストアからロードしたり、ストアに保存したりするstoreAPI
- A
log
API to log messages to the Graph Node output and Graph Explorer. - IPFS からファイルをロードするipfsAPI
- JSON データを解析するためのjsonAPI
- 暗号機能を使用するためのcryptoAPI
- Ethereum、JSON、GraphQL、AssemblyScript など、異なるタイプのシステム間で変換するための低レベルプリミティブ
バージョン
The apiVersion
in the Subgraph manifest specifies the mapping API version which is run by Graph Node for a given Subgraph.
バージョン | リリースノート |
---|---|
0.0.9 | Adds new host functions eth_get_balance & hasCode |
0.0.8 | Adds validation for existence of fields in the schema when saving an entity. |
0.0.7 | Ethereum タイプに TransactionReceipt と Log クラスを追加Ethereum Event オブジェクトに receipt フィールドを追加。 |
0.0.6 | Ethereum Transactionオブジェクトにnonce フィールドを追加Ethereum Blockオブジェクトに baseFeePerGas を追加。 |
0.0.5 | AssemblyScript upgraded to version 0.19.10 (this includes breaking changes, please see the Migration Guide )ethereum.transaction.gasUsed renamed to ethereum.transaction.gasLimit |
0.0.4 | Ethereum SmartContractCall オブジェクトにfunctionSignatureフィールドを追加 |
0.0.3 | Added from field to the Ethereum Call objectethereum.call.address renamed to 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で提供されています。
バイト配列
1'@graphprotocol/graph-ts'から{ ByteArray } をインポートします。
ByteArrayは、u8の配列を表します。
Construction
fromI32(x: i32): ByteArray
- Decomposesx
into bytes.- fromHexString(hex:: 文字列): ByteArray
- 入力長は偶数でなければなりません。0x
のプレフィックスはオプションとなります。
Type conversions
toHexString(): string
-0x
を先頭に持つ 16 進文字列に変換します。toString(): string
- バイトを UTF-8 文字列として解釈します。toBase58(): string
- バイトをbase58の文字列にエンコードします。toU32(): u32
- バイトをリトルエンディアンのu32
として解釈し、オーバーフローした場合にスローします。toI32(): i32
- バイト配列をリトルエンディアンのi32
として解釈し、オーバーフローした場合にスローします。
Operators
- equals(y: ByteArray): bool
-
x == y` と書くことができます。 concat(other: ByteArray) : ByteArray
-this
にother
を直接続けたByteArray
を返します。concatI32(other: i32) : ByteArray
-this
にother
のバイト表現を直接続けたByteArray
を返します。
BigDecimal
1'@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.
Construction
constructor(bigInt: BigInt)
-BigInt
からBigDecimal
を生成します。static fromString(s: string): BigDecimal
- 10進数の文字列をパースします。
Type conversions
- toString(): string` - 10進数の文字列を表示します。
Math
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
と書くことができます。ge(y: BigDecimal): bool
と書くことができます。neg(): BigDecimal
--x
と書くことができます。
BigInt
1'@graphprotocol/graph-ts'から { BigInt } をインポートします。
BigInt
は大きな整数を表現するために使用されます。これには uint32
から uint256
と int64
から int256
型のイーサリアムの値が含まれます。uint32以下の値、例えば
int32、
uint24、
int8は全て
i32` として表現されます。
BigIntクラスの API は以下の通りです。
Construction
-
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()
を呼び出します。Type conversions
-
x.toHex(): string
-BigInt
を16進数の文字列に変換します。 -
x.toString(): string
-BigInt
を10進数の文字列に変換します。 -
x.toI32(): i32
-BigInt
をi32
として返す。値がi32
に収まらない場合は失敗します。まずx.isI32()
をチェックするのが良いでしょう。 -
x.toBigDecimal(): BigDecimal
- 小数部のない10進数に変換します。
Math
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
- 小数点で割り、10進数の結果を返します。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
と書くことができます。
TypedMap
1'@graphprotocol/graph-ts'から { TypedMap } をインポートします。
TypedMap
はキーと値のペアを格納するために使用することができます。この例](https://github.com/graphprotocol/aragon-subgraph/blob/29dd38680c5e5104d9fdc2f90e740298c67e4a31/individual-dao-subgraph/mappings/constants.ts#L51)を参照してください。
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
のキーと値のペアを返します。map.get(key: K): V | null
-key
の値を返して、key
がマップに存在しない場合はnull
を返します。map.isSet(key: K): bool
-key
がマップに存在すればtrue
を返し、存在しなければfalse
を返します。
Bytes
1'@graphprotocol/graph-ts'から { Bytes } をインポートします。
Bytes
は任意の長さのバイト配列を表現するために使用されます。これには bytes
、bytes32
型などのイーサリアム値が含まれます。
Bytes
クラスはAssemblyScriptのUint8Arrayを拡張したもので、Uint8Array
のすべての機能に加え、以下の新しいメソッドをサポートしています:
Construction
fromHexString(hex: string) : Bytes
- 偶数桁の16進数からなる文字列hex
をByteArray
に変換します。文字列hex
はオプションで0x
から始めることができます。fromI32(i: i32): Bytes
-i
をバイト配列に変換します。
Type conversions
b.toHex()
- 配列のバイト数を16進数で表した文字列を返します。b.toString()
- 配列のバイト列をユニコード文字列に変換します。b.toBase58()
- イーサリアムバイトの値を base58 エンコーディングに変換します (IPFS ハッシュに使用)
Operators
b.concat(other: Bytes): Bytes
- -this
にother
を直接連結したBytes
を返します。b.concatI32(other: i32) : ByteArray
-this
にother
のバイト表現を直接続けたBytes
を返します。
住所
1'@graphprotocol/graph-ts'から { Address } をインポートします。
アドレス Address
はイーサリアムのアドレス address
値を表現するために Bytes
を継承しています。
Bytesの API の上に以下のメソッドを追加しています。
Address.fromString(s: string): Address
- 16進数文字列からAddress
を作成します。Address.fromBytes(b: Bytes): Address
-b
からAddress
を生成します。これは正確に20バイト長でなければなりません。それ以下のバイト数の値を渡すとエラーになります。
ストア API
1'@graphprotocol/graph-ts'から { store } をインポートします。
Store API は、グラフノードのストアにエンティティを読み込んだり、保存したり、削除したりすることができます。
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.
エンティティの作成
Ethereum のイベントからエンティティを作成する際の一般的なパターンを以下に示します。
1// Import the Transfer event class generated from the ERC20 ABI2import { Transfer as TransferEvent } from '../generated/ERC20/ERC20'34// Import the Transfer entity type generated from the GraphQL schema5import { Transfer } from '../generated/schema'67// Transfer event handler8export function handleTransfer(event: TransferEvent): void {9 // Create a Transfer entity, using the transaction hash as the entity ID10 let id = event.transaction.hash11 let transfer = new Transfer(id)1213 // Set properties on the entity, using the event parameters14 transfer.from = event.params.from15 transfer.to = event.params.to16 transfer.amount = event.params.amount1718 // Save the entity to the store19 transfer.save()20}
チェーンの処理中に 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.
ストアからのエンティティの読み込み
エンティティがすでに存在する場合、以下の方法でストアからロードすることができます。
1let id = event.transaction.hash // or however the ID is constructed2let transfer = Transfer.load(id)3if (transfer == null) {4 transfer = new Transfer(id)5}67// 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 onchain 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.
1let id = event.transaction.hash // または ID が構築される方法2let transfer = Transfer.loadInBlock(id)3if (transfer == null) {4 transfer = 新しい転送(id)5}67// 以前と同様に Transfer エンティティを使用します
注: 指定されたブロックにエンティティが作成されていない場合、ストア内に指定された ID を持つエンティティが存在する場合でも、loadInBlock は null を返します。
派生エンティティの検索
graph-node v0.31.0、@graphprotocol/graph-ts v0.31.0、および @graphprotocol/graph-cli v0.51.0 以降、loadMany メソッドが利用可能です。
これにより、イベント ハンドラー内から派生エンティティ フィールドをロードできるようになります。たとえば、次のスキーマがあるとします。
1type Token @entity {2 id: ID!3 holder: Holder!4 color: String5}67type Holder @entity {8 id: ID!9 tokens: [Token!]! @derivedFrom(field: "holder")10}
次のコードは、Holder エンティティの派生元である Token エンティティを読み込みます。
1let holder = Holder.load('test-id')2// Load the Token entities associated with a given holder3let tokens = holder.tokens.load()
既存のエンティティの更新
既存のエンティティを更新するには 2 つの方法があります。
- Transfer.load(id)などでエンティティをロードし、エンティティにプロパティを設定した後、.save()でストアに戻す。
- 単純にnew Transfer(id)でエンティティを作成し、エンティティにプロパティを設定し、ストアに .save()します。 エンティティがすでに存在する場合は、変更内容がマージされます。
プロパティの変更は、生成されたプロパティセッターのおかげで、ほとんどの場合、簡単です。
1let transfer = new Transfer(id)2transfer.from = ...3transfer.to = ...4transfer.amount = ...
また、次の 2 つの命令のいずれかで、プロパティの設定を解除することも可能です。
1transfer.from.unset()2transfer.from = null
これは、オプションのプロパティ、つまり GraphQL で!を付けずに宣言されているプロパティでのみ機能します。 例としては、owner: Bytesやamount: BigIntです。
エンティティから配列を取得すると、その配列のコピーが作成されるため、配列のプロパティの更新には少し手間がかかります。 つまり、配列を変更した後は、明示的に配列のプロパティを設定し直す必要があります。 次の例では、entity が numbers: [BigInt!]! を持っていると仮定します。
1// This won't work2entity.numbers.push(BigInt.fromI32(1))3entity.save()45// This will work6let numbers = entity.numbers7numbers.push(BigInt.fromI32(1))8entity.numbers = numbers9entity.save()
ストアからのエンティティの削除
現在、生成された型を使ってエンティティを削除する方法はありません。 代わりに、エンティティを削除するには、エンティティタイプの名前とエンティティ ID をstore.removeに渡す必要があります。
1mport { store } from '@graphprotocol/graph-ts'2...3let id = event.transaction.hash4store.remove('Transfer', id)
Ethereum API
Ethereum API は、スマートコントラクト、パブリックステート変数、コントラクト関数、イベント、トランザクション、ブロック、および Ethereum データのエンコード/デコードへのアクセスを提供します。
Ethereum タイプのサポート
As with entities, graph codegen
generates classes for all smart contracts and events used in a Subgraph. For this, the contract ABIs need to be part of the data source in the Subgraph manifest. Typically, the ABI files are stored in an abis/
folder.
With the generated classes, conversions between Ethereum types and the built-in types take place behind the scenes so that Subgraph authors do not have to worry about them.
The following example illustrates this. Given a Subgraph schema like
1type Transfer @entity {2 id: Bytes!3 from: Bytes!4 to: Bytes!5 amount: BigInt!6}
イーサリアムの Transfer(address,address,uint256)
イベントシグネチャを使用すると、from
, to
, uint256
型の値は Address
と BigInt
に変換され、Transfer
エンティティの Bytes!
プロパティと BigInt!
プロパティに渡すことができます:
1let id = event.transaction.hash2let transfer = new Transfer(id)3transfer.from = event.params.from4transfer.to = event.params.to5transfer.amount = event.params.amount6transfer.save()
イベントとブロック/トランザクションデータ
前述の例のTransferイベントのように、イベントハンドラに渡された Ethereum イベントは、イベントパラメータへのアクセスだけでなく、その親となるトランザクションや、それらが属するブロックへのアクセスも提供します。 event インスタンスからは、以下のデータを取得することができます(これらのクラスは、 graph-tsのethereumモジュールの一部です)。
1class Event {2 address: Address3 logIndex: BigInt4 transactionLogIndex: BigInt5 logType: string | null6 block: Block7 transaction: Transaction8 parameters: Array<EventParam>9 receipt: TransactionReceipt | null10}1112class Block {13 hash: Bytes14 parentHash: Bytes15 unclesHash: Bytes16 author: Address17 stateRoot: Bytes18 transactionsRoot: Bytes19 receiptsRoot: Bytes20 number: BigInt21 gasUsed: BigInt22 gasLimit: BigInt23 timestamp: BigInt24 difficulty: BigInt25 totalDifficulty: BigInt26 size: BigInt | null27 baseFeePerGas: BigInt | null28}2930class Transaction {31 hash: Bytes32 index: BigInt33 from: Address34 to: Address | null35 value: BigInt36 gasLimit: BigInt37 gasPrice: BigInt38 input: Bytes39 nonce: BigInt40}4142class TransactionReceipt {43 transactionHash: Bytes44 transactionIndex: BigInt45 blockHash: Bytes46 blockNumber: BigInt47 cumulativeGasUsed: BigInt48 gasUsed: BigInt49 contractAddress: Address50 logs: Array<Log>51 status: BigInt52 root: Bytes53 logsBloom: Bytes54}5556class Log {57 address: Address58 topics: Array<Bytes>59 data: Bytes60 blockHash: Bytes61 blockNumber: Bytes62 transactionHash: Bytes63 transactionIndex: BigInt64 logIndex: BigInt65 transactionLogIndex: BigInt66 logType: string67 removed: bool | null68}
スマートコントラクトの状態へのアクセス
The code generated by graph codegen
also includes classes for the smart contracts used in the Subgraph. These can be used to access public state variables and call functions of the contract at the current block.
よくあるパターンは、イベントが発生したコントラクトにアクセスすることです。 これは以下のコードで実現できます。
1// Import the generated contract class and generated Transfer event class2import { ERC20Contract, Transfer as TransferEvent } from '../generated/ERC20Contract/ERC20Contract'3// Import the generated entity class4import { Transfer } from '../generated/schema'56export function handleTransfer(event: TransferEvent) {7 // Bind the contract to the address that emitted the event8 let contract = ERC20Contract.bind(event.address)910 // Access state variables and functions by calling them11 let erc20Symbol = contract.symbol()12}
Transferは、エンティティタイプとの名前の衝突を避けるために、ここではTransferEventにエイリアスされています。
Ethereum の ERC20Contractにsymbolというパブリックな読み取り専用の関数があれば、.symbol()で呼び出すことができます。 パブリックな状態変数については、同じ名前のメソッドが自動的に作成されます。
Any other contract that is part of the Subgraph can be imported from the generated code and can be bound to a valid address.
リバートされた呼び出しの処理
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:
1let gravity = Gravity.bind(event.address)2let callResult = gravity.try_gravatarToOwner(gravatar)3if (callResult.reverted) {4 log.info('getGravatar reverted', [])5} else {6 let owner = callResult.value7}
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
ethereumモジュールのencode/ decode関数を使用して、Ethereum の ABI エンコーディングフォーマットに従ってデータをエンコード/デコードすることができます。
1import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'23let tupleArray: Array<ethereum.Value> = [4 ethereum.Value.fromAddress(Address.fromString('0x0000000000000000000000000000000000000420')),5 ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(62)),6]78let tuple = tupleArray as ethereum.Tuple910let encoded = ethereum.encode(ethereum.Value.fromTuple(tuple))!1112let decoded = ethereum.decode('(address,uint256)', encoded)
その他の情報:
- ABI Spec
- Encoding/decoding Rust library/CLI
- More complex example.
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.
1import { ethereum } from '@graphprotocol/graph-ts'23let address = Address.fromString('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')4let 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
.
1import { ethereum } from '@graphprotocol/graph-ts'23let contractAddr = Address.fromString('0x2E645469f354BB4F5c8a05B3b30A929361cf77eC')4let isContract = ethereum.hasCode(contractAddr).inner // returns true56let eoa = Address.fromString('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')7let isContract = ethereum.hasCode(eoa).inner // returns false
Logging API
1'@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
– logs a critical message and terminates the Subgraph.
log API は、フォーマット文字列と文字列値の配列を受け取ります。 そして、プレースホルダーを配列の文字列値で置き換えます。 最初のプレースホルダーは配列の最初の値に置き換えられ、2 番目のプレースホルダーは 2 番目の値に置き換えられ、以下のようになります。
1log.info('表示されるメッセージ。{}, {}, {}', [value.toString(), anotherValue.toString(), 'すでに文字列'])
1 つまたは複数の値を記録する
1 つの値を記録する
以下の例では、文字列値 “A” を配列に渡して[‘A’] にしてからログに記録しています。
1let myValue = 'A'23export function handleSomeEvent(event: SomeEvent): void {4 // Displays : "My value is: A"5 log.info('My value is: {}', [myValue])6}
既存の配列から 1 つのエントリをロギングする
以下の例では、配列に 3 つの値が含まれているにもかかわらず、引数の配列の最初の値だけがログに記録されます。
1let myArray = ['A', 'B', 'C']23export function handleSomeEvent(event: SomeEvent): void {4 // Displays : "My value is: A" (Even though three values are passed to `log.info`)5 log.info('My value is: {}', myArray)6}
既存の配列から複数のエントリを記録する
引数配列の各エントリは、ログメッセージ文字列に独自のプレースホルダーを必要とします。 以下の例では、ログメッセージに 3 つのプレースホルダーが含まれています。 このため、myArrayの 3 つの値すべてがログに記録されます。
1let myArray = ['A', 'B', 'C']23export function handleSomeEvent(event: SomeEvent): void {4 // Displays : "My first value is: A, second value is: B, third value is: C"5 log.info('My first value is: {}, second value is: {}, third value is: {}', myArray)6}
既存の配列から特定のエントリをロギングする
配列内の特定の値を表示するには、インデックス化された値を指定する必要があります。
1export function handleSomeEvent(event: SomeEvent): void {2 // Displays : "My third value is C"3 log.info('My third value is: {}', [myArray[2]])4}
イベント情報の記録
以下の例では、イベントからブロック番号、ブロックハッシュ、トランザクションハッシュをログに記録しています。
1'@graphprotocol/graph-ts'から { log } をインポートします。23export function handleSomeEvent(event: SomeEvent): void {4 log.debug('Block number: {}, block hash: {}, transaction hash: {}', [5 event.block.number.toString(), // "47596000"6 event.block.hash.toHexString(), // "0x..."7 event.transaction.hash.toHexString(), // "0x..."8 ])9}
IPFS API
1'@graphprotocol/graph-ts'から { ipfs } をインポートします。
Smart contracts occasionally anchor IPFS files onchain. This allows mappings to obtain the IPFS hashes from the contract and read the corresponding files from IPFS. The file data will be returned as Bytes
, which usually requires further processing, e.g. with the json
API documented later on this page.
IPFS のハッシュやパスが与えられた場合、IPFS からのファイルの読み込みは以下のように行われます。
1// Put this inside an event handler in the mapping2let hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D'3let data = ipfs.cat(hash)45// Paths like `QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile`6// that include files in directories are also supported7let path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'8let data = ipfs.cat(path)
注: ipfs.cat は今のところ決定論的なものではありません。もし要求がタイムアウトする前にIPFSネットワーク上でファイルを取得できなければ、 nullを返します。このため、常に null の結果をチェックする価値があります。
また、ipfs.map.を使って、大きなファイルをストリーミングで処理することも可能です。 この関数は、IPFS ファイルのハッシュまたはパス、コールバックの名前、そして動作を変更するためのフラグを受け取ります。
1import { JSONValue, Value } from '@graphprotocol/graph-ts'23export function processItem(value: JSONValue, userData: Value): void {4 // See the JSONValue documentation for details on dealing5 // with JSON values6 let obj = value.toObject()7 let id = obj.get('id')8 let title = obj.get('title')910 if (!id || !title) {11 return12 }1314 // Callbacks can also created entities15 let newItem = new Item(id)16 newItem.title = title.toString()17 newitem.parent = userData.toString() // Set parent to "parentId"18 newitem.save()19}2021// Put this inside an event handler in the mapping22ipfs.map('Qm...', 'processItem', Value.fromString('parentId'), ['json'])2324// Alternatively, use `ipfs.mapJSON`25ipfs.mapJSON('Qm...', 'processItem', Value.fromString('parentId'))
現在サポートされているフラグは json
だけで、これは ipfs.map
に渡さなければなりません。json フラグを指定すると、IPFS ファイルは一連の JSON 値で構成されます。ipfs.map
を呼び出すと、ファイルの各行を読み込んで JSONValue
にデシリアライズし、それぞれのコールバックを呼び出します。コールバックは JSONValue
からデータを格納するためにエンティティ操作を使用することができます。エンティティの変更は、ipfs.map
を呼び出したハンドラが正常に終了したときのみ保存されます。その間はメモリ上に保持されるので、ipfs.map
が処理できるファイルのサイズは制限されます。
On success, ipfs.map
returns void
. If any invocation of the callback causes an error, the handler that invoked ipfs.map
is aborted, and the Subgraph is marked as failed.
Crypto API
1'@graphprotocol/graph-ts'から { crypto } をインポートします。
crypto API は、マッピングで使用できる暗号化関数を提供します。 今のところ、1 つしかありません。
crypto.keccak256(input: ByteArray): ByteArray
JSON API
1'@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プロパティが付属しています。
1let value = json.fromBytes(...)2if (value.kind == JSONValueKind.BOOL) {3 ...4}
さらに、値が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
を変換します)
タイプ 変換参照
Source(s) | Destination | Conversion function |
---|---|---|
Address | Bytes | none |
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) |
Bytes | Address | Address.fromString(s) |
String | BigInt | BigDecimal.fromString(s) |
String | BigDecimal | BigDecimal.fromString(s) |
String (hexadecimal) | Bytes | ByteArray.fromHexString(s) |
String (UTF-8) | Bytes | ByteArray.fromUTF8(s) |
データソースのメタデータ
ハンドラを起動したデータソースのコントラクトアドレス、ネットワーク、コンテキストは、以下のようにして調べることができます。
dataSource.address(): Address
dataSource.network(): string
dataSource.context(): DataSourceContext
エンティティと DataSourceContext
ベースとなるエンティティクラスと子クラスの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
マニフェスト内のDataSourceContext
The context
section within dataSources
allows you to define key-value pairs that are accessible within your Subgraph mappings. The available types are Bool
, String
, Int
, Int8
, BigDecimal
, Bytes
, List
, and BigInt
.
以下は context
セクションのさまざまな型の使い方を示す YAML の例です:
1dataSources:2 - kind: ethereum/contract3 name: ContractName4 network: mainnet5 context:6 bool_example:7 type: Bool8 data: true9 string_example:10 type: String11 data: 'hello'12 int_example:13 type: Int14 data: 4215 int8_example:16 type: Int817 data: 12718 big_decimal_example:19 type: BigDecimal20 data: '10.99'21 bytes_example:22 type: Bytes23 data: '0x68656c6c6f'24 list_example:25 type: List26 data:27 - type: Int28 data: 129 - type: Int30 data: 231 - type: Int32 data: 333 big_int_example:34 type: BigInt35 data: '1000000000000000000000000'
Bool
: Specifies a Boolean value (true
orfalse
).String
: Specifies a String value.Int
: Specifies a 32-bit integer.Int8
: Specifies an 8-bit integer.BigDecimal
: Specifies a decimal number. Must be quoted.Bytes
: Specifies a hexadecimal string.List
: Specifies a list of items. Each item needs to specify its type and data.BigInt
: Specifies a large integer value. Must be quoted due to its large size.
This context is then accessible in your Subgraph mapping files, enabling more dynamic and configurable Subgraphs.