Cosmic Bull

Rendered from catalog/applications.md at commit f191063fd89d in the project repository. The committed file is the source of truth; this page is a rendering of it.

Application catalog

The five applications completed through the GitHub → Pearl pipeline.

All deployed on pearl-1, under the namespace gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/…, signed by the agent key g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3.

None of the five holds funds. All reject coins attached by a user call, none imports chain/banker, and every realm address is exists:false / coins "0".


Summary

#ApplicationCategoryDeployed SHAHeightFindings resolved
1fee_splitRevenue & value flow819239a5968030 RED / 3 YELLOW
2timelock_guardianSecurity / delayed executionbb05e646022130 RED / 0 YELLOW at final round (6 fixed in round 1)
3upgrade_registryUpgrade tracking2d5a7486028760 RED / 5 YELLOW
4permission_registryAccess controle3d6aea6046151 RED / 6 YELLOW
5service_registryDiscovery3c598d26055461 RED / 7 YELLOW

1 — fee_split

Repositoryhttps://github.com/SillyZir/fee_split
Deployed SHA819239ad5ddc46cf685f5ff363cabb7290848c1f
CategoryRevenue & value flow
Realm pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/fee_split
Realm addressg12v97h3jexeacya6r4pkrm722axgahet25e6lms
Deployment tx061c89b1fd34f696396a2ee4e0b39dc7a808cdb0e5916763d39a7afe80c43c16
Height596803
Recordpearl/DEPLOYMENT.md §7
Remediation layerpearl/r/feesplit/FIXES.md

Architecture. Named splits, each with recipients holding basis-point shares. Deposits are split per the shares at deposit time; recipients claim their accrued balance. A protocol fee switch defaults to zero and is immutably capped at 1%, with the fee snapshotted at deposit so an admin cannot retroactively re-price a deposit. Lifecycle: active → frozen → archived, with both value paths refusing an archived split.

Reused primitives. None — stdlib only. The upstream application is self-contained, and adding dependencies would have changed it rather than ported it.

Discovery classification. 626 packages enumerated on pearl-1. splitpayment (string-identity, no custody) and moul/splitter/v1 (accounting-only) — both RELATED IMPLEMENTATION, neither suitable. No exact duplicate found in the searched sources.

Live verification — PASS. CreateSplit (hunter/keeper 7000/3000); deposit at 0 bps with bank 100000 == 70000+30000+0 exact; claim with the recipient's balance delta matching exactly; SetFee(100bps); deposit at 100 bps with bank 80000 == 34650+44850+500 exact. Full drain to bank "0". Lifecycle proven: Freeze → deposit rejected "split is frozen"; Archive → deposit rejected "split is archived: split_1".

Adversarial — 6 rejections live: non-admin SetFee; non-recipient Claim; stray-send Claim; SetFee(101) over the cap; non-admin UpdateShares; coinless Deposit.

Invariants. Per-split sum(balances) + TotalClaimed == TotalDeposited held at every checkpoint (149500 == 0 + 149500 final). Realm-level bank == Σ claimables + feesAccrued verified against auth/accounts at three checkpoints, all exact.

Source provenance. The only application in the series where the deployed bytes are not byte-identical to the GitHub file. Transformation was T1 + T2: namespace rewrite plus a mechanical API-era port (chain/runtime.*chain/runtime/unsafe, NewBanker(bt)NewBanker(bt, cur), test-side crosscross(cur) and 3-arg → 4-arg uassert). Every substitution is occurrence-pinned in pearl/r/feesplit/port.py. The deployed bytes were verified byte-identical to a re-run of port.py over the GitHub commit, and to the workspace commit.

Limitations.


2 — timelock_guardian

Repositoryhttps://github.com/SillyZir/timelock_guardian
Deployed SHAbb05e64898967125b900a9275ca84229bff5e007 (= current HEAD)
CategorySecurity / delayed execution
Realm pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/timelock_guardian
Realm addressg1w06mqv4h53vtfgfeyz2eglplpwfpytcqqqjwkh
Deployment tx6db3f74c764523f8ea1d82f7cd419639a8bb597494b170a8d2ea56bc8779efbb
Height602213
Recordpearl/DEPLOYMENT.md §8
Remediation layerpearl/r/timelock_guardian/FIXES.md

Architecture. Targets, each with an owner and a guardian and a minimum delay. The owner schedules actions with a delay at or above the target's minimum; anyone may execute once the delay elapses (permissionless execution, so liveness does not depend on the owner); the guardian may veto; the owner may cancel. An action has a ready window and a 30-day grace period, after which anyone may Expire it. Two-step target ownership transfer.

Reused primitives. None — stdlib only.

Discovery classification. Performed; no committed DISCOVERY.md (the format was established at #5).

Live verification — PASS. RegisterTarget (owner=default, guardian=keeper, min 60s); schedule with execute-too-early rejected ("too early: 50s remaining" — integer seconds, a round-1 fix visible live); execution by hunter, proving the anyone-executes property; double-execute rejected; guardian veto with reap proven ("action not found"); owner cancel; two-step ownership with a wrong-acceptor rejected, and the original creator rejected from Schedule after transfer.

HTML-injection probe (Y3 escalation check). An action carrying <script> / <img onerror> / [link] payloads was scheduled live, then the rendered output was inspected through both the render API and raw gnoweb HTML: fully neutralized to (script)alert(1)(/script)…, with zero raw hostile tags in the served page. Y3 settled SAFE on live evidence.

Adversarial — 8 rejections live: foreign Schedule; foreign Cancel; non-guardian Veto; duplicate register; sub-floor minDelay; below-target-min delay; guardian-strip while pending; coin-attached Schedule ("this realm does not accept coins").

Invariants. Realm address exists:false / coins "0" at every checkpoint. Every abort message byte-matched the audited source.

Source provenance. T1 (gnomod-only) — the deployed .gno is byte-identical to the GitHub commit. Verified against the workspace and a fresh clone. 50/50 tests, lint clean, three audit rounds ending 0 RED / 0 YELLOW.

Limitations.


3 — upgrade_registry

Repositoryhttps://github.com/SillyZir/upgrade_registry
Deployed SHA2d5a74870b08d70ff8e56e6e1efbace1803dd3bd (= current HEAD; base 9d22f7f)
CategoryUpgrade tracking
Realm pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upgrade_registry
Realm addressg1g453tcmapqn6hj9zlydfz3mt3vxh8gq5vwv8sg
Deployment tx532be90ab90521b0d6d4b3f983ede9dd315c8975cf30ad5c8984837f4d57e34d
Height602876
Recordpearl/DEPLOYMENT.md §9
Remediation layerpearl/r/upgrade_registry/FIXES.md

Architecture. Contract entries keyed by address, registered self-provingly — Register records the caller's own address as the proof of control — with an owner nomination that the nominee must accept. Deprecate(old, new) records a successor, gated by a successor-consent check: the successor entry must be owned by the caller, so provenance cannot be forged. GetLatest walks the migration chain to its end; GetMigrationChain renders it with [deprecated] tags.

Reused primitives. None — stdlib only.

Discovery classification. Performed; no committed DISCOVERY.md. Later classified from the other side: service_registry's discovery record grades this realm COSMIC BULL EXISTING PRIMITIVE — complementary, not overlapping (address-keyed migration chains vs name-keyed path resolution; the two compose, neither subsumes).

Live verification — PASS. Register demo_vault_v1 by hunter and demo_vault_v2 by keeper, both nominating default; AcceptOwnership on both by default; Deprecate v1 → v2. Reads confirmed: GetLatest(v1) == v2, GetMigrationChain correct with the [deprecated] tag, GetInfo correct, GetOwnerContracts(default) returning both entries, and Render showing v2 Active / v1 Deprecated with successor.

Adversarial — 8 rejections live: pre-acceptance Deprecate; successor-consent forgery ("successor entry is not owned by the caller"); wrong-acceptor AcceptOwnership; self successor; unregistered successor; duplicate Register; invalid name; coin-attached Register.

Invariants. Realm address exists:false / coins "0" at every checkpoint.

Source provenance. T1 (gnomod-only) — deployed .gno byte-identical to the GitHub commit, verified against workspace and fresh clone. Pipeline: mechanical port (19/19) → audit (0 RED / 5 YELLOW) → remediation (all 5 fixed, 8 gap tests added → 27/27, verification audit 0R/0Y) → push → fresh-clone verification (27/27 from GitHub bytes) → deploy.

Limitations.


4 — permission_registry

Repositoryhttps://github.com/SillyZir/permission_registry
Deployed SHAe3d6aeaf3571ec35c2af68c5fbb756480b76ed03 (= current HEAD; base facb9f0)
CategoryAccess control
Realm pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/permission_registry
Realm addressg1x9tatmqcdlas2w6k724mrs2zcgh3awf3s5wkhk
Deployment txa30c09427173a45553a9befcac38d410aa0e416eb785145942ee5378d6a8c54f
Height604615
Source sha256603fec571a55d051353e101c64c0490a5268124abda8d88ac703b9bbf26fb763 (18070 B)
Recordpearl/DEPLOYMENT.md §10
Remediation layerpearl/r/permission_registry/FIXES.md

Architecture. A multi-tenant ACL: resource → permission → holder. Each resource has an admin (the creator); the admin grants and revokes named permissions to addresses; Has(resource, permission, holder) is the read that consumer realms call. Two-step admin transfer with nominee consent. Emptied permissions are pruned from the permission list. Deleted resource names enter a 90-day reservation that preserves the original creator's reclaim right.

Reused primitives. None — stdlib only.

Discovery classification. Performed; no committed DISCOVERY.md. Later classified from service_registry's record as COSMIC BULL EXISTING PRIMITIVE — pattern source, not dependency: no shared state, but its six audited remediation shapes became the template for #5.

Findings — 1 RED / 6 YELLOW, all resolved.

#FindingResolution
R1Namespace monopolizationMaxResourcesPerAdmin = 20 + O(1) adminResources counter; MaxResources 200 → 1000
Y1Latent Class-2 caller identityall 8 entrypoints take cur realm; caller() helper deleted
Y3Unbounded Renderbounded to 20 resources / 8 permissions
Y4One-step TransferAdmin bricks a resourcetwo-step with nominee consent + cancel; quota checked at consent
Y5No stray-send guardrejectStraySend(cur) on all 8 entrypoints
Y6Declared bounds with no test coveragecap tests added, including that pruning an emptied permission frees a slot
Y7Undocumented integrator contract on Hasexplicit INTEGRATOR CONTRACT block

Assessed and NOT changed: expired-tombstone growth, graded INFORMATIONAL with reasoning recorded — retired is never iterated, and the cost falls on the caller's own storage deposit. It was not downgraded to reach deployment.

Live verification — PASS. CreateResource with GetAdmin == default (proving cur.Previous().Address() live); Grant writer → hunter with Has(…)==true and Has(… keeper)==false; two-step admin transfer to keeper with the nomination proven inert (GetAdmin still default, GetPendingAdmin == keeper) then accepted, with the pre-existing grant surviving the handoff; a squat/reclaim sequence proving the creator's reclaim right survives a refused squat attempt; Revoke leaving GetPermissions == "none" and Render showing "No permissions defined" — live proof that the emptied permission was pruned.

Adversarial — 7 rejections live: non-admin Grant / DeleteResource / TransferAdmin by a permission holder (holding a permission confers no admin rights); consent forgery by a non-nominee; former admin Grant after handoff (authority moved, not copied — and the deployer holds no residual privilege); coin-attached CreateResource; markdown-injection resource name evil|](http://x)` rejected by the charset rule.

Invariants. Realm address exists:false / coins "0" at every checkpoint, including after the stray-send attempt. Siblings re-read and unchanged.

Source provenance. T1 (gnomod-only) — deployed .gno byte-identical to the GitHub commit. port.py is neutered (sys.exit): it pre-dates the remediation layer and re-running it would silently revert the fixes.

Limitations.


5 — service_registry

Repositoryhttps://github.com/SillyZir/service_registry
Deployed SHA3c598d2e68f31bcd9697fc702f2f78703c4988c7 (= current HEAD; base 8f77853)
CategoryDiscovery
Realm pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/service_registry
Realm addressg1hv2mj29cyr2z94358m5fakj2g87zaf4yhrqud2
Deployment tx60fc44a47fb8c38ca117609076d13b2dc1e75c407b1d70a70830fecf1fae30ba
Height605546
Source sha256ead72c9ea14a6358a1d259177483e91a4f048f1a85050a803c3828d0531ee996 (19781 B)
Costgas_used 33,712,081 · fee 101,138 ugnot · 3,053,000 ugnot refundable storage escrow
Recordpearl/DEPLOYMENT.md §11
Remediation layerpearl/r/service_registry/FIXES.md
Discovery recordDISCOVERY.md, committed in the application repository

Architecture. A global name → package-path directory. A name maps to one service record: owner, gno package path, type, description, metadata. Resolve(name) returns the path (aborting if absent); TryResolve is the non-panicking variant a consumer realm needs to avoid bricking itself inline. Ownership moves by two-step nominate/accept with cancel, with the per-owner quota checked at consent. Deregistration puts the name into a 90-day reservation held for the original registrant. Bounds: MaxServices = 1000, MaxServicesPerOwner = 20, MaxRenderServices = 25.

Reused primitives. gno.land/p/nt/markdown/sanitize/v0 — adopted as the Y5 security fix, replacing a hand-rolled four-substitution sanitizer. The on-chain copy was verified live before deployment against the local GNOROOT copy the tests compiled against.

Discovery classification. The first application to ship a committed DISCOVERY.md. Pearl-1 enumerated exhaustively (680 paths); 12 related implementations found and individually classified. Highlights:

ImplementationClassificationDecision
r/docs/registryRELATED — closest matchNot reused: keys owner:name, so a global Resolve("name") is not expressible; Endpoint is unvalidated free text; quarantined and not on pearl-1
r/demo/defi/grc20regRELATEDNot reused (GRC20-specific). Its self-proving registration was adopted as the benchmark this application is audited against — the gap became finding Y6 rather than being glossed over
ns* suite (7 realms, 34 paths)RELATED — largest neighborNot reused: resolves name → owner+profile, not name → package path; writes gated by a third party's assertIsTrustedLogic with external admin/recovery/guardian keys; paid expiring NFT namespace vs free permanent directory. Recorded as the honest answer to "does a name service already exist on pearl-1": yes, and it is substantial — it answers a different question.
r/sys/names, r/sys/usersRELATED (system layer)Not reused, and deliberately not depended on. Noted for the audit: passing this realm's pkgpath validation grants nothing on-chain
r/g1mjc0v90…/name_serviceRELATED (name collision)Not reused — Register(name, owner string) is the designation-forgery shape
r/samcrew/agent_registry_v2RELATEDNot reused (off-chain endpoints, payments, reviews). Its MaxAgentsPerCreator and ReviewRenderMax are independent ecosystem confirmation of the two bounds added in #4
p/nt/markdown/sanitize/v0REUSABLE EXISTING PRIMITIVEREUSED

Also recorded, for completeness and not treated as prior art: a GitHub repository of the same name whose first three commits are authored by SillyZir with identical commit messages — a detached copy of this application's own lineage, not an independent implementation.

Findings — 1 RED / 7 YELLOW, all resolved.

#FindingResolution
R1Namespace monopolizationMaxServicesPerOwner = 20 + O(1) zero-free ownerServices index
Y1Latent Class-2 caller identityall 6 entrypoints take cur realm; caller() helper deleted
Y2No stray-send guardrejectStraySend(cur) first statement of all 6 entrypoints
Y3Unbounded Render25 rows + explicit truncation notice
Y4One-step TransferOwnership bricks an entry — and since a bricked entry can never be deregistered, permanently holes the nametwo-step nominate/accept + cancel; quota checked at consent
Y5Hand-rolled sanitizer permits markdown link/image phishingadopted p/nt/markdown/sanitize/v0
Y6pkgPath is an unverified claim, no integrator contractsee below
Y7Silent repointing unobservableServiceUpdated now carries oldpkgpath and pkgpath

The Y6 scope refusal — on the record

Y6 was not taken to its maximal fix, deliberately. Requiring self-proving registration (as grc20reg does) would mean only realms — never their human operators — could ever register a name. That is a fundamentally different application, and therefore a hard-boundary stop, not a routine in-scope fix.

Shipped instead, proportionate: a three-point INTEGRATOR CONTRACT carried verbatim on Resolve, in SPEC.md, and in README.mdattestation-not-proof / name-is-not-authorization / target-can-change — plus the Y7 event change that makes a repoint observable.

A reviewer may disagree with this call. The reasoning and the alternative are both written down so they can disagree on evidence.

Live verification — PASS. Empty-state reads clean (ServiceCount() == (0, 1000), Render == "No services registered."). RegisterService fee_split with owner derived from cur.Previous().Address(); description rendered pull\-based and metadata basis\_points, proving the on-chain sanitizer resolves and escapes live; OwnerServiceCount(default) == (1, 20). Two-step handoff default → keeper with the nomination proven inert, then accepted — and the quota index moving atomically and zero-free (the default key deleted, not left at 0). Return handoff keeper → default proving the two-step path in both directions and cleaning up the live test artifact. Final live state: 1 entry, fee_split, owned by default, no nomination pending.

Adversarial — 9 rejections live: coin-attached RegisterService (on an otherwise-valid call, so the coin guard was the only possible cause); pkgpath traversal gno.land/r/demo/../../evil; uppercase name; duplicate name; self-nomination; accept with no nomination open; consent forgery by a non-nominee; hostile repoint by a non-owner; and — after the handoff — UpdateService and Deregister by the former owner who is also the original deployer, both refused. Authority moved, it did not copy, and the deployer holds no residual privilege over an entry it created. Read-path: Resolve("does_not_exist") aborts while TryResolve returns ("", false).

Invariants. Realm address exists:false / coins "0" after the stray-send attempt and all writes; deployed bytes import no chain/banker. Siblings untouched — [addpkg] heights re-read unchanged (596803 / 602213 / 602876 / 604615). Namespace went 13 → 14 packages: exactly one added.

Source provenance. T1 (gnomod-only) — deployed .gno byte-identical to the GitHub commit. Port fidelity re-verified independently of port.py by a fresh script reading the upstream bytes directly: all eight substitution counts pinned exactly (1, 1, 1, 12, 44, 10, 11, 2) with 0 OriginCaller occurrences upstream. The mechanical port was green 21/21 before remediation, so every later failure is attributable to the remediation layer alone; 31/31 after. port.py neutered (sys.exit, exit code 1 verified).

The deploy payload was built from a fresh clone, cmp-verified against the pearl tree, and the addpkg body string was round-tripped through a file and cmp'd before broadcast to prove the transcription was byte-exact. On-chain file list is exactly [gnomod.toml, service_registry.gno] — no test file leaked.

Limitations.


Two test-authoring bugs, recorded as reusable knowledge

Found during #5, applicable to any Gno test suite:

  1. testing.SetRealm is FRAME-SCOPED — an identity set inside a helper does not survive that helper's return. This silently ran a quota test as the empty address.
  2. sanitize.InlineText escapes . — so a hostname never appears verbatim in rendered output, and assertions pinned against raw text fail.

Both are in docs/TOOLCHAIN.md.


subscriptions — multi-provider subscription hub

Live: gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/subscriptions — deploy tx 60c23cd2d863e0e49553f936c6efcc52b62aa4b50f452b5feea4768528fd0cad, height 639086, realm address g1fpqpq59lgy57w6083ryd56utc4ksvdhw38lezl (chain-confirmed via Address()). Application-factory build #5, objective: provider-created plans, per-period subscriber payment, tracked state and billing periods, cancellation, and structural prevention of unauthorized, duplicate and out-of-window payments, with obligations explicit on chain and deterministic renewal/expiration/cancellation rules.

Shape. One realm composing coinio + feeledger (strategy 1 reuse; the new code is the plan/subscription state machine and the window arithmetic). Entitlement is height < paidThrough, status-independent; the renewal window is [paidThrough − period, paidThrough + period) with extension always from paidThrough; renewable and expirable heights partition exactly; Cancel is terminal and refund-free with paid entitlement honored (audit Y1's latestByKey fix makes EntitledFor — the one-call integration surface — honor that across cancellation). Payments settle instantly: H == U + F, no escrow. Fee architecture is the house pattern (10% compile-time cap, plan-creation snapshot under provider consent), deployed at 0 bps.

Verification. 22 unit tests; two-round fresh-context audit (0 RED, 2 YELLOW both fixed and verified RESOLVED); Gates A and B EQUIVALENT (closure digest f440a3b3…, same dependency set as service_market); custody byte-identical (sha256 61192802…); 11 live transactions across 2 keys including two grace renewals, a permissionless expire by a non-subscriber, and a full drain to exactly 0; 15 live adversarial rejections. The fee path's success legs ran only in tests — the live run stayed at 0 bps after a harness permission denial, recorded in DEPLOYMENT.md §17 with the other untested-live cases and their covering tests.