1package wugnot23import (4 "chain"5 "chain/banker"6 "chain/runtime"7 "chain/runtime/unsafe"8 "strings"910 "gno.land/p/nt/grc20/v0"11 "gno.land/p/nt/ufmt/v0"12 "gno.land/r/nt/grc20reg/v0"13)1415var (16 Token *grc20.Token17 adm *grc20.PrivateLedger18)1920const (21 ugnotMinDeposit int64 = 100022 wugnotMinDeposit int64 = 123)2425func init(cur realm) {26 // wugnot only ever creates this one token, so id 0 can't collide.27 Token, adm = grc20.NewToken("wrapped GNOT", "wugnot", 0, 0, cur)28 grc20reg.Register(cross(cur), Token, "")29}3031func Deposit(cur realm) {32 // Prevent cross-realm MITM: without this, an intermediary could33 // deposit on behalf of the caller and mint wugnot to itself34 // instead of the actual sender.35 runtime.AssertOriginCall()36 caller := cur.Previous().Address()37 sent := unsafe.OriginSend()38 amount := sent.AmountOf("ugnot")3940 require(int64(amount) >= ugnotMinDeposit, ufmt.Sprintf("Deposit below minimum: %d/%d ugnot.", amount, ugnotMinDeposit))4142 checkErr(adm.Mint(caller, int64(amount)))43}4445func Withdraw(cur realm, amount int64) {46 runtime.AssertOriginCall()47 require(amount >= wugnotMinDeposit, ufmt.Sprintf("Deposit below minimum: %d/%d wugnot.", amount, wugnotMinDeposit))4849 caller := cur.Previous().Address()50 pkgaddr := cur.Address()51 callerBal := Token.BalanceOf(caller)52 require(amount <= callerBal, ufmt.Sprintf("Insufficient balance: %d available, %d needed.", callerBal, amount))5354 // send swapped ugnots to qcaller55 stdBanker := banker.NewBanker(banker.BankerTypeRealmSend, cur)56 send := chain.Coins{{"ugnot", int64(amount)}}57 stdBanker.SendCoins(pkgaddr, caller, send)58 checkErr(adm.Burn(caller, amount))59}6061func Render(path string) string {62 parts := strings.Split(path, "/")63 c := len(parts)6465 switch {66 case path == "":67 return Token.RenderHome()68 case c == 2 && parts[0] == "balance":69 owner := address(parts[1])70 balance := Token.BalanceOf(owner)71 return ufmt.Sprintf("%d", balance)72 default:73 return "404"74 }75}7677func TotalSupply() int64 {78 return Token.TotalSupply()79}8081func BalanceOf(owner address) int64 {82 return Token.BalanceOf(owner)83}8485func Allowance(owner, spender address) int64 {86 return Token.Allowance(owner, spender)87}8889func Transfer(cur realm, to address, amount int64) {90 userTeller := adm.CallerTeller()91 checkErr(userTeller.Transfer(0, cur, to, amount))92}9394func Approve(cur realm, spender address, amount int64) {95 userTeller := adm.CallerTeller()96 checkErr(userTeller.Approve(0, cur, spender, amount))97}9899func TransferFrom(cur realm, from, to address, amount int64) {100 userTeller := adm.CallerTeller()101 checkErr(userTeller.TransferFrom(0, cur, from, to, amount))102}103104func require(condition bool, msg string) {105 if !condition {106 panic(msg)107 }108}109110func checkErr(err error) {111 if err != nil {112 panic(err)113 }114}115Allowance(owner string, spender string) int64
Approve(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, spender string, amount int64)
BalanceOf(owner string) int64
Deposit(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})
Render(path string) string
TotalSupply() int64
Transfer(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, to string, amount int64)
TransferFrom(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, from string, to string, amount int64)
Withdraw(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, amount int64)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.