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

README.md

3.83 Kb · 82 lines

gno.land/r/moul/x/grc20wrapdemo/v0

A permissionless wrapper factory for GRC20 tokens. Point it at any token registered in r/nt/grc20reg and it issues a new one backed by it, with a personality you pick. Point it at two and it issues a meta-token backed by both. No allowlist, no owner, and no authority over anybody's balance: every deposit is pulled with an allowance the holder granted.

Five minutes, start to finish

# 1. play money
maketx call -pkgpath gno.land/r/moul/x/grc20faucet/v0 -func Claim

# 2. let this realm pull your RED (the address is printed by Home(), and on the
#    realm's own page)
maketx call -pkgpath gno.land/r/moul/x/grc20faucet/v0 -func Approve \
  -args RED -args <Home()> -args 1000000

# 3. create a wrapper over RED, and deposit into it
maketx call -pkgpath gno.land/r/moul/x/grc20wrapdemo/v0 -func NewWrapper \
  -args gno.land/r/moul/x/grc20faucet/v0.RED -args pool -args pRED
maketx call -pkgpath gno.land/r/moul/x/grc20wrapdemo/v0 -func Deposit \
  -args pRED -args 500000

Step 2 is the one people skip. Without it every Deposit fails with insufficient allowance, which is the system working.

Modes

mode what the wrapped token does
plain 1:1 custody receipt
kilo 1 underlying unit becomes 1000 wrapped, +3 decimals
soulbound wrap and unwrap freely, never transferable
pool shares in the escrow; Donate pays every holder at once
sticky pool plus a 1% exit fee, left behind for whoever stays

And NewFusion(keyA, perA, keyB, perB, symbol), which bundles two registered tokens at a fixed proportion into one meta-token, Fuse in and Defuse out.

The parts worth reading the code for

pool is the entire yield-bearing-token pattern in two lines of arithmetic. Donate adds escrow and mints nothing, so every outstanding share is worth more, permanently and for everyone at once. A fee sink, a staking reward and an airdrop to holders are the same operation seen from three angles.

soulbound binds users, not realms. MsgCall cannot build the realm argument grc20's tellers need, so a signing account can only move the token through this realm's Transfer, where the veto lives. Another realm holding it can always move its own balance. Non-transferable here means "no user can pass it on", and the exit is always open: unwrap, and the underlying moves freely again.

Wrapping a wrapper works, and nothing special was needed to make it work. Every token this realm issues is itself registered in grc20reg, so its key feeds straight back into NewWrapper. A pool over a plain wrap of RED is a good way to see how thin the abstraction is.

Two wrappers over the same underlying share one escrow account (this realm's address), and are kept apart only by each vault's own Held() counter. Escrow reports that counter; the render page reports whether the account still covers it.

Built on p/moul/x/grc20wrap, which is where the wrapping actually happens. This realm is the chain wiring and a catalogue.


Part of 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/r/moul/x/grc20wrapdemo/v0 dependency graph

🧪 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.