Integration Recipes
Practical snippets for integrating wstGBP. They use viem and
wagmi ; the math mirrors the on-chain contract to the wei. Paste the
ABI into ./wstgbpAbi.ts first.
export const WSTGBP = '0x57C3571f10767E49C9d7b60feb6c67804783B7aE'
export const TGBP = '0x27f6c8289550fCE67f6B50BeD1F519966aFE5287'
export const MULTICALL3 = '0xcA11bde05977b3631167028862bE2a173976CA11'Read NAV and quoting state
mintcost() and burncost() are already fee-adjusted, so use them directly rather than
re-deriving from navprice().
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wstgbpAbi } from './wstgbpAbi'
import { WSTGBP } from './addresses'
const pub = createPublicClient({ chain: mainnet, transport: http() })
const [navprice, mintcost, burncost] = await Promise.all([
pub.readContract({ address: WSTGBP, abi: wstgbpAbi, functionName: 'navprice' }),
pub.readContract({ address: WSTGBP, abi: wstgbpAbi, functionName: 'mintcost' }),
pub.readContract({ address: WSTGBP, abi: wstgbpAbi, functionName: 'burncost' }),
])Batch every read in one Multicall3 call
Separate calls can land on different blocks, so the values tear. Batch with viem’s
multicall to read every value at one block (it routes through Multicall3 at
0xcA11bde05977b3631167028862bE2a173976CA11).
const wst = { address: WSTGBP, abi: wstgbpAbi } as const
const [
navprice, mintcost, burncost,
mintable, burnable, cooldown, capacity, totalSupply,
] = await pub.multicall({
allowFailure: false,
contracts: [
{ ...wst, functionName: 'navprice' },
{ ...wst, functionName: 'mintcost' },
{ ...wst, functionName: 'burncost' },
{ ...wst, functionName: 'mintable' },
{ ...wst, functionName: 'burnable' },
{ ...wst, functionName: 'cooldown' },
{ ...wst, functionName: 'capacity' },
{ ...wst, functionName: 'totalSupply' },
],
})Read the market window from the Gate
mintable() and burnable() report whether the market is open at the current block. The
market gate (the act proxy) exposes the schedule itself, so a UI can show when minting
opens next. See the Gate schedule reads for
the full surface. These functions live on the gate, not the token:
import { parseAbi } from 'viem'
export const ACT = '0xB59cB4d3075a8ce5013C78e8Bd7aDA3Fd1300f7f'
export const gateAbi = parseAbi([
'function bpsin() view returns (uint256)',
'function bpsout() view returns (uint256)',
'function nextOpenMint() view returns (uint256)',
'function nextHaltMint() view returns (uint256)',
'function nextOpenBurn() view returns (uint256)',
'function nextHaltBurn() view returns (uint256)',
])
const gate = { address: ACT, abi: gateAbi } as const
const [bpsin, bpsout, nextOpenMint, nextHaltMint] = await pub.multicall({
allowFailure: false,
contracts: [
{ ...gate, functionName: 'bpsin' },
{ ...gate, functionName: 'bpsout' },
{ ...gate, functionName: 'nextOpenMint' },
{ ...gate, functionName: 'nextHaltMint' },
],
})
// next* return the upcoming transition as a unix timestamp, with two sentinels:
// 0n -> boundary already passed (no transition ahead)
// 2n ** 256n - 1n (uint256.max) -> transition never scheduled
// The current mainnet config (market open indefinitely) returns 0n from
// nextOpen*() and uint256.max from nextHalt*(). Treat both as "no date",
// never render them as timestamps.Gasless approval with permit (EIP-2612)
Sign a standard Permit message instead of sending an approve transaction. The nonce
comes from nonces(owner); the domain is spelled out in the
Contract Reference. permit is
ban-list screened: relayer, owner, and spender must all pass the cop screen.
const nonce = await pub.readContract({
address: WSTGBP, abi: wstgbpAbi, functionName: 'nonces', args: [owner],
})
const signature = await wallet.signTypedData({
account,
domain: {
name: 'Wren Staked tGBP',
version: '1',
chainId: 1,
verifyingContract: WSTGBP,
},
types: {
Permit: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
primaryType: 'Permit',
message: { owner, spender, value, nonce, deadline },
})Preview mint & redeem
Quote previews with guard checks, so a UI can show why an amount won’t go through. The underlying WAD math (and reverse quoting) is derived in Mint & Redeem.
export const WAD = 10n ** 18n
export const wdiv = (x: bigint, y: bigint) => (x * WAD) / y // floor
export const wmul = (x: bigint, y: bigint) => (x * y) / WAD // floor
// mint: tGBP in -> wstGBP out
export function previewMint(args: {
amountIn: bigint; mintcost: bigint; totalSupply: bigint; capacity: bigint; mintable: boolean
}): { out: bigint; reason?: 'paused' | 'dust' | 'capacity' } {
if (!args.mintable) return { out: 0n, reason: 'paused' }
if (args.amountIn < args.mintcost) return { out: 0n, reason: 'dust' }
const out = wdiv(args.amountIn, args.mintcost)
if (args.totalSupply + out > args.capacity) return { out, reason: 'capacity' }
return { out }
}
// redeem: wstGBP in -> tGBP out
export function previewRedeem(args: {
amountIn: bigint; burncost: bigint; burnable: boolean
}): { out: bigint; reason?: 'paused' | 'dust' } {
if (!args.burnable) return { out: 0n, reason: 'paused' }
if (args.amountIn < WAD) return { out: 0n, reason: 'dust' } // min one whole wstGBP
return { out: wmul(args.amountIn, args.burncost) }
}Watch events
import { parseAbiItem } from 'viem'
// new mints
const unwatchMint = pub.watchEvent({
address: WSTGBP,
event: parseAbiItem(
'event ContractCreated(address indexed creator, uint256 indexed price, uint256 indexed amount)',
),
onLogs: (logs) => console.log('minted', logs),
})
// redemptions opened + claims settled
const unwatchClaim = pub.watchEvent({
address: WSTGBP,
event: parseAbiItem(
'event ClaimProcessed(uint256 indexed id, address indexed claimer, uint256 indexed amount)',
),
onLogs: (logs) => console.log('claimed', logs),
})wagmi (React)
import { useReadContracts } from 'wagmi'
import { wstgbpAbi } from './wstgbpAbi'
import { WSTGBP } from './addresses'
const wst = { address: WSTGBP, abi: wstgbpAbi } as const
export function useWstgbpState() {
return useReadContracts({
allowFailure: false,
contracts: [
{ ...wst, functionName: 'mintcost' },
{ ...wst, functionName: 'burncost' },
{ ...wst, functionName: 'mintable' },
{ ...wst, functionName: 'burnable' },
{ ...wst, functionName: 'cooldown' },
{ ...wst, functionName: 'totalSupply' },
],
})
}For mint/redeem write flows, see Mint & Redeem; for swaps, see Swap Recipes; for historical or aggregated data, use the subgraph in Data & Analytics.