Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

wrapped.gno

3.83 Kb · 124 lines
  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:1
  4// ERC-20 representation (and burn it back). On gno.land / sapphire there is no
  5// msg.value / payable, so there is NO real coin transfer here: Deposit and
  6// Withdraw are pure accounting operations that model the wrap/unwrap. Balances
  7// and totalSupply are plain uint64 ledgers kept in an avl.Tree.
  8package wrapped
  9
 10import (
 11	"strconv"
 12
 13	"chain"
 14	"chain/runtime/unsafe"
 15
 16	"gno.land/p/nt/avl/v0"
 17)
 18
 19// balances maps owner address (string) -> wrapped balance (uint64).
 20var (
 21	balances    avl.Tree
 22	totalSupply uint64
 23)
 24
 25// Deposit wraps `amount` units of the (notional) native coin, crediting the
 26// caller's wrapped balance and the global totalSupply. Accounting only: no real
 27// 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 += amount
 35	chain.Emit("Deposit", "dst", owner.String(), "wad", strconv.FormatUint(amount, 10))
 36}
 37
 38// Withdraw unwraps `amount` units, burning them from the caller's balance and
 39// 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 -= amount
 51	chain.Emit("Withdrawal", "src", owner.String(), "wad", strconv.FormatUint(amount, 10))
 52}
 53
 54// 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}
 71
 72// 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 0
 77	}
 78	return v.(uint64)
 79}
 80
 81// BalanceOf is the exported read-only accessor for a single owner.
 82func BalanceOf(owner address) uint64 { return balanceOf(owner) }
 83
 84// TotalSupply returns the total amount of wrapped units in existence.
 85func TotalSupply() uint64 { return totalSupply }
 86
 87func setBalance(owner address, amount uint64) {
 88	if amount == 0 {
 89		balances.Remove(owner.String())
 90		return
 91	}
 92	balances.Set(owner.String(), amount)
 93}
 94
 95// ---- pure/read-only helpers (unit-tested) ----
 96
 97// canDebit reports whether `bal` can cover `amount` for a burn/transfer.
 98func canDebit(bal, amount uint64) bool {
 99	return amount > 0 && bal >= amount
100}
101
102// formatUnits renders a raw uint64 amount as a decimal string.
103func formatUnits(n uint64) string {
104	return strconv.FormatUint(n, 10)
105}
106
107// 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"
112
113	if balances.Size() == 0 {
114		out += "_No balances yet. Call `Deposit` to wrap some units._\n"
115		return out
116	}
117
118	out += "| Owner | Balance |\n|---|---:|\n"
119	balances.Iterate("", "", func(key string, value interface{}) bool {
120		out += "| `" + key + "` | " + formatUnits(value.(uint64)) + " |\n"
121		return false
122	})
123	return out
124}