Transaction

B8A2F52F9B7663…A8396188F382

Block 26,014 · index 1 · indexed

Summary

Hash
B8A2F52F9B766399665322A363E17DE35FC22E9FA878C169DCE5A8396188F382
Block
26,014
Size
9622 bytes
Gas used
13,967,993 / 16,761,651
Fee
1000000ugnot
Memo
gnopublish
Status
success

Messages

Arguments · 9

  1. #1englishauction
  2. #2README.md
  3. #3# English Auction > ⚠️ **Experimental — generated with no human supervision** by the daily MCP pipeline (Solidity→Gno port). Not audited. See [r/moul/x/daily](https://github.com/moul/gno-contracts/blob/main/r/moul/x/daily/README.md). --- An idiomatic gno.land port of the classic Solidity **English (ascending-bid) auction**. It ports the core mechanics — a seller opens an auction, bidders submit strictly increasing bids, the displaced top bid becomes refundable, and after a block deadline anyone can settle it — into a single realm that hosts many concurrent auctions. Solidity's `msg.sender` maps to `unsafe.PreviousRealm().Address()`, `block.number` to `runtime.ChainHeight()`, `require` to `panic`, and events to `chain.Emit`. There is no real coin transfer: bid amounts and refunds are tracked as plain `uint64` accounting in ordered `avl.Tree`s (mirroring Solidity's `pendingReturns` withdraw pattern). Auctions and pending refunds are keyed so `Render` can iterate deterministically. ## Transactions - `Start(cur, item string, durationBlocks int64) int64` — open an auction (caller becomes the seller); ends at `ChainHeight() + durationBlocks`. Returns the id. - `Bid(cur, id int64, amount uint64)` — bid; must strictly exceed the current highest. The prior top bid becomes refundable. - `Withdraw(cur, id int64) uint64` — reclaim your displaced bids for an auction. - `End(cur, id int64)` — after the deadline, award the item to the top bidder. ## Example calls ``` # open a 100-block auction for a painting -> returns id 1 Start("Vintage painting", 100) # two bidders compete (amounts are accounting units, not real coins) Bid(1, 500) # alice Bid(1, 750) # bob outbids -> alice's 500 is now refundable Withdraw(1) # alice reclaims 500 # once ChainHeight() >= endHeight, anyone settles it End(1) # item awarded to bob at 750 ``` Visit the realm to see the live table of auctions: item, highest bid + bidder, blocks remaining or ended, and the winner. <!-- BEGIN GNOCONTRACTS FOOTER (generated by `make readmes`; do not edit below) --> --- Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage. **Dependency graph:** ![gno.land/r/moul/x/daily/englishauction/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/r/moul/x/daily/englishauction/v0/deps.png) > 🧪 **Highly experimental — potentially vibe-coded.** Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md). <!-- END GNOCONTRACTS FOOTER -->
  4. #4englishauction.gno
  5. #5// Package englishauction is an idiomatic gno.land port of the classic Solidity // English (ascending-bid) auction. Anyone can Start an auction for a named item // with a duration in blocks; bidders call Bid with a strictly increasing amount. // The previous highest bid becomes refundable (claim it with Withdraw). After // the auction's end height anyone may call End, awarding the item to the highest // bidder. Auctions and pending refunds live in ordered avl trees so Render can // iterate deterministically. package englishauction import ( "strconv" "chain" "chain/runtime" "chain/runtime/unsafe" "gno.land/p/nt/avl/v0" ) // Auction is a single ascending-bid auction. type Auction struct { ID int64 Seller address Item string EndHeight int64 HighestBid uint64 HighestBidder address Ended bool } var ( auctions avl.Tree // key(id) -> *Auction pending avl.Tree // "<id>:<addr>" -> uint64 refundable amount nextID int64 = 1 ) // key formats an id into a zero-padded, lexicographically-sortable string. func key(id int64) string { s := strconv.FormatInt(id, 10) for len(s) < 12 { s = "0" + s } return s } // pendKey formats the refund key for a given auction id and bidder. func pendKey(id int64, bidder address) string { return key(id) + ":" + bidder.String() } // Start opens a new auction for `item` running for `durationBlocks` blocks from // the current height. The caller becomes the seller. Returns the auction id. func Start(cur realm, item string, durationBlocks int64) int64 { if item == "" { panic("englishauction: item must not be empty") } if durationBlocks <= 0 { panic("englishauction: duration must be > 0 blocks") } seller := unsafe.PreviousRealm().Address() id := nextID nextID++ a := &Auction{ ID: id, Seller: seller, Item: item, EndHeight: runtime.ChainHeight() + durationBlocks, } auctions.Set(key(id), a) chain.Emit("Start", "id", strconv.FormatInt(id, 10), "seller", seller.String(), "item", item, "endHeight", strconv.FormatInt(a.EndHeight, 10), ) return id } // Bid places a bid of `amount` on auction `id`. It must strictly exceed the // current highest bid. The displaced highest bid becomes refundable to its // bidder via Withdraw. func Bid(cur realm, id int64, amount uint64) { a := mustGet(id) if a.Ended || runtime.ChainHeight() >= a.EndHeight { panic("englishauction: auction has ended") } if amount <= a.HighestBid { panic("englishauction: bid must strictly exceed current highest") } bidder := unsafe.PreviousRealm().Address() if bidder == a.Seller { panic("englishauction: seller cannot bid") } // The prior top bid becomes refundable (accumulate in case of repeats). if a.HighestBid > 0 { pk := pendKey(id, a.HighestBidder) pending.Set(pk, pendingOf(id, a.HighestBidder)+a.HighestBid) } a.HighestBid = amount a.HighestBidder = bidder chain.Emit("Bid", "id", strconv.FormatInt(id, 10), "bidder", bidder.String(), "amount", strconv.FormatUint(amount, 10), ) } // Withdraw refunds the caller's accumulated displaced bids for auction `id`. // Returns the amount refunded (0 if nothing pending). func Withdraw(cur realm, id int64) uint64 { mustGet(id) // ensure auction exists caller := unsafe.PreviousRealm().Address() amount := pendingOf(id, caller) if amount == 0 { return 0 } pending.Remove(pendKey(id, caller)) chain.Emit("Withdraw", "id", strconv.FormatInt(id, 10), "bidder", caller.String(), "amount", strconv.FormatUint(amount, 10), ) return amount } // End closes auction `id` once its end height is reached, awarding the item to // the highest bidder (if any). Anyone may call it. func End(cur realm, id int64) { a := mustGet(id) if a.Ended { panic("englishauction: auction already ended") } if runtime.ChainHeight() < a.EndHeight { panic("englishauction: auction not yet over") } a.Ended = true chain.Emit("End", "id", strconv.FormatInt(id, 10), "winner", a.HighestBidder.String(), "amount", strconv.FormatUint(a.HighestBid, 10), ) } // --- read-only helpers (safe from tests and Render) --- // mustGet returns the auction for `id`, panicking if it does not exist. func mustGet(id int64) *Auction { v := auctions.Get(key(id)) if v == nil { panic("englishauction: no such auction") } return v.(*Auction) } // pendingOf returns the refundable amount owed to `bidder` for auction `id`. func pendingOf(id int64, bidder address) uint64 { v := pending.Get(pendKey(id, bidder)) if v == nil { return 0 } return v.(uint64) } // blocksLeft returns how many blocks remain before `a` can be ended (0 if the // end height has been reached). func blocksLeft(a *Auction, height int64) int64 { if height >= a.EndHeight { return 0 } return a.EndHeight - height } // hasWinner reports whether the auction received at least one bid. func hasWinner(a *Auction) bool { return a.HighestBid > 0 } // Render lists every auction with item, top bid + bidder, time left, and winner. func Render(path string) string { out := "# English Auction\n\n" out += "Ascending-bid auctions. Start one, outbid others, and End it after " out += "its block deadline to award the item to the top bidder.\n\n" if auctions.Size() == 0 { out += "_No auctions yet. Call `Start` to open one._\n" return out } height := runtime.ChainHeight() out += "_Current block height: " + strconv.FormatInt(height, 10) + "_\n\n" out += "| ID | Item | Highest Bid | Bidder | Status | Winner |\n" out += "|---:|------|------------:|--------|--------|--------|\n" auctions.Iterate("", "", func(_ string, v interface{}) bool { a := v.(*Auction) bidStr := "—" bidderStr := "—" if hasWinner(a) { bidStr = strconv.FormatUint(a.HighestBid, 10) bidderStr = "`" + a.HighestBidder.String() + "`" } status := "" winner := "—" switch { case a.Ended: status = "ended" if hasWinner(a) { winner = "`" + a.HighestBidder.String() + "`" } else { winner = "no bids" } case height >= a.EndHeight: status = "awaiting End" default: status = strconv.FormatInt(blocksLeft(a, height), 10) + " blocks left" } out += "| " + strconv.FormatInt(a.ID, 10) + " | " + a.Item + " | " + bidStr + " | " + bidderStr + " | " + status + " | " + winner + " |\n" return false }) return out }
  6. #6gnomod.toml
  7. #7module = "gno.land/r/moul/x/daily/englishauction/v0" gno = "0.9"
  8. #8/gno.MemPackageType
  9. #9 MPUserProd

Result log

msg:0,success:true,log:,events:[]

← Back to block 26,014