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

amm/v0 package

Overview

Package amm is a minimal constant-product automated market maker for GRC20 token pairs, in a single file.

It holds many pools in one realm. A pool is created implicitly by its first liquidity deposit and is addressed by the two tokens' grc20reg keys, in either order. Swaps follow x*y=k with a 30 bps fee that stays in the pool and therefore accrues to the liquidity providers.

What it is not

Not an oracle: the reserve ratio is a spot price that any trader can move within a single transaction. Nothing should price off this realm. Not audited. Not a router: one hop, one pool, no path finding. Not a place to park value.

Design notes worth knowing before calling it

Reserves are stored fields and are NEVER derived from BalanceOf. That is the single decision that removes Uniswap V2's MINIMUM_LIQUIDITY burn, its skim/sync pair, and the first-depositor share-inflation attack in one go: sending tokens straight to this realm's address changes no reserve, no price and no share value. The price of that is blunt and worth stating: tokens sent directly to the realm address are PERMANENTLY STUCK.

The first deposit mints shares equal to the token-A amount rather than sqrt(A*B). The geometric mean is cosmetic, every later operation uses only ratios, and dropping it removes an integer square root over a 128-bit product. Later deposits mint min(A-side, B-side) with floor division on both, so an off-ratio deposit always rounds against the depositor.

v1 vs v0: LP shares are a real GRC20 token

v0 tracks LP positions in a private avl ledger: smallest possible, but a position can only be held by the address that opened it and is invisible to every other contract. v1 mints one GRC20 token per pool instead, holds its PrivateLedger, and registers it with grc20reg. A position is then an ordinary fungible token: transferable, approvable, usable as collateral, and readable by any realm that knows the registry key.

The cost is honest and measurable. Pool creation now also mints a token and writes a registry entry. Positions gain an allowance surface, and with it the classic GRC20 approve race. And because MsgCall cannot pass a realm argument, this realm has to re-export Transfer/Approve/TransferFrom/ Allowance wrappers over the LP token for signing users, four functions that v0 does not need at all. Another REALM can skip them and move its own LP balance through grc20reg directly.

All amounts are int64, as GRC20 mandates, and there is no 256-bit type in reach. Pricing therefore runs through a 128-bit mulDiv (math/bits), and every reserve is capped at maxReserve so that the plain int64 parts of the formula cannot overflow. See the comment on maxReserve for the arithmetic, and note the consequence: this AMM is unusable with 18-decimal tokens. Six to nine decimals is the practical band.

Design study and full analysis: https://github.com/moul/gno-contracts/issues/135

Function

Swap

func Swap(cur realm, keyIn, keyOut string, amountIn, minOut int64) int64

Swap sells amountIn of keyIn for keyOut and aborts unless at least minOut comes back. The caller must first Approve this realm's address on keyIn.

minOut is the only protection against being sandwiched or against the pool moving between quoting and execution. Pass a real bound; passing 0 means accepting any price at all.

Params

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/moul/x/amm/v0" -func "Swap" -args $'' -args $'' -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "gnoland-1" -remote "https://rpc.gno.land" ADDRESSgnokey query -remote "https://rpc.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/moul/x/amm/v0" -func "Swap" -args $'' -args $'' -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "gnoland-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.gno.land" call.tx