README.md
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:

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