Docs
La Recherche⌘ K
  • Accueil
  • À propos de The Graph
  • Réseaux pris en charge
  • Contrats du Protocole
  • Subgraphs
    • Substreams
      • Token API
        • AI Suite
          • Indexing
            • Resources
              Subgraphs > Developing > Creating > API AssemblyScript

              22 minutes

              API AssemblyScript

              Note : Si vous avez créé un subgraph avant la version graph-cli/graph-ts 0.22.0, alors vous utilisez une ancienne version d’AssemblyScript. Il est recommandé de consulter le Guide de migration.

              Découvrez les API intégrées qui peuvent être utilisées lors de l’écriture de mappages de subgraphs. Deux types d’API sont disponibles sont disponibles nativement :

              • La Bibliothèque TypeScript de The Graph⁠ (graph-ts)
              • Code généré à partir des fichiers de subgraphs par graph codegen

              Vous pouvez également ajouter d’autres bibliothèques comme dépendances, à condition qu’elles soient compatibles avec [AssemblyScript] (https://github.com/AssemblyScript/assemblyscript⁠).

              Étant donné que les mappages de langage sont écrits en AssemblyScript, il est utile de consulter les fonctionnalités de langage et de bibliothèque standard dans le du [wiki AssemblyScript] (https://github.com/AssemblyScript/assemblyscript/wiki⁠).

              Référence API

              La bibliothèque @graphprotocol/graph-ts fournit les API suivantes :

              • Une API ethereum pour travailler avec les contrats intelligents Ethereum, les événements, les blocs, les transactions et les valeurs Ethereum.
              • Une API store pour charger et enregistrer des entités depuis et vers le magasin Graph Node.
              • Une API log pour enregistrer des messages dans la sortie Graph Node et Graph Explorer.
              • Une API ipfs pour charger des fichiers depuis IPFS.
              • Une API json pour analyser les données JSON.
              • Une API crypto pour utiliser des fonctions cryptographiques.
              • Primitives de bas niveau pour traduire entre différents systèmes de types tels que Ethereum, JSON, GraphQL et AssemblyScript.

              Versions

              La apiVersion dans le manifeste du subgraph spécifie la version de l’API de mappage qui est exécutée par Graph Node pour un subgraph donné.

              VersionNotes de version
              0.0.9Ajout de nouvelles fonctions hôtes eth_get_balance & hasCode
              0.0.8Ajout de la validation pour l’existence des champs dans le schéma lors de l’enregistrement d’une entité.
              0.0.7Ajout des classes TransactionReceipt et Logaux types Ethereum
              Ajout du champ receipt à l’objet Ethereum Event
              0.0.6Ajout du champ nonce à l’objet Ethereum Transaction
              Ajout de baseFeePerGas à l’objet Ethereum Block
              0.0.5AssemblyScript mis à jour vers la version 0.19.10 (cela inclut des changements de rupture, veuillez consulter le Guide de migration)
              ethereum.transaction.gasUsed renommé en ethereum.transaction.gasLimit
              0.0.4Ajout du champ functionSignature à l’objet Ethereum SmartContractCall
              0.0.3Ajout du champ from à l’objet Ethereum Call
              ethereum.call.address renommé en ethereum.call.to
              0.0.2Ajout du champ input à l’objet Ethereum Transaction

              Types intégrés

              La documentation sur les types de base intégrés dans AssemblyScript se trouve dans le wiki AssemblyScript⁠.

              Les types additionnels suivants sont fournis par @graphprotocol/graph-ts.

              ByteArray

              1import { ByteArray } from '@graphprotocol/graph-ts'

              ByteArray représente un tableau de u8.

              Construction

              • fromI32(x: i32): ByteArray - Décompose x en octets.
              • fromHexString(hex: string): ByteArray - La longueur de la saisie doit être paire. Le préfixe 0x est optionnel.

              Conversions de type

              • toHexString(): string - Convertit en une chaîne de caractères hexadécimale ayant comme préfixe 0x.
              • toString(): string - Interprète les octets comme une chaîne UTF-8.
              • toBase58(): string` - Encode les octets en une chaîne de caractères de type base58.
              • toU32(): u32 - Interprète les octets comme un u32 en little-endian. Envoie une exception en cas de dépassement.
              • toI32(): i32 - Interprète le tableau d’octets comme un i32 en little-endian. Envoie une exception en cas de dépassement.

              Operateurs

              • equals(y: ByteArray): bool – peut être écrit comme x == y.
              • concat(other: ByteArray) : ByteArray - renvoie un nouveau ByteArray constitué de this directement suivi par other
              • concatI32(other: i32) : ByteArray - retourne un nouveau ByteArray constitué de this directement suivi par la représentation en octets de other

              BigDecimal

              1import { BigDecimal } from '@graphprotocol/graph-ts'

              BigDecimal est utilisé pour représenter des décimales à précision arbitraire.

              Remarque: En interne⁠ BigDecimal est stocké au format IEEE-754 décimal128 à virgule flottante⁠, qui supporte 34 chiffres significatifs. Cela rend BigDecimal inapproprié pour représenter des types à virgule fixe pouvant dépasser 34 chiffres, comme un Solidity ufixed256x18⁠ ou équivalent.

              Construction

              • constructor(bigInt: BigInt) – crée un BigDecimal à partir d’un BigInt.
              • static fromString(s: string): BigDecimal – analyse à partir d’une chaîne de caractères décimaux.

              Conversions de type

              • toString(): string – affiche en une chaîne de caractères décimaux.

              Math

              • plus(y: BigDecimal): BigDecimal – peut être écrit comme x + y.
              • minus(y: BigDecimal): BigDecimal – peut être écrit comme x - y.
              • times(y: BigDecimal): BigDecimal – peut être écrit comme x * y.
              • div(y: BigDecimal): BigDecimal – peut être écrit comme x / y.
              • equals(y: BigDecimal): bool – peut être écrit comme x == y.
              • notEqual(y: BigDecimal): bool – peut être écrit comme x != y.
              • lt(y: BigDecimal): bool – peut être écrit comme x < y.
              • le(y: BigDecimal): bool – peut être écrit comme x <= y.
              • gt(y: BigDecimal): bool – peut être écrit comme x > y.
              • ge(y: BigDecimal): bool – peut être écrit comme x >= y.
              • neg(): BigDecimal - peut être écrit comme -x.

              BigInt

              1importer { BigInt } depuis '@graphprotocol/graph-ts'

              BigInt est utilisé pour représenter de grands entiers. Cela inclut les valeurs Ethereum de type uint32 à uint256 et int64 àint256. Tout ce qui est en dessous de uint32, tel que int32, uint24 ou int8 est représenté sous forme de i32.

              La classe BigInt possède l’API suivante :

              Construction

              • BigInt.fromI32(x: i32): BigInt – crée un BigInt à partir d’un i32.

              • BigInt.fromString(s: string): BigInt– Analyse un BigInt à partir d’une chaîne de caractères.

              • BigInt.fromUnsignedBytes(x: Bytes): BigInt – Interprète bytes comme un entier non signé en little-endian. Si votre saisie est en big-endian, appelez d’abord .reverse().

              • BigInt.fromSignedBytes(x: Bytes): BigInt – Interprète bytes comme un entier signé en little-endian. Si votre saisie est en big-endian, appelez d’abord .reverse().

                Conversions de type

              • x.toHex(): string – transforme BigInt en une chaîne de caractères hexadécimaux.

              • x.toString(): string – transformeBigInt en une chaîne de caractères de nombres décimaux.

              • x.toI32(): i32 – renvoie le BigInt comme un i32; échoue si la valeur ne rentre pas dans un i32. Il est conseillé de vérifier d’abord x.isI32().

              • x.toBigDecimal(): BigDecimal - convertit en un nombre décimal sans virgule.

              Math

              • x.plus(y: BigInt): BigInt – peut être écrit comme x + y.
              • x.minus(y: BigInt): BigInt – peut être écrit comme x - y.
              • x.times(y: BigInt): BigInt – peut être écrit comme x * y.
              • x.div(y: BigInt): BigInt – peut être écrit comme x / y.
              • x.mod(y: BigInt): BigInt – peut être écrit comme x % y.
              • x.equals(y: BigInt): bool – peut être écrit comme x == y.
              • x.notEqual(y: BigInt): bool – peut être écrit comme x != y.
              • x.lt(y: BigInt): bool – peut être écrit comme x < y.
              • x.le(y: BigInt): bool – peut être écrit comme x <= y.
              • x.gt(y: BigInt): bool – peut être écrit comme x > y.
              • x.ge(y: BigInt): bool – peut être écrit comme x >= y.
              • x.neg(): BigInt – peut être écrit comme -x.
              • x.divDecimal(y: BigDecimal): BigDecimal – divise par un nombre décimal, donnant un résultat décimal.
              • x.isZero(): bool – Est pratique pour vérifier si le nombre est zéro.
              • x.isI32(): bool – Vérifie si le nombre rentre dans un i32.
              • x.abs(): BigInt – Valeur absolue.
              • x.pow(exp: u8): BigInt – Exponentiation.
              • bitOr(x: BigInt, y: BigInt): BigInt – peut être écrit comme x | y.
              • bitAnd(x: BigInt, y: BigInt): BigInt – peut être écrit comme x & y.
              • leftShift(x: BigInt, bits: u8): BigInt – peut être écrit comme x << y.
              • rightShift(x: BigInt, bits: u8): BigInt – peut être écrit comme x >> y.

              TypedMap

              1import { TypedMap } from '@graphprotocol/graph-ts'

              TypedMap peut être utilisé pour stocker des paires clé-valeur. Consultez cet exemple⁠.

              La classe TypedMap possède l’API suivante :

              • new TypedMap<K, V>() – crée une carte vide avec des clés de type K et des valeurs de type V
              • map.set(key: K, value: V): void – définit la valeur de key à value
              • map.getEntry(key: K): TypedMapEntry<K, V> | null – renvoie la paire clé-valeur pour une key ou null si la key n’existe pas dans la carte
              • map.get(key: K): V | null – renvoie la valeur pour une key ou null si la key n’existe pas dans la carte
              • map.isSet(key: K): bool – renvoie true si la key existe dans la carte et false si ce n’est pas le cas

              Octets

              1import { Bytes } from '@graphprotocol/graph-ts'

              Bytes est utilisé pour représenter des tableaux d’octets de longueur arbitraire. Ceci inclut les valeurs Ethereum de type bytes, bytes32, etc.

              La classe Bytes hérite de Uint8Array⁠ d’AssemblyScript et prend en charge toutes les fonctionnalités de Uint8Array ainsi que les nouvelles méthodes suivantes :

              Construction

              • fromHexString(hex: string) : Bytes - Convertit la chaîne de caractères hex qui doit comporter un nombre pair de chiffres hexadécimaux en un ByteArray. La chaîne de caractères hex peut de façon optionnelle commencer par 0x
              • fromI32(i: i32) : Bytes - Convertit i en un tableau de d’octets

              Conversions de type

              • b.toHex() – renvoie une chaîne de caractères hexadécimale représentant les octets dans le tableau
              • b.toString() – convertit les octets dans le tableau en une chaîne de caractères unicode
              • b.toBase58() – convertit une valeur Ethereum Bytes en codage de type base58 (utilisé pour les hachages IPFS)

              Operateurs

              • b.concat(other: Bytes) : Bytes - - renvoie un nouveau Bytes constitué de this suivi directement de other
              • b.concatI32(other: i32) : ByteArray - renvoie un nouveau Bytes constitué de this suivi directement de la représentation en octets de other

              Addresse

              1import { Address } du '@graphprotocol/graph-ts'

              Address hérite de Bytes pour représenter les valeurs address d’Ethereum.

              Cela ajoute la méthode suivante en plus de l’API Bytes :

              • Address.fromString(s: string): Address – crée une Address à partir d’une chaîne de caractères hexadécimale
              • Address.fromBytes(b: Bytes): Address – crée une Address à partir de b qui doit avoir exactement 20 octets de long. Passer une valeur avec moins ou plus d’octets entraînera une erreur

              Store API

              1import { store } from '@graphprotocol/graph-ts'

              L’API store permet de charger, sauvegarder et supprimer des entités dans et depuis le magasin Graph Node.

              Les entités écrites dans le store correspondent aux types @entity définis dans le schéma GraphQL du subgraph. Pour faciliter le travail avec ces entités, la commande graph codegen fournie par Graph CLI⁠ génère des classes d’entités, qui sont des sous-classes du type intégré Entity, avec des getters et des setters de propriétés pour les champs du schéma ainsi que des méthodes pour charger et sauvegarder ces entités.

              Création d’entités

              Ce qui suit est un modèle courant pour créer des entités à partir d’événements Ethereum.

              1// Importer la classe Transfer générée à partir de l'ABI ERC202import { Transfer as TransferEvent } from '../generated/ERC20/ERC20'34// Importer le type d'entité Transfer généré à partir du schéma GraphQL5import { Transfer } from '../generated/schema'67// Gestionnaire d'événement Transfer8export function handleTransfer(event: TransferEvent): void {9  // Créer une entité Transfer, en utilisant le hash de la transaction comme ID de l'entité10  let id = event.transaction.hash11  let transfer = new Transfer(id)1213  // Définir les propriétés sur l'entité, en utilisant les paramètres de l'événement14  transfer.from = event.params.from15  transfer.to = event.params.to16  transfer.amount = event.params.amount1718  // Sauvegarder l'entité dans le stockage19  transfer.save()20}

              Lorsqu’un événement Transfer est rencontré lors du traitement de la blockchain, il est transmis au gestionnaire d’événements handleTransfer en utilisant le type Transfer généré (ayant pour pseudonyme TransferEvent ici pour éviter un conflit de nom avec le type d’entité). Ce type permet d’accéder à des données telles que la transaction parente de l’événement et ses paramètres.

              Chaque entité doit avoir un ID unique pour éviter les collisions avec d’autres entités. Il est assez courant que les paramètres des événements incluent un identifiant unique pouvant être utilisé.

              Remarque : utiliser le hash de la transaction comme ID suppose qu’aucun autre événement dans la même transaction ne crée d’entités avec ce hash comme ID.

              Chargement d’entités depuis le magasin

              Si une entité existe déjà, elle peut être chargée depuis le magasin avec les éléments suivants :

              1let id = event.transaction.hash // ou selon la manière dont l'ID est construit2let transfer = Transfer.load(id)3if (transfer == null) {4  transfer = new Transfer(id)5}67// Utiliser l'entité Transfer comme précédemment

              Comme l’entité peut ne pas encore exister dans le magasin, la méthode load renvoie une valeur de type Transfer | null. Il peut être nécessaire de vérifier le cas null avant d’utiliser la valeur.

              Remarque : Le chargement des entités n’est nécessaire que si les modifications apportées dans le mappage dépendent des données précédentes d’une entité. Consultez la section suivante pour savoir les deux façons de mettre à jour les entités existantes.

              Recherche d’entités créées dans un bloc

              Depuis graph-node v0.31.0, @graphprotocol/graph-ts v0.30.0 et @graphprotocol/graph-cli v0.49.0 la méthode loadInBlock est disponible pour tous les types d’entités.

              L’API de store facilite la récupération des entités créées ou mises à jour dans le bloc actuel. Une situation typique pour cela est qu’un gestionnaire crée une transaction à partir d’un événement onchain et qu’un gestionnaire ultérieur souhaite accéder à cette transaction si elle existe.

              • Dans le cas où la transaction n’existe pas, le subgraph devra aller dans la base de données simplement pour découvrir que l’entité n’existe pas. Si l’auteur du subgraph sait déjà que l’entité a dû être créée dans le même bloc, l’utilisation de loadInBlock évite cet aller-retour dans la base de données.
              • Pour certains subgraphs, ces recherches manquées peuvent contribuer de manière significative au temps d’indexation.
              1let id = event.transaction.hash // ou de toute autre manière dont l'ID est construit2let transfer = Transfer.loadInBlock(id)3if (transfer == null) {4  transfer = new Transfer(id)5}67// Utiliser l'entité Transfer comme auparavant

              Remarque : S’il n’y a pas d’entité créée dans le bloc donné, loadInBlock renverra null même s’il y a une entité avec l’ID donné dans le magasin.

              Recherche d’entités dérivées

              Depuis graph-node v0.31.0, @graphprotocol/graph-ts v0.31.0 et@graphprotocol/graph-cli v0.51.0 la méthode loadRelated est disponible.

              Cela permet de charger des champs d’entités dérivés à partir d’un gestionnaire d’événements. Par exemple, étant donné le schéma suivant :

              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}

              Le code suivant chargera l’entité Token dont l’entité Holderest dérivée :

              1let holder = Holder.load('test-id')2// Charger les entités Token associées à un détenteur donné3let tokens = holder.tokens.load()

              Mise à jour des entités existantes

              Il existe deux manières de mettre à jour une entité existante :

              1. Chargez l’entité avec, par exemple, Transfer.load(id), définissez des propriétés sur l’entité, puis .save() pour la sauvegarder dans le magasin.
              2. Créez simplement l’entité avec, par exemple, new Transfer(id), séfinissez des propriétés sur l’entité, puis .save() pour la sauvegarder dans le magasin. Si l’entité existe déjà, les modifications y sont fusionnées.

              La modification des propriétés est simple dans la plupart des cas, grâce aux paramètres de propriétés générés :

              1let transfer = new Transfer(id)2transfer.from = ...3transfer.to = ...4transfer.amount = ...

              Il est également possible de supprimer des propriétés avec l’une des deux instructions suivantes :

              1transfer.from.unset()2transfer.from = null

              Ceci ne fonctionne qu’avec des propriétés optionnelles, c’est-à-dire des propriétés déclarées sans ! dans GraphQL. Deux exemples seraient owner: Bytes ou amount: BigInt.

              La mise à jour des propriétés de tableau est un peu plus complexe, car obtenir un tableau à partir d’une entité crée une copie de ce tableau. Cela signifie que les propriétés de tableau doivent être définies à nouveau explicitement après la modification du tableau. Ce qui suit suppose que entity a un champ numbers: [BigInt!]! .

              1// Cela ne fonctionnera pas2entity.numbers.push(BigInt.fromI32(1))3entity.save()45// Cela fonctionnera6let numbers = entity.numbers7numbers.push(BigInt.fromI32(1))8entity.numbers = numbers9entity.save()

              Supprimer des entités du magasin

              Il n’y a actuellement aucun moyen de supprimer une entité via les types générés. Au lieu de cela, la suppression d’une entité nécessite de passer le nom du type d’entité et l’ID de l’entité à store.remove:

              1import { store } from '@graphprotocol/graph-ts'2...3let id = event.transaction.hash4store.remove('Transfer', id)

              Ethereum API

              L’API Ethereum donne accès aux contrats intelligents, aux variables d’état public, aux fonctions de contrat, aux événements, aux transactions, aux blocs et aux données d’encodage/décodage Ethereum.

              Prise en charge des types Ethereum

              Comme pour les entités, graph codegen génère des classes pour tous les contrats intelligents et les événements utilisés dans un subgraph. Pour cela, les ABI des contrats doivent faire partie de la source de données dans le manifeste du subgraph. Typiquement, les fichiers ABI sont stockés dans un dossier abis/.

              Avec les classes générées, les conversions entre les types Ethereum et les types intégrés ont lieu en coulisses, de sorte que les auteurs de subgraphs n’ont pas à s’en préoccuper.

              L’exemple suivant l’illustre. Étant donné un schéma de Subgraphs tel que

              1type Transfer @entity {2  id: Bytes!3  from: Bytes!4  to: Bytes!5  amount: BigInt!6}

              et une signature d’événement Transfer(address,address,uint256) sur Ethereum, les valeurs from, to etamount de type address, address et uint256 sont enverties en Address et BigInt, leur permettant d’être passées aux propriétés Bytes! et BigInt! de l’entité Transfer :

              1let id = event.transaction.hash2let transfer = new Transfer(id)3transfer.from = event.params.from4transfer.to = event.params.to5transfer.amount = event.params.amount6transfer.save()

              Événements et données de bloc/transaction

              Les événements Ethereum passés aux gestionnaires d’événements, comme l’événement Transfer dans les exemples précédents, fournissent non seulement l’accès aux paramètres de l’événement, mais également à leur transaction parente et au bloc auquel ils appartiennent. Les données suivantes peuvent être obtenues à partir des instances d’ event (ces classes font partie du module ethereum dans graph-ts):

              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}

              Accès à l’état du contrat intelligent

              Le code généré par graph codegen comprend également des classes pour les contrats intelligents utilisés dans le subgraph. Celles-ci peuvent être utilisées pour accéder aux variables d’état publiques et appeler les fonctions du contrat dans le bloc actuel.

              Un modèle courant consiste à accéder au contrat dont provient un événement. Ceci est réalisé avec le code suivant :

              1// Importer la classe de contrat générée et la classe d'événement Transfer générée2import { ERC20Contract, Transfer as TransferEvent } from '../generated/ERC20Contract/ERC20Contract'3// Importer la classe d'entité générée4import { Transfer } from '../generated/schema'56export function handleTransfer(event: TransferEvent) {7  // Lier le contrat à l'adresse qui a émis l'événement8  let contract = ERC20Contract.bind(event.address)910  // Accéder aux variables d'état et aux fonctions en les appelant11  let erc20Symbol = contract.symbol()12}

              Transfer est remplacé par TransferEvent ici pour éviter un conflit de nommage avec le type d’entité

              Tant que le ERC20Contract sur Ethereum a une fonction publique en lecture seule appelée symbol, elle peut être appelée avec .symbol(). Pour les variables d’état publiques, une méthode du même nom est créée automatiquement.

              Tout autre contrat faisant partie du subgraph peut être importé à partir du code généré et peut être lié à une adresse valide.

              Gestion des appels retournés

              Si les méthodes en lecture seule de votre contrat peuvent échouer, vous devez gérer cela en appelant la méthode de contrat générée préfixée par try_.

              • Par exemple, le contrat Gravity expose la méthode gravatarToOwner . Ce code serait capable de gérer une erreur dans cette méthode :
              1let gravity = Gravity.bind(event.address)2let callResult = gravity.try_gravatarToOwner(gravatar)3if (callResult.reverted) {4  log.info('getGravatar a été annulé', [])5} else {6  let owner = callResult.value7}

              Remarque : Un Graph Node connecté à un client Geth ou Infura peut ne pas détecter toutes les réversions (reverts). Si vous en dépendez, nous recommandons d’utiliser un Graph Node connecté à un client Parity.

              Encodage/décodage ABI

              Les données peuvent être encodées et décodées selon le format de codage ABI d’Ethereum en utilisant les fonctions encode et decode du module 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)

              Pour plus d’informations:

              • Spécifications ABI⁠
              • Encodage/décodage [bibliothèque Rust/CLI] (https://github.com/rust-ethereum/ethabi⁠)
              • Exemple plus complexe⁠.

              Solde d’une adresse

              Le solde de jetons natifs d’une adresse peut être récupéré en utilisant le module ethereum. Cette fonctionnalité est disponible à partir de apiVersion: 0.0.9 définie dans subgraph.yaml. La fonction getBalance() récupère le solde de l’adresse spécifiée à la fin du bloc où l’événement est déclenché.

              1import { ethereum } from '@graphprotocol/graph-ts'23let address = Address.fromString('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')4let balance = ethereum.getBalance(address) // renvoie le solde en BigInt

              Vérifier si une adresse est une adresse de contrat intelligent ou une adresse détenue par des personnes (EOA)

              Pour vérifier si une adresse est une adresse de contrat intelligent ou une adresse détenue extérieurement (EOA), utilisez la fonction hasCode() du module ethereum qui retournera un boolean. Cette fonctionnalité est disponible à partir de apiVersion: 0.0.9 qui est définie dans subgraph.yaml.

              1import { ethereum } from '@graphprotocol/graph-ts'23let contractAddr = Address.fromString('0x2E645469f354BB4F5c8a05B3b30A929361cf77eC')4let isContract = ethereum.hasCode(contractAddr).inner // renvoie true56let eoa = Address.fromString('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')7let isContract = ethereum.hasCode(eoa).inner // renvoie false

              Logging API

              1import { log } from '@graphprotocol/graph-ts'

              L’API log permet aux subgraphs de consigner des informations sur la sortie standard de Graph Node ainsi que sur Graph Explorer. Les messages peuvent être enregistrés à différents niveaux. Une syntaxe de chaîne de caractère de format de base est fournie pour composer les messages de journal à partir d’un argument.

              L’API log inclut les fonctions suivantes :

              • log.debug(fmt: string, args: Array<string>): void - enregistre un message de débogage.
              • log.info(fmt: string, args: Array<string>): void - enregistre un message d’information.
              • log.warning(fmt: string, args: Array<string>): void - enregistre un avertissement.
              • log.error(fmt: string, args: Array<string>): void - enregistre un message d’erreur.
              • log.critical(fmt : string, args : Array<string>) : void - enregistre un message critique et met fin au Subgraph.

              L’API log prend une chaîne de caractères de format et un tableau de valeurs de chaîne de caractères. Elle remplace ensuite les espaces réservés par les valeurs de chaîne de caractères du tableau. Le premier espace réservé {} est remplacé par la première valeur du tableau, le second {} est remplacé par la deuxième valeur, et ainsi de suite.

              1log.info('Message à afficher : {}, {}, {}', [value.toString(), anotherValue.toString(), 'déjà une chaîne'])

              Enregistrer une ou plusieurs valeurs

              Enregistrer une seule valeur

              Dans l’exemple ci-dessous, la valeur de chaîne de caractères “A” est passée dans un tableau pour devenir ['A'] avant d’être enregistrée:

              1let myValue = 'A'23export function handleSomeEvent(event: SomeEvent): void {4  // Affiche : "Ma valeur est : A"5  log.info('Ma valeur est : {}', [myValue])6}
              Journalisation d’une seule entrée à partir d’un tableau existant

              Dans l’exemple ci-dessous, seule la première valeur du tableau d’arguments est journalisée, bien que le tableau contienne trois valeurs.

              1let myArray = ['A', 'B', 'C']23export function handleSomeEvent(event: SomeEvent): void {4  // Affiche : "Ma valeur est : A"  (Même si trois valeurs sont passées à `log.info`)5  log.info('Ma valeur est : {}', myArray)6}

              Journalisation de plusieurs entrées d’un tableau existant

              Chaque entrée dans le tableau des arguments nécessite son propre espace réservé {} dans la chaîne de caractères du message de log. L’exemple ci-dessous contient trois espaces réservés {} dans le message de log. À cause de cela, toutes les trois valeurs dans myArray sont enregistrées.

              1let myArray = ['A', 'B', 'C']23export function handleSomeEvent(event: SomeEvent): void {4  // Affiche : "Ma première valeur est : A, la deuxième valeur est : B, la troisième valeur est : C"5  log.info('Ma première valeur est : {}, la deuxième valeur est : {}, la troisième valeur est : {}', myArray)6}
              Enregistrer une entrée spécifique à partir d’un tableau existant

              Pour afficher une valeur spécifique dans le tableau, la valeur indexée doit être fournie.

              1export function handleSomeEvent(event: SomeEvent): void {2  // Affiche : "Ma troisième valeur est C"3  log.info('Ma troisième valeur est : {}', [myArray[2]])4}
              Journalisation des informations sur les événements

              L’exemple ci-dessous enregistre le numéro de bloc, le hachage de bloc et le hachage de transaction d’un événement :

              1import { log } from '@graphprotocol/graph-ts'23export function handleSomeEvent(event: SomeEvent): void {4  log.debug('Numéro de bloc : {}, hachage de bloc : {}, hachage de transaction : {}', [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'

              Les contrats intelligents ancrent parfois des fichiers IPFS onchain. Cela permet aux mappages d’obtenir les hashs IPFS du contrat et de lire les fichiers correspondants depuis IPFS. Les données du fichier seront renvoyées sous forme de Bytes, ce qui nécessite généralement un traitement supplémentaire, par exemple avec l’API json documentée plus loin sur cette page.

              Étant donné un hachage ou un chemin IPFS, la lecture d’un fichier depuis IPFS se fait comme suit :

              1// Mettez ceci à l'intérieur d'un gestionnaire d'événements dans le mapping2let hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D'3let data = ipfs.cat(hash)45// Les chemins comme `QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile`6// qui incluent des fichiers dans des répertoires sont également pris en charge7let path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'8let data = ipfs.cat(path)

              Remarque: ipfs.cat n’est pas déterministe pour le moment. Si le fichier ne peut pas être récupéré sur le réseau IPFS avant l’expiration de la demande, il retournera null. Pour cette raison, il est toujours utile de vérifier le résultat pour null.

              Il est également possible de traiter des fichiers plus volumineux en streaming avec ipfs.map. La fonction s’attend à recevoir un hash ou à un chemin pour un fichier IPFS, le nom d’un callback, et des indicateurs pour modifier son comportement :

              1import { JSONValue, Value } from '@graphprotocol/graph-ts'23export function processItem(value: JSONValue, userData: Value): void {4  // Voir la documentation JSONValue pour les détails sur le traitement5  // des valeurs JSON6  let obj = value.toObject()7  let id = obj.get('id')8  let title = obj.get('title')910  if (!id || !title) {11    return12  }1314  // Les callbacks peuvent également créer des entités15  let newItem = new Item(id)16  newItem.title = title.toString()17  newItem.parent = userData.toString() // Définit le parent à "parentId"18  newItem.save()19}2021// Mettez ceci à l'intérieur d'un gestionnaire d'événements dans le mapping22ipfs.map('Qm...', 'processItem', Value.fromString('parentId'), ['json'])2324// Alternativement, utilisez `ipfs.mapJSON`25ipfs.mapJSON('Qm...', 'processItem', Value.fromString('parentId'))

              Le seul indicateur actuellement pris en charge est json, qui doit être passé à ipfs.map. Avec l’indicateur json , le fichier IPFS doit consister en une série de valeurs JSON, une valeur par ligne. L’appel à ipfs.map lira chaque ligne du fichier, la désérialisera en un JSONValue et appellera le callback pour chacune d’entre elles. Le callback peut alors utiliser des opérations des entités pour stocker des données à partir du JSONValue. Les modifications d’entité ne sont enregistrées que lorsque le gestionnaire qui a appelé ipfs.map se termine avec succès ; en attendant, elles sont conservées en mémoire, et la taille du fichier que ipfs.map peut traiter est donc limitée.

              En cas de succès, ipfs.map renvoie void. Si une invocation du callback provoque une erreur, le gestionnaire qui a invoqué ipfs.map est interrompu, et le subgraph est marqué comme ayant échoué.

              Crypto API

              1import { crypto } from '@graphprotocol/graph-ts'

              L’API crypto rend des fonctions cryptographiques disponibles pour une utilisation dans les mappages. Actuellement, il n’y en a qu’une seule :

              • crypto.keccak256(input: ByteArray): ByteArray

              JSON API

              1import { json, JSONValueKind } from '@graphprotocol/graph-ts'

              Les données JSON peuvent être analysées en utilisant l’API json:

              • json.fromBytes(data: Bytes): JSONValue – analyse les données JSON à partir d’un tableau Bytes interprété comme une séquence UTF-8 valide
              • json.try_fromBytes(data: Bytes): Result<JSONValue, boolean> – version sécurisée de json.fromBytes, elle renvoie une variante d’erreur si l’analyse échoue
              • json.fromString(data: string): JSONValue – analyse les données JSON à partir d’une String UTF-8 valide
              • json.try_fromString(data: string): Result<JSONValue, boolean> – version sécurisée de json.fromString, elle renvoie une variante d’erreur si l’analyse échoue

              La classe JSONValue fournit un moyen d’extraire des valeurs d’un document JSON arbitraire. Étant donné que les valeurs JSON peuvent être des booléens, des nombres, des tableaux et plus encore, JSONValue est accompagné d’une propriété kind pour vérifier le type d’une valeur :

              1let value = json.fromBytes(...)2if (value.kind == JSONValueKind.BOOL) {3  ...4}

              De plus, il existe une méthode pour vérifier si la valeur est null:

              • value.isNull(): boolean

              Lorsque le type d’une valeur est certain, il peut être converti en un type intégré n utilisant l’une des méthodes suivantes :

              • value.toBool(): boolean
              • value.toI64(): i64
              • value.toF64(): f64
              • value.toBigInt(): BigInt
              • value.toString(): string
              • value.toArray(): Array<JSONValue> - (et ensuite convertir JSONValue avec l’une des 5 méthodes ci-dessus)

              Référence des conversions de types

              Source(s)DestinationFonctions de conversion
              AddressBytesaucune
              AddressStrings.toHexString()
              BigDecimalStrings.toString()
              BigIntBigDecimals.toBigDecimal()
              BigIntString (hexadecimal)s.toHexString() or s.toHex()
              BigIntString (unicode)s.toString()
              BigInti32s.toI32()
              BooleanBooleanaucune
              Bytes (signé)BigIntBigInt.fromSignedBytes(s)
              Bytes (non signé)BigIntBigInt.fromUnsignedBytes(s)
              BytesString (hexadecimal)s.toHexString() or s.toHex()
              BytesString (unicode)s.toString()
              BytesString (base58)s.toBase58()
              Bytesi32s.toI32()
              Bytesu32s.toU32()
              BytesJSONjson.fromBytes(s)
              int8i32aucune
              int32i32aucune
              int32BigIntBigInt.fromI32(s)
              uint24i32aucune
              int64 - int256BigIntaucune
              uint32 - uint256BigIntaucune
              JSONbooleans.toBool()
              JSONi64s.toI64()
              JSONu64s.toU64()
              JSONf64s.toF64()
              JSONBigInts.toBigInt()
              JSONstrings.toString()
              JSONArrays.toArray()
              JSONObjects.toObject()
              StringAddressAddress.fromString(s)
              BytesAddressAddress.fromBytes(s)
              StringBigIntBigInt.fromString(s)
              StringBigDecimalBigDecimal.fromString(s)
              String (hexadecimal)BytesByteArray.fromHexString(s)
              String (UTF-8)BytesByteArray.fromUTF8(s)

              Métadonnées de la source de données

              Vous pouvez inspecter l’adresse du contrat, le réseau et le contexte de la source de données qui a invoqué le gestionnaire grâce un namespace dataSource :

              • dataSource.address(): Address
              • dataSource.network(): string
              • dataSource.context(): DataSourceContext

              Entité et DataSourceContext

              La classe de base Entity et la classe enfant DataSourceContext disposent d’assistants pour définir et récupérer dynamiquement des champs :

              • 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 in Manifest

              La section context de dataSources vous permet de définir des paires clé-valeur accessibles dans vos mappages de subgraphs. Les types disponibles sont Bool, String, Int, Int8, BigDecimal, Bytes, List, et BigInt.

              Voici un exemple YAML illustrant l’utilisation de différents types dans la section 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 : Spécifie une valeur booléenne (true ou false).
              • String : Spécifie une valeur de type chaîne de caractères.
              • Int : Spécifie un nombre entier de 32 bits.
              • Int8 : Spécifie un entier de 8 bits.
              • BigDecimal : Spécifie un nombre décimal. Doit être entre mis guillemets.
              • Bytes : Spécifie une chaîne de caractères hexadécimale.
              • List : Spécifie une liste d’éléments. Chaque élément doit spécifier son type et ses données.
              • BigInt : Spécifie une grande valeur entière. Elle doit être mise entre guillemets en raison de sa grande taille.

              Ce contexte est ensuite accessible dans vos fichiers de mappage de Subgraph, ce qui permet de créer des Subgraphs plus dynamiques et configurables.

              ⁠Edit on GitHub⁠

              PrésentationProblèmes communs
              On this page
              • Référence API
              • Versions
              • Types intégrés
              • Store API
              • Ethereum API
              • Logging API
              • IPFS API
              • Crypto API
              • JSON API
              • Référence des conversions de types
              • Métadonnées de la source de données
              • Entité et DataSourceContext
              • DataSourceContext in Manifest
              The GraphStatusTestnetActifs de la MarqueForumSécuritéPolitique de confidentialitéConditions d'utilisation