Transaction

C800EDFB3B98C0…ECC70967F92E

Block 26,349 · index 0 · indexed

Summary

Hash
C800EDFB3B98C04E4347372BDC4FCA00851CD203DD92CC4D7B03ECC70967F92E
Block
26,349
Size
6886 bytes
Gas used
10,990,062 / 13,188,134
Fee
1000000ugnot
Memo
gnopublish
Status
success

Messages

#1AddPackagegno.land/r/moul/x/daily/faucet/v09 arguments

Arguments · 9

  1. #1faucet
  2. #2README.md
  3. #3# Token Faucet > ⚠️ **Experimental — generated with no human supervision.** This realm was > produced automatically by an MCP-driven agent to exercise the gno MCP server > and tooling, and to generate test content for gno compilers, linters and > formatters. **Not audited. Not for production.** Full context & folder README: > [r/moul/x/daily](https://github.com/moul/gno-contracts/blob/main/r/moul/x/daily/README.md) --- A toy points faucet realm for the gno.land sapphire testnet. Any caller can `Claim` 100 points, but only once every 100 blocks per address — the cooldown is enforced deterministically via `runtime.ChainHeight()`. Per-caller balances and last-claim heights are stored in an `avl.Tree`, and `Render` shows the total distributed, total claim count, and a table of all claimers with their balances. ## Realm path ``` gno.land/r/REPLACE_ADDR/faucet ``` (`REPLACE_ADDR` is replaced with the deploy address at deploy time.) ## Example calls ```sh # Claim 100 points (subject to the 100-block cooldown). gnokey maketx call -pkgpath "gno.land/r/REPLACE_ADDR/faucet" \ -func Claim -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast \ -chainid sapphire-1 mykey # Query a balance (read-only). gnokey query "vm/qeval" -data \ 'gno.land/r/REPLACE_ADDR/faucet.BalanceOf("g1...youraddr")' # View the dashboard. gnokey query "vm/qrender" -data 'gno.land/r/REPLACE_ADDR/faucet:' ``` ## Behavior - `Claim(cur realm)` — grants `ClaimAmount` (100) points to the caller; aborts if the caller's previous claim was less than `CooldownBlocks` (100) blocks ago. - `BalanceOf(addr string) int64` — current balance for an address (0 if unknown). - `Render(path string) string` — Markdown dashboard: stats + claimer table. <!-- 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/faucet/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/r/moul/x/daily/faucet/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. #4faucet.gno
  5. #5// Package faucet is a toy points faucet realm for the gno.land sapphire testnet. // // Any caller may Claim() 100 points, but only once per cooldown window of 100 // blocks. Cooldown is enforced deterministically via runtime.ChainHeight() — no // real clocks, no RNG. Per-caller balance and last-claim height live in an // avl.Tree so Render iterates in deterministic (address-sorted) order. package faucet import ( "chain" "chain/runtime" "chain/runtime/unsafe" "strconv" "strings" "gno.land/p/nt/avl/v0" ) const ( // ClaimAmount is granted on every successful claim. ClaimAmount = 100 // CooldownBlocks is the minimum number of blocks between two claims by the // same caller. CooldownBlocks = 100 ) // claimer holds the per-address state. type claimer struct { Balance int64 // total points accumulated LastClaim int64 // chain height of the last successful claim Claims int64 // number of successful claims by this address } var ( // claimers maps address string -> *claimer. claimers = avl.NewTree() // totalDistributed is the running sum of all points ever granted. totalDistributed int64 // totalClaims is the total number of successful claims across all callers. totalClaims int64 ) // Claim grants ClaimAmount points to the caller, subject to the per-caller // cooldown. It aborts (cross-realm) if the caller must still wait. func Claim(cur realm) { caller := unsafe.PreviousRealm().Address() key := caller.String() height := runtime.ChainHeight() var c *claimer if v := claimers.Get(key); v != nil { c = v.(*claimer) wait := c.LastClaim + CooldownBlocks - height if wait > 0 { panic("cooldown active: " + strconv.FormatInt(wait, 10) + " block(s) remaining before you can claim again") } } else { c = &claimer{} } c.Balance += ClaimAmount c.LastClaim = height c.Claims++ claimers.Set(key, c) totalDistributed += ClaimAmount totalClaims++ chain.Emit( "Claim", "caller", key, "amount", strconv.FormatInt(ClaimAmount, 10), "balance", strconv.FormatInt(c.Balance, 10), "height", strconv.FormatInt(height, 10), ) } // BalanceOf returns the current point balance of addr (0 if never claimed). func BalanceOf(addr string) int64 { if v := claimers.Get(addr); v != nil { return v.(*claimer).Balance } return 0 } // Render produces a Markdown dashboard of faucet activity. func Render(path string) string { var b strings.Builder b.WriteString("# Token Faucet\n\n") b.WriteString("A toy points faucet. Call `Claim` to receive **") b.WriteString(strconv.FormatInt(ClaimAmount, 10)) b.WriteString(" points** — but only once every **") b.WriteString(strconv.FormatInt(CooldownBlocks, 10)) b.WriteString(" blocks** per address.\n\n") b.WriteString("## Stats\n\n") b.WriteString("- Total distributed: **") b.WriteString(strconv.FormatInt(totalDistributed, 10)) b.WriteString("** points\n") b.WriteString("- Total claims: **") b.WriteString(strconv.FormatInt(totalClaims, 10)) b.WriteString("**\n") b.WriteString("- Unique claimers: **") b.WriteString(strconv.Itoa(claimers.Size())) b.WriteString("**\n") b.WriteString("- Current block height: **") b.WriteString(strconv.FormatInt(runtime.ChainHeight(), 10)) b.WriteString("**\n\n") b.WriteString("## Claimers\n\n") if claimers.Size() == 0 { b.WriteString("_No one has claimed yet. Be the first!_\n") return b.String() } b.WriteString("| Address | Balance | Claims | Last claim (height) |\n") b.WriteString("| --- | ---: | ---: | ---: |\n") claimers.Iterate("", "", func(key string, value interface{}) bool { c := value.(*claimer) b.WriteString("| `") b.WriteString(key) b.WriteString("` | ") b.WriteString(strconv.FormatInt(c.Balance, 10)) b.WriteString(" | ") b.WriteString(strconv.FormatInt(c.Claims, 10)) b.WriteString(" | ") b.WriteString(strconv.FormatInt(c.LastClaim, 10)) b.WriteString(" |\n") return false }) return b.String() }
  6. #6gnomod.toml
  7. #7module = "gno.land/r/moul/x/daily/faucet/v0" gno = "0.9"
  8. #8/gno.MemPackageType
  9. #9 MPUserProd

Result log

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

← Back to block 26,349