Sui RWA Indexer & GraphQL API
Overview
A custom indexer for Upside Sui security tokens (SharedToken). Native Sui
ownership indexes cannot list holders because every token object is shared.
This indexer stores an event log and a live object set, then exposes them over
GraphQL for the TA API and client wallets.
Key Features
- Checkpoint ingestion via
sui-indexer-alt-framework - Event types: mint, burn, transfer, force_transfer
- Live
SharedTokenbalances and object IDs - GraphQL API with GraphiQL IDE
- Chronological ordering for cap-table rebuild
Authentication
Use the X-API-Key header on POST /graphql.
curl -H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ __typename }"}' \
https://sui-rwa-indexer.upside.gg/graphql
Endpoints
Production (mainnet)
- GraphQL:
https://sui-rwa-indexer.upside.gg/graphql - GraphiQL:
https://sui-rwa-indexer.upside.gg/graphiql - Health:
https://sui-rwa-indexer.upside.gg/health
Staging (testnet)
- GraphQL:
https://sui-rwa-indexer-staging.upside.gg/graphql - GraphiQL:
https://sui-rwa-indexer-staging.upside.gg/graphiql - Health:
https://sui-rwa-indexer-staging.upside.gg/health
Token identity
Pass the fully-qualified coin type as coinType, for example:
0xPACKAGE::test_token::TEST_TOKEN
The short form of the address works too, and so does any letter case: every query pads the coin type and the owner address before the lookup.
tokenActivity
query TokenActivity($coinType: String!, $limit: Int, $offset: Int, $order: SortOrder) {
tokenActivity(coinType: $coinType, limit: $limit, offset: $offset, order: $order) {
activityType
txDigest
eventSeq
checkpoint
checkpointTimestamp
amount
coinType
decimals
fromAddress
toAddress
signer
tokenObjectId
}
}
checkpointTimestamp is unix seconds (string), matching Solana slotTimestamp.
Object-set queries
query HolderView($coinType: String!, $owner: String!) {
tokenBalance(coinType: $coinType, owner: $owner) {
owner
balance
objectCount
decimals
}
tokenObjects(coinType: $coinType, owner: $owner, limit: 50) {
objectId
owner
balance
version
checkpoint
}
}
query Holders($coinType: String!) {
tokenHolders(coinType: $coinType, limit: 100) {
owner
balance
objectCount
}
}
An owner whose live objects add up to zero is not in the holder list.
indexerStatus
A balance describes the chain only up to the checkpoint that the indexer has reached, and an owner whose first mint is not indexed yet looks exactly like an owner who holds nothing. Read the watermark before you treat an answer as final.
query IndexerStatus {
indexerStatus {
pipeline
checkpoint
checkpointTimestamp
ageSeconds
}
}
token_activity serves tokenActivity, and shared_token_objects serves the
balance and holder queries. In steady state ageSeconds stays near the
checkpoint interval of the network. A large value means the data is stale, for
example during a backfill.