Build with Cosmic Bull
The reusable packages are live, verified and importable by anyone. This page walks the whole journey: an objective, the packages that fit it, when not to use them, the exact imports, real minimal examples, and how to verify every claim against the chain before you depend on it.
1. Start from an objective
The worked example on this page: build a Gno application that accepts payments, tracks bounded fees, and holds a scheduled obligation. Swap in your own objective; the journey is the same.
2. Discover the packages
Four reusable /p/ primitives are live on pearl-1. For this objective: coinio (accepting and paying out coins, safely), feeledger (balances and bounded fees, with a conservation contract), and duebook (scheduled obligations with exactly-once claims).
coinio
value-handling
Native-coin I/O for realms: the Receive receipt-guard trio (caller shape, envelope, denomination), Payout via RealmSend, reserve-protected Sweep, and HeldAt.
used by 6 live realms
duebook
scheduling
Deferred-action scheduling. Claim is consume-then-act over never-reused IDs, so at most one Claim per ID can succeed across all transactions. No closure or capability crosses a realm boundary.
used by 1 live realm
feeledger
accounting
Per-account balance ledger with an explicit basis-point fee pot; error-pure and overflow-checked. Conservation contract: held == UsersTotal + FeesAccrued + surplus.
used by 8 live realms
permbook
access-control
Named permissions granted to and revoked from addresses, O(log P + log H) membership. Each consumer allocates its own Book with its own Limits, so capacity contention across applications is structurally impossible.
used by 1 live realm
Machine-readable versions of everything on this site, for tooling: data/portfolio.json (the verified manifest: paths, provenance, dependencies, consumers, limitations) and api/ (the chain-derived API reference, one Markdown file per package). Both are verbatim copies of the artifacts this site is generated from.
3. Decide when — and when not — to use them
curated Each package page carries a curated summary and its known limitations; read both before composing. The one-line cautions:
- duebook — One consumer on chain (duebook_demo); its reusability is a design argument, not a demonstrated fact.
- feeledger — The unexported-*Ledger-pointer consumer rule is documented in the catalog but not in-package; the deployed copy is frozen.
- permbook — One consumer on chain (permbook_demo); its reusability is a design argument, not a demonstrated fact.
When not to use them: if you need upgradeable logic (deployed bytes are immutable), non-ugnot assets beyond what coinio's denom parameter covers, or push-based payouts (everything here is pull/claim by design).
4. Import them
On gno.land the import path is the deployed address; there is no package manager and nothing to pin — the bytes at these paths can never change.
import "gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio"
import "gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/duebook"
import "gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger"Declare each in your gnomod.toml module as usual.
5. Read the APIs
gnoweb's $help shows only top-level functions of a /p/ package — for these packages that hides most of the surface (types and methods). The full chain-derived API is on each package page here, coinio, duebook, feeledger, permbook, and as raw Markdown under api/.
6. Start from a real minimal example
These three live realms are the canonical minimal consumers — each exists precisely to demonstrate one primitive composed for real, and each was deployed, byte-verified and attacked on chain:
| coindemo | the smallest real coinio + feeledger composition: an echo-vault that receives, credits, and pays back out | source |
| duebook_demo | a persistent duebook Book driven by real transactions: schedule, claim-exactly-once, expire | source |
| permbook_demo | a permbook permission gate proven to open and close across blocks, with holder-vs-admin authority separation | source |
For a full-scale composition, read subscriptions — plans, windowed renewals and fee handling over the same two value primitives.
7. Call a live realm
Realms are driven from the command line, and you do not need to hand-write the transaction: gnoweb generates the exact command for any exported function, with the argument names filled in — the call builder for service_registry.AcceptOwnership. It looks like this:
gnokey maketx call \
-pkgpath gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/service_registry \
-func AcceptOwnership \
-gas-fee 1000000ugnot -gas-wanted 2000000 \
-remote https://rpc.pearl.testnets.gno.land:443 \
-chainid pearl-1 \
<your-key>Read-only views cost nothing to inspect; every package page links the rendered page and the state explorer. If you are integrating against a realm that moves value, read its known limitations and the linked deployment record first — those record what was not verified on chain, which is usually the part that matters.
8. Verify before you depend
Every package page carries the digest of the deployed bytes and the command that fetches them from the chain — proof that needs no trust in this site. For coinio:
curl -sS 'https://pearl.testnets.gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio$download&file=coinio.gno' | shasum -a 256Expect ea9d467d380ff2971695d452f96fe64ea46d847d094023f755edf5f79995b09d (5,685 bytes). The same check works for every package, with its own digest on its page.
9. Compose your application
The pattern every live consumer follows: guard the payment at the door, account for it in the ledger, record the obligation, and pay out only by pull. In outline:
// A sketch of the composition -- the demo realms above are the
// full, deployed, attacked pattern. Receive guards the payment,
// the ledger holds balances and the bounded fee, the book holds
// the scheduled obligation.
var (
ledger = feeledger.MustNew(maxFeeBps) // hard fee cap, forever
book = duebook.MustNew(minDelay, maxDelay, maxOpen)
)
func Pay(cur realm) {
payer, amount := coinio.Receive(0, cur, "ugnot")
ledger.MustDeposit(payer.String(), amount, feeBps)
book.MustSchedule(payer.String(), payload,
runtime.ChainHeight(), delay, ttl)
}
func Claim(cur realm, amount int64) {
caller := cur.Previous().Address()
if err := ledger.Withdraw(caller.String(), amount); err != nil {
panic(err)
}
coinio.Payout(0, cur, caller, "ugnot", amount)
}From here, the Verification page explains exactly what has been proved about everything you just imported — and what has not.