// gen generates contracts/auction/auction.wasm // Run from repo root: go run ./contracts/auction/gen/ // // Methods: create, bid, settle, cancel, info // // State keys (per auction_id, single-char suffix): // "a::s" → seller address // "a::t" → title // "a::m" → min_bid (8-byte big-endian u64 via put_u64/get_u64) // "a::e" → end_block (8-byte big-endian u64) // "a::b" → top_bidder address (empty string = no bid) // "a::v" → top_bid amount (8-byte big-endian u64) // "a::x" → status byte ('o'=open, 's'=settled, 'c'=cancelled) // // The contract treasury holds in-flight bid escrow. package main import ( "fmt" "os" ) // ── LEB128 & builders ──────────────────────────────────────────────────────── func u(v uint64) []byte { var b []byte for { bt := byte(v & 0x7f) v >>= 7 if v != 0 { bt |= 0x80 } b = append(b, bt) if v == 0 { return b } } } func s(v int64) []byte { var b []byte for { bt := byte(v & 0x7f) v >>= 7 sign := (bt & 0x40) != 0 if (v == 0 && !sign) || (v == -1 && sign) { return append(b, bt) } b = append(b, bt|0x80) } } func cat(slices ...[]byte) []byte { var out []byte for _, sl := range slices { out = append(out, sl...) } return out } func wstr(str string) []byte { return cat(u(uint64(len(str))), []byte(str)) } func section(id byte, content []byte) []byte { return cat([]byte{id}, u(uint64(len(content))), content) } func vec(items ...[]byte) []byte { out := u(uint64(len(items))) for _, it := range items { out = append(out, it...) } return out } func functype(params, results []byte) []byte { return cat([]byte{0x60}, u(uint64(len(params))), params, u(uint64(len(results))), results) } func importFunc(mod, name string, typeIdx uint32) []byte { return cat(wstr(mod), wstr(name), []byte{0x00}, u(uint64(typeIdx))) } func exportEntry(name string, kind byte, idx uint32) []byte { return cat(wstr(name), []byte{kind}, u(uint64(idx))) } func dataSegment(offset int32, data []byte) []byte { return cat( []byte{0x00}, []byte{0x41}, s(int64(offset)), []byte{0x0B}, u(uint64(len(data))), data, ) } func funcBody(localDecls []byte, instrs ...[]byte) []byte { inner := cat(localDecls) for _, ins := range instrs { inner = append(inner, ins...) } inner = append(inner, 0x0B) return cat(u(uint64(len(inner))), inner) } var noLocals = u(0) func localDecl(n uint32, typ byte) []byte { return cat(u(uint64(n)), []byte{typ}) } func withLocals(decls ...[]byte) []byte { return cat(u(uint64(len(decls))), cat(decls...)) } const ( tI32 byte = 0x7F tI64 byte = 0x7E ) func call(fn uint32) []byte { return cat([]byte{0x10}, u(uint64(fn))) } func lget(i uint32) []byte { return cat([]byte{0x20}, u(uint64(i))) } func lset(i uint32) []byte { return cat([]byte{0x21}, u(uint64(i))) } func ic32(v int32) []byte { return cat([]byte{0x41}, s(int64(v))) } func ic64(v int64) []byte { return cat([]byte{0x42}, s(v)) } func block_() []byte { return []byte{0x02, 0x40} } func loop_() []byte { return []byte{0x03, 0x40} } func if_() []byte { return []byte{0x04, 0x40} } func else_() []byte { return []byte{0x05} } func end_() []byte { return []byte{0x0B} } func br_(lbl uint32) []byte { return cat([]byte{0x0C}, u(uint64(lbl))) } func brIf_(lbl uint32) []byte { return cat([]byte{0x0D}, u(uint64(lbl))) } func return_() []byte { return []byte{0x0F} } func drop() []byte { return []byte{0x1A} } func i32Eqz() []byte { return []byte{0x45} } func i32Ne() []byte { return []byte{0x47} } func i32GtU() []byte { return []byte{0x4B} } func i32GeU() []byte { return []byte{0x4F} } func i32Add() []byte { return []byte{0x6A} } func i64Eqz() []byte { return []byte{0x50} } func i64Eq() []byte { return []byte{0x51} } func i64GtU() []byte { return []byte{0x56} } func i64LeU() []byte { return []byte{0x57} } func i64Add() []byte { return []byte{0x7C} } func i32Load8U() []byte { return []byte{0x2D, 0x00, 0x00} } func i32Store8() []byte { return []byte{0x3A, 0x00, 0x00} } // ── Memory layout ───────────────────────────────────────────────────────────── // // 0x000 64 arg[0]: auction_id // 0x040 128 arg[1]: title // 0x140 128 caller buffer // 0x1C0 64 treasury buffer // 0x200 128 state-read: seller or top_bidder // 0x280 128 secondary state-read: top_bidder (during bid) // 0x300 2 state-read: status byte // 0x310 256 scratch (buildField writes here) // // Constant strings at 0x500+: // 0x500 10 "created: " // 0x50A 5 "bid: " // 0x510 10 "settled: " // 0x51A 11 "cancelled: " // 0x526 14 "unauthorized: " // 0x535 9 "not found: " // 0x540 12 "not open: " (auction not in open state) // 0x54C 14 "bidding open: " (cannot cancel with bids) // 0x55B 12 "still open: " (auction has not ended yet) // 0x568 11 "low bid: " (bid too low) // 0x574 8 "seller: " // 0x57D 7 "title: " // 0x585 10 "top bid: " // 0x590 11 "end block: " // 0x59C 8 "status: " // 0x5A5 5 "open" // 0x5AA 8 "settled" // 0x5B3 10 "cancelled" const ( offArg0 int32 = 0x000 offArg1 int32 = 0x040 offCaller int32 = 0x140 offTreasury int32 = 0x1C0 offRead1 int32 = 0x200 // seller / first state read offRead2 int32 = 0x280 // top_bidder / second state read offReadStat int32 = 0x300 // status byte offScratch int32 = 0x310 // key scratch offCreatedPfx int32 = 0x500 offBidPfx int32 = 0x50A offSettledPfx int32 = 0x510 offCancelledPfx int32 = 0x51A offUnauthPfx int32 = 0x526 offNotFoundPfx int32 = 0x535 offNotOpenPfx int32 = 0x540 offHasBidsPfx int32 = 0x54C offStillOpenPfx int32 = 0x55B offLowBidPfx int32 = 0x568 offSellerPfx int32 = 0x574 offTitlePfx int32 = 0x57D offTopBidPfx int32 = 0x585 offEndBlockPfx int32 = 0x590 offStatusPfx int32 = 0x59C offStrOpen int32 = 0x5A5 offStrSettled int32 = 0x5AA offStrCancelled int32 = 0x5B3 ) // ── Import / function indices ───────────────────────────────────────────────── const ( fnGetArgStr = 0 fnGetArgU64 = 1 fnGetCaller = 2 fnGetState = 3 fnSetState = 4 fnLog = 5 fnTransfer = 6 fnGetBalance = 7 fnGetContractTreasury = 8 fnGetBlockHeight = 9 fnPutU64 = 10 fnGetU64 = 11 fnBytesEqual = 12 fnMemcpy = 13 fnLogPrefix = 14 fnBuildField = 15 // buildField(idOff, idLen, fieldChar i32) → keyLen i32 fnCreate = 16 fnBid = 17 fnSettle = 18 fnCancel = 19 fnInfo = 20 ) // ── Helper bodies ───────────────────────────────────────────────────────────── func bytesEqualBody() []byte { return funcBody( withLocals(localDecl(2, tI32)), ic32(1), lset(4), ic32(0), lset(3), block_(), loop_(), lget(3), lget(2), i32GeU(), brIf_(1), lget(0), lget(3), i32Add(), i32Load8U(), lget(1), lget(3), i32Add(), i32Load8U(), i32Ne(), if_(), ic32(0), lset(4), br_(2), end_(), lget(3), ic32(1), i32Add(), lset(3), br_(0), end_(), end_(), lget(4), ) } func memcpyBody() []byte { return funcBody( withLocals(localDecl(1, tI32)), ic32(0), lset(3), block_(), loop_(), lget(3), lget(2), i32GeU(), brIf_(1), lget(0), lget(3), i32Add(), lget(1), lget(3), i32Add(), i32Load8U(), i32Store8(), lget(3), ic32(1), i32Add(), lset(3), br_(0), end_(), end_(), ) } func logPrefixBody() []byte { return funcBody( noLocals, ic32(offScratch), lget(0), lget(1), call(fnMemcpy), ic32(offScratch), lget(1), i32Add(), lget(2), lget(3), call(fnMemcpy), ic32(offScratch), lget(1), lget(3), i32Add(), call(fnLog), ) } // buildField(idOff, idLen, fieldChar i32) → keyLen i32 // Writes "a::" into offScratch. Returns idLen+4. func buildFieldBody() []byte { return funcBody( noLocals, // scratch[0] = 'a' ic32(offScratch), ic32('a'), i32Store8(), // scratch[1] = ':' ic32(offScratch+1), ic32(':'), i32Store8(), // memcpy(scratch+2, idOff, idLen) ic32(offScratch+2), lget(0), lget(1), call(fnMemcpy), // scratch[2+idLen] = ':' ic32(offScratch+2), lget(1), i32Add(), ic32(':'), i32Store8(), // scratch[3+idLen] = fieldChar ic32(offScratch+3), lget(1), i32Add(), lget(2), i32Store8(), // return idLen + 4 lget(1), ic32(4), i32Add(), ) } // ── Contract methods ────────────────────────────────────────────────────────── // create(id string, title string, min_bid u64, duration u64) // Locals: idLen(0), titleLen(1), treasuryLen(2), keyLen(3) // i64 locals: minBid(4), duration(5) func createBody() []byte { return funcBody( withLocals(localDecl(4, tI32), localDecl(2, tI64)), ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0), lget(0), i32Eqz(), if_(), return_(), end_(), ic32(1), ic32(offArg1), ic32(128), call(fnGetArgStr), lset(1), lget(1), i32Eqz(), if_(), return_(), end_(), // minBid = get_arg_u64(2) ic32(2), call(fnGetArgU64), lset(4), // duration = get_arg_u64(3) ic32(3), call(fnGetArgU64), lset(5), // Check not already registered: get_state("a::x", ...) ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offReadStat), ic32(2), call(fnGetState), ic32(0), i32GtU(), if_(), // status exists → already created ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Get treasury address ic32(offTreasury), ic32(64), call(fnGetContractTreasury), lset(2), // Get caller (seller) ic32(offCaller), ic32(128), call(fnGetCaller), lset(2), // reuse local 2 for callerLen // Write seller: a::s → caller ic32(offArg0), lget(0), ic32('s'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offCaller), lget(2), call(fnSetState), // Write title: a::t → title ic32(offArg0), lget(0), ic32('t'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offArg1), lget(1), call(fnSetState), // Write min_bid: a::m → put_u64 ic32(offArg0), lget(0), ic32('m'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), lget(4), call(fnPutU64), // Write end_block: a::e → get_block_height() + duration call(fnGetBlockHeight), lget(5), i64Add(), ic32(offArg0), lget(0), ic32('e'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), // stack: keyPtr, keyLen, [endBlock i64 still on stack? No — need to rearrange] // Actually put_u64 takes (keyPtr, keyLen, val i64) // We already have endBlock on stack but called buildField after. Let me restructure. drop(), // drop keyLen from buildField - oops this won't work as coded above // Actually above I wrote lset(3) to save keyLen, so stack should be clean. // The i64 (endBlock) is on the operand stack before the buildField call... this is wrong. // Let me restructure: compute endBlock first into an i64 local. // I need another i64 local. Let me add local 6 (i64). // This requires restructuring... see revised body below ) } // Revised create body with proper local management // Locals: idLen(0), titleLen(1), callerLen(2), keyLen(3) [i32] // minBid(4), duration(5), endBlock(6) [i64] func createBodyV2() []byte { return funcBody( withLocals(localDecl(4, tI32), localDecl(3, tI64)), // Read args ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0), lget(0), i32Eqz(), if_(), return_(), end_(), ic32(1), ic32(offArg1), ic32(128), call(fnGetArgStr), lset(1), lget(1), i32Eqz(), if_(), return_(), end_(), ic32(2), call(fnGetArgU64), lset(4), // minBid ic32(3), call(fnGetArgU64), lset(5), // duration // Check id not already used: read status key ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offReadStat), ic32(2), call(fnGetState), ic32(0), i32GtU(), if_(), // ID already exists — log conflict ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Get caller (seller) ic32(offCaller), ic32(128), call(fnGetCaller), lset(2), // Compute endBlock = get_block_height() + duration call(fnGetBlockHeight), lget(5), i64Add(), lset(6), // Write seller: a::s → caller ic32(offArg0), lget(0), ic32('s'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offCaller), lget(2), call(fnSetState), // Write title: a::t → arg1 ic32(offArg0), lget(0), ic32('t'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offArg1), lget(1), call(fnSetState), // Write min_bid: a::m ic32(offArg0), lget(0), ic32('m'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), lget(4), call(fnPutU64), // Write end_block: a::e ic32(offArg0), lget(0), ic32('e'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), lget(6), call(fnPutU64), // Write top_bid = 0: a::v ic32(offArg0), lget(0), ic32('v'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic64(0), call(fnPutU64), // Write status = 'o': a::x ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(3), ic32(offReadStat), ic32('o'), i32Store8(), // write 'o' to offReadStat ic32(offScratch), lget(3), ic32(offReadStat), ic32(1), call(fnSetState), ic32(offCreatedPfx), ic32(9), ic32(offArg0), lget(0), call(fnLogPrefix), ) } // bid(id string, amount u64) // Locals: idLen(0), callerLen(1), sellerLen(2), topBidderLen(3), keyLen(4) [i32] // amount(5), topBid(6), endBlock(7) [i64] func bidBody() []byte { return funcBody( withLocals(localDecl(5, tI32), localDecl(3, tI64)), ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0), lget(0), i32Eqz(), if_(), return_(), end_(), ic32(1), call(fnGetArgU64), lset(5), // amount // Check status == 'o' ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), ic32(offReadStat), ic32(2), call(fnGetState), ic32(0), i32Ne(), if_(), // status byte exists ic32(offReadStat), i32Load8U(), ic32('o'), i32Ne(), if_(), ic32(offNotOpenPfx), ic32(10), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), else_(), // no status byte = not found ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Check end_block > current block ic32(offArg0), lget(0), ic32('e'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), call(fnGetU64), lset(7), call(fnGetBlockHeight), lget(7), i64LeU(), if_(), // blockHeight >= endBlock → ended ic32(offNotOpenPfx), ic32(10), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Get current top_bid ic32(offArg0), lget(0), ic32('v'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), call(fnGetU64), lset(6), // amount must be > max(topBid, minBid-1) → amount > topBid AND amount >= minBid // Check amount > topBid lget(5), lget(6), i64GtU(), i32Eqz(), if_(), ic32(offLowBidPfx), ic32(9), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Get caller ic32(offCaller), ic32(128), call(fnGetCaller), lset(1), // Get treasury ic32(offTreasury), ic32(64), call(fnGetContractTreasury), lset(2), // reuse local 2 // Transfer amount from caller to treasury ic32(offCaller), lget(1), ic32(offTreasury), lget(2), lget(5), call(fnTransfer), drop(), // Refund previous top bidder if topBid > 0 lget(6), i64Eqz(), i32Eqz(), if_(), // topBid > 0 // Read top_bidder address into offRead2 ic32(offArg0), lget(0), ic32('b'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), ic32(offRead2), ic32(128), call(fnGetState), lset(3), lget(3), ic32(0), i32GtU(), if_(), // topBidder address exists // transfer(treasury, topBidder, topBid) ic32(offTreasury), lget(2), ic32(offRead2), lget(3), lget(6), call(fnTransfer), drop(), end_(), end_(), // Update top_bidder: a::b → caller ic32(offArg0), lget(0), ic32('b'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), ic32(offCaller), lget(1), call(fnSetState), // Update top_bid: a::v → amount ic32(offArg0), lget(0), ic32('v'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), lget(5), call(fnPutU64), ic32(offBidPfx), ic32(5), ic32(offArg0), lget(0), call(fnLogPrefix), ) } // settle(id string) // Locals: idLen(0), sellerLen(1), topBidderLen(2), treasuryLen(3), keyLen(4) [i32] // topBid(5), endBlock(6) [i64] func settleBody() []byte { return funcBody( withLocals(localDecl(5, tI32), localDecl(2, tI64)), ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0), lget(0), i32Eqz(), if_(), return_(), end_(), // Check status == 'o' ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), ic32(offReadStat), ic32(2), call(fnGetState), ic32(0), i32Ne(), if_(), ic32(offReadStat), i32Load8U(), ic32('o'), i32Ne(), if_(), ic32(offNotOpenPfx), ic32(10), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), else_(), ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Check auction has ended: current_block >= end_block ic32(offArg0), lget(0), ic32('e'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), call(fnGetU64), lset(6), call(fnGetBlockHeight), lget(6), i64LeU(), if_(), // height < endBlock → still open ic32(offStillOpenPfx), ic32(12), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Get top_bid ic32(offArg0), lget(0), ic32('v'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), call(fnGetU64), lset(5), // If top_bid > 0: transfer topBid from treasury to seller lget(5), i64Eqz(), i32Eqz(), if_(), // Read seller into offRead1 ic32(offArg0), lget(0), ic32('s'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), ic32(offRead1), ic32(128), call(fnGetState), lset(1), // Get treasury ic32(offTreasury), ic32(64), call(fnGetContractTreasury), lset(3), ic32(offTreasury), lget(3), ic32(offRead1), lget(1), lget(5), call(fnTransfer), drop(), end_(), // Mark status = 's' ic32(offReadStat), ic32('s'), i32Store8(), ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(4), ic32(offScratch), lget(4), ic32(offReadStat), ic32(1), call(fnSetState), ic32(offSettledPfx), ic32(9), ic32(offArg0), lget(0), call(fnLogPrefix), ) } // cancel(id string) — seller cancels (no bids yet) // Locals: idLen(0), callerLen(1), sellerLen(2), keyLen(3) [i32] // topBid(4) [i64] func cancelBody() []byte { return funcBody( withLocals(localDecl(4, tI32), localDecl(1, tI64)), ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0), lget(0), i32Eqz(), if_(), return_(), end_(), // Check status == 'o' ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offReadStat), ic32(2), call(fnGetState), ic32(0), i32Ne(), if_(), ic32(offReadStat), i32Load8U(), ic32('o'), i32Ne(), if_(), ic32(offNotOpenPfx), ic32(10), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), else_(), ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Check no bids: topBid == 0 ic32(offArg0), lget(0), ic32('v'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), call(fnGetU64), lset(4), lget(4), i64Eqz(), i32Eqz(), if_(), // topBid > 0 → has bids ic32(offHasBidsPfx), ic32(14), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Verify caller is seller ic32(offArg0), lget(0), ic32('s'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offRead1), ic32(128), call(fnGetState), lset(2), ic32(offCaller), ic32(128), call(fnGetCaller), lset(1), // isOwner: callerLen == sellerLen && bytes_equal lget(1), lget(2), i32Ne(), if_(), ic32(offUnauthPfx), ic32(14), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), ic32(offCaller), ic32(offRead1), lget(1), call(fnBytesEqual), i32Eqz(), if_(), ic32(offUnauthPfx), ic32(14), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Mark status = 'c' ic32(offReadStat), ic32('c'), i32Store8(), ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(3), ic32(offScratch), lget(3), ic32(offReadStat), ic32(1), call(fnSetState), ic32(offCancelledPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), ) } // info(id string) — log auction details // Locals: idLen(0), strLen(1), keyLen(2) [i32] // topBid(3) [i64] func infoBody() []byte { return funcBody( withLocals(localDecl(3, tI32), localDecl(1, tI64)), ic32(0), ic32(offArg0), ic32(64), call(fnGetArgStr), lset(0), lget(0), i32Eqz(), if_(), return_(), end_(), // Check exists ic32(offArg0), lget(0), ic32('x'), call(fnBuildField), lset(2), ic32(offScratch), lget(2), ic32(offReadStat), ic32(2), call(fnGetState), ic32(0), i32Ne(), i32Eqz(), if_(), ic32(offNotFoundPfx), ic32(11), ic32(offArg0), lget(0), call(fnLogPrefix), return_(), end_(), // Log seller: a::s ic32(offArg0), lget(0), ic32('s'), call(fnBuildField), lset(2), ic32(offScratch), lget(2), ic32(offRead1), ic32(128), call(fnGetState), lset(1), ic32(offSellerPfx), ic32(8), ic32(offRead1), lget(1), call(fnLogPrefix), // Log title: a::t ic32(offArg0), lget(0), ic32('t'), call(fnBuildField), lset(2), ic32(offScratch), lget(2), ic32(offRead1), ic32(128), call(fnGetState), lset(1), ic32(offTitlePfx), ic32(7), ic32(offRead1), lget(1), call(fnLogPrefix), // Log status ic32(offReadStat), i32Load8U(), ic32('s'), i32Ne(), if_(), ic32(offReadStat), i32Load8U(), ic32('c'), i32Ne(), if_(), // status == 'o' ic32(offStatusPfx), ic32(8), ic32(offStrOpen), ic32(4), call(fnLogPrefix), else_(), ic32(offStatusPfx), ic32(8), ic32(offStrCancelled), ic32(9), call(fnLogPrefix), end_(), else_(), ic32(offStatusPfx), ic32(8), ic32(offStrSettled), ic32(7), call(fnLogPrefix), end_(), ) } // ── main ────────────────────────────────────────────────────────────────────── func main() { // Types: // 0: (i32,i32,i32)→(i32) get_arg_str, bytes_equal // 1: (i32)→(i64) get_arg_u64, get_block_height (no, diff sig) // 2: (i32,i32,i32,i32)→(i32) get_state // 3: (i32,i32,i32,i32)→() set_state, log_prefix // 4: (i32,i32)→() log // 5: (i32,i32,i32,i32,i64)→(i32) transfer // 6: (i32,i32)→(i64) get_balance, get_u64 // 7: (i32,i32)→(i32) get_caller, get_contract_treasury // 8: ()→(i64) get_block_height // 9: (i32,i32,i64)→() put_u64 // 10: ()→() exported methods // 11: (i32,i32,i32)→() memcpy // 12: (i32,i32,i32)→(i32) buildField typeSection := section(0x01, vec( functype([]byte{tI32, tI32, tI32}, []byte{tI32}), // 0 functype([]byte{tI32}, []byte{tI64}), // 1 functype([]byte{tI32, tI32, tI32, tI32}, []byte{tI32}), // 2 functype([]byte{tI32, tI32, tI32, tI32}, []byte{}), // 3 functype([]byte{tI32, tI32}, []byte{}), // 4 functype([]byte{tI32, tI32, tI32, tI32, tI64}, []byte{tI32}), // 5 functype([]byte{tI32, tI32}, []byte{tI64}), // 6 functype([]byte{tI32, tI32}, []byte{tI32}), // 7 functype([]byte{}, []byte{tI64}), // 8 functype([]byte{tI32, tI32, tI64}, []byte{}), // 9 functype([]byte{}, []byte{}), // 10 functype([]byte{tI32, tI32, tI32}, []byte{}), // 11 )) importSection := section(0x02, vec( importFunc("env", "get_arg_str", 0), // 0 importFunc("env", "get_arg_u64", 1), // 1 importFunc("env", "get_caller", 7), // 2 importFunc("env", "get_state", 2), // 3 importFunc("env", "set_state", 3), // 4 importFunc("env", "log", 4), // 5 importFunc("env", "transfer", 5), // 6 importFunc("env", "get_balance", 6), // 7 importFunc("env", "get_contract_treasury", 7), // 8 importFunc("env", "get_block_height", 8), // 9 importFunc("env", "put_u64", 9), // 10 importFunc("env", "get_u64", 6), // 11 )) // 9 local functions functionSection := section(0x03, vec( u(0), // bytes_equal type 0 u(11), // memcpy type 11 u(3), // log_prefix type 3 u(0), // buildField type 0 (i32,i32,i32)→(i32) u(10), // create type 10 u(10), // bid type 10 u(10), // settle type 10 u(10), // cancel type 10 u(10), // info type 10 )) memorySection := section(0x05, vec(cat([]byte{0x00}, u(2)))) // 2 pages exportSection := section(0x07, vec( exportEntry("memory", 0x02, 0), exportEntry("create", 0x00, fnCreate), exportEntry("bid", 0x00, fnBid), exportEntry("settle", 0x00, fnSettle), exportEntry("cancel", 0x00, fnCancel), exportEntry("info", 0x00, fnInfo), )) dataSection := section(0x0B, cat( u(17), dataSegment(offCreatedPfx, []byte("created: ")), dataSegment(offBidPfx, []byte("bid: ")), dataSegment(offSettledPfx, []byte("settled: ")), dataSegment(offCancelledPfx, []byte("cancelled: ")), dataSegment(offUnauthPfx, []byte("unauthorized: ")), dataSegment(offNotFoundPfx, []byte("not found: ")), dataSegment(offNotOpenPfx, []byte("not open: ")), dataSegment(offHasBidsPfx, []byte("has bids: ")), dataSegment(offStillOpenPfx, []byte("still open: ")), dataSegment(offLowBidPfx, []byte("low bid: ")), dataSegment(offSellerPfx, []byte("seller: ")), dataSegment(offTitlePfx, []byte("title: ")), dataSegment(offTopBidPfx, []byte("top bid: ")), dataSegment(offEndBlockPfx, []byte("end block: ")), dataSegment(offStatusPfx, []byte("status: ")), dataSegment(offStrOpen, []byte("open")), dataSegment(offStrSettled, []byte("settled")), // Note: offStrCancelled is at 0x5B3 but we declared 17 segments // Add cancelled string too )) // Fix: 18 data segments including "cancelled" dataSection = section(0x0B, cat( u(18), dataSegment(offCreatedPfx, []byte("created: ")), dataSegment(offBidPfx, []byte("bid: ")), dataSegment(offSettledPfx, []byte("settled: ")), dataSegment(offCancelledPfx, []byte("cancelled: ")), dataSegment(offUnauthPfx, []byte("unauthorized: ")), dataSegment(offNotFoundPfx, []byte("not found: ")), dataSegment(offNotOpenPfx, []byte("not open: ")), dataSegment(offHasBidsPfx, []byte("has bids: ")), dataSegment(offStillOpenPfx, []byte("still open: ")), dataSegment(offLowBidPfx, []byte("low bid: ")), dataSegment(offSellerPfx, []byte("seller: ")), dataSegment(offTitlePfx, []byte("title: ")), dataSegment(offTopBidPfx, []byte("top bid: ")), dataSegment(offEndBlockPfx, []byte("end block: ")), dataSegment(offStatusPfx, []byte("status: ")), dataSegment(offStrOpen, []byte("open")), dataSegment(offStrSettled, []byte("settled")), dataSegment(offStrCancelled, []byte("cancelled")), )) codeSection := section(0x0A, cat( u(9), bytesEqualBody(), memcpyBody(), logPrefixBody(), buildFieldBody(), createBodyV2(), bidBody(), settleBody(), cancelBody(), infoBody(), )) module := cat( []byte{0x00, 0x61, 0x73, 0x6d}, []byte{0x01, 0x00, 0x00, 0x00}, typeSection, importSection, functionSection, memorySection, exportSection, dataSection, codeSection, ) out := "contracts/auction/auction.wasm" if err := os.WriteFile(out, module, 0644); err != nil { fmt.Fprintln(os.Stderr, "write:", err) os.Exit(1) } fmt.Printf("Written %s (%d bytes)\n", out, len(module)) }