Realm on pearl-1
revshare
gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/revshare
realmfactory-applicationrevenue
Team revenue realm that IS a subscription provider: creates plans on the live subscriptions realm as the provider (admin-gated), pulls accrued revenue across the realm boundary via permissionless Pull (ClaimAll cross-call, measured held-delta), and splits it among weighted members (<=20, weights 1..10000) into pull-claimable feeledger balances, rounding dust to the highest-weight member. Conservation Held == UsersTotal + S; the downstream receivable is accounted, not custodied. Factory benchmark #7 (economic composition).
Identity
| Import path | gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/revshare |
|---|---|
| Kind | realm (/r/) |
| Chain | pearl-1 |
| Namespace | g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3 |
| Realm address | g1ccm649r4y542awaafhnl4v8ukuyhqqjmrtdwge confirmed against the realm itself |
Provenance
chain-attested| Deployed at height | 662,737 |
|---|---|
| Deploy transaction | a59b13509186fd244bc7c26316bed7b3accb5edd1345cff2106a6ff9bee74cd3 look it up on the RPC |
| Deployer | g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3 |
| Gas used | 33,482,374 |
| Storage | 32,207 bytes, deposit 3220700ugnot |
| Files on chain | gnomod.toml revshare.gno |
| Deployed bytes | revshare.gno — 16,794 bytes |
| sha256 | 33529d65b8d7635ba2b1e09aa92462a137959263abbbcabfda717121a4872014 |
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/revshare$download&file=revshare.gno' | shasum -a 256Expected: 33529d65b8d7635ba2b1e09aa92462a137959263abbbcabfda717121a4872014 — 16,794 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 22 exported functions.
Every function below deep-links to gnoweb's call builder, which generates a ready-to-run gnokey maketx call for it:
AcceptAdminAddMemberBalanceOfClaimClaimAllCreatePlanHeldMemberCountMemberWeightNumPlansPlanIDPullPulledReceivableRemoveMemberRenderRetirePlanSetWeightSweepDenomTotalWeightTransferAdminUsersTotal
Overview
Package revshare is a team revenue realm that IS a subscription provider. The live subscriptions realm supports realm providers but warns, in its own frozen header, that a realm provider "must expose its own crossing path to Claim, or what it earns is stranded." revshare is that crossing path, plus the one thing a team needs on top of it: pulled revenue is split among weighted members into pull-claimable balances.
THE ECONOMIC COMPOSITION, PRECISELY:
components : subscriptions (live realm — the revenue machine and the upstream custodian), feeledger (member balance accounting, fee cap 0), coinio (payouts, held-balance reads, reserve-protected sweep). value boundaries : B1 subscriber EOA -> subscriptions (plan price, origin envelope; governed by subscriptions' own H == U + F). B2 subscriptions -> revshare (banker send: ClaimAll pays the caller, and the caller is this realm). B3 revshare -> member EOA (coinio.Payout on Claim/ClaimAll). who owns which state : subscriptions owns plans, subs and the provider's claimable balance (revshare's RECEIVABLE); revshare owns the member table, weights, and the member balances in its own ledger. No state is shared; the only coupling is the crossing calls and the coins that move over B2. who controls funds : upstream, only a claim by this realm can move its receivable (provider-keyed ledger). Here, member balances move only to their owner (pull claims); the admin can NEVER touch earned balances — sweep reserves them, weight changes affect only FUTURE distributions. identity propagation : downstream sees cur.Previous() = THIS realm on every crossing call, so the plan provider and the claim beneficiary are the realm address by construction — no admin or member identity ever reaches the downstream realm. conservation : Held == UsersTotal + S (surplus above the Liabilities() reserve, recoverable only by SweepDenom). Distribution is exact: shares are floor(amountw/W) via the overflow-free split (A/W)w + ((A%W)*w)/W, and the remainder goes to the highest-weight member (ties: lowest address) — fee_split's deterministic dust policy, so no residual pool exists. Cross-boundary: lifetime Pulled equals the sum of all distributions, and the downstream receivable is NOT part of Held. ordering : Pull refuses BEFORE the downstream call (no members configured = refuse), claims downstream, MEASURES the arrival as a held-balance delta, then distributes exactly what arrived. State-after-call: the only local mutations happen after the boundary, on measured coins. downstream abort : "nothing to claim" (or any downstream panic) aborts the whole Pull — no local state exists yet to corrupt, by ordering AND by VM atomicity. There is no recover anywhere in this realm, and none may be added. replay : a second Pull finds a zero downstream balance and aborts there. Distribution credits are driven by the measured delta, so a replayed Pull cannot double-count even in principle. trust : revshare does not trust the downstream reply beyond "it did not abort" — it distributes the measured balance delta, not a reported amount. Downstream validates nothing about this caller; the provider ledger is keyed by address. terminal states : plans retire downstream (provider-only, exposed here admin-gated); members can be removed (earned balances survive removal and stay claimable); the realm itself has no terminal state — a team that walks away leaves only pull-claimable balances. adversarial callers : Pull is permissionless — it can only move the receivable into member balances at the fixed weights, so a stranger's Pull is a free favor. Plan creation/retirement is admin-gated (the downstream per-provider plan quota is a griefable resource). Members trust the admin for FUTURE weights only, never for earned balances. All entrypoints refuse coin-carrying transactions (the downstream assertNoSend reads the origin envelope; ours matches).
One team per deploy: subscriptions keeps ONE claimable balance per provider address, so a multi-team router behind one realm address could not attribute revenue at the boundary. This is a measured constraint of the downstream API, not a choice.
Imports
chainchain/runtime/unsafegno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coiniogno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledgergno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/subscriptionsstrconv
Constants and variables
MaxMembers bounds the distribution loop; MaxWeight bounds a single weight. Together they cap totalWeight at 200,000, which makes the remainder step of the split ((A%W)*w) provably overflow-free for any int64 coin amount — the conservation math cannot trap.
const (
MaxMembers = 20
MaxWeight = int64(10000)
)
Denom is the only asset this realm accounts.
const Denom = "ugnot"
Functions
AcceptAdmin
func AcceptAdmin(cur realm)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asAcceptAdmin(cross(cur), ...).
AcceptAdmin completes the handover; only the staged successor may. The sweeper role moves with the admin.
AddMember
func AddMember(cur realm, a address, weight int64)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asAddMember(cross(cur), ...).
AddMember adds a weighted member. Weight changes never touch earned balances; they shape future pulls only.
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 asClaim(cross(cur), ...).
Claim sends amount ugnot of the caller's earned balance to the caller.
ClaimAll
func ClaimAll(cur realm)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asClaimAll(cross(cur), ...).
ClaimAll sends the caller's entire earned balance to the caller.
CreatePlan
func CreatePlan(cur realm, title, description string, price, periodBlocks, maxFeeBps int64) int64
Crossing function. Callable from a transaction via
MsgCall, and from another realm asCreatePlan(cross(cur), ...).
CreatePlan creates a subscription plan THROUGH this realm, making the realm the plan's provider downstream. Admin only: the per-provider plan quota downstream is a griefable resource.
Held
func Held() int64
MemberCount
func MemberCount() int64
MemberWeight
func MemberWeight(a address) int64
NumPlans
func NumPlans() int64
PlanID
func PlanID(i int64) int64
Pull
func Pull(cur realm) int64
Crossing function. Callable from a transaction via
MsgCall, and from another realm asPull(cross(cur), ...).
Pull claims this realm's entire accrued provider balance from the subscriptions realm and distributes it to the members by weight. Permissionless: pulling can only move the receivable into member balances at the fixed weights, so anyone may crank it. Refuses BEFORE the downstream call when no member could receive the funds.
Pulled
func Pulled() int64
Receivable
func Receivable() int64
Receivable reads this realm's accrued, not-yet-pulled provider balance inside the subscriptions realm — the other side of value boundary B2. It is deliberately NOT part of Held or of the local conservation equation.
RemoveMember
func RemoveMember(cur realm, a address)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asRemoveMember(cross(cur), ...).
RemoveMember removes a member from future distributions. The member's earned balance is untouched and stays claimable forever.
Render
func Render(path string) string
RetirePlan
func RetirePlan(cur realm, planID int64)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asRetirePlan(cross(cur), ...).
RetirePlan retires one of this realm's plans downstream. Admin only.
SetWeight
func SetWeight(cur realm, a address, weight int64)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asSetWeight(cross(cur), ...).
SetWeight changes a member's weight for future distributions.
SweepDenom
func SweepDenom(cur realm, denom string)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asSweepDenom(cross(cur), ...).
SweepDenom recovers out-of-band coins to the sweeper. For the accounting denom the reserve is the full ledger liability — member balances are structurally unsweepable. Sweeper only.
TotalWeight
func TotalWeight() int64
TransferAdmin
func TransferAdmin(cur realm, successor address)
Crossing function. Callable from a transaction via
MsgCall, and from another realm asTransferAdmin(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| Imports | chain, chain/runtime/unsafe, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger, gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/subscriptions, strconv |
|---|---|
| First-party dependencies | gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger, gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/subscriptions |
| Used by | none |
Known limitations
Recorded by the people who built and deployed it. This list is deliberately not empty where honesty costs something.
curated- Admin two-step handover, SweepDenom success legs, SetWeight/RemoveMember and the 20-member cap are unit-tested but were not exercised live; each is correlated to its committed test in DEPLOYMENT.md section 19.
- One team per deploy: subscriptions keeps one claimable balance per provider address, so multi-team routing behind one realm address is unaccountable at the boundary (measured downstream constraint).
- Pull-time weights govern accrued-but-unpulled receivable (documented trust model; permissionless Pull is the member-side self-protection); admin loss with an empty member table strands the receivable (operating note: keep at least one member configured while plans are live).
- Pull gas (~30,000ugnot at padded gas_wanted) exceeded the demo pull amounts; the crank is amount-independent so batching amortizes it (3% of a 1M pull) -- demo economics intentionally experimental, stated in the record.
- Members should be EOAs; a realm member strands its own claims (same caveat as sibling realms).
Source and records
| Source file | pearl/r/revshare/revshare.gno at commit 4fc6c79cd480 in the project repository (not public — the digest command above is the check that needs no repository) |
|---|---|
| Matches the deployed bytes | yes — byte-identical |
| Records | catalog/applications.md#revsharepearl/DEPLOYMENT.md |