AssemblyScript API Part 2
Storage API
The storage API allows to load, save, and delete entities from the HyperGraph node storage.
There is a one-to-one correspondence between the entities written in the storage mapping table and the @entity type defined in the schema.graphql file of the subgraph. In order to facilitate the use of these entities, Graph CLI (HyperGraph, please use the graph codegen command provided by @hgdotnetwork/graph-cli) to generate entity classes, which are subclasses of the built-in Entity type, with the attribute getters and setters of the fields in the Schema and load ) And save (save) methods to manipulate these entities.
Create entity
The following are common patterns for creating entities based on Ethereum events.
When processing blockchain data encounters a Transfer event, it will use the generated Transfer type (actually an alias of TransferEvent to avoid naming conflicts with the entity type) and pass it to the handleTransfer event handler. This type allows access to data, such as the parent transaction of the event and its parameters.
Each entity must have a unique ID to avoid conflicts with other entities. It is quite common for event parameters to contain unique identifiers that can be used. Note: Using the transaction hash as the ID assumes that no other event in the same transaction creates an entity that uses the hash as the ID.
Loading an entity from storage If the entity already exists, you can load it from storage using the following methods:
Since the entity may not yet exist in storage, the type returned by the load method is Transfer or null. Therefore, it may be necessary to check whether the value is null before using it.
Note: You only need to load the entity if the changes made during the mapping implementation depend on the previous data of the entity. See the next section for two ways to update existing entities.
Updating existing entities There are two ways to update existing entities:
Load the entity, such as Transfer.load(id), set properties on the entity, and then .save() save the updated entity to storage.
Just use new Transfer(id) to create an entity, set properties on the entity, and then use .save() to save the entity to storage. If the entity already exists, the changes will be merged into it. In most cases, because the property setter (setter method) is generated, changing the property is simple:
You can also use one of the following two commands to unset attributes:
This only applies to optional attributes, that is, attributes without! In the declared attributes.
This only applies to optional properties, that is, properties without! In the declared properties of GraphQL. Two examples of such attributes are:
owner:Bytes or amount:BigInt
Updating the array properties takes more effort, because getting the array from the entity creates a copy of the array. This means that you must explicitly set the array properties again after changing the array. The following assumes that the entity has a numeric array field: [BigInt!]! field.
Deleting entities from storage Currently, entities cannot be deleted from the generated type. On the contrary, to delete an entity, you need to pass the name of the entity type and the entity ID to store.remove to delete:
Ethereum API The Ethereum API provides access to smart contracts, public state variables, contract functions, events, transactions, and blocks.
Support for Ethereum types Like entities, the graph codegen command generates corresponding classes for all smart contracts and events used in the subgraph. For this, the contract ABI must be part of the data source in the subgraph declaration list.
Usually, ABI files are stored in the abis/ folder. Using the generated class, the conversion between the Ethereum type and the built-in type is performed in the underlying mechanism, so the subgraph developer does not need to care.
The following example illustrates this. Given a schema definition of a subgraph, such as
Then there is a Transfer(address,address,uint256) event signature on Ethereum, three parameters: from, to and Amount, the types are address, address and uint256 respectively. In data processing, address and uint256 will be converted to Address and BigInt, so that they can be passed to the Bytes! and BigInt! properties of the Transfer entity:
Event, block/transaction data
The Ethereum event passed to the event handler, such as the Transfer event in the previous example, not only provides access to the event parameters, but also access to its parent transaction and the block to which it belongs. The following data can be obtained from the event instance (these classes are part of the Ethereum module in graph-ts):
Access to smart contract status The code generated by the graph codegen command also includes the smart contract classes used in the subgraph. These can be used to access public state variables and call other methods of the smart contract in the current block. A common pattern is the smart contract that accesses the origin of the event. This can be achieved with the following code:
The ERC20 smart contract on Ethereum has a public read-only function called symbol, which can be called using .symbol(). For public state variables, a method with the same name will be automatically created. Any other contract of the subgraph can be imported from the generated code and can be bound to a valid address.
Logging and debugging
The log API allows the subgraph to log information to the standard output of the HyperGraph node and the Graph browser. You can use different log levels to log messages. A basic format string syntax is provided to compose log messages based on parameter variables.
The log API includes the following functions: log.debug(fmt: string, args: Array): void——Record debugging messages. log.info(fmt: string, args: Array): void——Record prompt messages. log.warning(fmt: string, args: Array): void——log warning log.error(fmt: string, args: Array): void——log error message. log.critical(fmt: string, args: Array): void——log important messages and terminate the subgraph. The log API accepts format strings and arrays of string values. Then, it replaces the placeholders with string values in the array. The first {} placeholder is replaced with the first value in the array, the second {} placeholder is replaced with the second value, and so on.
Record one or more values Record a single value
In the following example, the string value "A" is passed into an array to become ['A'] before being recorded:
Record a single entry from an existing array In the following example, although the array contains three values, only the first value of the parameter array is recorded.
Record multiple entries from an existing array. Each entry in the arguments array needs to have its own placeholder {} in the log message string. The following example includes three placeholders {} in the log message. Therefore, all three values in myArray will be recorded.
Record a specific entry from an existing array To display a specific value in the array, an index value must be provided.
Record event information The following example records the block number, block hash, and transaction hash of the event:
IPFS API
Smart contracts sometimes anchor IPFS files on the blockchain. This allows the mapping to obtain the IPFS hash from the smart contract and read the corresponding file from IPFS. The file data will be returned in the Bytes data format, which usually requires further processing, such as using the JSON API mentioned later in this section.
Given an IPFS hash or path, you can read files from IPFS as follows:
Note: ipfs.cat has not yet been determined. If the file cannot be retrieved through the IPFS network before the request times out, it will return a null value (null). Therefore, it is necessary to always check whether the result is null. In order to ensure that the files can be retrieved, they must be associated with the IPFS node corresponding to the HyperGraph node. If you use hosting services, the Heco network uses https://f.hg.netwoprk/, and the BSC network uses https://pf.hg.network.
You can also use ipfs.map to stream larger files. This function requires the hash or path of the IPFS file, the name of the callback, and the flags used to modify its behavior:
Currently the only supported flag is json, which must be passed to ipfs.map. With the json flag, the IPFS file must contain a series of JSON values, one value per line. Calling ipfs.map will read every line in the file, deserialize it into JSONValue and call the callback function for each of them. The callback can then use entity operations to store data from JSONValue. The changed content of the entity is stored only when the handler calling ipfs.map completes successfully. At the same time, they are stored in memory, so the file size that ipfs.map can handle is limited.
After success, ipfs.map will return void. If any call of the callback results in an error, the handler calling ipfs.map will abort and mark the submap as failed.
Encryption API
The encryption API makes functions related to encryption algorithms available for mapping. Currently there is only one:
crypto.keccak256(input: ByteArray): ByteArray
JSON API
JSON data can be parsed using the json API:
json.fromBytes(data:Bytes):JSONValue-Parsing JSON data from the Bytes array The JSONValue class provides a method to extract values from any JSON document. Since JSON values can be booleans, numbers, arrays, etc., JSONValue has a property to check the value type:
In addition, there is a way to check whether the value is empty:
value.isNull():boolean
When the type of the value is determined, it can be converted to a built-in type using one of the following methods:
value.toBool():boolean
value.toI64():i64
value.toF64():f64
value.toBigInt():BigInt
value.toString():string
value.toArray():Array ——(Then use one of the above 5 methods to convert JSONValue)
Type conversion reference
Data source metadata
You can check the smart contract address, network and context of the data source calling the handler through the dataSource namespace:
dataSource.address(): Address
dataSource.network(): string
dataSource.context(): DataSourceContext
Entity and DataSourceContext The basic Entity class and sub-DataSourceContext class have tool methods to dynamically set and get the ability of fields:
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
Last updated