func Allowance
ActionAllowance returns what `owner` let `spender` draw of `symbol`.
Package grc20wrapdemo is a permissionless wrapper factory for GRC20 tokens.
gno.land/r/moul/x/grc20wrapdemo/v0A 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.
# 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.
| 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.
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.
Package grc20wrapdemo is a permissionless wrapper factory for GRC20 tokens.
Point it at any token registered in gno.land/r/nt/grc20reg/v0 and it issues a new one backed by it, with a personality you pick from a list. Point it at two and it issues a meta-token backed by both. Nothing is whitelisted, nothing is owned, and the realm never gains authority over anybody's balance: every deposit is pulled with an allowance the holder granted to this realm's address.
The five wrapper modes, all from gno.land/p/moul/x/grc20wrap/v0:
1plain 1:1 custody. A receipt. The boring one that proves the rest works.
2kilo 1 underlying unit becomes 1000 wrapped ones, +3 decimals.
3soulbound wrap and unwrap freely, but the wrapped token never changes hands.
4pool shares in the escrow: Donate raises what every share redeems for.
5sticky pool, plus a 1% exit fee that stays behind for whoever holds on.
And one fusion mode: NewFusion bundles two registered tokens at a fixed proportion into a single meta-token, redeemable back into both.
Every token this realm issues is itself registered in grc20reg, so its key can be fed straight back into NewWrapper or NewFusion. A pool over a kilo over a plain wrap of RED is legal, works, and is a good way to see how thin the abstraction really is.
Approve this realm's address on the underlying token, through THAT token's own realm. Home() prints the address. Without it every Deposit fails with "insufficient allowance", which is the system working.
Play money to try it on: gno.land/r/moul/x/grc20faucet/v0.
Allowance returns what `owner` let `spender` draw of `symbol`.
Approve lets `spender` draw `amount` of `symbol` from the caller's balance.
BalanceOf returns `owner`'s balance of `symbol`.
Count is how many tokens this realm has issued.
Defuse burns `units` of `symbol` and returns every leg to the caller.
Deposit escrows `amount` of the underlying and mints `symbol` to the caller. It returns how much was minted, which is not `amount` unless the mode is plain. Approve Home() on the underlying first.
Donate escrows `amount` of the underlying for `symbol` and mints nothing.
Under a pool or sticky mode this is a gift to every current holder at once, and it is irreversible: there is no share to redeem it with. Under any other mode it is a gift to nobody, since the rate ignores the escrow.
Escrow returns the underlying escrowed behind a wrapper.
Fuse escrows every leg of `symbol` and mints `units` of it to the caller. Approve Home() on BOTH legs first.
Key returns the grc20reg key of the token this realm issued as `symbol`.
Leg describes the i-th component of a fusion: its symbol, the units escrowed per meta unit, and the units escrowed so far.
Legs returns how many components a fusion has.
1func NewFusion(cur realm, keyA string, perA int64, keyB string, perB int64, symbol string) stringNewFusion issues a meta-token backed by two registered tokens at a fixed proportion: one smallest unit of the meta-token is always worth `perA` smallest units of A plus `perB` of B. It returns the new token's registry key.
The proportion never changes, and the meta-token is minted and burned only against the real thing, so it cannot drift from its backing or be arbitraged. What it can do is make the pair one transferable object.
NewWrapper issues a token wrapping `tokenKey`, a key in grc20reg, under the given mode, and registers it. It returns the new token's own registry key.
`symbol` is yours to choose, must be unique in this realm, and follows the GRC20 rules: 1 to 11 characters of [A-Za-z0-9_-].
TotalSupply returns how much of `symbol` is outstanding.
Transfer moves the caller's own units of `symbol`. A soulbound wrapper refuses here, and nowhere else.
TransferFrom spends an allowance the caller was granted on `symbol`.
Withdraw burns `amount` of `symbol` and returns the underlying to the caller. It returns how much came back.