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

v0 source realm

Package grc20wrapdemo is a permissionless wrapper factory for GRC20 tokens.

Readme View source

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.

Overview

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:

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

Wrapping a wrapper

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.

The one thing a caller must do first

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.

Functions 19

func Allowance

Action
1func Allowance(symbol string, owner, spender address) int64
source

Allowance returns what `owner` let `spender` draw of `symbol`.

func Approve

crossing Action
1func Approve(cur realm, symbol string, spender address, amount int64)
source

Approve lets `spender` draw `amount` of `symbol` from the caller's balance.

func BalanceOf

Action
1func BalanceOf(symbol string, owner address) int64
source

BalanceOf returns `owner`'s balance of `symbol`.

func Defuse

crossing Action
1func Defuse(cur realm, symbol string, units int64)
source

Defuse burns `units` of `symbol` and returns every leg to the caller.

func Deposit

crossing Action
1func Deposit(cur realm, symbol string, amount int64) int64
source

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.

func Donate

crossing Action
1func Donate(cur realm, symbol string, amount int64)
source

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.

func Escrow

Action
1func Escrow(symbol string) int64
source

Escrow returns the underlying escrowed behind a wrapper.

func Fuse

crossing Action
1func Fuse(cur realm, symbol string, units int64)
source

Fuse escrows every leg of `symbol` and mints `units` of it to the caller. Approve Home() on BOTH legs first.

func Key

Action
1func Key(symbol string) string
source

Key returns the grc20reg key of the token this realm issued as `symbol`.

func Leg

Action
1func Leg(symbol string, i int) (string, int64, int64)
source

Leg describes the i-th component of a fusion: its symbol, the units escrowed per meta unit, and the units escrowed so far.

func Legs

Action
1func Legs(symbol string) int
source

Legs returns how many components a fusion has.

func NewFusion

crossing Action
1func NewFusion(cur realm, keyA string, perA int64, keyB string, perB int64, symbol string) string
source

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

func NewWrapper

crossing Action
1func NewWrapper(cur realm, tokenKey, mode, symbol string) string
source

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_-].

func TotalSupply

Action
1func TotalSupply(symbol string) int64
source

TotalSupply returns how much of `symbol` is outstanding.

func Transfer

crossing Action
1func Transfer(cur realm, symbol string, to address, amount int64)
source

Transfer moves the caller's own units of `symbol`. A soulbound wrapper refuses here, and nowhere else.

func TransferFrom

crossing Action
1func TransferFrom(cur realm, symbol string, from, to address, amount int64)
source

TransferFrom spends an allowance the caller was granted on `symbol`.

func Withdraw

crossing Action
1func Withdraw(cur realm, symbol string, amount int64) int64
source

Withdraw burns `amount` of `symbol` and returns the underlying to the caller. It returns how much came back.

Imports 7

Source Files 5