Cosmic Bull

Realm on pearl-1

upkeep

gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upkeep

realmfactory-applicationautomation-incentives

RenderedSourceCall builderState

curated

Keeper-incentive realm: a funder-financed reward pot pays whoever triggers a permissionless maintenance valve through it. PokeExpire cross-calls the live subscriptions.Expire and PokeExecute the live timelock_guardian.Execute -- genuine realm-to-realm crossing calls; the reward is credited only when the downstream realm accepts the valve call in the same transaction. Rewards are admin-set under a compile-time 20000ugnot cap, pull-claimed via feeledger. Factory benchmark #6 (realm-to-realm composition).

Identity

Import pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upkeep
Kindrealm (/r/)
Chainpearl-1
Namespaceg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Realm addressg147epwr4mlp7h5cg2hktssvfnln8arrzxvmpxng confirmed against the realm itself

Provenance

chain-attested
Deployed at height659,854
Deploy transaction3f21f1214810e832d853813b7a13ef27388a36ded84bba92c7211b9ecc606f74 look it up on the RPC
Deployerg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Gas used32,135,297
Storage28,629 bytes, deposit 2862900ugnot
Files on chaingnomod.toml upkeep.gno
Deployed bytesupkeep.gno — 14,955 bytes
sha256eb6f1cdd5b9ee85ae93e1ba66381736a5d23163ccc08d5508c58045c5060ed44

Do not take the hash above on trust. $download returns the bytes pearl-1 is actually running; this command fetches them and prints their digest, which should equal the one in the table:

curl -sS 'https://pearl.testnets.gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/upkeep$download&file=upkeep.gno' | shasum -a 256

Expected: eb6f1cdd5b9ee85ae93e1ba66381736a5d23163ccc08d5508c58045c5060ed44 — 14,955 bytes. This was checked for all 23 packages while building this site's architecture record; every one matched. Use curl: pearl's edge answers Python's default user-agent with HTTP 403.

API

chain-derived 17 exported functions.

Every function below deep-links to gnoweb's call builder, which generates a ready-to-run gnokey maketx call for it:

AcceptAdminBalanceOfClaimClaimAllFundFundedHeldPokeExecutePokeExpirePokesPotRenderRewardForSetRewardSweepDenomTransferAdminUsersTotal

Overview

Package upkeep pays people to run the ecosystem's permissionless valves. The portfolio's realms deliberately expose maintenance entrypoints that anyone may call — subscriptions.Expire frees a lapsed subscription slot, timelock_guardian.Execute fires a matured timelocked action — because no slot's liveness may depend on an interested party showing up. This realm adds the missing economics: funders finance a reward pot, and whoever triggers a valve THROUGH this realm is credited a bounded reward, claimable by pull.

THE REALM-TO-REALM BOUNDARY, PRECISELY:

which calls which : upkeep -> subscriptions.Expire(cross, id) upkeep -> timelock_guardian.Execute(cross, id) why it is necessary : the reward must be conditioned on the valve actually firing. Only making the call from inside this realm ties "the valve fired" and "the reward is credited" into one atomic transaction; observing from outside cannot. caller identity : downstream sees cur.Previous() = THIS realm, not the poking EOA. Both valves are permissionless BY DESIGN and use the caller identity for nothing, so the intermediary changes no authorization outcome. This realm is not a deputy for any downstream authority — it holds none to confuse. authorization boundary: upstream, anyone may poke (the reward is the only thing at stake and the pot is the only source). Downstream, each valve enforces its own STATE conditions (grace elapsed, delay matured) exactly as it would for a direct caller. ordering : downstream call FIRST, reward accounting AFTER. A downstream abort therefore reverts the whole transaction before any pot or ledger mutation exists. failure behavior : any downstream panic (not expirable, too early, already executed, unknown id...) aborts this transaction. No partial state, no reward, by VM atomicity — not by cleanup code. atomicity assumptions : a Gno transaction is all-or-nothing across realm boundaries; there is no catch/recover anywhere on this path (and none may be added — recovery would break exactly this guarantee). value movement : none crosses the boundary. Both valves move no coins; the poke transaction must carry no coins (subscriptions' assertNoSend reads the ORIGIN envelope unconditionally — measured, not assumed). Rewards move only inside this realm's ledger, funded by explicit Fund transactions. downstream rejection : reward denied automatically — the abort is the denial. downstream trust : neither valve trusts nor validates the caller; both validate state. This realm symmetrically does not trust the downstream REPLY beyond "it did not abort". replay : enforced downstream. A second Expire on the same subscription aborts ("subscription is expired"); a second Execute aborts ("action already executed"). A poker cannot be paid twice for one valve event. adversarial callers : an EOA or realm poking with bogus ids, premature targets, or replays hits a downstream abort and pays its own gas. The remaining economic edge — manufacturing expirable state to farm rewards — differs per task. sub_expire: every farmed subscription permanently locks a sub-record storage deposit of roughly 30,000ugnot at the observed 100ugnot/byte rate (Expire flips status; it does not free the record), which exceeds MaxReward before price and gas — loss-making at any legal setting. timelock_execute: a farmed Action record is small and its deposit can sit below the cap, so farming resistance there rests on the admin keeping the setting below the measured cycle cost. Funders trust the cap AND the admin's reward policy, not the cap alone. The pot is a donation either way — farming can drain it, never third-party balances.

Rewards default to 0 per task; the admin sets them within the compile-time MaxReward. The pot only moves down via successful pokes and only up via Fund. Conservation: Held == pot + UsersTotal (+ out-of-band surplus, recoverable above that reserve by SweepDenom). The ledger's fee cap is 0 — no fee exists anywhere in this realm.

Imports

Constants and variables

Task identifiers — the two supported valves.

const (
	TaskSubExpire       = "sub_expire"
	TaskTimelockExecute = "timelock_execute"
)

Denom is the only asset this realm accepts.

const Denom = "ugnot"

MaxReward is the compile-time ceiling on the per-poke reward: 20,000ugnot (0.02 GNOT). It bounds what any single poke can extract from the pot. For sub_expire it also defeats farming outright: one manufactured expirable subscription permanently locks a sub-record deposit of ~30,000ugnot at the observed 100ugnot/byte rate — already above the cap before price and gas. For timelock_execute the farmed Action record is smaller and its deposit can sit below the cap, so there the admin's setting, kept below the measured farm-cycle cost, is what deters farming. Funders trust the cap and the admin's policy together; the pot they fund is an explicit donation either way.

const MaxReward = int64(20000)

Functions

AcceptAdmin

func AcceptAdmin(cur realm)

Crossing function. Callable from a transaction via MsgCall, and from another realm as AcceptAdmin(cross(cur), ...).

AcceptAdmin completes the handover; only the staged successor may. The sweeper role moves with the admin.

BalanceOf

func BalanceOf(a address) int64

Claim

func Claim(cur realm, amount int64)

Crossing function. Callable from a transaction via MsgCall, and from another realm as Claim(cross(cur), ...).

Claim sends amount ugnot of the caller's earned balance back to the caller.

ClaimAll

func ClaimAll(cur realm)

Crossing function. Callable from a transaction via MsgCall, and from another realm as ClaimAll(cross(cur), ...).

ClaimAll sends the caller's entire earned balance back to the caller.

Fund

func Fund(cur realm)

Crossing function. Callable from a transaction via MsgCall, and from another realm as Fund(cross(cur), ...).

Fund adds the attached coins to the reward pot. Anyone may fund; funding is a donation to ecosystem maintenance and is not refundable.

Funded

func Funded() int64

Held

func Held() int64

PokeExecute

func PokeExecute(cur realm, actionID string)

Crossing function. Callable from a transaction via MsgCall, and from another realm as PokeExecute(cross(cur), ...).

PokeExecute triggers timelock_guardian.Execute(actionID) through this realm and credits the caller the timelock_execute reward. The guardian decides whether the action is executable; its abort is the authorization.

PokeExpire

func PokeExpire(cur realm, subID int64)

Crossing function. Callable from a transaction via MsgCall, and from another realm as PokeExpire(cross(cur), ...).

PokeExpire triggers subscriptions.Expire(subID) through this realm and credits the caller the sub_expire reward. The downstream realm decides whether the subscription is expirable; its abort is the authorization. The transaction must attach no coins (the downstream realm checks the origin envelope).

Pokes

func Pokes() int64

Pot

func Pot() int64

Render

func Render(path string) string

RewardFor

func RewardFor(task string) int64

SetReward

func SetReward(cur realm, task string, amount int64)

Crossing function. Callable from a transaction via MsgCall, and from another realm as SetReward(cross(cur), ...).

SetReward configures the per-poke reward for a task, bounded by MaxReward. Admin only. Zero disables the task.

SweepDenom

func SweepDenom(cur realm, denom string)

Crossing function. Callable from a transaction via MsgCall, and from another realm as SweepDenom(cross(cur), ...).

SweepDenom recovers out-of-band coins to the sweeper. For the pot denom the reserve is pot + earned balances — both structurally unreachable. Sweeper only.

TransferAdmin

func TransferAdmin(cur realm, successor address)

Crossing function. Callable from a transaction via MsgCall, and from another realm as TransferAdmin(cross(cur), ...).

TransferAdmin stages a two-step admin handover.

UsersTotal

func UsersTotal() int64

Doc text is reproduced as vm/qdoc returns it. The node markdown-escapes doc comments, so a bracket or angle bracket may carry a backslash the committed source does not have. The source itself is at source and in this repository.

Dependencies

chain-attested
Importschain, chain/runtime/unsafe, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger, gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/subscriptions, gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/timelock_guardian, strconv
First-party dependenciesgno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger, gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/subscriptions, gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/timelock_guardian
Used bynone

Known limitations

Recorded by the people who built and deployed it. This list is deliberately not empty where honesty costs something.

curated

Source and records

Source filepearl/r/upkeep/upkeep.gno at commit 4fc6c79cd480 in the project repository (not public — the digest command above is the check that needs no repository)
Matches the deployed bytesyes — byte-identical
Recordscatalog/applications.md#upkeep
pearl/DEPLOYMENT.md