1// Package wrapped is an accounting-only port of Wrapped Ether (WETH).2//3// The canonical WETH contract lets anyone lock native ETH and mint a 1:14// ERC-20 representation (and burn it back). On gno.land / sapphire there is no5// msg.value / payable, so there is NO real coin transfer here: Deposit and6// Withdraw are pure accounting operations that model the wrap/unwrap. Balances7// and totalSupply are plain uint64 ledgers kept in an avl.Tree.8package wrapped910import (11 "strconv"1213 "chain"14 "chain/runtime/unsafe"1516 "gno.land/p/nt/avl/v0"17)1819// balances maps owner address (string) -> wrapped balance (uint64).20var (21 balances avl.Tree22 totalSupply uint6423)2425// Deposit wraps `amount` units of the (notional) native coin, crediting the26// caller's wrapped balance and the global totalSupply. Accounting only: no real27// coin ever moves — it models locking native funds to mint the wrapped token.28func Deposit(cur realm, amount uint64) {29 if amount == 0 {30 panic("wrapped: deposit amount must be > 0")31 }32 owner := unsafe.PreviousRealm().Address()33 setBalance(owner, balanceOf(owner)+amount)34 totalSupply += amount35 chain.Emit("Deposit", "dst", owner.String(), "wad", strconv.FormatUint(amount, 10))36}3738// Withdraw unwraps `amount` units, burning them from the caller's balance and39// from totalSupply. Panics if the caller lacks the balance.40func Withdraw(cur realm, amount uint64) {41 if amount == 0 {42 panic("wrapped: withdraw amount must be > 0")43 }44 owner := unsafe.PreviousRealm().Address()45 bal := balanceOf(owner)46 if bal < amount {47 panic("wrapped: insufficient balance")48 }49 setBalance(owner, bal-amount)50 totalSupply -= amount51 chain.Emit("Withdrawal", "src", owner.String(), "wad", strconv.FormatUint(amount, 10))52}5354// Transfer moves `amount` wrapped units from the caller to `to`.55func Transfer(cur realm, to address, amount uint64) {56 if amount == 0 {57 panic("wrapped: transfer amount must be > 0")58 }59 from := unsafe.PreviousRealm().Address()60 if from == to {61 panic("wrapped: cannot transfer to self")62 }63 fromBal := balanceOf(from)64 if fromBal < amount {65 panic("wrapped: insufficient balance")66 }67 setBalance(from, fromBal-amount)68 setBalance(to, balanceOf(to)+amount)69 chain.Emit("Transfer", "src", from.String(), "dst", to.String(), "wad", strconv.FormatUint(amount, 10))70}7172// balanceOf returns the wrapped balance of `owner` (read-only, not crossing).73func balanceOf(owner address) uint64 {74 v := balances.Get(owner.String())75 if v == nil {76 return 077 }78 return v.(uint64)79}8081// BalanceOf is the exported read-only accessor for a single owner.82func BalanceOf(owner address) uint64 { return balanceOf(owner) }8384// TotalSupply returns the total amount of wrapped units in existence.85func TotalSupply() uint64 { return totalSupply }8687func setBalance(owner address, amount uint64) {88 if amount == 0 {89 balances.Remove(owner.String())90 return91 }92 balances.Set(owner.String(), amount)93}9495// ---- pure/read-only helpers (unit-tested) ----9697// canDebit reports whether `bal` can cover `amount` for a burn/transfer.98func canDebit(bal, amount uint64) bool {99 return amount > 0 && bal >= amount100}101102// formatUnits renders a raw uint64 amount as a decimal string.103func formatUnits(n uint64) string {104 return strconv.FormatUint(n, 10)105}106107// Render shows the total supply and a table of non-zero balances.108func Render(path string) string {109 out := "# Wrapped (WETH-style, accounting-only)\n\n"110 out += "Deposit mints wrapped units, Withdraw burns them. No real coins move — this is a pure ledger.\n\n"111 out += "**Total supply:** " + formatUnits(totalSupply) + "\n\n"112113 if balances.Size() == 0 {114 out += "_No balances yet. Call `Deposit` to wrap some units._\n"115 return out116 }117118 out += "| Owner | Balance |\n|---|---:|\n"119 balances.Iterate("", "", func(key string, value interface{}) bool {120 out += "| `" + key + "` | " + formatUnits(value.(uint64)) + " |\n"121 return false122 })123 return out124}125BalanceOf(owner string) uint64
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}, amount uint64)
Render(path string) string
TotalSupply() uint64
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 uint64)
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 uint64)
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.