Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

router source realm

Package router provides swap routing and execution across GnoSwap liquidity pools.

Readme View source

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: 0.15% on all swaps
  • Max Hops: 3 pools per route
  • Deadline Buffer: 5-30 minutes recommended

Core Functions

ExactInSwapRoute

Swaps exact input amount for minimum output.

  • Fixed input, variable output
  • Reverts if output < amountOutMin
  • Supports multi-hop routing

ExactOutSwapRoute

Swaps for exact output amount with maximum input.

  • Fixed output, variable input
  • Reverts if input > amountInMax
  • Calculates path backwards

DrySwapRoute

Simulates swap without execution.

  • Frontend price quotes
  • Slippage calculation
  • Gas estimation
  • Path validation

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 BAR to BAZ:

gno.land/r/demo/bar:gno.land/r/demo/baz: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/demo/bar:gno.land/r/demo/baz:3000  # if bar < baz 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: When using native GNOT tokens, there's a critical distinction between token identifiers and route paths:

  • Token Parameters: Use "ugnot" for inputToken and outputToken parameters
  • Route Paths: Must use "gno.land/r/gnoland/wugnot" in route strings

This dual-identifier system exists because:

  • Pools only operate on wrapped tokens (WUGNOT)
  • Router functions accept native token identifiers for user convenience
  • Internal processing automatically converts between native and wrapped forms

Correct Usage Example:

 1// CORRECT: inputToken="ugnot", route uses wugnot path
 2ExactInSwapRoute(
 3    "ugnot",                                    // input token identifier
 4    "gno.land/r/demo/bar",                    // output token
 5    "1000000",
 6    "gno.land/r/gnoland/wugnot:gno.land/r/demo/bar:3000", // route uses wugnot
 7    "100", "950000", deadline, ""
 8)
 9
10// INCORRECT: using "ugnot" in route will fail
11ExactInSwapRoute(
12    "ugnot", "gno.land/r/demo/bar", "1000000",
13    "ugnot:gno.land/r/demo/bar:3000",          // Wrong: pools don't exist for "ugnot"
14    "100", "950000", deadline, ""
15)

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 BAR to BAZ
Route: gno.land/r/demo/bar:gno.land/r/demo/baz:3000
# Router interprets: tokenIn=bar, tokenOut=baz, fee=3000

Multi-hop example (BAR → BAZ → QUX):

# Each segment follows swap direction, connected by *POOL*
gno.land/r/demo/bar:gno.land/r/demo/baz:3000*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500

Quote Distribution

Split large trades across routes to minimize impact:

  • quoteArr: Percentage per route (must sum to 100)
  • Example: "30,70" = 30% route1, 70% route2

GNOT Handling

The Router automatically handles native GNOT token operations through wrapping/unwrapping mechanisms:

Token Identifier Requirements

  • Input Token: Use "ugnot" to specify native GNOT as input token
  • Output Token: Use "ugnot" to specify native GNOT as output token
  • Routes: Must always use wrapped token path "gno.land/r/gnoland/wugnot" in route specifications

Native Token Send Requirements

When using native GNOT tokens, you must send the appropriate amount of native ugnot with your function call:

  • ExactInSwapRoute: Send exactly amountIn amount of ugnot
  • ExactInSingleSwapRoute: Send exactly amountIn amount of ugnot
  • ExactOutSwapRoute: Send exactly amountInMax amount of ugnot
  • ExactOutSingleSwapRoute: Send exactly amountInMax amount of ugnot

WUGNOT Approval Requirements for Refunds

1// Before calling router functions with native tokens
2wugnot.Approve(cross, routerAddress, maxAmount)

This approval is required because:

  • Router wraps native GNOT to WUGNOT for internal processing
  • Unused GNOT is refunded by transferring WUGNOT from user and unwrapping it
  • The unwrapWithTransferFrom function requires WUGNOT transfer approval

Refund Logic

  • ExactIn Functions: Unused GNOT is automatically refunded after swap
  • ExactOut Functions: Excess GNOT (difference between amountInMax and actual input used) is refunded
  • Refunds use unwrapWithTransferFrom which requires prior WUGNOT approval

Example with Native GNOT

 1// 1. First approve WUGNOT spending for potential refunds
 2wugnot.Approve(cross, routerAddress, 1000000) // Approve max amount
 3
 4// 2. Call swap function with native GNOT, sending ugnot
 5// Note: inputToken="ugnot" but route uses wugnot path
 6amountIn, amountOut := ExactInSwapRoute(
 7    "ugnot",                                    // input token (native)
 8    "gno.land/r/demo/bar",                    // output token
 9    "1000000",                                // amount (send this much ugnot)
10    "gno.land/r/gnoland/wugnot:gno.land/r/demo/bar:3000", // route uses wugnot
11    "100",                                    // 100% through route
12    "950000",                                 // min output
13    time.Now().Unix() + 300,                  // deadline
14    "",                                       // no referrer
15)
16// Any unused GNOT will be automatically refunded

Slippage Protection

  • Set amountOutMin = expected * (1 - slippage%)
  • 0.5-1% for stable pairs
  • 1-3% for volatile pairs
  • Reverts if exceeded

Usage

Basic Token Swaps

 1// Simple exact input swap
 2amountIn, amountOut := ExactInSwapRoute(
 3    "gno.land/r/demo/bar",     // input token
 4    "gno.land/r/demo/baz",     // output token
 5    "1000000",                 // amount (6 decimals)
 6    "gno.land/r/demo/bar:gno.land/r/demo/baz:3000", // route
 7    "100",                     // 100% through route
 8    "950000",                  // min output
 9    time.Now().Unix() + 300,   // deadline
10    "g1referrer...",           // referral
11)
12
13// Multi-hop swap
14ExactInSwapRoute(
15    "gno.land/r/demo/bar",
16    "gno.land/r/demo/baz",
17    "1000000",
18    "gno.land/r/demo/bar:gno.land/r/gnoland/wugnot:3000*POOL*gno.land/r/gnoland/wugnot:gno.land/r/demo/baz:3000",
19    "100",
20    "900000",
21    deadline,
22    "",
23)
24
25// Split route for large trades
26ExactInSwapRoute(
27    "gno.land/r/demo/usdc",
28    "ugnot",
29    "10000000000",
30    "gno.land/r/demo/usdc:gno.land/r/gnoland/wugnot:500,gno.land/r/demo/usdc:gno.land/r/gnoland/wugnot:3000",
31    "60,40",  // 60% through 0.05%, 40% through 0.3%
32    "9500000000",
33    deadline,
34    "",
35)

Single Swap with Partial Execution

Single swap functions support partial execution through price limits:

 1// Partial swap with price limit - may not consume full input amount
 2amountIn, amountOut := ExactInSingleSwapRoute(
 3    "gno.land/r/demo/bar",     // input token
 4    "gno.land/r/demo/baz",     // output token
 5    "1000000",                 // max amount to swap
 6    "gno.land/r/demo/bar:gno.land/r/demo/baz:3000", // single route
 7    "950000",                  // min output
 8    "1000000000000000000",     // sqrtPriceLimitX96 (price limit)
 9    deadline,
10    "",
11)
12// If price limit is reached, only partial amount is swapped
13// Remaining input tokens stay with user (no refund needed for GRC20 tokens)

Native GNOT Swaps with Refunds

When using native GNOT, automatic refunds handle unused amounts:

 1// STEP 1: Approve WUGNOT for potential refunds
 2wugnot.Approve(cross, routerAddress, 2000000) // Approve more than needed
 3
 4// STEP 2: ExactIn with native GNOT (send exactly amountIn)
 5amountIn, amountOut := ExactInSwapRoute(
 6    "ugnot",                    // native input
 7    "gno.land/r/demo/bar",     // output token
 8    "1000000",                 // send this amount of ugnot with call
 9    "gno.land/r/gnoland/wugnot:gno.land/r/demo/bar:3000",
10    "100", "950000", deadline, ""
11)
12// Any unused GNOT automatically refunded
13
14// STEP 3: ExactOut with native GNOT (send amountInMax)
15amountIn, amountOut := ExactOutSwapRoute(
16    "ugnot",                    // native input
17    "gno.land/r/demo/bar",     // output token
18    "1000000",                 // exact output desired
19    "gno.land/r/gnoland/wugnot:gno.land/r/demo/bar:3000",
20    "100",
21    "1200000",                 // send this max amount of ugnot with call
22    deadline, ""
23)
24// Excess GNOT (1200000 - actual_input_used) automatically refunded
25
26// STEP 4: Single swap with partial execution + refund
27amountIn, amountOut := ExactInSingleSwapRoute(
28    "ugnot",                    // native input
29    "gno.land/r/demo/bar",     // output token
30    "1000000",                 // send this amount of ugnot with call
31    "gno.land/r/gnoland/wugnot:gno.land/r/demo/bar:3000",
32    "950000",
33    "1000000000000000000",     // price limit may cause partial swap
34    deadline, ""
35)
36// Unswapped GNOT due to price limit automatically refunded

Important Developer Notes

Common Integration Pitfalls

  1. WUGNOT Approval Forgotten: Most transaction failures with native GNOT occur because developers forget to approve WUGNOT spending before calling router functions.

  2. Route vs Token Identifier Confusion: Using "ugnot" in route strings instead of "gno.land/r/gnoland/wugnot" will cause transactions to fail since no pools exist for the "ugnot" identifier.

  3. Incorrect Native Token Send Amount:

    • ExactIn functions: Must send exactly amountIn of native gnot
    • ExactOut functions: Must send exactly amountInMax of native gnot
    • Sending wrong amounts will cause transaction reversion
  4. Missing Refund Handling: When integrating, remember that native GNOT refunds are automatic but require prior WUGNOT approval.

Frontend Integration Checklist

  • Implement WUGNOT approval before native GNOT swaps
  • Use correct token identifiers: "ugnot" for parameters, "gno.land/r/gnoland/wugnot" for routes
  • Send correct native token amounts with function calls
  • Handle automatic refunds in UI balance updates
  • Test both partial and full swap scenarios
  • Implement proper error handling for failed approvals

Single Swap Partial Execution

The ExactInSingleSwapRoute and ExactOutSingleSwapRoute functions support partial execution when sqrtPriceLimitX96 is set. This means:

  • Swap may consume less than the specified input amount
  • Price impact is limited by the price limit parameter
  • Remaining tokens are handled automatically (refunded for native GNOT, stay with user for GRC20)
  • This is useful for large trades to prevent excessive slippage

Security

  • Path validation prevents circular routes
  • Deadline prevents stale transactions
  • Slippage limits protect against MEV
  • Router fees immutable per swap
  • WUGNOT approval requirement prevents unauthorized token transfers

Overview

Package router provides swap routing and execution across GnoSwap liquidity pools.

The router handles token swaps with multi-hop routing, slippage protection, and automatic GNOT wrapping/unwrapping. It supports both exact input and exact output swap modes with deadline validation.

Key features: - Multi-hop routing across up to 3 pools - Quote distribution for optimal execution - Native GNOT handling with automatic wrap/unwrap - Slippage protection via min/max amounts - Router fee (0.15%) on all swaps - Deadline enforcement to prevent stale transactions

The router acts as a proxy to version-specific implementations, currently routing to v1 for all swap operations.

Constants 1

Functions 12

func DrySwapRoute

Action
1func DrySwapRoute(
2	inputToken, outputToken string,
3	specifiedAmount string,
4	swapTypeStr string,
5	strRouteArr, quoteArr string,
6	tokenAmountLimit string,
7) (string, string, bool)
source

DrySwapRoute simulates a swap route without executing it.

Parameters:

  • inputToken: path of input token
  • outputToken: path of output token
  • specifiedAmount: specified amount for the swap
  • swapTypeStr: swap type string ("ExactIn" or "ExactOut")
  • strRouteArr: encoded route array
  • quoteArr: encoded quote array
  • tokenAmountLimit: token amount limit

Returns:

  • string: estimated input amount
  • string: estimated output amount
  • bool: success status

func ExactInSingleSwapRoute

crossing Action
1func ExactInSingleSwapRoute(cur realm, inputToken string, outputToken string, amountIn string, routeArr string, amountOutMin string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string)
source

ExactInSingleSwapRoute executes a single-hop swap with exact input amount.

Parameters:

  • inputToken: path of input token
  • outputToken: path of output token
  • amountIn: exact input amount
  • routeArr: encoded route
  • amountOutMin: minimum output amount
  • sqrtPriceLimitX96: price limit for the swap
  • deadline: transaction deadline
  • referrer: referrer address for reward tracking

Returns:

  • string: actual input amount
  • string: actual output amount

func ExactInSwapRoute

crossing Action
1func ExactInSwapRoute(cur realm, inputToken string, outputToken string, amountIn string, routeArr string, quoteArr string, amountOutMin string, deadline int64, referrer string) (string, string)
source

ExactInSwapRoute executes a multi-hop swap with exact input amount.

Parameters:

  • inputToken: path of input token
  • outputToken: path of output token
  • amountIn: exact input amount
  • routeArr: encoded route array
  • quoteArr: encoded quote array
  • amountOutMin: minimum output amount
  • deadline: transaction deadline
  • referrer: referrer address for reward tracking

Returns:

  • string: actual input amount
  • string: actual output amount

func ExactOutSingleSwapRoute

crossing Action
1func ExactOutSingleSwapRoute(cur realm, inputToken string, outputToken string, amountOut string, routeArr string, amountInMax string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string)
source

ExactOutSingleSwapRoute executes a single-hop swap with exact output amount.

Parameters:

  • inputToken: path of input token
  • outputToken: path of output token
  • amountOut: exact output amount
  • routeArr: encoded route
  • amountInMax: maximum input amount
  • sqrtPriceLimitX96: price limit for the swap
  • deadline: transaction deadline
  • referrer: referrer address for reward tracking

Returns:

  • string: actual input amount
  • string: actual output amount

func ExactOutSwapRoute

crossing Action
1func ExactOutSwapRoute(cur realm, inputToken string, outputToken string, amountOut string, routeArr string, quoteArr string, amountInMax string, deadline int64, referrer string) (string, string)
source

ExactOutSwapRoute executes a multi-hop swap with exact output amount.

Parameters:

  • inputToken: path of input token
  • outputToken: path of output token
  • amountOut: exact output amount
  • routeArr: encoded route array
  • quoteArr: encoded quote array
  • amountInMax: maximum input amount
  • deadline: transaction deadline
  • referrer: referrer address for reward tracking

Returns:

  • string: actual input amount
  • string: actual output amount

func RegisterInitializer

crossing Action
1func RegisterInitializer(cur realm, initializer func(_ int, rlm realm, routerStore IRouterStore) IRouter)
source

RegisterInitializer registers a new router implementation version. This function is called by each version (v1, v2, etc.) during initialization to register their implementation with the proxy system.

The initializer function creates a new instance of the implementation using the provided routerStore interface.

Security: Only contracts within the domain path can register initializers. Each package path can only register once to prevent duplicate registrations.

func SetSwapFee

crossing Action
1func SetSwapFee(cur realm, fee uint64)
source

SetSwapFee sets the swap fee rate.

Parameters:

  • fee: new swap fee in basis points

func SwapCallback

crossing Action
1func SwapCallback(cur realm, token0Path string, token1Path string, amount0Delta int64, amount1Delta int64, payer address) error
source

SwapCallback is called by pools to transfer tokens during a swap.

func UpgradeImpl

crossing Action
1func UpgradeImpl(cur realm, packagePath string)
source

UpgradeImpl switches the active router implementation to a different version. This function allows seamless upgrades from one version to another without data migration or downtime.

Security: Only admin or governance can perform upgrades. The new implementation must have been previously registered via RegisterInitializer.

func NewRouterStore

Action
1func NewRouterStore(kvStore store.KVStore) IRouterStore
source

NewRouterStore creates a new router store instance with the provided KV store. This function is used by the upgrade system to create storage instances for each implementation.

Types 3

type IRouter

interface
 1type IRouter interface {
 2	ExactInSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountIn string, routeArr string, quoteArr string, amountOutMin string, deadline int64, referrer string) (string, string)
 3	ExactInSingleSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountIn string, routeArr string, amountOutMin string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string)
 4
 5	ExactOutSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountOut string, routeArr string, quoteArr string, amountInMax string, deadline int64, referrer string) (string, string)
 6	ExactOutSingleSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountOut string, routeArr string, amountInMax string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string)
 7
 8	DrySwapRoute(inputToken, outputToken, specifiedAmount, swapTypeStr, strRouteArr, quoteArr, tokenAmountLimit string) (string, string, bool)
 9	SwapCallback(_ int, rlm realm, token0Path string, token1Path string, amount0Delta int64, amount1Delta int64, payer address) error
10
11	GetSwapFee() uint64
12	SetSwapFee(_ int, rlm realm, fee uint64)
13}
source

type IRouterStore

interface
1type IRouterStore interface {
2	HasSwapFeeKey() bool
3	GetSwapFee() uint64
4	SetSwapFee(_ int, rlm realm, fee uint64) error
5	HasPendingProtocolFeesKey() bool
6	GetPendingProtocolFees() map[string]int64
7	SetPendingProtocolFees(_ int, rlm realm, fees map[string]int64) error
8}
source

type StoreKey

ident
1type StoreKey string
source

Methods on StoreKey

func String

method on StoreKey
1func (s StoreKey) String() string
source

Imports 6

Source Files 8

Directories 1