> ## Documentation Index
> Fetch the complete documentation index at: https://ormilabs.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How to query USDT0 data on Stable Chain using Ormi subgraphs

## Intro

This guide shows you how to index and query USDT0 on Stable using Ormi’s 0xGraph. By the end, you’ll have a live subgraph that tracks transfers, mints, burns and related events, and you’ll be able to query USDT0 activity with GraphQL.

## Prerequisites

* [An Ormi Labs account](https://app.ormilabs.com/)
* [Graph CLI installed](https://www.npmjs.com/package/@graphprotocol/graph-cli?ref=blog.ormilabs.com)
* [node.js installed](https://nodejs.org/en)
* [Git installed](https://git-scm.com/downloads)

## 1. Create and configure your subgraph project

### 1.1 Get your Ormi API key

1. Log in to [Ormi](https://app.ormilabs.com/) and go to your dashboard.
2. From the dashboard, create an API key for deployments.

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi01.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=0cd5b4caac6a0d2b9df2ec38f8751f11" alt="Create an API key" width="1894" height="884" data-path="images/0xgraph/tutorials/ormi01.png" />

  <figcaption>Create an API key</figcaption>
</Frame>

Keep this page open, we will need the API key to deploy a subgraph.

### 1.2 Install Graph CLI

On your local machine, run the following in your terminal:

```bash theme={null}
npm install -g @graphprotocol/graph-cli
```

### 1.3 Create a directory for your subgraph

```bash theme={null}
mkdir usdt0-stable
cd usdt0-stable
```

We will call the folder `usdt0-stable` in this example.

### 1.4 Initialize the project

Run bash in the directory folder

```bash theme={null}
npm init -y
```

### 1.5 Install dependencies

```bash theme={null}
npm install --save-dev @graphprotocol/graph-ts
npm install --save-dev assemblyscript
```

### 1.6 Create the required files

You will need:

* subgraph.yaml
* schema.graphql
* mappings/USDT0.ts
* abis/USDT0.json

After creating these files, put them in the `usdt0-stable` folder.

#### Directory layout

```
usdt0-stable/
├─ abis/
│  └─ USDT0.json
│
├─ mappings/
│  └─ USDT0.ts
│
├─ schema.graphql
│
├─ subgraph.yaml
│
├─ generated/
│  ├─ schema.ts
│  └─ USDT0/
│     └─ USDT0.ts
│
├─ build/
│  └─ USDT0/
│     └─ USDT0.wasm
│
├─ node_modules/
```

You will also see `node_modules/` after installing dependencies - that is expected.

### 1.7 subgraph.yaml

```yaml theme={null}
specVersion: 1.2.0
schema:
  file: ./schema.graphql

dataSources:
  - kind: ethereum
    name: USDT0
    network: stable
    source:
      address: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736"
      abi: USDT0
      startBlock: 2443970
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.7
      language: wasm/assemblyscript
      entities:
        - Token
        - Account
        - Transfer
        - Mint
        - Burn
        - BlocklistChange
        - Authorization
      abis:
        - name: USDT0
          file: ./abis/USDT0.json
      eventHandlers:
        - event: Transfer(indexed address,indexed address,uint256)
          handler: handleTransfer
        - event: Mint(indexed address,uint256)
          handler: handleMint
        - event: Burn(indexed address,uint256)
          handler: handleBurn
        - event: CrosschainMint(indexed address,uint256,indexed address)
          handler: handleCrosschainMint
        - event: CrosschainBurn(indexed address,uint256,indexed address)
          handler: handleCrosschainBurn
        - event: BlockPlaced(indexed address)
          handler: handleBlockPlaced
        - event: BlockReleased(indexed address)
          handler: handleBlockReleased
        - event: DestroyedBlockedFunds(indexed address,uint256)
          handler: handleDestroyedBlockedFunds
        - event: AuthorizationUsed(indexed address,indexed bytes32)
          handler: handleAuthorizationUsed
        - event: AuthorizationCanceled(indexed address,indexed bytes32)
          handler: handleAuthorizationCanceled
        - event: LogUpdateNameAndSymbol(string,string)
          handler: handleLogUpdateNameAndSymbol
        - event: OwnershipTransferred(indexed address,indexed address)
          handler: handleOwnershipTransferred
        - event: LogSetOFTContract(indexed address)
          handler: handleLogSetOFTContract
      file: ./mappings/USDT0.ts
```

### 1.8 schema.graphql

```graphql theme={null}
type Token @entity(immutable: false) {
  id: ID! # contract address
  name: String!
  symbol: String!
  decimals: Int!
  totalSupply: BigInt! # derived from Mint/Burn/Crosschain*/DestroyedBlockedFunds
  createdAtBlock: BigInt!
  createdAtTimestamp: BigInt!

  transferCount: BigInt!
  mintCount: BigInt!
  burnCount: BigInt!
  crosschainMintCount: BigInt!
  crosschainBurnCount: BigInt!

  owner: Account
  oftContract: Bytes
}

type Account @entity(immutable: false) {
  id: ID! # address
  balance: BigInt! # derived solely from events
  isBlocked: Boolean! # derived from BlockPlaced/BlockReleased
  createdAtBlock: BigInt!
  createdAtTimestamp: BigInt!
  transferCount: BigInt!
}

type Transfer @entity(immutable: true) {
  id: ID! # txHash-logIndex
  token: Token!
  from: Account
  to: Account
  value: BigInt!
  txHash: Bytes!
  blockNumber: BigInt!
  timestamp: BigInt!
}

type Mint @entity(immutable: true) {
  id: ID!
  token: Token!
  to: Account!
  amount: BigInt!
  isCrosschain: Boolean!
  sender: Account
  txHash: Bytes!
  blockNumber: BigInt!
  timestamp: BigInt!
}

type Burn @entity(immutable: true) {
  id: ID!
  token: Token!
  from: Account
  amount: BigInt!
  isCrosschain: Boolean!
  sender: Account
  txHash: Bytes!
  blockNumber: BigInt!
  timestamp: BigInt!
}

type BlocklistChange @entity(immutable: true) {
  id: ID!
  user: Account!
  isBlocked: Boolean!
  destroyedBalance: BigInt
  txHash: Bytes!
  blockNumber: BigInt!
  timestamp: BigInt!
}

type Authorization @entity(immutable: false) {
  id: ID! # `${authorizer}-${nonce}`
  authorizer: Account!
  nonce: Bytes!
  used: Boolean!
  canceled: Boolean!
  txHashUsed: Bytes
  txHashCanceled: Bytes
}
```

### 1.9 Mapping files in typescript

```typescript theme={null}
// mappings/USDT0.ts

import { BigInt, Address, Bytes } from "@graphprotocol/graph-ts";

import {
  Transfer as TransferEvent,
  Mint as MintEvent,
  Burn as BurnEvent,
  CrosschainMint as CrosschainMintEvent,
  CrosschainBurn as CrosschainBurnEvent,
  BlockPlaced,
  BlockReleased,
  DestroyedBlockedFunds,
  AuthorizationUsed,
  AuthorizationCanceled,
  LogUpdateNameAndSymbol,
  OwnershipTransferred,
  LogSetOFTContract,
} from "../generated/USDT0/USDT0";

import { Token, Account, Transfer, Mint, Burn, BlocklistChange, Authorization } from "../generated/schema";

const USDT0_ADDRESS = "0x779Ded0c9e1022225f8E0630b35a9b54bE713736";
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";

// Helpers

function createEventId(txHash: Bytes, logIndex: BigInt): string {
  return txHash.toHex() + "-" + logIndex.toString();
}

function getToken(eventBlockNumber: BigInt, eventTimestamp: BigInt): Token {
  let token = Token.load(USDT0_ADDRESS);
  if (token == null) {
    token = new Token(USDT0_ADDRESS);
    token.name = "USDT0";
    token.symbol = "USDT0";
    token.decimals = 6;
    token.totalSupply = BigInt.zero();
    token.createdAtBlock = eventBlockNumber;
    token.createdAtTimestamp = eventTimestamp;
    token.transferCount = BigInt.zero();
    token.mintCount = BigInt.zero();
    token.burnCount = BigInt.zero();
    token.crosschainMintCount = BigInt.zero();
    token.crosschainBurnCount = BigInt.zero();
  }
  return token as Token;
}

function getAccount(addr: Address, blockNumber: BigInt, timestamp: BigInt): Account {
  let id = addr.toHex();
  let account = Account.load(id);
  if (account == null) {
    account = new Account(id);
    account.balance = BigInt.zero();
    account.isBlocked = false;
    account.createdAtBlock = blockNumber;
    account.createdAtTimestamp = timestamp;
    account.transferCount = BigInt.zero();
  }
  return account as Account;
}

// Handlers

export function handleTransfer(event: TransferEvent): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let from = getAccount(event.params.from, event.block.number, event.block.timestamp);
  let to = getAccount(event.params.to, event.block.number, event.block.timestamp);

  let value = event.params.value;

  // compare strings directly instead of using .equals()
  if (from.id != ZERO_ADDRESS) {
    from.balance = from.balance.minus(value);
    from.transferCount = from.transferCount.plus(BigInt.fromI32(1));
    from.save();
  }

  if (to.id != ZERO_ADDRESS) {
    to.balance = to.balance.plus(value);
    to.transferCount = to.transferCount.plus(BigInt.fromI32(1));
    to.save();
  }

  token.transferCount = token.transferCount.plus(BigInt.fromI32(1));
  token.save();

  let transfer = new Transfer(createEventId(event.transaction.hash, event.logIndex));
  transfer.token = token.id;
  transfer.from = from.id;
  transfer.to = to.id;
  transfer.value = value;
  transfer.txHash = event.transaction.hash;
  transfer.blockNumber = event.block.number;
  transfer.timestamp = event.block.timestamp;
  transfer.save();
}

export function handleMint(event: MintEvent): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let to = getAccount(event.params._destination, event.block.number, event.block.timestamp);
  let amount = event.params._amount;

  to.balance = to.balance.plus(amount);
  to.save();

  token.totalSupply = token.totalSupply.plus(amount);
  token.mintCount = token.mintCount.plus(BigInt.fromI32(1));
  token.save();

  let mint = new Mint(createEventId(event.transaction.hash, event.logIndex));
  mint.token = token.id;
  mint.to = to.id;
  mint.amount = amount;
  mint.isCrosschain = false;
  mint.sender = null;
  mint.txHash = event.transaction.hash;
  mint.blockNumber = event.block.number;
  mint.timestamp = event.block.timestamp;
  mint.save();
}

export function handleBurn(event: BurnEvent): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let from = getAccount(event.params.from, event.block.number, event.block.timestamp);
  let amount = event.params.amount;

  from.balance = from.balance.minus(amount);
  from.save();

  token.totalSupply = token.totalSupply.minus(amount);
  token.burnCount = token.burnCount.plus(BigInt.fromI32(1));
  token.save();

  let burn = new Burn(createEventId(event.transaction.hash, event.logIndex));
  burn.token = token.id;
  burn.from = from.id;
  burn.amount = amount;
  burn.isCrosschain = false;
  burn.sender = null;
  burn.txHash = event.transaction.hash;
  burn.blockNumber = event.block.number;
  burn.timestamp = event.block.timestamp;
  burn.save();
}

export function handleCrosschainMint(event: CrosschainMintEvent): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let to = getAccount(event.params.to, event.block.number, event.block.timestamp);
  let sender = getAccount(event.params.sender, event.block.number, event.block.timestamp);
  let amount = event.params.amount;

  to.balance = to.balance.plus(amount);
  to.save();

  token.totalSupply = token.totalSupply.plus(amount);
  token.crosschainMintCount = token.crosschainMintCount.plus(BigInt.fromI32(1));
  token.save();

  let mint = new Mint(createEventId(event.transaction.hash, event.logIndex));
  mint.token = token.id;
  mint.to = to.id;
  mint.amount = amount;
  mint.isCrosschain = true;
  mint.sender = sender.id;
  mint.txHash = event.transaction.hash;
  mint.blockNumber = event.block.number;
  mint.timestamp = event.block.timestamp;
  mint.save();
}

export function handleCrosschainBurn(event: CrosschainBurnEvent): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let from = getAccount(event.params.from, event.block.number, event.block.timestamp);
  let sender = getAccount(event.params.sender, event.block.number, event.block.timestamp);
  let amount = event.params.amount;

  from.balance = from.balance.minus(amount);
  from.save();

  token.totalSupply = token.totalSupply.minus(amount);
  token.crosschainBurnCount = token.crosschainBurnCount.plus(BigInt.fromI32(1));
  token.save();

  let burn = new Burn(createEventId(event.transaction.hash, event.logIndex));
  burn.token = token.id;
  burn.from = from.id;
  burn.amount = amount;
  burn.isCrosschain = true;
  burn.sender = sender.id;
  burn.txHash = event.transaction.hash;
  burn.blockNumber = event.block.number;
  burn.timestamp = event.block.timestamp;
  burn.save();
}

export function handleBlockPlaced(event: BlockPlaced): void {
  let user = getAccount(event.params._user, event.block.number, event.block.timestamp);
  user.isBlocked = true;
  user.save();

  let change = new BlocklistChange(createEventId(event.transaction.hash, event.logIndex));
  change.user = user.id;
  change.isBlocked = true;
  change.destroyedBalance = null;
  change.txHash = event.transaction.hash;
  change.blockNumber = event.block.number;
  change.timestamp = event.block.timestamp;
  change.save();
}

export function handleBlockReleased(event: BlockReleased): void {
  let user = getAccount(event.params._user, event.block.number, event.block.timestamp);
  user.isBlocked = false;
  user.save();

  let change = new BlocklistChange(createEventId(event.transaction.hash, event.logIndex));
  change.user = user.id;
  change.isBlocked = false;
  change.destroyedBalance = null;
  change.txHash = event.transaction.hash;
  change.blockNumber = event.block.number;
  change.timestamp = event.block.timestamp;
  change.save();
}

export function handleDestroyedBlockedFunds(event: DestroyedBlockedFunds): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let user = getAccount(event.params._blockedUser, event.block.number, event.block.timestamp);
  let amount = event.params._balance;

  token.totalSupply = token.totalSupply.minus(amount);
  token.save();

  user.balance = BigInt.zero();
  user.save();

  let change = new BlocklistChange(createEventId(event.transaction.hash, event.logIndex));
  change.user = user.id;
  change.isBlocked = user.isBlocked;
  change.destroyedBalance = amount;
  change.txHash = event.transaction.hash;
  change.blockNumber = event.block.number;
  change.timestamp = event.block.timestamp;
  change.save();
}

export function handleAuthorizationUsed(event: AuthorizationUsed): void {
  let authorizer = getAccount(event.params.authorizer, event.block.number, event.block.timestamp);
  let id = authorizer.id + "-" + event.params.nonce.toHex();
  let auth = Authorization.load(id);
  if (auth == null) {
    auth = new Authorization(id);
    auth.authorizer = authorizer.id;
    auth.nonce = event.params.nonce;
    auth.used = false;
    auth.canceled = false;
  }
  auth.used = true;
  auth.txHashUsed = event.transaction.hash;
  auth.save();
}

export function handleAuthorizationCanceled(event: AuthorizationCanceled): void {
  let authorizer = getAccount(event.params.authorizer, event.block.number, event.block.timestamp);
  let id = authorizer.id + "-" + event.params.nonce.toHex();
  let auth = Authorization.load(id);
  if (auth == null) {
    auth = new Authorization(id);
    auth.authorizer = authorizer.id;
    auth.nonce = event.params.nonce;
    auth.used = false;
    auth.canceled = false;
  }
  auth.canceled = true;
  auth.txHashCanceled = event.transaction.hash;
  auth.save();
}

export function handleLogUpdateNameAndSymbol(event: LogUpdateNameAndSymbol): void {
  let token = getToken(event.block.number, event.block.timestamp);
  token.name = event.params.name;
  token.symbol = event.params.symbol;
  token.save();
}

export function handleOwnershipTransferred(event: OwnershipTransferred): void {
  let token = getToken(event.block.number, event.block.timestamp);
  let newOwner = getAccount(event.params.newOwner, event.block.number, event.block.timestamp);
  token.owner = newOwner.id;
  token.save();
}

export function handleLogSetOFTContract(event: LogSetOFTContract): void {
  let token = getToken(event.block.number, event.block.timestamp);
  token.oftContract = event.params.oftContract;
  token.save();
}
```

### 1.9 ABIs

```
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"}],"name":"BlockPlaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"}],"name":"BlockReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"CrosschainBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"CrosschainMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_blockedUser","type":"address"},{"indexed":false,"internalType":"uint256","name":"_balance","type":"uint256"}],"name":"DestroyedBlockedFunds","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oftContract","type":"address"}],"name":"LogSetOFTContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"}],"name":"LogUpdateNameAndSymbol","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_destination","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECEIVE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"addToBlockedList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"crosschainBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"crosschainMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_blockedUser","type":"address"}],"name":"destroyBlockedFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTrusted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_recipients","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"}],"name":"multiTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oftContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"removeFromBlockedList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oftContract","type":"address"}],"name":"setOFTContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"updateNameAndSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"}]

```

## 2. Build the Subgraph

Generate types:

```bash theme={null}
graph codegen
```

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi02.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=0bdb531a7639e379821bff865ce5183c" alt="Run codegen" width="1244" height="443" data-path="images/0xgraph/tutorials/ormi02.png" />

  <figcaption>Run codegen</figcaption>
</Frame>

Now run:

```bash theme={null}
graph build
```

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi03.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=3a7be7e8067b378ef0495a6ce4ce04f9" alt="Build graph" width="1153" height="372" data-path="images/0xgraph/tutorials/ormi03.png" />

  <figcaption>graph build</figcaption>
</Frame>

## 3. Deploy the Subgraph to Ormi

Return to your [API key](https://app.ormilabs.com/dashboard/api) from the dashboard. Replace `<graph-name>` and `<API key>` with your actual values

```bash theme={null}
graph deploy <graph-name> --node  https://subgraph.api.ormilabs.com/deploy --ipfs https://subgraph.api.ormilabs.com/ipfs --deploy-key <API key>
```

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi04.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=a30518713da3429df6c9be00653f4365" alt="Deploy graph" width="1610" height="554" data-path="images/0xgraph/tutorials/ormi04.png" />

  <figcaption>graph deploy</figcaption>
</Frame>

### Track sync status

You can check syncing in the dashboard by going to the Subgraphs tab:

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi05.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=ce3a4eb9867c1d79250dc5a52a78c22c" alt="Track sync status" width="2072" height="1057" data-path="images/0xgraph/tutorials/ormi05.png" />

  <figcaption>track sync status</figcaption>
</Frame>

## 4. Query USDT0

Click on the button where the red arrow is pointing.

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi06.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=f009cfe15499957bb0012876df896869" alt="Click on graphql icon" width="1991" height="981" data-path="images/0xgraph/tutorials/ormi06.png" />

  <figcaption>Click on graphql icon</figcaption>
</Frame>

Once synced, click the GraphQL endpoint link in the dashboard.

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi07.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=02b58e43bec7eef0425b4ae137a446fd" alt="Graphql link" width="1812" height="956" data-path="images/0xgraph/tutorials/ormi07.png" />

  <figcaption>graphql link</figcaption>
</Frame>

### Sample query

Run this query to fetch the latest transfers

```graphql theme={null}
{
  transfers(first: 10, orderBy: timestamp, orderDirection: desc) {
    id
    from {
      id
    }
    to {
      id
    }
    value
    blockNumber
    timestamp
    txHash
  }
}
```

<Frame>
  <img src="https://mintcdn.com/ormilabs/2_HuVVq5g9vs03Oa/images/0xgraph/tutorials/ormi08.png?fit=max&auto=format&n=2_HuVVq5g9vs03Oa&q=85&s=f5f1ee013c1c3d2d50fbe65223b95678" alt="Query graphql" width="2451" height="1195" data-path="images/0xgraph/tutorials/ormi08.png" />

  <figcaption>graphql query</figcaption>
</Frame>

## Done!

You now have a live subgraph indexing USDT0 on Stable via [Ormi's 0xGraph](https://app.ormilabs.com/).

Want the full walkthrough with context? Check out the [USDT0 Subgraph Tutorial](https://blog.ormilabs.com/how-to-query-usdt0-stablecoin-data-on-stable-chain-using-ormis-subgraphs/) on the Ormi Blog.
