Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

README.md

6.15 Kb · 131 lines

forge

An on-chain software forge, browsable in gnoweb and writable only through signed transactions. The domain model lives in gno.land/p/nym-moultest123/forge/v1; this realm is the wiring, the routes and the events.

The code itself is not here. Git objects stay in git, behind whatever mirror a repo declares. What the chain keeps is the part a forge is trusted for: which object a branch points at, in what order, on whose authority, and what was reviewed before it moved.

Routes

path page
/ every repo, with counts
/<ns>/<name> repo overview: refs, recent log, open changes and issues
/<ns>/<name>/log the full reference log, paginated with ?page=N
/<ns>/<name>/issues issues, ?page=N
/<ns>/<name>/issues/<id> one issue and its replies
/<ns>/<name>/changes change requests, ?page=N
/<ns>/<name>/changes/<id> one change, its reviews and its replies
/help what the realm is and how to call it

Every action link on those pages is a txlink into the matching function, so the whole forge is usable from gnoweb without a client.

Writing

1gnokey maketx call -pkgpath gno.land/r/nym-moultest123/forge/v0 \
2  -func CreateRepo -args "moul/forge" -args "an on-chain forge" -args "" \
3  -gas-fee 30000ugnot -gas-wanted 3000000 \
4  -broadcast -chainid <chain> -remote <rpc> <key>
1# move a branch: the fourth argument is the tip you expect to replace
2gnokey maketx call -pkgpath gno.land/r/nym-moultest123/forge/v0 \
3  -func SetRef -args "moul/forge" -args "refs/heads/main" \
4  -args "<expected-oid>" -args "<new-oid>" -args "ship it" \
5  -gas-fee 30000ugnot -gas-wanted 3000000 \
6  -broadcast -chainid <chain> -remote <rpc> <key>

A stale expectation aborts the transaction instead of overwriting the branch. A move with no expectation is ForceSetRef, needs maintainer, and is recorded as a force forever.

Arguments that would be slices are comma-separated strings (SetMirrors, OpenIssue labels): a transaction can only carry strings, so a []string parameter would not be callable from gnokey.

Reading

Read paths are free. Browse the routes above, or query:

1gnokey query vm/qeval -data 'gno.land/r/nym-moultest123/forge/v0.RefOID("moul/forge","refs/heads/main")' -remote <rpc>
2gnokey query vm/qeval -data 'gno.land/r/nym-moultest123/forge/v0.LogHead("moul/forge")' -remote <rpc>
3
4# Which repo publishes a deployed package path, and what it last released.
5gnokey query vm/qeval -data 'gno.land/r/nym-moultest123/forge/v0.PackageRepo("gno.land/r/nym-moultest123/home")' -remote <rpc>
6gnokey query vm/qeval -data 'gno.land/r/nym-moultest123/forge/v0.LatestReleaseTag("moul/forge")' -remote <rpc>

LogHead is the digest of the last log entry, committing to every entry before it. Pin it in a release note or a package manifest and the repo's whole history becomes falsifiable by anyone who can read the chain.

Namespaces

A repo id is <namespace>/<name>. The namespace is either a name the caller holds in r/sys/users or the caller's own bech32 address, checked on every CreateRepo and Fork:

  • g1.../forge works for any account with nothing to register and nothing to lose, including a realm, whose address is its namespace. That is what makes a DAO-owned repo work.
  • moul/forge requires the moul name to resolve to the caller, renames included, since the registry resolves aliases to the same record.

Nobody can claim a namespace they do not own, so there is no squatting to arbitrate and no reservation list to maintain.

Roles

reader < writer < maintainer < admin < owner. Writers move refs, maintainers force and merge, admins manage members and the merge policy, and the last owner cannot be demoted. Opening an issue or a change request needs no role at all: the author pays gas and locks the storage deposit for their own bytes, which is the spam gate.

A role can be held by another realm, because the realm resolves its caller without requiring an end user. A repo whose owner is a DAO realm is a repo whose merge button is a governance vote, which is the thing a centralized forge structurally cannot offer.

Events

Every mutation emits one: RepoCreated, RepoForked, RepoUpdated, MemberSet, RefLog, IssueOpened, IssueComment, IssueClosed, IssueReopened, IssueLabeled, ChangeOpened, ChangeUpdated, ChangeReviewed, ChangeComment, ChangeClosed, ChangeMerged. RefLog carries the sequence number and the chain digest, so an indexer can mirror the log without replaying state.

Costs

A realm write locks 100ugnot per byte, refundable when the data is deleted. A log entry is roughly 200 bytes including the digest, so a push costs about 0.02 GNOT of deposit plus gas: the reason this design anchors refs instead of storing objects. An issue with a 500-byte body is about 0.05 GNOT.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

On mainnet: deployment status transactions unique callers deployed revision

Dependency graph:

gno.land/r/nym-moultest123/forge/v0 dependency graph

⚠️ Disclaimer: provided as-is, without warranty; not security-audited. Full disclaimer: DISCLAIMER.