# `gno.land/p/moul/x/pair/v0` One constant-product AMM pair (`x*y=k`, 30 bps to the liquidity providers), as a pure package, so that the realm holding a pair can be twenty lines of glue. This is the shared half of the **instance-per-realm** pattern: gno's answer to the Ethereum factory shape, where an ecosystem is a frontend over thousands of tiny identical contracts, one per token couple. | artifact | what it is | |---|---| | `p/moul/x/pair/v0` | this package, the whole behaviour, deployed once | | an instance realm | ~20 lines: two constants, an `init` that registers, one-line re-exports. See `r/moul/x/pairs/aaabbb/v0` | | `r/moul/x/pairreg/v0` | the registry every instance announces itself to, and the unified frontend over all of them | | `tools/pairgen` | the factory, which runs on your machine because gno has no on-chain deploy | ## What gno changes about the Ethereum pattern - **No on-chain factory.** `vm/add_package` is permanently denied to realm code, so an instance is an `addpkg` transaction signed by a human, priced in gas and a storage deposit. `tools/pairgen` fills the template and prints the command. - **Spawning is still permissionless.** Any address may deploy under `gno.land/r//**` with no registered username, so anyone can run their own instance and land in the registry. - **No clone trick needed.** Ethereum copies bytecode or delegatecalls through an EIP-1167 proxy; an import stores this package once for every instance. - **The registry sees live state.** Instances register a `*pair.Pair` pointer, so one `vm/qrender` renders every instance's real reserves, with no indexer. - **Nothing attests the code.** No realm can read another package's source, so an instance's code can only be verified off chain, by diffing it against freshly generated output. Unforgeable identity, no code attestation: the mirror image of CREATE2. ## Using it from an instance ```go var p *pair.Pair func init(cur realm) { p = pair.New(keyA, keyB, grc20reg.MustGet(keyA), grc20reg.MustGet(keyB)) pairreg.Register(cross(cur), p) } func Swap(cur realm, keyIn string, amountIn, minOut int64) int64 { return p.Swap(0, cur, keyIn, amountIn, minOut) } ``` Every state-changing method is shaped `(_ int, rlm realm, ...)`. That is forced, not stylistic: a pure package cannot declare a crossing function (`func F(cur realm, ...)` fails to compile there), and the parameter cannot be named `cur` either. The realm value arrives non-crossing, which is exactly what is wanted: the frame stays the instance realm, so funds move to and from the **instance's** address and grc20's `rlm.IsCurrent()` spoof check still passes. `p/moul/x/framelab/v0` is the 30-line probe that pins this property. A pure package also cannot import a realm, so this one never resolves a token by path: the instance passes `*grc20.Token` handles in. ## Economics, and what is deliberately absent Reserves are stored fields, never derived from `BalanceOf`, which removes `MINIMUM_LIQUIDITY`, `skim`/`sync` and the first-depositor inflation attack in one decision. The price: tokens sent directly to an instance's address are permanently stuck. The first deposit mints `shares = amountA` with no `sqrt`; later deposits mint `min(A-side, B-side)` with floor division, so an off-ratio deposit rounds against the depositor. No oracle, no flash swap, no routing, no protocol fee, no governance. All amounts are `int64` and the fee denominator is 1000, so every reserve is capped at `MaxReserve = MaxInt64/1000`. **Unusable with 18-decimal tokens**; six to nine decimals is the practical band. Full design study of the economics: [gno-contracts#135](https://github.com/moul/gno-contracts/issues/135). ## When to copy this pattern, and when not to Uniswap V4 moved from a pair-per-contract factory to a singleton, and [PR #137](https://github.com/moul/gno-contracts/pull/137) is the same AMM as one realm holding N pools. An AMM is therefore the contested case, kept here as a deliberate A/B. Reach for instance-per-realm when instances have **different owners, trust and lifecycles** (a user's shop, a DAO, a game table). Keep one realm with N objects when instances are fungible parts of one shared network (liquidity, an order book, a global index). --- Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** โ€” moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage. **Dependency graph:** ![gno.land/p/moul/x/pair/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/p/moul/x/pair/v0/deps.png) > ๐Ÿงช **Highly experimental โ€” potentially vibe-coded.** Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md).