Transaction

22C8B63EFB64EB…D4E7C6DA28F5

Block 77,257 · index 0 · indexed

Summary

Hash
22C8B63EFB64EB0FF6526E13376C217C6C1F698B2D7A94454138D4E7C6DA28F5
Block
77,257
Size
38282 bytes
Gas used
40,281,330 / 48,337,560
Fee
48338ugnot
Status
success

Messages

#1AddPackagegno.land/r/gnoswap/router23 arguments

Arguments · 23

  1. #1router
  2. #2README.md
  3. #3# 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. ## Gnoweb The root `Render("")` delegates to the active implementation. It exposes separate status and read-only swap-fee sections. Native Gnoweb execution forms show one user-facing swap action per page: - `""`: `ExactInSingleSwapRoute` - `"swap/exact-in"`: `ExactInSwapRoute` - `"swap/exact-out-single"`: `ExactOutSingleSwapRoute` - `"swap/exact-out"`: `ExactOutSwapRoute` Input placeholders show token-key, route, and percentage examples without separate explanatory paragraphs. Token amounts are integer base units. Set `amountOutMin` or `amountInMax` for slippage protection, use a future Unix `deadline`, and set multi-route `quoteArr` percentages to sum to 100. Approve each input GRC20 token for the router realm before swapping. The single-route price limit accepts `sqrtPriceLimitX96` as a base-10 Q64.96 square-root price; `0` disables it. No privileged fee-setting form, guidance route, or navigation link is exposed. `SetSwapFee` itself is unchanged. No internal callback form is exposed. Unsupported render paths, including `"fee"`, return `404`. ## 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 as `gno.land/r/gnoland/wugnot.wugnot` for both inputs/outputs and route specifications. - Do not pass `"ugnot"` as `inputToken` or `outputToken` to 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 `wugnot` token contract path directly. - Native-token refund and unwrap flows are not part of the current router implementation. #### Example with Wrapped GNOT Examples in this document 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. ```go // 1. Approve WUGNOT spending for the router wugnot.Approve(cross(cur), routerAddress, 1000000) // 2. Call swap function with wrapped GNOT paths amountIn, amountOut := ExactInSwapRoute( cross(cur), "gno.land/r/gnoland/wugnot.wugnot", // input token "gno.land/r/gnoswap/gns.GNS", // output token "1000000", // amount in wrapped token units "gno.land/r/gnoland/wugnot.wugnot:gno.land/r/gnoswap/gns.GNS:3000", "100", // 100% through route "950000", // min output time.Now().Unix() + 300, // deadline "", // no referrer ) ``` 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 ### Basic Token Swaps ```go // Simple exact input swap amountIn, amountOut := ExactInSwapRoute( cross(cur), "gno.land/r/gnoswap/gns.GNS", // input token "gno.land/r/gnoland/wugnot.wugnot", // output token "1000000", // amount (6 decimals) "gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000", // route "100", // 100% through route "950000", // min output time.Now().Unix() + 300, // deadline "g1referrer...", // referral ) // Multi-hop swap ExactInSwapRoute( cross(cur), "gno.land/r/gnoswap/gns.GNS", "gno.land/r/<namespace>/token_c.TOKEN_C", "1000000", "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", "100", "900000", deadline, "", ) // Split route for large trades ExactInSwapRoute( cross(cur), "gno.land/r/gnoswap/gns.GNS", "gno.land/r/gnoland/wugnot.wugnot", "10000000000", "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", "60,40", // 60% through 0.05%, 40% through 0.3% "9500000000", deadline, "", ) ``` Single-hop functions support partial execution through a nonzero `sqrtPriceLimitX96`: ```go // Partial swap with price limit - may not consume full input amount amountIn, amountOut := ExactInSingleSwapRoute( cross(cur), "gno.land/r/gnoswap/gns.GNS", // input token "gno.land/r/gnoland/wugnot.wugnot", // output token "1000000", // max amount to swap "gno.land/r/gnoswap/gns.GNS:gno.land/r/gnoland/wugnot.wugnot:3000", // single route "950000", // min output "1000000000000000000", // sqrtPriceLimitX96 (price limit) deadline, "", ) // If the price limit is reached, only a partial amount is swapped. For exact-in // this can consume less input; exact-out can deliver less than its target. // amountOutMin or amountInMax remains enforced, respectively. ``` ## Important Developer Notes ### Common Integration Pitfalls 1. **Native Token Assumptions**: Passing `"ugnot"` to router swap functions will fail because router entrypoints reject native-coin handling. 2. **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. 3. **Wrong Token Path**: - Use `gno.land/r/gnoland/wugnot.wugnot` when swapping wrapped GNOT - Do not pass native `ugnot` to router swap functions - Route strings must stay in swap-direction order and use token contract paths ### 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 (`amountOutMin` or `amountInMax`) 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
  4. #4doc.gno
  5. #5// Package router provides swap routing and execution across GnoSwap liquidity pools. // // Router domain proxy for single-hop and multi-hop exact-in, exact-out, and // dry-route operations. // // Live exact-in and exact-out calls validate a deadline and the corresponding // amount limit (minimum output or maximum input). DrySwapRoute is a read-only // quote path with no deadline or token transfer. // // The router fee is charged on output tokens. It defaults to 15 bps (0.15%) // and is configurable by admin/governance from 0 through 1000 bps (0–10%); // the current rate is fixed for each individual execution. // // The router acts as a proxy to version-specific implementations, // currently routing to v1 for all swap operations. package router
  6. #6getter_utils.gno
  7. #7package router // cloneStringInt64Map returns a copy so callers cannot reach the stored map. func cloneStringInt64Map(src map[string]int64) map[string]int64 { if src == nil { return nil } cloned := make(map[string]int64, len(src)) for k, v := range src { cloned[k] = v } return cloned }
  8. #8gnomod.toml
  9. #9module = "gno.land/r/gnoswap/router" gno = "0.9"
  10. #10proxy.gno
  11. #11package router // ExactInSwapRoute executes a multi-hop swap for an exact input amount. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - inputToken: input token path // - outputToken: output token path // - amountIn: exact input amount // - routeArr: encoded route // - quoteArr: encoded quotes // - amountOutMin: minimum output amount // - deadline: transaction deadline // - referrer: referral address // // Returns: // - amountIn: input amount consumed // - amountOut: net output amount delivered after the router fee // // Halt check: reverts while the Router halt scope is active. func ExactInSwapRoute(cur realm, inputToken string, outputToken string, amountIn string, routeArr string, quoteArr string, amountOutMin string, deadline int64, referrer string) (string, string) { return getImplementation().ExactInSwapRoute(0, cur, inputToken, outputToken, amountIn, routeArr, quoteArr, amountOutMin, deadline, referrer) } // ExactInSingleSwapRoute executes a single-hop swap for an exact input amount. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - inputToken: input token path // - outputToken: output token path // - amountIn: exact input amount // - routeArr: encoded route // - amountOutMin: minimum output amount // - sqrtPriceLimitX96: Q64.96 price limit // - deadline: transaction deadline // - referrer: referral address // // Returns: // - amountIn: input amount consumed (a nonzero price limit may stop early) // - amountOut: net output amount delivered after the router fee // // Halt check: reverts while the Router halt scope is active. func ExactInSingleSwapRoute(cur realm, inputToken string, outputToken string, amountIn string, routeArr string, amountOutMin string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string) { return getImplementation().ExactInSingleSwapRoute(0, cur, inputToken, outputToken, amountIn, routeArr, amountOutMin, sqrtPriceLimitX96, deadline, referrer) } // ExactOutSwapRoute executes a multi-hop swap for a requested post-fee output // target. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - inputToken: input token path // - outputToken: output token path // - amountOut: requested net output target // - routeArr: encoded route // - quoteArr: encoded quotes // - amountInMax: maximum input amount // - deadline: transaction deadline // - referrer: referral address // // Returns: // - amountIn: input amount consumed // - amountOut: net output delivered after the router fee // // Halt check: reverts while the Router halt scope is active. func ExactOutSwapRoute(cur realm, inputToken string, outputToken string, amountOut string, routeArr string, quoteArr string, amountInMax string, deadline int64, referrer string) (string, string) { return getImplementation().ExactOutSwapRoute(0, cur, inputToken, outputToken, amountOut, routeArr, quoteArr, amountInMax, deadline, referrer) } // ExactOutSingleSwapRoute executes a single-hop swap for a requested post-fee // output target. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - inputToken: input token path // - outputToken: output token path // - amountOut: requested net output target // - routeArr: encoded route // - amountInMax: maximum input amount // - sqrtPriceLimitX96: Q64.96 price limit // - deadline: transaction deadline // - referrer: referral address // // Returns: // - amountIn: input amount consumed (a nonzero price limit may stop early) // - amountOut: net output delivered after the router fee; it may be below // the requested target when the limit is reached // // Halt check: reverts while the Router halt scope is active. func ExactOutSingleSwapRoute(cur realm, inputToken string, outputToken string, amountOut string, routeArr string, amountInMax string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string) { return getImplementation().ExactOutSingleSwapRoute(0, cur, inputToken, outputToken, amountOut, routeArr, amountInMax, sqrtPriceLimitX96, deadline, referrer) } // DrySwapRoute simulates a swap route without changing state. // // Parameters: // - inputToken: input token path // - outputToken: output token path // - specifiedAmount: exact input or output amount // - swapTypeStr: `EXACT_IN` or `EXACT_OUT` // - strRouteArr: encoded route // - quoteArr: encoded quotes // - tokenAmountLimit: minimum output or maximum input amount // // Returns: // - amountIn: estimated input amount // - amountOut: estimated output amount // - err: non-nil when route validation or simulation fails func DrySwapRoute( inputToken, outputToken string, specifiedAmount string, swapTypeStr string, strRouteArr, quoteArr string, tokenAmountLimit string, ) (string, string, error) { return getImplementation().DrySwapRoute(inputToken, outputToken, specifiedAmount, swapTypeStr, strRouteArr, quoteArr, tokenAmountLimit) } // SwapCallback transfers amounts owed by a pool during a swap. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - token0Path: token0 path // - token1Path: token1 path // - amount0Delta: token0 amount owed to or by the pool // - amount1Delta: token1 amount owed to or by the pool // - payer: address that supplies positive deltas // // Returns: // - err: non-nil when payment validation or transfer fails // // Halt check: reverts while the Router halt scope is active. func SwapCallback(cur realm, token0Path string, token1Path string, amount0Delta int64, amount1Delta int64, payer address) error { return getImplementation().SwapCallback(0, cur, token0Path, token1Path, amount0Delta, amount1Delta, payer) } // GetSwapFee returns the current router fee rate. // // Returns: // - fee: fee rate in basis points func GetSwapFee() uint64 { return getImplementation().GetSwapFee() } // SetSwapFee sets the router fee rate. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - fee: fee rate in basis points // // Halt check: reverts while the Router or ProtocolFee halt scope is active. func SetSwapFee(cur realm, fee uint64) { getImplementation().SetSwapFee(0, cur, fee) } // GetPendingProtocolFees returns a copy of uncollected protocol fees by token. // // Returns: // - fees: pending protocol fee amount keyed by token path func GetPendingProtocolFees() map[string]int64 { return cloneStringInt64Map(getImplementation().GetPendingProtocolFees()) }
  12. #12render.gno
  13. #13package router // Render delegates web rendering to the active implementation. func Render(path string) string { return getImplementation().Render(path) }
  14. #14state.gno
  15. #15package router import ( "chain" "errors" "gno.land/p/gnoswap/store/v1" "gno.land/p/gnoswap/version_manager/v1" ) const domainPath = "gno.land/r/gnoswap/router" var ( currentAddress = chain.PackageAddress(domainPath) kvStore store.KVStore versionManager version_manager.VersionManager implementation IRouter ) func init() { // Create a new KV store instance for this domain kvStore = store.NewKVStore(currentAddress) // Initialize the initializers map to store implementation registration functions versionManager = version_manager.NewVersionManager( domainPath, kvStore, initializeDomainStore, ) implementation = nil } func initializeDomainStore(_ int, rlm realm, kvStore store.KVStore) any { return NewRouterStore(kvStore) } func getImplementation() IRouter { if implementation == nil { panic("implementation is not initialized") } return implementation } func updateImplementation() error { result := versionManager.GetCurrentImplementation() if result == nil { return errors.New("implementation is not initialized") } impl, ok := result.(IRouter) if !ok { return errors.New("impl is not an IRouter") } implementation = impl return nil }
  16. #16store.gno
  17. #17package router import ( "errors" "gno.land/p/gnoswap/store/v1" ufmt "gno.land/p/nt/ufmt/v0" ) const errSpoofedRealm = "rlm does not match the current crossing frame" type StoreKey string // String converts the typed store key to the string key used by KVStore. // // Returns: // - key: underlying string representation of the store key func (s StoreKey) String() string { return string(s) } const ( StoreKeySwapFee StoreKey = "swapFee" // Swap fee in basis points StoreKeyPendingProtocolFees StoreKey = "pendingProtocolFees" // tokenPath -> amount held locally for protocol_fee ) type routerStore struct { kvStore store.KVStore } // HasSwapFeeKey reports whether persistent storage contains the router swap-fee key. // // Returns: // - exists: true when the swap-fee key is present, otherwise false func (s *routerStore) HasSwapFeeKey() bool { return s.kvStore.Has(StoreKeySwapFee.String()) } // GetSwapFee retrieves the current swap fee from persistent storage. // // Returns: // - fee: configured router fee in basis points; panics if the key is missing or has the wrong type func (s *routerStore) GetSwapFee() uint64 { result, err := s.kvStore.Get(StoreKeySwapFee.String()) if err != nil { panic(err) } swapFee, ok := result.(uint64) if !ok { panic(ufmt.Sprintf("failed to cast result to uint64: %T", result)) } return swapFee } // SetSwapFee stores the router fee in persistent storage. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: current realm context; must be the current crossing frame // - fee: router fee rate in basis points // // Returns: // - err: nil when storage succeeds; an error when rlm is not current or KVStore rejects the write func (s *routerStore) SetSwapFee(_ int, rlm realm, fee uint64) error { if !rlm.IsCurrent() { return errors.New(errSpoofedRealm) } return s.kvStore.Set(0, rlm, StoreKeySwapFee.String(), fee) } // HasPendingProtocolFeesKey reports whether persistent storage contains the pending-fees map. // // Returns: // - exists: true when the pending protocol-fees key is present, otherwise false func (s *routerStore) HasPendingProtocolFeesKey() bool { return s.kvStore.Has(StoreKeyPendingProtocolFees.String()) } // GetPendingProtocolFees retrieves the token-path keyed pending protocol-fees map. // // Returns: // - fees: stored token-path to pending amount map; panics if storage is missing or has the wrong type func (s *routerStore) GetPendingProtocolFees() map[string]int64 { result, err := s.kvStore.Get(StoreKeyPendingProtocolFees.String()) if err != nil { panic(err) } pendingProtocolFees, ok := result.(map[string]int64) if !ok { panic(ufmt.Sprintf("failed to cast result to map[string]int64: %T", result)) } return pendingProtocolFees } // SetPendingProtocolFees replaces the pending protocol-fees map in persistent storage. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: current realm context; must be the current crossing frame // - fees: token-path keyed pending fee amounts to store; entries are copied into realm-owned storage // // Returns: // - err: nil when storage succeeds; an error when rlm is not current or KVStore rejects the write func (s *routerStore) SetPendingProtocolFees(_ int, rlm realm, fees map[string]int64) error { if !rlm.IsCurrent() { return errors.New(errSpoofedRealm) } // The map is copied here so it is allocated by, and therefore mutable from, this realm. owned := make(map[string]int64, len(fees)) for tokenPath, amount := range fees { owned[tokenPath] = amount } return s.kvStore.Set(0, rlm, StoreKeyPendingProtocolFees.String(), owned) } // GetPendingProtocolFee returns the pending amount recorded for one token path. // // Parameters: // - tokenPath: token contract path whose pending protocol fee is queried // // Returns: // - amount: pending fee amount for tokenPath, or zero when no entry exists func (s *routerStore) GetPendingProtocolFee(tokenPath string) int64 { return s.GetPendingProtocolFees()[tokenPath] } // SetPendingProtocolFee updates one token path's pending protocol-fee amount. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: current realm context; must be current and authorized to write storage // - tokenPath: token contract path whose pending amount is updated // - amount: pending protocol-fee amount to record // // Returns: // - err: nil when updated; an error when the realm is spoofed or lacks KVStore write permission func (s *routerStore) SetPendingProtocolFee(_ int, rlm realm, tokenPath string, amount int64) error { if !rlm.IsCurrent() { return errors.New(errSpoofedRealm) } if rlm.IsCode() && !s.kvStore.IsWriteAuthorized(rlm.Address()) { return errors.New(store.ErrWritePermissionDenied) } s.GetPendingProtocolFees()[tokenPath] = amount return nil } // RemovePendingProtocolFee deletes one token path's pending protocol-fee entry. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: current realm context; must be current and authorized to write storage // - tokenPath: token contract path whose pending amount is removed // // Returns: // - err: nil when removed; an error when the realm is spoofed or lacks KVStore write permission func (s *routerStore) RemovePendingProtocolFee(_ int, rlm realm, tokenPath string) error { if !rlm.IsCurrent() { return errors.New(errSpoofedRealm) } if rlm.IsCode() && !s.kvStore.IsWriteAuthorized(rlm.Address()) { return errors.New(store.ErrWritePermissionDenied) } delete(s.GetPendingProtocolFees(), tokenPath) return nil } // NewRouterStore creates a router store backed by the provided KV store. // // Parameters: // - kvStore: persistent key-value store used for router fee and pending-fee data // // Returns: // - routerStore: router storage implementation using kvStore func NewRouterStore(kvStore store.KVStore) IRouterStore { rs := &routerStore{ kvStore: kvStore, } return rs }
  18. #18types.gno
  19. #19package router type IRouter interface { // ExactInSwapRoute executes a multi-hop exact-input swap. // // Parameters: // - _: leading implementation discriminator; callers pass 0 // - rlm: propagated current realm context used for swap validation and transfers // - inputToken: input token contract path // - outputToken: output token contract path // - amountIn: exact input amount encoded as a decimal string // - routeArr: comma-separated route paths, each with up to three pool hops // - quoteArr: comma-separated route allocation percentages summing to 100 // - amountOutMin: minimum net output amount encoded as a decimal string // - deadline: Unix timestamp after which the swap is rejected // - referrer: optional referral address used for registration // // Returns: // - amountIn: actual input amount consumed, encoded as a decimal string // - amountOut: net output amount after router fee, encoded as a decimal string ExactInSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountIn string, routeArr string, quoteArr string, amountOutMin string, deadline int64, referrer string) (string, string) // ExactInSingleSwapRoute executes an exact-input swap through one pool. // // Parameters: // - _: leading implementation discriminator; callers pass 0 // - rlm: propagated current realm context used for swap validation and transfers // - inputToken: input token contract path // - outputToken: output token contract path // - amountIn: exact input amount encoded as a decimal string // - routeArr: single-hop route path // - amountOutMin: minimum net output amount encoded as a decimal string // - sqrtPriceLimitX96: optional Q64.96 square-root price limit encoded as a decimal string // - deadline: Unix timestamp after which the swap is rejected // - referrer: optional referral address used for registration // // Returns: // - amountIn: actual input amount consumed, encoded as a decimal string // - amountOut: net output amount after router fee, encoded as a decimal string ExactInSingleSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountIn string, routeArr string, amountOutMin string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string) // ExactOutSwapRoute executes a multi-hop swap for a requested net output. // // Parameters: // - _: leading implementation discriminator; callers pass 0 // - rlm: propagated current realm context used for swap validation and transfers // - inputToken: input token contract path // - outputToken: output token contract path // - amountOut: requested net output amount encoded as a decimal string // - routeArr: comma-separated route paths, each with up to three pool hops // - quoteArr: comma-separated route allocation percentages summing to 100 // - amountInMax: maximum input amount encoded as a decimal string // - deadline: Unix timestamp after which the swap is rejected // - referrer: optional referral address used for registration // // Returns: // - amountIn: actual input amount consumed, encoded as a decimal string // - amountOut: net output amount after router fee, encoded as a decimal string ExactOutSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountOut string, routeArr string, quoteArr string, amountInMax string, deadline int64, referrer string) (string, string) // ExactOutSingleSwapRoute executes an exact-output swap through one pool. // // Parameters: // - _: leading implementation discriminator; callers pass 0 // - rlm: propagated current realm context used for swap validation and transfers // - inputToken: input token contract path // - outputToken: output token contract path // - amountOut: requested net output amount encoded as a decimal string // - routeArr: single-hop route path // - amountInMax: maximum input amount encoded as a decimal string // - sqrtPriceLimitX96: optional Q64.96 square-root price limit encoded as a decimal string // - deadline: Unix timestamp after which the swap is rejected // - referrer: optional referral address used for registration // // Returns: // - amountIn: actual input amount consumed, encoded as a decimal string // - amountOut: net output amount after router fee, encoded as a decimal string ExactOutSingleSwapRoute(_ int, rlm realm, inputToken string, outputToken string, amountOut string, routeArr string, amountInMax string, sqrtPriceLimitX96 string, deadline int64, referrer string) (string, string) // DrySwapRoute simulates a route without writing state or transferring tokens. // // Parameters: // - inputToken: input token contract path // - outputToken: output token contract path // - specifiedAmount: exact input or output amount encoded as a decimal string // - swapTypeStr: swap type string, either EXACT_IN or EXACT_OUT // - strRouteArr: comma-separated encoded route paths // - quoteArr: comma-separated route allocation percentages summing to 100 // - tokenAmountLimit: minimum output for EXACT_IN or maximum input for EXACT_OUT // // Returns: // - amountIn: simulated input amount encoded as a decimal string // - amountOut: simulated net output amount encoded as a decimal string // - err: nil on success; validation, liquidity, or slippage error on failure DrySwapRoute(inputToken, outputToken, specifiedAmount, swapTypeStr, strRouteArr, quoteArr, tokenAmountLimit string) (string, string, error) // SwapCallback pays a pool's positive input delta during a swap. // // Parameters: // - _: leading callback discriminator; callers pass 0 // - rlm: propagated current realm context; implementation verifies it is current // - token0Path: token-0 contract path in canonical pool order // - token1Path: token-1 contract path in canonical pool order // - amount0Delta: signed token-0 delta; positive means the pool is owed tokens // - amount1Delta: signed token-1 delta; positive means the pool is owed tokens // - payer: address whose balance supplies the positive delta // // Returns: // - err: nil after payment; error when realm, liquidity delta, or transfer validation fails SwapCallback(_ int, rlm realm, token0Path string, token1Path string, amount0Delta int64, amount1Delta int64, payer address) error // GetSwapFee reads the router fee rate. // // Returns: // - fee: router fee in basis points GetSwapFee() uint64 // SetSwapFee updates the router fee rate. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: propagated current realm context used for authorized storage writes // - fee: router fee in basis points SetSwapFee(_ int, rlm realm, fee uint64) // GetPendingProtocolFees reads pending protocol fees keyed by token path. // // Returns: // - fees: token-path to pending-fee amount map GetPendingProtocolFees() map[string]int64 Render(path string) string } type IRouterStore interface { // HasSwapFeeKey reports whether a stored router fee exists. // // Returns: // - exists: true when the swap-fee key is present HasSwapFeeKey() bool // GetSwapFee reads the stored router fee. // // Returns: // - fee: configured router fee in basis points GetSwapFee() uint64 // SetSwapFee persists the router fee. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: propagated current realm context; storage validates current-frame status // - fee: router fee in basis points // // Returns: // - err: nil on success; storage or realm-validation error otherwise SetSwapFee(_ int, rlm realm, fee uint64) error // HasPendingProtocolFeesKey reports whether a stored pending-fees map exists. // // Returns: // - exists: true when the pending-fees key is present HasPendingProtocolFeesKey() bool // GetPendingProtocolFees reads all pending protocol fees. // // Returns: // - fees: token-path to pending-fee amount map GetPendingProtocolFees() map[string]int64 // SetPendingProtocolFees replaces all pending protocol fees. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: propagated current realm context; storage validates current-frame status // - fees: token-path to pending-fee amount map to persist // // Returns: // - err: nil on success; storage or realm-validation error otherwise SetPendingProtocolFees(_ int, rlm realm, fees map[string]int64) error // GetPendingProtocolFee reads one token's pending fee. // // Parameters: // - tokenPath: token contract path to query // // Returns: // - amount: pending amount for tokenPath, or zero if absent GetPendingProtocolFee(tokenPath string) int64 // SetPendingProtocolFee updates one token's pending fee. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: propagated current realm context; storage validates current-frame and write authorization // - tokenPath: token contract path to update // - amount: pending amount to record // // Returns: // - err: nil on success; realm or storage authorization error otherwise SetPendingProtocolFee(_ int, rlm realm, tokenPath string, amount int64) error // RemovePendingProtocolFee deletes one token's pending fee. // // Parameters: // - _: leading call discriminator; callers pass 0 // - rlm: propagated current realm context; storage validates current-frame and write authorization // - tokenPath: token contract path to remove // // Returns: // - err: nil on success; realm or storage authorization error otherwise RemovePendingProtocolFee(_ int, rlm realm, tokenPath string) error }
  20. #20upgrade.gno
  21. #21package router import ( "gno.land/r/gnoswap/access/v1" ) // RegisterInitializer registers a new router implementation version. // Each implementation package calls it during initialization before it can be selected. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - initializer: callback that receives the propagated realm context and router store, then constructs the IRouter implementation func RegisterInitializer(cur realm, initializer func(_ int, rlm realm, routerStore IRouterStore) IRouter) { initializerFunc := func(_ int, rlm realm, domainStore any) any { access.AssertIsRlmCurrent(0, rlm) currentRouterStore, ok := domainStore.(IRouterStore) if !ok { panic("domainStore is not an IRouterStore") } return initializer(0, rlm, currentRouterStore) } err := versionManager.RegisterInitializer(0, cur, initializerFunc) if err != nil { panic(err) } err = updateImplementation() if err != nil { panic(err) } } // UpgradeImpl switches the active router implementation to a different registered version. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this realm // - packagePath: package path of the previously registered implementation to activate func UpgradeImpl(cur realm, packagePath string) { // Ensure only admin or governance can perform upgrades caller := cur.Previous().Address() access.AssertIsAdminOrGovernance(caller) err := versionManager.ChangeImplementation(0, cur, packagePath) if err != nil { panic(err) } err = updateImplementation() if err != nil { panic(err) } } // GetImplementationPackagePath returns the package path of the currently active implementation. // // Returns: // - packagePath: package path of the active implementation func GetImplementationPackagePath() string { return versionManager.GetCurrentPackagePath() }
  22. #22/gno.MemPackageType
  23. #23 MPUserAll

Result log

msg:0,success:true,log:,events:[]

← Back to block 77,257