Skip to Content
wstGBP is live on Ethereum mainnet · all addresses in these docs are verifiable on-chain
GuidesUniswap v4 & Aggregators

Uniswap v4 & Aggregators

wstGBP trades on-chain through a tGBP/wstGBP Uniswap v4 pool whose hook (WsgemBackstopHook) routes every swap through the wrapper’s atomic mint/redeem at the protocol’s own oracle prices: buys execute at wstGBP.mintcost(), sells at wstGBP.burncost(). That gives the pool effectively infinite depth inside the wrapper’s own ~25bps bid/ask band — the spread is the wrapper’s redeem fee, with no extra hook fee — and both prices ratchet up as NAV accrues.

Two properties follow directly from the design:

  • No LP. beforeAddLiquidity reverts — the pool never holds AMM liquidity; every swap is a wrapper mint or redeem.
  • No capital, no owner. The hook is ownerless, holds no funds, and adds no fee, admin, or pause of its own — it wraps the swap’s own tokens.

The hook is a pure pass-through to the wstGBP wrapper: the execution price is whatever mintcost()/burncost() return at that block, and swaps are subject to the same on-chain governance surface as direct mint/redeem — the oracle price, market open/close, capacity, cooldown, and compliance gates described in the Contract Reference. Always pass real slippage bounds.

Deployed contracts — Ethereum mainnet (chainId 1)

All four contracts are ownerless and hold no capital.

ContractPurposeAddress
WsgemBackstopHookThe v4 hook0xfE36B48c9c0240991E4CEf006a2445F2ff524888
WsgemSwapRouterSettle-first v4 swap router0x21734507fDca48A3b4e8C496280b63a37D3bD0C8
WsgemQuoterOn-chain quotes & executability preview0x9B409f87aeaADBE912632b1E4de855B6aFCc71Ee
WsgemDirectAdapterAggregator / solver adapter (no pool)0xBE402d34f31133B1Dc00277f24F8ce2d975CBe23
Uniswap v4 PoolManagerCanonical v4 singleton0x000000000004444c5dc75cB358380D2e3dE08A90

Pool id & canonical PoolKey

Uniswap v4 pools have no address — the pool lives inside the PoolManager singleton, keyed by poolId = keccak256(abi.encode(PoolKey)):

FieldValue
currency0tGBP — 0x27f6c8289550fCE67f6B50BeD1F519966aFE5287
currency1wstGBP — 0x57C3571f10767E49C9d7b60feb6c67804783B7aE
fee0
tickSpacing1
hooks0xfE36B48c9c0240991E4CEf006a2445F2ff524888
poolId0xdb21c31f461611ebeeab8af1280c77a82bb81725e1bf9d6093fbbc207a375ce5

Pin the canonical PoolKey. The router is intentionally generic over PoolKey, and the hook validates only the two currencies — not the fee, tick spacing, or hook address. Integrators, bots, and frontends must hardcode or validate the exact key above and never route through a user- or route-supplied key. (The quoter needs no key — it is bound to the wrapper at construction.)

Swap direction

tGBP < wstGBP numerically, so currency0 = tGBP, currency1 = wstGBP:

  • zeroForOne == truebuy wstGBP (pay tGBP; executes as a wrapper mint at mintcost()).
  • zeroForOne == falsesell wstGBP (receive tGBP; executes as a wrapper redeem at burncost()).

Both tokens are 18 decimals; all prices are WAD (1e18) tGBP-per-wstGBP.

Swapping on v4 — WsgemSwapRouter

v4 swaps against this hook must be settle-first (pay the input before the swap executes). Route through WsgemSwapRouter or any settle-first solver — a plain swap-then-settle v4 router will revert.

function swapExactInput( PoolKey calldata key, bool zeroForOne, uint256 amountIn, uint256 minAmountOut, address recipient, // address(0) => msg.sender uint256 deadline ) external returns (uint256 amountOut); function swapExactOutput( PoolKey calldata key, bool zeroForOne, uint256 amountOut, uint256 maxAmountIn, // surplus is refunded address recipient, uint256 deadline ) external returns (uint256 amountIn);

Both have Permit2 variants (swapExactInputPermit2 / swapExactOutputPermit2) that fund the swap from a Permit2 SignatureTransfer instead of a router approval; the permit’s token must be the input currency and its deadline is the swap deadline.

The router enforces minAmountOut (exact-input), maxAmountIn (exact-output), and full delivery of the exact output — a swap reverts rather than silently delivering less than agreed. Quotes are point-in-time and the oracle ratchets between quote and execution, so never send minAmountOut = 0.

Quoting — WsgemQuoter

Pre-flight swaps with the quoter rather than simulating reverts:

function quoteExactInput(bool zeroForOne, uint256 amountIn) external view returns (uint256 amountOut); function quoteExactOutput(bool zeroForOne, uint256 amountOut) external view returns (uint256 amountIn); // amountSpecified: negative = exact-input, positive = exact-output (PoolManager convention) function previewSwap(bool zeroForOne, int256 amountSpecified) external view returns (uint256 amountIn, uint256 amountOut, bool executable, string memory reason);

previewSwap reports the live blockers instead of reverting — market closed, dust threshold, capacity exceeded, wrapper underfunded, redeem cooldown active, or oracle paused. Quoter output matches execution exactly.

Off-chain, quote directly from wstGBP.mintcost() / burncost() with the same WAD math as direct mint/redeem — see Mint & Redeem.

Aggregators & solvers — WsgemDirectAdapter

WsgemDirectAdapter is a standalone, ownerless approve → swap contract that calls wstGBP.mint/redeem directly — no pool, no v4 callback, ordinary swap-then-settle semantics. DEX aggregators (Odos, LI.FI, Paraswap) and CoW Protocol solvers can call it like any swap contract; no settle-first router is needed. Prices and guards are identical to the hook’s.

// tokenIn == tGBP buys wstGBP (mint); tokenIn == wstGBP sells (redeem) function swapExactInput( address tokenIn, uint256 amountIn, uint256 minAmountOut, address recipient, // address(0) => msg.sender uint256 deadline ) external returns (uint256 amountOut); function swapExactOutput( address tokenIn, uint256 amountOut, uint256 maxAmountIn, // only the computed exact input is pulled address recipient, uint256 deadline ) external returns (uint256 amountIn); function quoteExactInput(address tokenIn, uint256 amountIn) external view returns (uint256 amountOut); function quoteExactOutput(address tokenIn, uint256 amountOut) external view returns (uint256 amountIn);

Permit2 variants (swapExactInputPermit2 / swapExactOutputPermit2) are available here too. The adapter is a pure price-taker with no price bounds of its own — pass real slippage bounds.

“CoW Hooks” are user pre/post-interactions, not a liquidity source. Giving CoW solvers access to this venue means route integration  of the adapter.

What integrators should monitor

All of these are public on-chain reads on wstGBP (0x57C3…B7aE); they gate the pool, the router, and the adapter alike:

ReadWhy it matters
mintcost() / burncost()The live execution prices (ratchet up as NAV accrues).
mintable() / burnable()Market open/close — closed mint reverts buys, closed burn reverts sells.
cooldown()Must be 0 for sells; non-zero makes sells revert (RedeemCooldownActive) rather than queue a deferred payout. Buys are unaffected.
capacity() vs totalSupply()Remaining buy headroom — a buy past capacity reverts (ExceedsCap).
tGBP.balanceOf(wstGBP)Sell-side funding depth — sells past it revert (WrapperUnderfunded), never partially fill.

Compliance gating applies to swaps as it does to direct mint/redeem: the swap recipient must not be banned on tGBP (see Contract Reference) — buys settle wstGBP through the PoolManager to the recipient, and every leg is compliance-checked.

Choosing a venue

You areUse
Routing v4-native flowWsgemSwapRouter against the canonical PoolKey
A DEX aggregator or CoW solverWsgemDirectAdapter (approve + swap)
QuotingWsgemQuoter, the adapter’s quote views, or off-chain mintcost()/burncost() math
Minting/redeeming your own fundsDirect mint/redeem — cheapest gas for the identical price

Copy-paste viem snippets for all of the above — quoting, router swaps, adapter swaps, and venue monitoring — live in Swap Recipes.

Last updated on