18 minutes
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.
Reference API
Knihovna @graphprotocol/graph-ts
poskytuje následující API:
- API
ethereum
pro práci s inteligentními kontrakty Ethereum, událostmi, bloky, transakcemi a hodnotami Ethereum. - API
store
pro načítání a ukládání entit z a do úložiště Graf uzel. - A
log
API to log messages to the Graph Node output and Graph Explorer. - API
ipfs
pro načítání souborů ze IPFS. - API
json
pro rozbor dat JSON. - API
crypto
pro použití kryptografických funkcí. - Nízkoúrovňové primitivy pro překlad mezi různými typovými systémy, jako je Ethereum, JSON, GraphQL a AssemblyScript.
Verze
The apiVersion
in the Subgraph manifest specifies the mapping API version which is run by Graph Node for a given Subgraph.
Verze | Poznámky vydání |
---|---|
0.0.9 | Adds new host functions eth_get_balance & hasCode |
0.0.8 | Přidá ověření existence polí ve schéma při ukládání entity. |
0.0.7 | Přidání tříd TransactionReceipt a Log do typů EthereumPřidání pole receipt do objektu Ethereum událost |
0.0.6 | Přidáno pole nonce do objektu Ethereum TransactionPřidáno baseFeePerGas do objektu Ethereum bloku |
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 | Přidání pole functionSignature do objektu Ethereum SmartContractCall |
0.0.3 | Added from field to the Ethereum Call objectethereum.call.address renamed to ethereum.call.to |
0.0.2 | Přidání pole input do objektu Ethereum Transackce |
Vestavěné typy
Documentation on the base types built into AssemblyScript can be found in the AssemblyScript wiki.
Následující doplňkové typy poskytuje @graphprotocol/graph-ts
.
ByteArray
1import { ByteArray } from '@graphprotocol/graph-ts'
ByteArray
představuje pole u8
.
Construction
fromI32(x: i32): ByteArray
- Rozebratx
na bajty.fromHexString(hex: string): - Vstupní délka musí být sudá. Předpona
0x` je nepovinná.
Type conversions
toHexString(): string
- Převede na hexadecimální řetězec s předponou0x
.toString(): string
- čte bajty jako řetězec UTF-8.toBase58(): string
- Zakóduje bajty do řetězce base58.toU32(): u32
- Interpretuje bajty jako little-endianu32
. Hodí v případě přetečení.toI32(): i32
- Interpretuje pole bajtů jako little-endiani32
. V případě přetečení hází.
Operators
equals(y: ByteArray): bool
– lze zapsat jakox == y
.concat(other: ByteArray) : ByteArray
- vrátí novéByteArray
složené zthis
přímo následovanéother
concatI32(other: i32) : ByteArray
- vrátí novéByteArray
složené zthis
přímo následované bytovou reprezentacíother
BigDecimal
1import { BigDecimal } from '@graphprotocol/graph-ts'
`BigDecimal se používá k reprezentaci libovolně přesných desetinných míst.
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)
- vytvoříBigDecimal
zBigInt
.static fromString(s: string): BigDecimal
– parses from a decimal string.
Type conversions
toString(): string
- vypisuje do desetinného řetězce.
Math
plus(y: BigDecimal): BigDecimal
– lze zapsat jakox + y
.minus(y: BigDecimal): BigDecimal
– lze zapsat jakox - y
.times(y: BigDecimal): BigDecimal
– lze zapsat jakox * y
.div(y: BigDecimal): BigDecimal
– lze zapsat jakox / y
.equals(y: BigDecimal): bool
– lze zapsat jakox == y
.notEqual(y: BigDecimal): bool
– lze zapsat jako`x !=.lt(y: BigDecimal): bool
– lze zapsat jakox < y
.le(y: BigDecimal): bool
– lze zapsat jakox <= y
.gt(y: BigDecimal): bool
– lze zapsat jakox > y
.ge(y: BigDecimal): bool
– lze zapsat jakox >= y
.neg(): BigDecimal - lze zapsat jako -x
.
BigInt
1import { BigInt } from '@graphprotocol/graph-ts'
BigInt
se používá k reprezentaci velkých celých čísel. Patří sem hodnoty Etherea typu uint32
až uint256
a int64
až int256
. Vše pod uint32
, jako například uint32
, uint24
nebo uint8
, je reprezentováno jako i32
.
Třída BigInt
má následující API:
Construction
-
BigInt.fromI32(x: i32): BigInt
- vytvoříBigInt
zi32
. -
BigInt.fromString(s: string): BigInt
- ZpracujeBigInt
z řetězce. -
BigInt.fromUnsignedBytes(x: Bytes): - Interpretuje
bytesjako celé číslo bez znaménka, little-endian. Pokud je váš vstup big-endian, zavolejte nejprve
.reverse()`. -
BigInt.fromSignedBytes(x: Bytes): - Interpretuje
bytesjako celé číslo se znaménkem, little-endian. Pokud je váš vstup big-endian, zavolejte nejprve
.reverse()`.Type conversions
-
x.toHex(): string
- změníBigInt
na řetězec hexadecimálních znaků. -
x.toString(): string
- změníBigInt
na řetězec desetinných čísel. -
x.toI32(): i32
- vrátíBigInt
jakoi32
; selže, pokud se hodnota nevejde doi32
. Je dobré nejprve zkontrolovatx.isI32()
. -
x.toBigDecimal(): BigDecimal
- převede na desetinné číslo bez zlomkové části.
Math
x.plus(y: BigInt): BigInt
– lze zapsat jakox + y
.x.minus(y: BigInt): BigInt
– lze zapsat jakox - y
.x.times(y: BigInt): BigInt
– lze zapsat jakox * y
.x.div(y: BigInt): BigInt
– lze zapsat jakox / y
.x.mod(y: BigInt): BigInt
– lze zapsat jakox % y
.x.equals(y: BigInt): bool
– lze zapsat jakox == y
.x.notEqual(y: BigInt): bool
–lze zapsat jakox != y
.x.lt(y: BigInt): bool
– lze zapsat jakox < y
.x.le(y: BigInt): bool
– lze zapsat jakox <= y
.x.gt(y: BigInt): bool
– lze zapsat jakox > y
.x.ge(y: BigInt): bool
– lze zapsat jakox >= y
.x.neg(): BigInt
– lze zapsat jako-x
.x.divDecimal(y: BigDecimal): BigDecimal
– dělí desetinným číslem, čímž získá desetinný výsledek.x.isZero(): bool
– Slouží ke kontrole, zda je číslo rovno nule.x.isI32(): bool
– Zjistí, zda se číslo vejde doi32
.x.abs(): BigInt
– absolutní hodnota.x.pow(exp: u8): BigInt
– umocňování.bitOr(x: BigInt, y: BigInt): BigInt
– lze zapsat jakox | y
.bitAnd(x: BigInt, y: BigInt): BigInt
– lze zapsat jakox & y
.leftShift(x: BigInt, bits: u8): BigInt
– lze zapsat jakox << y
.rightShift(x: BigInt, bits: u8): BigInt
– lze zapsat jakox >> y
.
TypedMap
1import { TypedMap } from '@graphprotocol/graph-ts'
TypedMap
lze použít k ukládání dvojic klíč-hodnota. Viz tento příklad.
Třída TypedMap
má následující API:
new TypedMap<K, V>()
– vytvoří prázdnou mapu s klíči typuK
a hodnotami typuV
map.set(key: K, value: V): void
– nastaví hodnotukey
navalue
map.getEntry(key: K): TypedMapEntry<K, V> | null
– vrátí dvojici klíč-hodnota prokey
nebonull
, pokudkey
v mapě neexistujemap.get(key: K): V | null
– vrací hodnotu prokey
nebonull
, pokudkey
v mapě neexistujemap.isSet(key: K): bool
– vracítrue
, pokudklíč
v mapě existuje, afalse
, pokud ne
Bajtů
1import { Bytes } from '@graphprotocol/graph-ts'
Bytes
se používá k reprezentaci libovolně dlouhých polí bajtů. Patří sem hodnoty Ethereum typu bytes
, bytes32
atd.
Třída Bytes
rozšiřuje třídu AssemblyScript Uint8Array a podporuje všechny funkce třídy Uint8Array
a navíc následující nové metody:
Construction
fromHexString(hex: string) : Bytes
- Převede řetězechex
, který se musí skládat ze sudého počtu hexadecimálních číslic, naByteArray
. Řetězechex
může volitelně začínat znakem0x
fromI32(i: i32) : Bytes
- Převodi
na pole bajtů
Type conversions
b.toHex()
– vrací hexadecimální řetězec reprezentující bajty v polib.toString()
– převede bajty v poli na řetězec unicode znakůb.toBase58()
–změní hodnotu Ethereum Bytes na kódování base58 (používá se pro IPFS hashe)
Operators
b.concat(other: Bytes) : Bytes
- - “Vrátit novýBytes
skládající se zthis
, který je přímo následovánother
.”b.concatI32(other: i32) : ByteArray
- vrátí novýBytes
složený zthis
přímo následovaný bajtovou reprezentacíother
Adresa
1import { Address } from '@graphprotocol/graph-ts'
Address
rozšiřuje Bytes
pro reprezentaci hodnot adresa
Ethereum.
Přidává následující metodu nad API Bytes
:
Address.fromString(s: string): Address
- vytvoříAddress
z hexadecimálního řetězceAddress.fromBytes(b: Bytes): Adresa
- vytvoříAdresu
zb
, která musí být dlouhá přesně 20 bajtů. Předání hodnoty s menším nebo větším počtem bajtů bude mít za následek chybu
API ukládat
1import { store } from '@graphprotocol/graph-ts'
API store
umožňuje načítat, ukládat a odebírat entity z a do úložiště Graf uzel.
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.
Vytváření entity
Následuje běžný vzor pro vytváření entity z událostí Ethereum.
1// Importovat třídu události Transfer vygenerovanou z ERC20 ABI2import { Transfer as TransferEvent } z '../generated/ERC20/ERC20'34// Importovat typ entity Transfer vygenerovaný ze schématu GraphQL5import { Transfer } z '../generated/schema'67// Obsluha události Transfer8export function handleTransfer(event: TransferEvent): void {9 // Vytvoří entitu Transfer s použitím hashe transakce jako ID entity10 let id = event.transaction.hash11 let transfer = new Transfer(id)1213 // Nastavte vlastnosti entity pomocí parametrů události14 transfer.from = event.params.from15 transfer.to = event.params.to16 transfer.amount = event.params.amount1718 // Uložení entity do úložiště19 transfer.save()20}
Pokud se při zpracování řetězce vyskytne událost Transfer
, je předána obsluze události handleTransfer
pomocí vygenerovaného typu Transfer
(zde alias TransferEvent
, aby nedošlo ke konfliktu názvů s typem entity). Tento typ umožňuje přístup k datům, jako je nadřazená transakce události a její parametr.
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.
Načítání entity z úložiště
Pokud již entita existuje, lze ji z úložiště načíst pomocí následujících příkazů:
1let id = event.transaction.hash // nebo jakkoli je ID konstruováno2let transfer = Transfer.load(id)3if (transfer == null) {4 transfer = new Transfer(id)5}67// Použijte entitu Transfer jako dříve
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.
Vyhledávání entit vytvořených v rámci bloku
Od verzí graph-node
v0.31.0, @graphprotocol/graph-ts
v0.30.0 a @graphprotocol/graph-cli
v0.49.0 je metoda loadInBlock
dostupná pro všechny typy entit.
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 // or however the ID is constructed2let transfer = Transfer.loadInBlock(id)3if (transfer == null) {4 transfer = new Transfer(id)5}67// Use the Transfer entity as before
Poznámka: Pokud v daném bloku není vytvořena žádná entita, vrátí loadInBlock
hodnotu null
, i když v úložišti existuje entita s daným ID.
Vyhledávání odvozených entity
Od verzí graph-node
v0.31.0, @graphprotocol/graph-ts
v0.31.0 a @graphprotocol/graph-cli
v0.51.0 je k dispozici metoda loadRelated
.
To umožňuje načítání odvozených polí entityh z obsluhy události. Například při následujícím schématu:
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}
Následující kód načte entitu Token
, ze které byla odvozena entita Holder
:
1let holder = Holder.load('test-id')2// Načtení entit tokenů přidružených k danému držiteli3let tokens = holder.tokens.load()
Aktualizace stávajících entity
Existují dva způsoby, jak aktualizovat existující entity:
- Načtěte entitu např. pomocí
Transfer.load(id)
, nastavte vlastnosti entity a poté ji.save()
uložte zpět do úložiště. - Jednoduše vytvořte entitu např. pomocí
new Transfer(id)
, nastavte vlastnosti entity a poté ji.save()
uložte do úložiště. Pokud entita již existuje, změny se do ní sloučí.
Změna vlastností je ve většině případů jednoduchá díky generovaným nastavovačům vlastností:
1let transfer = new Transfer(id)2transfer.from = ...3transfer.to = ...4transfer.amount = ...
Vlastnosti lze také zrušit jedním z následujících dvou příkazů:
1transfer.from.unset()2transfer.from = null
To funguje pouze u nepovinných vlastností, tj. vlastností, které jsou v jazyce GraphQL deklarovány bez znaku !
. Dva příklady: owner: Bytes
nebo amount: BigInt
.
Aktualizace vlastností pole je trochu složitější, protože získání pole z entity vytvoří kopii tohoto pole. To znamená, že vlastnosti pole je třeba po změně pole znovu explicitně nastavit. Následující příklad předpokládá, že entita
má čísla: [BigInt!]!
pole.
1// Tohle nebude fungovat2entity.numbers.push(BigInt.fromI32(1))3entity.save()45// Toto bude fungovat6let numbers = entity.numbers7numbers.push(BigInt.fromI32(1))8entity.numbers = numbers9entity.save()
Odstranění entit z úložiště
V současné době není možné odstranit entitu prostřednictvím generovaných typů. Místo toho je pro odstranění entity nutné předat název typu entity a ID entity příkazu store.remove
:
1import { store } from '@graphprotocol/graph-ts'2...3let id = event.transaction.hash4store.remove('Transfer', id)
Ethereum API
Ethereum API poskytuje přístup k inteligentním smlouvám, veřejným stavovým proměnným, funkcím smluv, událostem, transakcím, blokům a kódování/dekódování dat Etherea.
Podpora typů 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}
a podpis události Transfer(address,address,uint256)
na platformě Ethereum jsou hodnoty from
, to
a amount
typu adresa
, adresa
a uint256
převedeny na Address
a BigInt
, což umožňuje jejich předání do vlastností Bytes!
a BigInt!
entity Transfer
:
1let id = event.transaction.hash2let transfer = new Transfer(id)3transfer.from = event.params.from4transfer.to = event.params.to5transfer.amount = event.params.amount6transfer.save()
Události a bloková/transakční data
Události Ethereum předávané obsluze událostí, jako je událost Transfer
v předchozích příkladech, poskytují přístup nejen k parametrům události, ale také k nadřazené transakci a bloku, jehož jsou součástí. Z instancí event
(tyto třídy jsou součástí modulu ethereum
v graph-ts
) lze získat následující údaje:
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}
Přístup ke stavu inteligentní smlouvy
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.
Běžným vzorem je přístup ke smlouvě, ze které událost pochází. Toho lze dosáhnout pomocí následujícího kódu:
1// Import vygenerované třídy smlouvy a vygenerované třídy události Transfer2import { ERC20Contract, Transfer as TransferEvent } z '../generated/ERC20Contract/ERC20Contract'3// Importovat vygenerovanou třídu entit4import { Transfer } z "../generated/schema56export function handleTransfer(event: TransferEvent) {7 // Vázat smlouvu na adresu, která událost vyslala8 let contract = ERC20Contract.bind(event.address)910 // Přístup ke stavovým proměnným a funkcím jejich voláním11 let erc20Symbol = contract.symbol()12}
Transfer
je zde aliasován na TransferEvent
, aby nedošlo ke konfliktu názvů s typ entity
Pokud má smlouva ERC20Contract
na platformě Ethereum veřejnou funkci pouze pro čtení s názvem symbol
, lze ji volat pomocí .symbol()
. Pro veřejné stavové proměnné se automaticky vytvoří metoda se stejným názvem.
Any other contract that is part of the Subgraph can be imported from the generated code and can be bound to a valid address.
Zpracování vrácených volání
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.
Kódování/dekódování ABI
Data lze kódovat a dekódovat podle formátu kódování ABI Ethereum pomocí funkcí encode
a decode
v modulu ethereum
.
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)
Více informací:
- 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
1import { log } from '@graphprotocol/graph-ts'
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 obsahuje následující funkce:
log.debug(fmt: string, args: Array<string>): void
- zaznamená ladicí zprávu.log.info(fmt: string, args: Array<string>): void
- zaznamená informační zprávu.log.warning(fmt: string, args: Array<string>): void
- zaznamená varování.log.error(fmt: string, args: Array<string>): void
- zaznamená chybovou zprávu.log.critical(fmt: string, args: Array<string>): void
– logs a critical message and terminates the Subgraph.
log
API přebírá formátovací řetězec a pole řetězcových hodnot. Poté nahradí zástupné symboly řetězcovými hodnotami z pole. První zástupný symbol „“ bude nahrazen první hodnotou v poli, druhý zástupný symbol „“ bude nahrazen druhou hodnotou a tak dále.
1log.info('Message to be displayed: {}, {}, {}', [value.toString(), anotherValue.toString(), 'already a string'])
Zaznamenávání jedné nebo více hodnot
Zaznamenávání jedné hodnoty
V níže uvedeném příkladu je řetězcová hodnota “A” předána do pole a stane se z ní ['A']
, než je zapsána:
1let myValue = 'A'23export function handleSomeEvent(event: SomeEvent): void {4 // Displays : "My value is: A"5 log.info('My value is: {}', [myValue])6}
Protokolování jedné položky z existujícího pole
V příkladu níže je zaznamenána pouze první hodnota pole argumentů, přestože pole obsahuje tři hodnoty.
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}
Protokolování více záznamů z existujícího pole
Každá položka v poli argumentů vyžaduje vlastní zástupný znak {}
v řetězci zprávy protokolu. Níže uvedený příklad obsahuje tři zástupné zna. Z tohoto důvodu jsou zaznamenány všechny tři hodnoty v poli myArray
.
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}
Protokolování konkrétní položky z existujícího pole
Chcete-li zobrazit konkrétní hodnotu v poli, je třeba zadat indexovanou hodnotu.
1export function handleSomeEvent(event: SomeEvent): void {2 // Displays : "My third value is C"3 log.info('My third value is: {}', [myArray[2]])4}
Zaznamenávání informací o událostech
Níže uvedený příklad zaznamenává číslo bloku, hash bloku a hash transakce z události:
1import { log } from '@graphprotocol/graph-ts'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
1import { ipfs } from '@graphprotocol/graph-ts'
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.
Při zadání hashe nebo cesty IPFS se čtení souboru ze systému IPFS provádí následujícím způsobem:
1// Vložte to do obsluhy události v mapování2let hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D'3let data = ipfs.cat(hash)45// Cesty jako `QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile`6// které obsahují soubory v adresářích, jsou také podporovány7let path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'8let data = ipfs.cat(cesta)
Poznámka: ipfs.cat
není v současné době deterministický. Pokud se soubor nepodaří načíst přes síť IPFS před vypršením požadavku, vrátí se null
. Z tohoto důvodu se vždy vyplatí zkontrolovat výsledek na null
.
Pomocí nástroje ipfs.map
je také možné zpracovávat větší soubory proudovým způsobem. Funkce očekává hash nebo cestu k souboru IPFS, název zpětného volání a příznaky pro úpravu chování:
1import { JSONValue, Value } z '@graphprotocol/graph-ts'23export function processItem(value: JSONValue, userData: Value): void {4 // Podrobnosti o zpracování viz dokumentace k JSONValue5 // s hodnotami JSON6 let obj = value.toObject()7 let id = obj.get('id')8 let title = obj.get('title')910 if (!id || !title) {11 return12 }1314 // Callbacky mohou také vytvářet entity15 let newItem = new Item(id)16 newItem.title = title.toString()17 newitem.parent = userData.toString() // Nastavit rodiče na "parentId"18 newitem.save()19}2021// Toto vložte do obsluhy události v mapování22ipfs.map('Qm...', 'processItem', Value.fromString('parentId'), ['json'])2324// Případně použijte `ipfs.mapJSON`25ipfs.mapJSON('Qm...', 'processItem', Value.fromString('parentId'))
V současné době je podporován pouze příznak json
, který musí být předán souboru ipfs.map
. S příznakem json
se soubor IPFS musí skládat z řady hodnot JSON, jedna hodnota na řádek. Volání příkazu ipfs.map
přečte každý řádek souboru, deserializuje jej do hodnoty JSONValue
a pro každou z nich zavolá zpětné volání. Zpětné volání pak může použít operace entit k uložení dat z JSONValue
. Změny entit se uloží až po úspěšném ukončení obsluhy, která volala ipfs.map
; do té doby se uchovávají v paměti, a velikost souboru, který může ipfs.map
zpracovat, je proto omezená.
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
1import { crypto } from '@graphprotocol/graph-ts'
API crypto
zpřístupňuje kryptografické funkce pro použití v mapování. Nyní je k dispozici pouze jedna:
crypto.keccak256(input: ByteArray): ByteArray
JSON API
1import { json, JSONValueKind } from '@graphprotocol/graph-ts'
Data JSON lze analyzovat pomocí API json
:
json.fromBytes(data: Bytes): JSONValue
- analyzuje data JSON z poleBytes
interpretovaného jako platná posloupnost UTF-8json.try_fromBytes(data: Bytes): Výsledek<JSONValue, boolean>
- bezpečná verzejson.fromBytes
, vrací chybovou variantu, pokud se parsování nezdařilojson.fromString(data: string): JSONValue
- analyzuje data JSON z platného UTF-8Řetězce
json.try_fromString(data: string): Výsledek<JSONValue, boolean>
- bezpečná verzejson.fromString
, vrací chybovou variantu, pokud se parsování nezdařilo
Třída JSONValue
poskytuje způsob, jak vytáhnout hodnoty z libovolného dokumentu JSON. Protože hodnoty JSON mohou být logické, číselné, pole a další, je JSONValue
vybavena vlastností kind
pro kontrolu typu hodnoty:
1let value = json.fromBytes(...)2if (value.kind == JSONValueKind.BOOL) {3 ...4}
Kromě toho existuje metoda pro kontrolu, zda je hodnota null
:
value.isNull(): boolean
Pokud je typ hodnoty jistý, lze ji převést na vestavěný typ pomocí jedné z následujících metod:
value.toBool(): boolean
value.toI64(): i64
value.toF64(): f64
value.toBigInt(): BigInt
value.toString(): string
value.toArray(): Array<JSONValue>
- (a poté převéstJSONValue
pomocí jedné z 5 výše uvedených metod)
Převody typů Reference
Zdroj(e) | Destinace | Funkce převodu |
---|---|---|
Address | Bytes | none |
Address | String | s.toHexString() |
BigDecimal | String | s.toString() |
BigInt | BigDecimal | s.toBigDecimal() |
BigInt | String (hexadecimální) | 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 (hexadecimální) | 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.fromBytes(s) |
String | BigInt | BigInt.fromString(s) |
String | BigDecimal | BigDecimal.fromString(s) |
String (hexadecimální) | Bytes | ByteArray.fromHexString(s) |
String (UTF-8) | Bytes | ByteArray.fromUTF8(s) |
Metadata zdroje dat
Adresu smlouvy, síť a kontext zdroje dat, který obslužnou rutinu vyvolal, můžete zkontrolovat prostřednictvím jmenného prostoru dataSource
:
dataSource.address(): Address
dataSource.network(): string
dataSource.context(): DataSourceContext
Entity a DataSourceContext
Základní třída Entity
a podřízená třída DataSourceContext
mají pomocníky pro dynamické nastavování a získávání polí:
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 v manifestu
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
.
Zde je příklad YAML ilustrující použití různých typů v sekci context
:
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
: Určuje Boolean hodnotu (true
nebofalse
).String
: Určuje hodnotu řetězce.Int
: Určuje 32bitové celé číslo.Int8
: Určuje 8bitové celé číslo.BigDecimal
: Určuje desetinné číslo. Musí být uvedeno v uvozovkách.Bytes
: Určuje hexadecimální řetězec.Seznam
: Určuje seznam položek. U každé položky je třeba zadat její typ a data.BigInt
: Určuje velkou celočíselnou hodnotu. Kvůli velké velikosti musí být uvedena v uvozovkách.
This context is then accessible in your Subgraph mapping files, enabling more dynamic and configurable Subgraphs.