AssemblyScript API
Reading time: 20 minutes
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 Reference
The @graphprotocol/graph-ts
library provides the following APIs:
- An
ethereum
API for working with Ethereum smart contracts, events, blocks, transactions, and Ethereum values. - A
store
API to load and save entities from and to the Graph Node store. - A
log
API to log messages to the Graph Node output and Graph Explorer. - An
ipfs
API to load files from IPFS. - A
json
API to parse JSON data. - A
crypto
API to use cryptographic functions. - Low-level primitives to translate between different type systems such as Ethereum, JSON, GraphQL and AssemblyScript.
Versions
The apiVersion
in the subgraph manifest specifies the mapping API version which is run by Graph Node for a given subgraph.
Version | Release notes |
---|---|
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 | Added TransactionReceipt and Log classes to the Ethereum typesAdded receipt field to the Ethereum Event object |
0.0.6 | Added nonce field to the Ethereum Transaction objectAdded baseFeePerGas to the Ethereum Block object |
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 | Added functionSignature field to the Ethereum SmartContractCall object |
0.0.3 | Added from field to the Ethereum Call objectethereum.call.address renamed to ethereum.call.to |
0.0.2 | Added input field to the Ethereum Transaction object |
Built-in Types
Documentation on the base types built into AssemblyScript can be found in the AssemblyScript wiki.
The following additional types are provided by @graphprotocol/graph-ts
.
ByteArray
import { ByteArray } from '@graphprotocol/graph-ts'
ByteArray
represents an array of u8
.
Construction
fromI32(x: i32): ByteArray
- Decomposesx
into bytes.fromHexString(hex: string): ByteArray
- Input length must be even. Prefixing with0x
is optional.
Type conversions
toHexString(): string
- Converts to a hex string prefixed with0x
.toString(): string
- Interprets the bytes as a UTF-8 string.toBase58(): string
- Encodes the bytes into a base58 string.toU32(): u32
- Interprets the bytes as a little-endianu32
. Throws in case of overflow.toI32(): i32
- Interprets the byte array as a little-endiani32
. Throws in case of overflow.
Operators
equals(y: ByteArray): bool
– can be written asx == y
.concat(other: ByteArray) : ByteArray
- return a newByteArray
consisting ofthis
directly followed byother
concatI32(other: i32) : ByteArray
- return a newByteArray
consisting ofthis
directly followed by the byte representation ofother
BigDecimal
import { BigDecimal } from '@graphprotocol/graph-ts'
BigDecimal
is used to represent arbitrary precision decimals.
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)
– creates aBigDecimal
from anBigInt
.static fromString(s: string): BigDecimal
– parses from a decimal string.
Type conversions
toString(): string
– prints to a decimal string.
Math
plus(y: BigDecimal): BigDecimal
– can be written asx + y
.minus(y: BigDecimal): BigDecimal
– can be written asx - y
.times(y: BigDecimal): BigDecimal
– can be written asx * y
.div(y: BigDecimal): BigDecimal
– can be written asx / y
.equals(y: BigDecimal): bool
– can be written asx == y
.notEqual(y: BigDecimal): bool
– can be written asx != y
.lt(y: BigDecimal): bool
– can be written asx < y
.le(y: BigDecimal): bool
– can be written asx <= y
.gt(y: BigDecimal): bool
– can be written asx > y
.ge(y: BigDecimal): bool
– can be written asx >= y
.neg(): BigDecimal
- can be written as-x
.
BigInt
import { BigInt } from '@graphprotocol/graph-ts'
BigInt
is used to represent big integers. This includes Ethereum values of type uint32
to uint256
and int64
to int256
. Everything below uint32
, such as int32
, uint24
or int8
is represented as i32
.
The BigInt
class has the following API:
Construction
-
BigInt.fromI32(x: i32): BigInt
– creates aBigInt
from ani32
. -
BigInt.fromString(s: string): BigInt
– Parses aBigInt
from a string. -
BigInt.fromUnsignedBytes(x: Bytes): BigInt
– Interpretsbytes
as an unsigned, little-endian integer. If your input is big-endian, call.reverse()
first. -
BigInt.fromSignedBytes(x: Bytes): BigInt
– Interpretsbytes
as a signed, little-endian integer. If your input is big-endian, call.reverse()
first.Type conversions
-
x.toHex(): string
– turnsBigInt
into a string of hexadecimal characters. -
x.toString(): string
– turnsBigInt
into a decimal number string. -
x.toI32(): i32
– returns theBigInt
as ani32
; fails if the value does not fit intoi32
. It’s a good idea to first checkx.isI32()
. -
x.toBigDecimal(): BigDecimal
- converts into a decimal with no fractional part.
Math
x.plus(y: BigInt): BigInt
– can be written asx + y
.x.minus(y: BigInt): BigInt
– can be written asx - y
.x.times(y: BigInt): BigInt
– can be written asx * y
.x.div(y: BigInt): BigInt
– can be written asx / y
.x.mod(y: BigInt): BigInt
– can be written asx % y
.x.equals(y: BigInt): bool
– can be written asx == y
.x.notEqual(y: BigInt): bool
– can be written asx != y
.x.lt(y: BigInt): bool
– can be written asx < y
.x.le(y: BigInt): bool
– can be written asx <= y
.x.gt(y: BigInt): bool
– can be written asx > y
.x.ge(y: BigInt): bool
– can be written asx >= y
.x.neg(): BigInt
– can be written as-x
.x.divDecimal(y: BigDecimal): BigDecimal
– divides by a decimal, giving a decimal result.x.isZero(): bool
– Convenience for checking if the number is zero.x.isI32(): bool
– Check if the number fits in ani32
.x.abs(): BigInt
– Absolute value.x.pow(exp: u8): BigInt
– Exponentiation.bitOr(x: BigInt, y: BigInt): BigInt
– can be written asx | y
.bitAnd(x: BigInt, y: BigInt): BigInt
– can be written asx & y
.leftShift(x: BigInt, bits: u8): BigInt
– can be written asx << y
.rightShift(x: BigInt, bits: u8): BigInt
– can be written asx >> y
.
TypedMap
import { TypedMap } from '@graphprotocol/graph-ts'
TypedMap
can be used to store key-value pairs. See this example.
The TypedMap
class has the following API:
new TypedMap<K, V>()
– creates an empty map with keys of typeK
and values of typeV
map.set(key: K, value: V): void
– sets the value ofkey
tovalue
map.getEntry(key: K): TypedMapEntry<K, V> | null
– returns the key-value pair for akey
ornull
if thekey
does not exist in the mapmap.get(key: K): V | null
– returns the value for akey
ornull
if thekey
does not exist in the mapmap.isSet(key: K): bool
– returnstrue
if thekey
exists in the map andfalse
if it does not
Bytes
import { Bytes } from '@graphprotocol/graph-ts'
Bytes
is used to represent arbitrary-length arrays of bytes. This includes Ethereum values of type bytes
, bytes32
, etc.
The Bytes
class extends AssemblyScript’s Uint8Array and this supports all the Uint8Array
functionality, plus the following new methods:
Construction
fromHexString(hex: string) : Bytes
- Convert the stringhex
which must consist of an even number of hexadecimal digits to aByteArray
. The stringhex
can optionally start with0x
fromI32(i: i32) : Bytes
- Converti
to an array of bytes
Type conversions
b.toHex()
– returns a hexadecimal string representing the bytes in the arrayb.toString()
– converts the bytes in the array to a string of unicode charactersb.toBase58()
– turns an Ethereum Bytes value to base58 encoding (used for IPFS hashes)
Operators
b.concat(other: Bytes) : Bytes
- - return newBytes
consisting ofthis
directly followed byother
b.concatI32(other: i32) : ByteArray
- return newBytes
consisting ofthis
directly follow by the byte representation ofother
Address
import { Address } from '@graphprotocol/graph-ts'
Address
extends Bytes
to represent Ethereum address
values.
It adds the following method on top of the Bytes
API:
Address.fromString(s: string): Address
– creates anAddress
from a hexadecimal stringAddress.fromBytes(b: Bytes): Address
– create anAddress
fromb
which must be exactly 20 bytes long. Passing in a value with fewer or more bytes will result in an error
Store API
import { store } from '@graphprotocol/graph-ts'
The store
API allows to load, save and remove entities from and to the Graph Node store.
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.
Creating entities
The following is a common pattern for creating entities from Ethereum events.
// 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 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()}
When a Transfer
event is encountered while processing the chain, it is passed to the handleTransfer
event handler using the generated Transfer
type (aliased to TransferEvent
here to avoid a naming conflict with the entity type). This type allows accessing data such as the event’s parent transaction and its parameters.
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.
Loading entities from the store
If an entity already exists, it can be loaded from the store with the following:
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
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.
Looking up entities created withing a block
As of graph-node
v0.31.0, @graphprotocol/graph-ts
v0.30.0 and @graphprotocol/graph-cli
v0.49.0 the