TopazTOPAZDocs

Developers

Integration Guide

A developer-facing tour of the protocol. Whether you're a project team listing your token, an aggregator routing through Topaz, or a builder reading pool state for an oracle, this is the entry point.

Common integration paths

  • Aggregator / router integration — quote Topaz pools and execute swaps through Router (v2) or SwapRouter (Slipstream).
  • Token listing as a project — get whitelisted, create your pool, request a gauge, post incentives.
  • Oracle consumer — read TWAPs from Slipstream pools for your dapp.
  • Vault / strategy builder — automate concentrated-liquidity range management or veTOPAZ voting strategies.

Routing & quoting

For programmatic swaps, three quoter contracts cover all routes:

  • Router — v2-style multihop swaps. Use getAmountsOut for quoting.
  • QuoterV2 — Slipstream-only multihop quotes. Off-chain only (it reverts to return data — the standard Uniswap V3 quoter pattern).
  • MixedRouteQuoterV1 — quotes that mix v2 and Slipstream pools in a single path. Use this when routing across both pool types.

Encoding a Slipstream path:

solidity
// Single hop
bytes memory path = abi.encodePacked(
    tokenIn,           // 20 bytes
    uint24(tickSpacing), // 3 bytes
    tokenOut           // 20 bytes
);

// Multi-hop via WBNB
bytes memory path = abi.encodePacked(
    tokenIn,           // 20 bytes
    uint24(50),        // tickSpacing for first hop (low-vol)
    WBNB,              // 20 bytes
    uint24(200),       // tickSpacing for second hop (volatile)
    tokenOut           // 20 bytes
);

See Contracts for all addresses including the mixed-route quoter and Swaps & Routing for end-user routing concepts.

Listing a token / pool (for projects)

The complete checklist for bringing a new token onto Topaz:

  1. 1Deploy or identify the ERC-20 contract on BNB Chain. Standard ERC-20 only — fee-on-transfer tokens are partially supported by the v2 router but not by the Slipstream periphery.
  2. 2Create the pool. For v2: PoolFactory.createPool(tokenA, tokenB, stable). For Slipstream: CLFactory.createPool(tokenA, tokenB, tickSpacing, sqrtPriceX96). Both are permissionless.
  3. 3Seed initial liquidity. Provide both tokens at a price you're willing to defend. First deposit sets the price; subsequent depositors must match the ratio.
  4. 4Request whitelisting. Two whitelists matter: (a) token whitelist for use as bribe rewards, and (b) for new tokens, token whitelist on the Voter to allow permissionless gauge creation. Coordinate with governance — reach out via Telegram or governance forum.
  5. 5Get a gauge created. Once your token is whitelisted (or for a fully-whitelisted pair, by anyone), call Voter.createGauge(poolFactory, pool). Without a gauge, the pool exists but receives no emissions.
  6. 6Post incentives. Approve and call BribeVotingReward.notifyRewardAmount(token, amount) on the gauge's bribe contract to attract votes. See Incentives (Bribes).
Custom (non-whitelisted) pairs
A gauge for a pair containing a non-whitelisted token can only be created by governance, not permissionlessly. Plan ahead if your token isn't yet on the Voter whitelist.

Reading pool state on-chain

Common reads:

  • PoolFactory.getPool(tokenA, tokenB, stable) — fetch v2 pool address (returns 0x0 if absent).
  • CLFactory.getPool(tokenA, tokenB, tickSpacing) — fetch Slipstream pool address.
  • Voter.gauges(pool) — fetch a pool's gauge address (0x0 if none).
  • Voter.isAlive(gauge) — check whether a gauge is currently active.
  • CLPool.slot0() — current sqrtPriceX96, tick, observation index, etc.
  • CLPool.observe([secondsAgo1, secondsAgo2]) — compute a TWAP from the in-pool oracle. See Oracles & TWAP.

Working with the gauge directly

For programmatic LP integrations:

solidity
// v2 LP token staking
ILpToken(lpToken).approve(gauge, amount);
IGauge(gauge).deposit(amount);

// Claim emissions
IGauge(gauge).getReward(msg.sender);

// Withdraw
IGauge(gauge).withdraw(amount);

// Slipstream NFT staking
INonfungiblePositionManager(npm).approve(gauge, tokenId);
ICLGauge(gauge).deposit(tokenId);
ICLGauge(gauge).getReward(tokenId);
ICLGauge(gauge).withdraw(tokenId);

Gauges follow the standard notifyRewardAmount /rewardPerToken /earnedpattern from MasterChef / Synthetix. Rewards stream linearly across 604,800 seconds after each epoch's emission allocation.

Voting on behalf of a contract

Smart-contract vaults that hold veTOPAZ NFTs can vote and claim like any wallet. Standard flow:

solidity
// One-time setup: vault must own (or be approved for) the veNFT
IVoter(voter).vote(
    tokenId,
    [pool1, pool2, ...],
    [weight1, weight2, ...]
);

// Each epoch, after the flip:
IVoter(voter).claimBribes(
    [bribeContract1, ...],
    [[token1A, token1B], ...],
    tokenId
);
IVoter(voter).claimFees(
    [feeContract1, ...],
    [[token1A, token1B], ...],
    tokenId
);
One vote per epoch
The Voter enforces a single vote per NFT per epoch (with exceptions for whitelisted NFTs that can vote during the final hour). Plan vault automations accordingly — re-voting before the next epoch boundary reverts.

Indexing & subgraph

Topaz emits standard events at every state change — pool creates, swaps, mints, burns, votes, gauge distributions, and reward claims. Indexers can subscribe to these directly via BscScan log endpoints or run a custom subgraph. If you build public indexing infrastructure for the protocol, get in touch via Telegram for cross-linking.

Continue reading