Transaction

DF6A3C54F085BE…C777734E290F

Block 25,994 · index 0 · indexed

Summary

Hash
DF6A3C54F085BE64F9BEB46017D81227C88C61E877C44E92D3E6C777734E290F
Block
25,994
Size
6401 bytes
Gas used
10,832,276 / 12,998,791
Fee
1000000ugnot
Memo
gnopublish
Status
success

Messages

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

Arguments · 9

  1. #1blog
  2. #2README.md
  3. #3# Personal Blog > ⚠️ **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 multi-author on-chain blog realm for gno.land. Anyone can publish a post; each post records its author (the calling address) and the block height at which it was published. Posts are stored persistently and rendered newest-first, with a dedicated page for each post's full text. **Realm path:** `gno.land/r/REPLACE_ADDR/blog` ## Example calls Publish a post (state-mutating, crossing function): ``` gnokey maketx call -pkgpath "gno.land/r/REPLACE_ADDR/blog" \ -func Publish -args "My first post" -args "Hello, gno.land!" \ -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid sapphire-1 KEY ``` Read views (no transaction needed): - Root — list all posts, newest first: render `gno.land/r/REPLACE_ADDR/blog` - Single post by id: render `gno.land/r/REPLACE_ADDR/blog:/0` `PostCount()` returns the total number of published posts. <!-- 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/blog/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/r/moul/x/daily/blog/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. #4blog.gno
  5. #5// Package blog is a multi-author on-chain blog realm for gno.land. // // Any caller can Publish a post; posts are stored persistently and rendered // newest-first. Each post records its author (the calling address) and the // block height at which it was published. package blog import ( "strconv" "strings" "chain" "chain/runtime" "chain/runtime/unsafe" "gno.land/p/nt/avl/v0" ) // Post is a single blog entry. type Post struct { ID int Title string Body string Author address Height int64 } // posts holds every published post keyed by its zero-padded id (for // deterministic ordering) and nextID is the id assigned to the next post. var ( posts avl.Tree // key: zero-padded id string -> *Post nextID int ) // key returns a fixed-width, zero-padded key so avl.Tree iteration is ordered // by numeric id (and thus by publication order). func key(id int) string { s := strconv.Itoa(id) for len(s) < 12 { s = "0" + s } return s } // Publish creates a new post authored by the caller and returns its id. // It is a state-mutating exported function, so it takes `cur realm`. func Publish(cur realm, title string, body string) int { title = strings.TrimSpace(title) body = strings.TrimSpace(body) if title == "" { panic("blog: title must not be empty") } if body == "" { panic("blog: body must not be empty") } id := nextID nextID++ p := &Post{ ID: id, Title: title, Body: body, Author: unsafe.PreviousRealm().Address(), Height: runtime.ChainHeight(), } posts.Set(key(id), p) chain.Emit( "PostPublished", "id", strconv.Itoa(id), "author", p.Author.String(), ) return id } // PostCount returns the number of published posts. func PostCount() int { return posts.Size() } // snippet returns a short one-line preview of the body. func snippet(body string) string { // collapse newlines so the preview stays on a single markdown line s := strings.ReplaceAll(body, "\n", " ") s = strings.TrimSpace(s) const max = 140 if len(s) > max { return s[:max] + "…" } return s } // Render lists all posts newest-first at the root, or a single post's full // text at path "/<id>". Render is NOT a crossing function. func Render(path string) string { path = strings.TrimSpace(path) if path == "" || path == "/" { return renderList() } idStr := strings.TrimPrefix(path, "/") id, err := strconv.Atoi(idStr) if err != nil { return "# Not found\n\nInvalid post path: `" + path + "`\n\n[← back](/r/REPLACE_ADDR/blog)\n" } v := posts.Get(key(id)) if v == nil { return "# Not found\n\nNo post with id " + idStr + ".\n\n[← back](/r/REPLACE_ADDR/blog)\n" } return renderPost(v.(*Post)) } func renderList() string { var b strings.Builder b.WriteString("# 📝 Blog\n\n") if posts.Size() == 0 { b.WriteString("_No posts yet. Be the first to `Publish`._\n") return b.String() } b.WriteString(strconv.Itoa(posts.Size()) + " post(s), newest first.\n\n") // avl iterates ascending; iterate in reverse for newest-first. posts.ReverseIterate("", "", func(_ string, v interface{}) bool { p := v.(*Post) b.WriteString("## [") b.WriteString(p.Title) b.WriteString("](/r/REPLACE_ADDR/blog:/") b.WriteString(strconv.Itoa(p.ID)) b.WriteString(")\n\n") b.WriteString("by `") b.WriteString(p.Author.String()) b.WriteString("` · height ") b.WriteString(strconv.FormatInt(p.Height, 10)) b.WriteString("\n\n") b.WriteString(snippet(p.Body)) b.WriteString("\n\n---\n\n") return false }) return b.String() } func renderPost(p *Post) string { var b strings.Builder b.WriteString("# ") b.WriteString(p.Title) b.WriteString("\n\n") b.WriteString("by `") b.WriteString(p.Author.String()) b.WriteString("` · height ") b.WriteString(strconv.FormatInt(p.Height, 10)) b.WriteString("\n\n") b.WriteString(p.Body) b.WriteString("\n\n---\n\n[← back to all posts](/r/REPLACE_ADDR/blog)\n") return b.String() }
  6. #6gnomod.toml
  7. #7module = "gno.land/r/moul/x/daily/blog/v0" gno = "0.9"
  8. #8/gno.MemPackageType
  9. #9 MPUserProd

Result log

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

← Back to block 25,994