AssemblyScript API
注意: graph-cli
/graph-ts
のバージョン 0.22.0
より前にサブグラフを作成した場合、古いバージョンのAssemblyScriptを使用しているので、マイグレーションガイド
を参照することをお勧めします。
このページでは、サブグラフのマッピングを記述する際に、どのような組み込み API を使用できるかを説明します。 すぐに使える API は 2 種類あります:
- the Graph TypeScript library (
graph-ts
) and - graph codegenによってサブグラフファイルから生成されたコードです。
また、AssemblyScriptとの互換性があれば、他のライブラリを依存関係に追加することも可能です。 マッピングはこの言語で書かれているので、言語や標準ライブラリの機能については、 AssemblyScript wikiが参考になります。
@graphprotocol/graph-tsライブラリは、以下の API を提供しています:
- Ethereum スマートコントラクト、イベント、ブロック、トランザクション、Ethereum の値を扱うためのethereumAPI
- エンティティをグラフノードのストアからロードしたり、ストアに保存したりするstoreAPI
- Graph Node の出力や Graph Explorer にメッセージを記録するためのlogAPI です
- IPFS からファイルをロードするipfsAPI
- JSON データを解析するためのjsonAPI
- 暗号機能を使用するためのcryptoAPI
- Ethereum、JSON、GraphQL、AssemblyScript など、異なるタイプのシステム間で変換するための低レベルプリミティブ
サブグラフマニフェストapiVersionは、特定のサブグラフのマッピングAPIバージョンを指定します。このバージョンは、Graph Nodeによって実行されます。
バージョン | リリースノート |
---|---|
0.0.7 | Ethereum タイプに TransactionReceipt と Log クラスを追加Ethereum Event オブジェクトに receipt フィールドを追加。 |
0.0.6 | Ethereum Transactionオブジェクトにnonce フィールドを追加Ethereum Blockオブジェクトに baseFeePerGas を追加。 |
0.0.5 | AssemblyScriptはバージョン0.19.10にアップグレードされました(このバージョンアップには変更点が含まれていますので Migration Guide ) をご覧ください)。 ethereum.transaction.gasUsed の名前がethereum.transaction.gasLimit に変更 |
0.0.4 | Ethereum SmartContractCall オブジェクトにfunctionSignatureフィールドを追加 |
0.0.3 | イーサリアムコールオブジェクトに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の配列を表します。
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
を返します。
'@graphprotocol/graph-ts'から { BigDecimal } をインポートします。
BigDecimalは、任意の精度の小数を表現するために使用されます。
注意: 内部的に BigDecimal
は IEEE-754 decimal128 浮動小数点フォーマット で格納されます。このフォーマットはシグニフィカンドの小数点以下 34 桁をサポートしています。このため、 BigDecimal
は、Solidity の ufixed256x18
やそれに相当するような、34 桁よりも広い桁数の固定小数点型を表現するのには適していません。
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
と書くことができます。
'@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
と書くことができます。
'@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
を返します。
'@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
を返します。
'@graphprotocol/graph-ts'から { Address } をインポートします。
アドレス Address
はイーサリアムのアドレス address
値を表現するために Bytes
を継承しています。
Bytesの API の上に以下のメソッドを追加しています。
Address.fromString(s: string): Address
- 16進数文字列からAddress
を作成します。Address.fromBytes(b: Bytes): Address
-b
からAddress
を生成します。これは正確に20バイト長でなければなりません。それ以下のバイト数の値を渡すとエラーになります。
'@graphprotocol/graph-ts'から { store } をインポートします。
Store API は、グラフノードのストアにエンティティを読み込んだり、保存したり、削除したりすることができます。
Storeに書き込まれたエンティティは、サブグラフのGraphQLスキーマで定義された @entity
型に一対一でマッピングされます。これらのエンティティを便利に扱うために、Graph CLI が提供する graph codegen
コマンドはエンティティクラスを生成します。これは組み込みの Entity
型のサブクラスで、スキーマのフィールドのプロパティゲッターとセッター、およびこれらのエンティティをロードしたり保存したりするメソッドを持ちます。
Ethereum のイベントからエンティティを作成する際の一般的なパターンを以下に示します。
// 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 を持たなければなりません。 イベントのパラメータには、使用可能な一意の識別子が含まれているのが一般的です。 注:トランザクションのハッシュを ID として使用することは、同じトランザクション内の他のイベントがこのハッシュを 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のケースをチェックする必要があるかもしれません。
Note: エンティティのロードは、マッピングでの変更がエンティティの以前のデータに依存する場合にのみ必要です。 既存のエンティティを更新する 2 つの方法については、次のセクションを参照してください。
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 // または ID が構築される方法let transfer = Transfer.loadInBlock(id)if (transfer == null) {transfer = 新しい転送(id)}// 以前と同様に Transfer エンティティを使用します
注: 指定されたブロックにエンティティが作成されていない場合、ストア内に指定された ID を持つエンティティが存在する場合でも、loadInBlock は null を返します。
graph-node v0.31.0、@graphprotocol/graph-ts v0.31.0、および @graphprotocol/graph-cli v0.51.0 以降、loadMany メソッドが利用可能です。
これにより、イベント ハンドラー内から派生エンティティ フィールドをロードできるようになります。たとえば、次のスキーマがあるとします。
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')// Load the Token entities associated with a given holderlet tokens = holder.tokens.load()
既存のエンティティを更新するには 2 つの方法があります。
- Transfer.load(id)などでエンティティをロードし、エンティティにプロパティを設定した後、.save()でストアに戻す。
- 単純にnew Transfer(id)でエンティティを作成し、エンティティにプロパティを設定し、ストアに .save()します。 エンティティがすでに存在する場合は、変更内容がマージされます。
プロパティの変更は、生成されたプロパティセッターのおかげで、ほとんどの場合、簡単です。
let transfer = new Transfer(id)transfer.from = ...transfer.to = ...transfer.amount = ...
また、次の 2 つの命令のいずれかで、プロパティの設定を解除することも可能です。
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に渡す必要があります。
mport { store } from '@graphprotocol/graph-ts'...let id = event.transaction.hashstore.remove('Transfer', id)
Ethereum API は、スマートコントラクト、パブリックステート変数、コントラクト関数、イベント、トランザクション、ブロック、および Ethereum データのエンコード/デコードへのアクセスを提供します。
エンティティと同様に、graph codegenは、サブグラフで使用されるすべてのスマートコントラクトとイベントのためのクラスを生成します。 このためには、コントラクト ABI がサブグラフマニフェストのデータソースの一部である必要があります。 通常、ABI ファイルはabis/フォルダに格納されています。
生成されたクラスでは、Ethereum Typeとbuilt-in types間の変換が舞台裏で行われるため、サブグラフ作成者はそれらを気にする必要がありません。
以下の例で説明します。 以下のようなサブグラフのスキーマが与えられます。
type Transfer @entity {id: Bytes!from: Bytes!to: Bytes!amount: BigInt!}
イーサリアムの Transfer(address,address,uint256)
イベントシグネチャを使用すると、from
, to
, uint256
型の値は Address
と BigInt
に変換され、Transfer
エンティティの Bytes!
プロパティと BigInt!
プロパティに渡すことができます:
let id = event.transaction.hashlet transfer = new Transfer(id)transfer.from = event.params.fromtransfer.to = event.params.totransfer.amount = event.params.amounttransfer.save()
前述の例のTransferイベントのように、イベントハンドラに渡された Ethereum イベントは、イベントパラメータへのアクセスだけでなく、その親となるトランザクションや、それらが属するブロックへのアクセスも提供します。 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にエイリアスされています。
Ethereum の 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 ノードを使用することをお勧めします。
ethereumモジュールのencode/ decode関数を使用して、Ethereum の ABI エンコーディングフォーマットに従ってデータをエンコード/デコードすることができます。
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 Spec
- Encoding/decoding Rust library/CLI
- More complex example.
'@graphprotocol/graph-ts'から{ log } をインポートします。
log API は、サブグラフがグラフノードの標準出力やグラフエクスプローラに情報を記録するためのものです。 メッセージは、異なるログレベルを使って記録することができます。 基本的なフォーマット文字列の構文が提供されており、引数からログメッセージを構成することができます。
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 は、フォーマット文字列と文字列値の配列を受け取ります。 そして、プレースホルダーを配列の文字列値で置き換えます。 最初のプレースホルダーは配列の最初の値に置き換えられ、2 番目のプレースホルダーは 2 番目の値に置き換えられ、以下のようになります。
log.info('表示されるメッセージ。{}, {}, {}', [value.toString(), anotherValue.toString(), 'すでに文字列'])
以下の例では、文字列値 "A" を配列に渡して['A'] にしてからログに記録しています。
let myValue = 'A'export function handleSomeEvent(event: SomeEvent): void {// Displays : "My value is: A"log.info('My value is: {}', [myValue])}
以下の例では、配列に 3 つの値が含まれているにもかかわらず、引数の配列の最初の値だけがログに記録されます。
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)}
引数配列の各エントリは、ログメッセージ文字列に独自のプレースホルダーを必要とします。 以下の例では、ログメッセージに 3 つのプレースホルダーが含まれています。 このため、myArrayの 3 つの値すべてがログに記録されます。
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]])}
以下の例では、イベントからブロック番号、ブロックハッシュ、トランザクションハッシュをログに記録しています。
'@graphprotocol/graph-ts'から { log } をインポートします。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 のハッシュやパスが与えられた場合、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 は、マッピングで使用できる暗号化関数を提供します。 今のところ、1 つしかありません。
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
を変換します)
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クラスには、フィールドを動的に設定・取得するためのヘルパーが用意されています。
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
DataSourcesの
contextセクションでは、サブグラフマッピング内でアクセス可能なキーと値のペアを定義することができます。使用可能な型は
Bool、
String、
Int、
Int8、
BigDecimal、
Bytes、
List、
BigInt` です。
以下は context
セクションのさまざまな型の使い方を示す YAML の例です:
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
: 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.
このコンテキストは、サブグラフのマッピング・ファイルからアクセスでき、よりダイナミックで設定可能なサブグラフを実現します。