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

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 / topaz 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}