How to query USDT0 stablecoin data on Stable Chain using Ormi’s Subgraphs
Learn how to index USDT0 stablecoin data on Stable Chain using Ormi’s 0xGraph. This step-by-step guide shows you how to deploy a production-ready subgraph, track USDT0 transfers, mints, burns, etc, and query real-time and historical stablecoin data with GraphQL.
Indexing and querying smart contract data on new chains can be challenging. Stable Chain introduced USDT0 stablecoin to support institutional stablecoin flows, but using this data in production requires fast, reliable indexing.
This guide shows how to deploy and query a USDT0 subgraph on Stable Chain using Ormi’s 0xGraph, a real-time and fully Graph-compatible indexing engine built for high-throughput chains. If you have used The Graph before, the workflow will feel familiar while running faster and with far less overhead.
You can follow along even if you are new to Ormi. Setup takes only a few minutes.
Want the quick version?
See the official USDT0 Subgraph tutorial in Ormi Docs
What is USDT0?
USDT0 is Tether’s omnichain token standard that brings USDT to new blockchains. It locks USDT on Ethereum and issues equivalent tokens on destination chains through LayerZero. Users can transfer USDT0 across supported chains without needing liquidity, and redeem it back 1:1 for USDT. USDT0 standardizes how Tether assets expand to new ecosystems and aims to make Tether the default asset issuer on every chain.
What you’ll build
By the end of this tutorial, you will:
- Deploy a subgraph indexing USDT0 events on the Stable Chain
- Track transfers, minting, burning, and more
- Query live and historical USDT0 data through a GraphQL endpoint
- Use Ormi’s dashboard to monitor sync health in real time
This setup is production-ready and free to use.
Prerequisites
- An Ormi account → Create one here
- Node.js installed → https://nodejs.org
- Git installed → https://git-scm.com
- Graph CLI installed →
npm install -g @graphprotocol/graph-cli
Getting started
Step 1: Create an API key
Log in to the Ormi dashboard > API Keys > Create Key.

Keep this page open; you’ll need the key during deployment.
Step 2: Create a Project Folder
mkdir usdt0-stable
cd usdt0-stableInitialize a Node project:
npm init -yStep 3: Install dependencies
npm install --save-dev @graphprotocol/graph-ts
npm install --save-dev assemblyscript
Add the required files
usdt0-stable/
├─ abis/
│ └─ USDT0.json
├─ mappings/
│ └─ USDT0.ts
├─ schema.graphql
├─ subgraph.yaml
├─ generated/
└─ build/ Below are the exact contents used for this USDT0 example.
subgraph.yaml
yaml
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.tsschema.graphql
graphql
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
}USDT0.ts Mapping file
typescript
// 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()
}USDT0 ABI
[{"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"}]Build the Subgraph

Generate types:
graph codegen
Build:
graph buildYou should see .wasmfiles inside /build.
Deploy to Ormi Subgraph
Use your API key and choose a subgraph name

graph deploy <graph-name> \
--node https://subgraph.api.ormilabs.com/deploy \
--ipfs https://subgraph.api.ormilabs.com/ipfs \
--deploy-key <API key>Once deployed, the subgraph will appear in your Ormi dashboard.
Check sync status
Go to Subgraphs > select your subgraph > view Sync Status.

Ormi indexes Stable Chain in real time, so syncing is much faster than legacy providers.
Query USDT0 data.
Open the built-in GraphQL Explorer from the dashboard.

Run this sample query to fetch the latest transfers:
{
transfers(first: 10, orderBy: timestamp, orderDirection: desc) {
id
from { id }
to { id }
value
blockNumber
timestamp
txHash
}
}
You’ll immediately see live results from Stable Chain.
You’re done
You now have a live USDT0 subgraph indexing on Stable Chain using Ormi’s 0xGraph.
Use this foundation to build:
- dashboards
- wallets
- compliance tooling
- settlement systems
- agent-based automation
- analytics pipelines
For more subgraph tutorials and supported chains, visit:
About Ormi
Ormi is the next-generation data layer for Web3, purpose-built for real-time, high-throughput applications like DeFi, gaming, wallets, and on-chain infrastructure. Its hybrid architecture ensures sub-30ms latency and up to 4,000 RPS for live subgraph indexing.
With 99.9% uptime and deployments across ecosystems representing $50B+ in TVL and $100B+ in annual transaction volume, Ormi is trusted to power the most demanding production environments without throttling or delay.