/r/gnoswap/router/v1
Router
Swap routing engine for optimal trade execution across pools.
Overview
Router handles swap execution across multiple pools, finding optimal paths and managing slippage protection for traders.
Configuration
- Router Fee: 15 bps (0.15%) by default on output tokens; configurable by admin/governance from 0 through 1000 bps (0–10%)
- Max Hops: 3 pools per route
- Deadline Buffer: 5-30 minutes recommended for live swaps
Core Functions
ExactInSwapRoute
Swaps an exact input amount for output, subject to a minimum net output.
- Fixed input, variable output
- The returned output is after the router fee
- Reverts if output < amountOutMin
- Supports multi-hop routing
ExactOutSwapRoute
Swaps for a requested final user output amount with maximum input. The
amountOut target is post-router-fee: the router requests the corresponding
gross pool output, deducts the fee, then validates and transfers the net output.
- With no single-hop price limit, targets the requested post-fee output within the implementation's small per-hop rounding tolerance
- A nonzero single-hop price limit may stop early and return a partial output
- Reverts if input > amountInMax
- Calculates path backwards
DrySwapRoute
Simulates a swap without execution.
- Frontend price quotes
- Slippage calculation
- Path validation
- No deadline check or token transfer
Technical Details
Route Format vs Pool Format - IMPORTANT DISTINCTION
Route Format (Swap Direction)
Routes in the router follow swap direction ordering: tokenIn:tokenOut:fee
- First token = Input token (what you're swapping FROM)
- Second token = Output token (what you're swapping TO)
- This represents the actual flow of the swap
Example for swapping GNS to WUGNOT:
gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000
Pool Format (Alphabetical)
Pools are identified using alphabetical ordering: token0:token1:fee
- token0 < token1 (lexicographically sorted)
- This is the canonical pool identifier
Example pool identifier (same pool as above):
gno.land/r/gnoland/wugnot.wugnot:gno.land/r/gnoswap/gns.GNS:3000 # gnoland/wugnot < gnoswap/gns alphabetically
Key Difference
- Router routes: Follow your swap direction (BAR→BAZ means bar:baz in route)
- Pool identifiers: Always alphabetically sorted (might be bar:baz or baz:bar)
- The router automatically handles the conversion between these formats
Native Token Route Specification
IMPORTANT: Router swap functions do not accept native ugnot directly.
- Token Parameters: Use token keys (
pkgPath.SYMBOL) such as"gno.land/r/gnoland/wugnot.wugnot" - Route Paths: Also use token keys (
pkgPath.SYMBOL) such as"gno.land/r/gnoland/wugnot.wugnot"
This matches the current implementation:
- Pools operate on token contract paths, including wrapped GNOT (
wugnot) - Router swap entrypoints reject native-coin handling
- Native-token refund and unwrap flows are not part of the current router implementation
Route String Format
Single-hop format:
tokenIn:tokenOut:fee
Multi-hop format (using POOL separator):
tokenIn:tokenB:fee1*POOL*tokenB:tokenC:fee2*POOL*tokenC:tokenOut:fee3
Single-hop example:
# Swapping GNS to WUGNOT
Route: gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000
# Router interprets: tokenIn=gns, tokenOut=wugnot, fee=3000
Multi-hop example (GNS → WUGNOT → TOKEN_C):
# Each segment follows swap direction, connected by *POOL*
gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000*POOL*gno.land/r/gnoland/wugnot.wugnot:gno.land/r/<namespace>/token_c.TOKEN_C:500
Quote Distribution
Split large trades across routes to minimize impact:
quoteArr: positive percentage per route, with one quote for each route- Quotes must sum to 100; at most 7 routes are accepted
- Example: "30,70" = 30% route1, 70% route2
Native Token Handling
The current router implementation does not handle native ugnot directly. It rejects native-coin handling and routes swaps only through token keys (pkgPath.SYMBOL) such as wrapped GNOT (wugnot).
Token Identifier Requirements
- Use token keys (
pkgPath.SYMBOL) such asgno.land/r/gnoland/wugnot.wugnotfor both inputs/outputs and route specifications. - Do not pass
"ugnot"asinputTokenoroutputTokento router swap functions.
Approval and Transfer Requirements
- Approve the router to spend the token contract you are swapping from.
- If you want wrapped GNOT exposure, use the
wugnottoken contract path directly. - Native-token refund and unwrap flows are not part of the current router implementation.
For live liquidity-changing swaps:
- Set
amountOutMin = expected * (1 - slippage%) - 0.5-1% for stable pairs
- 1-3% for volatile pairs
- Reverts if the net output is below the minimum
Usage
These snippets call the public domain proxy from a realm function with a current cur token.
Import the proxy package and qualify its function names in integrating code.
Basic Token Swaps
1// Simple exact input swap
2amountIn, amountOut := ExactInSwapRoute(
3 cross(cur),
4 "gno.land/r/gnoswap/gns.GNS", // input token
5 "gno.land/r/gnoland/wugnot.wugnot", // output token
6 "1000000", // amount (6 decimals)
7 "gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000", // route
8 "100", // 100% through route
9 "950000", // min output
10 time.Now().Unix() + 300, // deadline
11 "g1referrer...", // referral
12)
13
14// Multi-hop swap
15ExactInSwapRoute(
16 cross(cur),
17 "gno.land/r/gnoswap/gns.GNS",
18 "gno.land/r/<namespace>/token_c.TOKEN_C",
19 "1000000",
20 "gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000*POOL*gno.land/r/gnoland/wugnot.wugnot:gno.land/r/<namespace>/token_c.TOKEN_C:3000",
21 "100",
22 "900000",
23 deadline,
24 "",
25)
26
27// Split route for large trades
28ExactInSwapRoute(
29 cross(cur),
30 "gno.land/r/gnoswap/gns.GNS",
31 "gno.land/r/gnoland/wugnot.wugnot",
32 "10000000000",
33 "gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:500,gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000",
34 "60,40", // 60% through 0.05%, 40% through 0.3%
35 "9500000000",
36 deadline,
37 "",
38)
Single-hop functions support partial execution through a nonzero
sqrtPriceLimitX96:
1// Partial swap with price limit - may not consume full input amount
2amountIn, amountOut := ExactInSingleSwapRoute(
3 cross(cur),
4 "gno.land/r/gnoswap/gns.GNS", // input token
5 "gno.land/r/gnoland/wugnot.wugnot", // output token
6 "1000000", // max amount to swap
7 "gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000", // single route
8 "950000", // min output
9 "1000000000000000000", // sqrtPriceLimitX96 (price limit)
10 deadline,
11 "",
12)
13// If the price limit is reached, only a partial amount is swapped. For exact-in
14// this can consume less input; exact-out can deliver less than its target.
15// amountOutMin or amountInMax remains enforced, respectively.
Important Developer Notes
Common Integration Pitfalls
-
Native Token Assumptions: Passing
"ugnot"to router swap functions will fail because router entrypoints reject native-coin handling. -
Route vs Token Identifier Confusion: Using
"ugnot"in route strings instead of"gno.land/r/gnoland/wugnot.wugnot"will cause transactions to fail since no pools exist for the"ugnot"identifier. -
Wrong Token Path:
- Use
gno.land/r/gnoland/wugnot.wugnotwhen swapping wrapped GNOT - Do not pass native
ugnotto router swap functions - Route strings must stay in swap-direction order and use token contract paths
- Use
Frontend Integration Checklist
- Implement WUGNOT approval before wrapped-GNOT swaps
- Use token keys (
pkgPath.SYMBOL) such as"gno.land/r/gnoland/wugnot.wugnot"for both parameters and routes - Test both partial and full swap scenarios
- Implement proper error handling for failed approvals
Both single-hop functions support partial execution when
sqrtPriceLimitX96 is nonzero:
- Exact-in may consume less than the specified input amount
- Exact-out may deliver less than the requested post-fee output
- The relevant amount limit (
amountOutMinoramountInMax) still applies - Remaining input tokens stay with the user because the router uses token contract transfers
- A zero limit uses the global tick-math boundary and preserves full exact semantics
Security
- Path validation checks syntax, endpoints, hop continuity, and pool existence; it does not reject circular routes
- Deadline prevents stale live transactions
- Slippage limits protect against unfavorable execution
- The router fee rate is configurable; the current rate is fixed during one execution
- WUGNOT approval requirement prevents unauthorized token transfers