PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/moul/x/daily/englishauction/v1

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v1
Namespace
moul / x / daily / englishauction
Files
5 (README)(gnomod.toml)
Exported functions
5
Module
gno.land/r/moul/x/daily/englishauction/v1
gno
0.9

Files (5)

  • README.mdmarkdown
  • gnomod.tomltoml
  • englishauction.gnogno
  • englishauction_test.gnogno
  • render_example_test.gnogno
englishauction.gnogno
1// Package englishauction is an idiomatic gno.land port of the classic Solidity2// English (ascending-bid) auction. Anyone can Start an auction for a named item3// with a duration in blocks; bidders call Bid with a strictly increasing amount.4// The previous highest bid becomes refundable (claim it with Withdraw). After5// the auction's end height anyone may call End, awarding the item to the highest6// bidder. Auctions and pending refunds live in ordered avl trees so Render can7// iterate deterministically.8package englishauction910import (11	"strconv"1213	"chain"14	"chain/runtime"15	"chain/runtime/unsafe"1617	"gno.land/p/moul/kit/store/v0"18	"gno.land/p/nt/avl/v0"19)2021// Auction is a single ascending-bid auction. It carries no ID field: the id22// belongs to the store, which hands it back on lookup and iteration.23type Auction struct {24	Seller        address25	Item          string26	EndHeight     int6427	HighestBid    uint6428	HighestBidder address29	Ended         bool30}3132var (33	// auctions assigns the auction ids. v0 kept its own nextID plus a key()34	// that zero-padded to width 12, which stopped ordering Render past 10^12.35	auctions = store.Named("englishauction: auction")3637	pending avl.Tree // "<id>:<addr>" -> uint64 refundable amount38)3940// pendKey formats the refund key for a given auction id and bidder. It uses41// the decimal id rather than the store key: pending is only ever point-read,42// never iterated, so it needs a readable key and not an ordered one.43func pendKey(id int64, bidder address) string {44	return strconv.FormatInt(id, 10) + ":" + bidder.String()45}4647// Start opens a new auction for `item` running for `durationBlocks` blocks from48// the current height. The caller becomes the seller. Returns the auction id.49func Start(cur realm, item string, durationBlocks int64) int64 {50	if item == "" {51		panic("englishauction: item must not be empty")52	}53	if durationBlocks <= 0 {54		panic("englishauction: duration must be > 0 blocks")55	}56	seller := unsafe.PreviousRealm().Address()57	a := &Auction{58		Seller:    seller,59		Item:      item,60		EndHeight: runtime.ChainHeight() + durationBlocks,61	}62	id := int64(auctions.Add(a))6364	chain.Emit("Start",65		"id", strconv.FormatInt(id, 10),66		"seller", seller.String(),67		"item", item,68		"endHeight", strconv.FormatInt(a.EndHeight, 10),69	)70	return id71}7273// Bid places a bid of `amount` on auction `id`. It must strictly exceed the74// current highest bid. The displaced highest bid becomes refundable to its75// bidder via Withdraw.76func Bid(cur realm, id int64, amount uint64) {77	a := mustGet(id)78	if a.Ended || runtime.ChainHeight() >= a.EndHeight {79		panic("englishauction: auction has ended")80	}81	if amount <= a.HighestBid {82		panic("englishauction: bid must strictly exceed current highest")83	}84	bidder := unsafe.PreviousRealm().Address()85	if bidder == a.Seller {86		panic("englishauction: seller cannot bid")87	}8889	// The prior top bid becomes refundable (accumulate in case of repeats).90	if a.HighestBid > 0 {91		pk := pendKey(id, a.HighestBidder)92		pending.Set(pk, pendingOf(id, a.HighestBidder)+a.HighestBid)93	}9495	a.HighestBid = amount96	a.HighestBidder = bidder9798	chain.Emit("Bid",99		"id", strconv.FormatInt(id, 10),100		"bidder", bidder.String(),101		"amount", strconv.FormatUint(amount, 10),102	)103}104105// Withdraw refunds the caller's accumulated displaced bids for auction `id`.106// Returns the amount refunded (0 if nothing pending).107func Withdraw(cur realm, id int64) uint64 {108	mustGet(id) // ensure auction exists109	caller := unsafe.PreviousRealm().Address()110	amount := pendingOf(id, caller)111	if amount == 0 {112		return 0113	}114	pending.Remove(pendKey(id, caller))115	chain.Emit("Withdraw",116		"id", strconv.FormatInt(id, 10),117		"bidder", caller.String(),118		"amount", strconv.FormatUint(amount, 10),119	)120	return amount121}122123// End closes auction `id` once its end height is reached, awarding the item to124// the highest bidder (if any). Anyone may call it.125func End(cur realm, id int64) {126	a := mustGet(id)127	if a.Ended {128		panic("englishauction: auction already ended")129	}130	if runtime.ChainHeight() < a.EndHeight {131		panic("englishauction: auction not yet over")132	}133	a.Ended = true134135	chain.Emit("End",136		"id", strconv.FormatInt(id, 10),137		"winner", a.HighestBidder.String(),138		"amount", strconv.FormatUint(a.HighestBid, 10),139	)140}141142// --- read-only helpers (safe from tests and Render) ---143144// mustGet returns the auction for `id`, panicking if it does not exist. The145// store's label puts the id in the message, which v0's fixed string146// ("englishauction: no such auction") left out.147func mustGet(id int64) *Auction {148	return auctions.MustGet(store.ID(id)).(*Auction)149}150151// pendingOf returns the refundable amount owed to `bidder` for auction `id`.152func pendingOf(id int64, bidder address) uint64 {153	v := pending.Get(pendKey(id, bidder))154	if v == nil {155		return 0156	}157	return v.(uint64)158}159160// blocksLeft returns how many blocks remain before `a` can be ended (0 if the161// end height has been reached).162func blocksLeft(a *Auction, height int64) int64 {163	if height >= a.EndHeight {164		return 0165	}166	return a.EndHeight - height167}168169// hasWinner reports whether the auction received at least one bid.170func hasWinner(a *Auction) bool {171	return a.HighestBid > 0172}173174// Render lists every auction with item, top bid + bidder, time left, and winner.175func Render(path string) string {176	out := "# English Auction\n\n"177	out += "Ascending-bid auctions. Start one, outbid others, and End it after "178	out += "its block deadline to award the item to the top bidder.\n\n"179180	if auctions.Len() == 0 {181		out += "_No auctions yet. Call `Start` to open one._\n"182		return out183	}184185	height := runtime.ChainHeight()186	out += "_Current block height: " + strconv.FormatInt(height, 10) + "_\n\n"187	out += "| ID | Item | Highest Bid | Bidder | Status | Winner |\n"188	out += "|---:|------|------------:|--------|--------|--------|\n"189190	auctions.Each(func(id store.ID, v any) {191		a := v.(*Auction)192193		bidStr := "—"194		bidderStr := "—"195		if hasWinner(a) {196			bidStr = strconv.FormatUint(a.HighestBid, 10)197			bidderStr = "`" + a.HighestBidder.String() + "`"198		}199200		status := ""201		winner := "—"202		switch {203		case a.Ended:204			status = "ended"205			if hasWinner(a) {206				winner = "`" + a.HighestBidder.String() + "`"207			} else {208				winner = "no bids"209			}210		case height >= a.EndHeight:211			status = "awaiting End"212		default:213			status = strconv.FormatInt(blocksLeft(a, height), 10) + " blocks left"214		}215216		out += "| " + id.String() + " | " + a.Item + " | " +217			bidStr + " | " + bidderStr + " | " + status + " | " + winner + " |\n"218	})219	return out220}221

Functions

  • Bid(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}, id int64, amount uint64)

  • End(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}, id int64)

  • Render(path string) string

  • Start(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}, item string, durationBlocks int64) 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}, id int64) uint64

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

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.