Skip to Content
wstGBP is live on Ethereum mainnet. All addresses in these docs are verifiable on-chain.
Data & Analytics

Data & Analytics

The wstGBP subgraph indexes the token and its modules on Ethereum mainnet via The Graph , exposing supply, holders, price history, gate config, and the full redemption lifecycle over GraphQL. Use it for anything historical or aggregated; use direct reads for live state. For common aggregates over plain REST (no Graph API key), see the REST API.

Endpoints

Confirm the production query URL before relying on it: the live gateway URL is issued at deploy time and is not committed in the source repo. Querying the decentralized gateway requires your own Graph API key.

# Decentralized gateway (production). Send your Graph API key as a header: # Authorization: Bearer <API_KEY> https://gateway.thegraph.com/api/subgraphs/id/BEJdaXsoMoJwXJgcaUYKfXqksmov6NRzhdJT8PxHphoG # (legacy key-in-path form, still accepted) https://gateway.thegraph.com/api/<API_KEY>/subgraphs/id/BEJdaXsoMoJwXJgcaUYKfXqksmov6NRzhdJT8PxHphoG # Subgraph Studio (development / testing) https://api.studio.thegraph.com/query/<STUDIO_ID>/wstgbp/<VERSION>

Indexed data sources

All start at block 24852284 (the deployment cluster):

SourceAddressIndexed
wstGBP (token)0x57C3571f10767E49C9d7b60feb6c67804783B7aETransfer, Approval, ContractCreated, ContractRedemption, ClaimProcessed, Settled, Issued, Smelted
Price (pip)0x6A79dCe61A12aa4b75449e0B03746260765D07dFPoke, Kiss, Diss, File, proxy/admin events
Gate (act)0xB59cB4d3075a8ce5013C78e8Bd7aDA3Fd1300f7fOpen/Halt mint & burn, Bpsin, Bpsout, Cooldown, Capacity
Treasury (adm)0xa8F5bE8457D6ed5c659647fa8d107C3F2086626ABestow, Depose (issuer registry)
Guard (cop)0x794cF5948444b14105587455EbE96Caace036d52proxy/admin events

Key entities

  • Protocol (singleton, id "wstGBP"): totalSupply, holderCount, totalMinted, totalRedemptionClaims, totalClaimed (tGBP actually paid out, vs claims registered), redemptionCount, totalIssued, totalSmelted, totalSettled, plus links to currentPrice and gateConfig.
  • Account: per-holder balance and lifetime totals; isIssuer.
  • Redemption (+ RedemptionStatus: PENDING / PARTIALLY_CLAIMED / FULLY_CLAIMED) and ClaimEvent: the redemption lifecycle per on-chain id.
  • PriceUpdate history + CurrentPrice singleton (with the feed’s decimals); PriceFileEvent (oracle File parameter changes) and FeedReader / FeedReaderEvent (the Kiss/Diss price-feed reader allowlist).
  • GateConfig singleton: the openMint / haltMint / openBurn / haltBurn market-window schedule plus bpsin / bpsout / cooldown / capacity, with GateConfigChange history.
  • Issuer / IssuerEvent: the treasury issuer registry (Bestow/Depose).
  • Event logs: TransferEvent, ApprovalEvent, MintEvent, IssueEvent, SmeltEvent, SettleEvent; admin/proxy: Ward + WardEvent, ImplementationChange, ProxyState.

Denomination gotchas: redemption and claim amounts are denominated in the underlying gem (tGBP), not in wstGBP burned; the wstGBP burned is captured by the Transfer to 0x0. And the raw price on PriceUpdate / CurrentPrice is in the feed’s own decimals (CurrentPrice.priceDecimals), whereas the token’s navprice() used for quoting is always WAD (18 decimals).

Example queries

{ protocol(id: "wstGBP") { totalSupply holderCount totalRedemptionClaims currentPrice { price priceDecimals isPaused } gateConfig { bpsin bpsout cooldown capacity } } redemptions(where: { status: PARTIALLY_CLAIMED }) { id claimAmount # underlying-gem (tGBP) owed, NOT wstGBP burned remaining claims { amount timestamp } } transferEvents(first: 5, orderBy: timestamp, orderDirection: desc) { from to amount isMint isBurn } }

Price history (for charting accrual)

{ priceUpdates(first: 100, orderBy: timestamp, orderDirection: asc) { price timestamp isPause } }

The rising price series is the NAV curve described in Architecture.

Trailing APR from the NAV curve

To turn the curve into a headline figure, measure the return across a trailing window (30 days here) and annualize over the actual elapsed seconds. Pokes land weekly, so fixed-window math would distort the figure. Fetch the in-window pokes plus one anchor poke just before the window start (the first in-window poke can be up to a week inside the boundary), excluding pauses (isPause: false):

query NavGrowth($since: BigInt!) { window: priceUpdates( first: 100, orderBy: timestamp, orderDirection: asc, where: { timestamp_gte: $since, isPause: false } ) { price timestamp } anchor: priceUpdates( first: 1, orderBy: timestamp, orderDirection: desc, where: { timestamp_lt: $since, isPause: false } ) { price timestamp } }
const WAD = 10n ** 18n const wdiv = (x: bigint, y: bigint) => (x * WAD) / y const SECONDS_PER_YEAR = 365n * 24n * 60n * 60n // simple APR, no compounding // start = the anchor poke (or the first in-window poke if no anchor exists), // end = the latest in-window poke function computeTrailingApr( start: { price: bigint; timestamp: number }, end: { price: bigint; timestamp: number }, ): bigint | null { if (start.price <= 0n) return null const elapsed = BigInt(end.timestamp - start.timestamp) if (elapsed <= 0n) return null const growthWad = wdiv(end.price - start.price, start.price) return (growthWad * SECONDS_PER_YEAR) / elapsed // APR in WAD: 1e18 == 100% }

$since is now - 30 days as a unix timestamp. Both prices come from the same feed, so the feed-decimals caveat above cancels out in the ratio.

Last updated on