New
Ask AI
New constructs an empty Book owned by admin, with explicit limits.
Command
gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/p/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/permbook.New(,)"
Result
Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.
Package permbook is a bounded, authorization-carrying facade over gno.land/p/nt/groups/v0. It lets a realm define named permissions, grant them to addresses, revoke them, and ask "does this address currently hold this permission" without iterating anything.
It holds no coins, imports no banker, stores no callbacks, and owns no package-level state. The importing realm allocates a *Book and keeps it private.
It adds exactly four things to groups, and deliberately nothing else:
Everything else — the B+-tree registry, the member sets, ordered iteration, the readonly views — comes from groups. This package writes no data-structure code.
Has costs two independent B+-tree descents: O(log P) to find the permission, O(log H) to find the holder. It is NOT a function of how many permissions `who` already holds. That matters: every other named-permission implementation surveyed answers this by iterating the subject's permissions, which makes the most-privileged address the most expensive to check — the wrong asymptotic for an authorization check on a hot path.
Mutators take (_ int, rlm realm) and identify the principal as rlm.Previous().Address(), after asserting rlm.IsCurrent(). The consuming realm threads its own cur:
1func Grant(cur realm, perm string, addr address) {
2 if err := book.Grant(0, cur, perm, addr); err != nil {
3 panic(err)
4 }
5}
IsCurrent() rejects a stale or stashed realm value, so a hostile realm cannot replay an old cur to impersonate the admin. This is the same shape as p/nt/ownable/v0 and p/nt/ownable/v0/exts/authorizable.
A permission comes into existence on its first grant and ceases to exist when its last holder is revoked. There is no create step and no reserved name. Has returns false either way, so the distinction is invisible to a caller and the book does not accumulate empty buckets.
1(absent) ──Grant──> held by 1..MaxHoldersPerPermission ──Revoke last──> (absent)
2 │
3 └── DropPermission ──> (absent)
NominateAdmin records a nominee; only AcceptAdmin, called by that nominee, moves the admin. A one-step transfer to a well-formed-but-unowned address is permanently fatal — address.IsValid only checks bech32 form, so a mistyped address passes validation and leaves a book nobody can ever grant or revoke on again. This is the Y4 finding from the audit of Cosmic Bull's own r/permission_registry, carried forward.
THREAD A LIVE cur. rlm.IsCurrent() proves the realm value came from a live crossing frame, and rlm.Previous().Address() is then the principal that crossed into your realm. A consumer that wraps a permbook mutator in a NON-crossing exported helper resolves its importer's caller instead of its importer — Class-2 designation forgery, in the consumer. Call permbook mutators from your own crossing entrypoints, passing that entrypoint's own cur.
DO NOT LEAK THE *Book. No method here returns a mutable handle, but a consumer that exports its *Book — or returns it from a function reachable by another realm — hands out every mutator on it, and borrow rule #2 commits those writes under YOUR realm's authority. Keep it in an unexported package-level variable.
Has ANSWERS ABOUT AN ADDRESS, NOT ABOUT YOUR CALLER. It performs no authentication. Derive the address from your own crossing entrypoint's cur.Previous().Address() and pass it in.
CHOOSE LIMITS DELIBERATELY. They are fixed for the life of a Book. A consumer that needs different bounds later must allocate a second Book; nothing here migrates state between them.
A groups.Group carries a base address set alongside its named roles. This package never writes to it, so it is provably empty for any Book, and "in the base set" can never mean "holds a permission".
New constructs an empty Book owned by admin, with explicit limits.
gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/p/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/permbook.New(,)"
NewDefault constructs an empty Book owned by admin, with DefaultLimits.
gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/p/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/permbook.NewDefault()"
DefaultLimits returns the limits used by NewDefault.
gnokey query vm/qeval -remote "https://rpc.gno.land" -data "gno.land/p/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/permbook.DefaultLimits()"