Transaction

3539D2DD3AF2A3…435ED06EB451

Block 26,375 · index 0 · indexed

Summary

Hash
3539D2DD3AF2A395E4D8B44E30ACE77E5D9AFE30ADC12F431A52435ED06EB451
Block
26,375
Size
8362 bytes
Gas used
13,175,684 / 15,810,880
Fee
1000000ugnot
Memo
gnopublish
Status
success

Messages

Arguments · 9

  1. #1multisig
  2. #2README.md
  3. #3# M-of-N Multisig > ⚠️ **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) --- An approval multisig realm, ported from the classic Solidity idea. A fixed set of owners is configured once with a required approval threshold. Any owner can create a proposal, owners approve it, and when the number of distinct approvals reaches the threshold the proposal is automatically marked `Executed`. This realm tracks approvals only — it does not custody or move funds. **Realm path:** `gno.land/r/REPLACE_ADDR/multisig` ## Example calls ```sh # Initialize once: 3 owners, need 2 approvals to execute. gnokey maketx call -pkgpath "gno.land/r/REPLACE_ADDR/multisig" \ -func Setup -args "g1addr1,g1addr2,g1addr3" -args 2 ... # An owner creates a proposal (returns its id, e.g. 0). gnokey maketx call -pkgpath "gno.land/r/REPLACE_ADDR/multisig" \ -func Propose -args "send funds to treasury" ... # Owners approve; the 2nd distinct approval flips it to Executed. gnokey maketx call -pkgpath "gno.land/r/REPLACE_ADDR/multisig" \ -func Approve -args 0 ... ``` Render the realm (owners, threshold, proposals with approval counts + state) by browsing to its path on gno.land. <!-- 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/multisig/v0 dependency graph](https://raw.githubusercontent.com/moul/gno-contracts/main/_assets/gno.land/r/moul/x/daily/multisig/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. #4gnomod.toml
  5. #5module = "gno.land/r/moul/x/daily/multisig/v0" gno = "0.9"
  6. #6multisig.gno
  7. #7// Package multisig implements an M-of-N approval multisig realm. // // It is a port of the classic Solidity multisig idea: a fixed set of owners // is configured once, any owner may create a proposal, owners approve it, and // once the number of distinct approvals reaches the threshold the proposal is // marked "Executed". This realm tracks approvals only — it does not move funds. package multisig import ( "errors" "strconv" "strings" "chain" "chain/runtime/unsafe" "gno.land/p/nt/avl/v0" ) // State of a single proposal. type stateKind int const ( statePending stateKind = iota stateExecuted ) func (s stateKind) String() string { if s == stateExecuted { return "Executed" } return "Pending" } // proposal is a single approval request. type proposal struct { id int description string proposer address approvals *avl.Tree // owner address string -> struct{}{}, distinct approvers state stateKind } // Package-level persistent state. var ( owners *avl.Tree // owner address string -> struct{}{} ownerCount int threshold int initialized bool proposals *avl.Tree // decimal id string -> *proposal nextID int ) var ( errAlreadyInit = errors.New("multisig: already initialized") errNotInit = errors.New("multisig: not initialized") errBadThreshold = errors.New("multisig: threshold must be between 1 and number of owners") errNoOwners = errors.New("multisig: at least one owner required") errNotOwner = errors.New("multisig: caller is not an owner") errNoProposal = errors.New("multisig: proposal not found") errDupApproval = errors.New("multisig: caller already approved this proposal") errExecuted = errors.New("multisig: proposal already executed") ) func init() { owners = avl.NewTree() proposals = avl.NewTree() } // caller returns the address of the realm/user that called into this realm. func caller() address { return unsafe.PreviousRealm().Address() } func isOwner(a address) bool { return owners.Has(a.String()) } // Setup configures the multisig exactly once. owners is a comma-separated list // of bech32 addresses; threshold is the number of approvals required to execute // a proposal. It panics (cross-realm abort) on invalid input or if already set. func Setup(cur realm, ownersCSV string, thresholdN int) { if initialized { panic(errAlreadyInit) } parts := strings.Split(ownersCSV, ",") count := 0 for _, p := range parts { a := strings.TrimSpace(p) if a == "" { continue } addr := address(a) if owners.Has(addr.String()) { continue // dedupe } owners.Set(addr.String(), struct{}{}) count++ } if count == 0 { panic(errNoOwners) } if thresholdN < 1 || thresholdN > count { panic(errBadThreshold) } ownerCount = count threshold = thresholdN initialized = true chain.Emit("Setup", "owners", strconv.Itoa(count), "threshold", strconv.Itoa(thresholdN)) } // Propose creates a new proposal authored by an owner and returns its id. func Propose(cur realm, description string) int { if !initialized { panic(errNotInit) } c := caller() if !isOwner(c) { panic(errNotOwner) } id := nextID nextID++ p := &proposal{ id: id, description: description, proposer: c, approvals: avl.NewTree(), state: statePending, } proposals.Set(strconv.Itoa(id), p) chain.Emit("Propose", "id", strconv.Itoa(id), "proposer", c.String()) return id } // Approve records an owner's approval for a proposal. When the count of distinct // approvals reaches the threshold, the proposal becomes Executed. func Approve(cur realm, id int) { if !initialized { panic(errNotInit) } c := caller() if !isOwner(c) { panic(errNotOwner) } v := proposals.Get(strconv.Itoa(id)) if v == nil { panic(errNoProposal) } p := v.(*proposal) if p.state == stateExecuted { panic(errExecuted) } if p.approvals.Has(c.String()) { panic(errDupApproval) } p.approvals.Set(c.String(), struct{}{}) chain.Emit("Approve", "id", strconv.Itoa(id), "owner", c.String(), "approvals", strconv.Itoa(p.approvals.Size())) if p.approvals.Size() >= threshold { p.state = stateExecuted chain.Emit("Executed", "id", strconv.Itoa(id)) } } // Render returns a Markdown view of the multisig configuration and proposals. func Render(path string) string { var b strings.Builder b.WriteString("# M-of-N Multisig\n\n") if !initialized { b.WriteString("_Not initialized. Call `Setup(owners, threshold)` once._\n") return b.String() } b.WriteString("**Threshold:** ") b.WriteString(strconv.Itoa(threshold)) b.WriteString(" of ") b.WriteString(strconv.Itoa(ownerCount)) b.WriteString("\n\n## Owners\n\n") owners.Iterate("", "", func(key string, _ interface{}) bool { b.WriteString("- `") b.WriteString(key) b.WriteString("`\n") return false }) b.WriteString("\n## Proposals\n\n") if proposals.Size() == 0 { b.WriteString("_No proposals yet._\n") return b.String() } b.WriteString("| ID | Description | Proposer | Approvals | State |\n") b.WriteString("|----|-------------|----------|-----------|-------|\n") proposals.Iterate("", "", func(_ string, v interface{}) bool { p := v.(*proposal) b.WriteString("| ") b.WriteString(strconv.Itoa(p.id)) b.WriteString(" | ") b.WriteString(p.description) b.WriteString(" | `") b.WriteString(p.proposer.String()) b.WriteString("` | ") b.WriteString(strconv.Itoa(p.approvals.Size())) b.WriteString("/") b.WriteString(strconv.Itoa(threshold)) b.WriteString(" | ") b.WriteString(p.state.String()) b.WriteString(" |\n") return false }) return b.String() }
  8. #8/gno.MemPackageType
  9. #9 MPUserProd

Result log

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

← Back to block 26,375