PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/subscriptions

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
subscriptions
Namespace
g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39
Files
3 (gnomod.toml)
Exported functions
34
Module
gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/subscriptions
gno
0.9

Files (3)

  • gnomod.tomltoml
  • subscriptions.gnogno
  • subscriptions_test.gnogno
subscriptions_test.gnogno
1package subscriptions23import (4	"chain"5	"chain/banker"6	"chain/runtime"7	"strings"8	"testing"910	"gno.land/p/nt/testutils/v0"11	"gno.land/p/nt/uassert/v0"12)1314var (15	testAdmin = testutils.TestAddress("subadmin")16	prov1     = testutils.TestAddress("subprov1")17	prov2     = testutils.TestAddress("subprov2")18	alice     = testutils.TestAddress("subalice")19	bob       = testutils.TestAddress("subbob")20	mallory   = testutils.TestAddress("submallory")21)2223// Established harness facts, carried from the sibling realms' suites:24// init runs with an empty origin context (the real deploy captures the25// origin caller); the banker resets between tests while realm globals26// persist, so conservation is asserted in DELTA form after re-seeding27// carried liabilities; testing.SetRealm affects only the frame that28// calls it; and testing.SkipHeights WIPES the origin/realm context, so29// every caller is re-armed after a skip.30func init() {31	admin = testAdmin32	feeRecipient = testAdmin33	self = chain.PackageAddress("gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/subscriptions")34}3536type baseline struct{ held, users, fees int64 }3738func begin() baseline {39	if l := Liabilities(); l > 0 {40		testing.IssueCoins(Address(), ugnot(l))41	}42	return snap()43}4445func snap() baseline {46	return baseline{held: Held(), users: UsersTotal(), fees: FeesAccrued()}47}4849// conserved asserts ΔH == ΔU + ΔF + extraSurplus — the realm's monetary50// invariant in delta form. There is no escrow pool in this realm.51func (b baseline) conserved(t *testing.T, extraSurplus int64) {52	t.Helper()53	dH := Held() - b.held54	dU := UsersTotal() - b.users55	dF := FeesAccrued() - b.fees56	if dH != dU+dF+extraSurplus {57		t.Fatalf("conservation violated: ΔH=%d ΔU=%d ΔF=%d ΔS=%d", dH, dU, dF, extraSurplus)58	}59	if Liabilities() != UsersTotal()+FeesAccrued() {60		t.Fatalf("Liabilities() = %d, want U+F", Liabilities())61	}62}6364func coinsOf(addr address) int64 {65	return banker.NewReadonlyBanker().GetCoin(addr, Denom)66}6768func ugnot(n int64) chain.Coins {69	return chain.NewCoins(chain.NewCoin(Denom, n))70}7172// NOTE ON THE HARNESS. testing.SetRealm applies to the frame that CALLS73// it, so the caller identity must be armed in the SAME frame as the74// entrypoint invocation — the three lines are inlined at every site,75// matching the sibling suites.7677// planAs publishes a plan (non-payable: envelope explicitly cleared).78func planAs(cur realm, from address, title string, price, period int64) int64 {79	testing.SetRealm(testing.NewUserRealm(from))80	testing.SetOriginCaller(from)81	testing.SetOriginSend(nil)82	return CreatePlan(cross(cur), title, "d", price, period, MaxFeeBps)83}8485// subscribeAs performs a chain-faithful subscribe: envelope staged AND landed.86func subscribeAs(cur realm, from address, planID, pay int64) int64 {87	testing.SetRealm(testing.NewUserRealm(from))88	testing.SetOriginCaller(from)89	testing.SetOriginSend(ugnot(pay))90	testing.IssueCoins(Address(), ugnot(pay))91	return Subscribe(cross(cur), planID)92}9394// renewAs performs a chain-faithful renewal.95func renewAs(cur realm, from address, subID, pay int64) {96	testing.SetRealm(testing.NewUserRealm(from))97	testing.SetOriginCaller(from)98	testing.SetOriginSend(ugnot(pay))99	testing.IssueCoins(Address(), ugnot(pay))100	Renew(cross(cur), subID)101}102103func TestInitialConfig(t *testing.T) {104	if Admin() != testAdmin || FeeRecipient() != testAdmin {105		t.Fatal("seeded roles mismatch")106	}107	var zero address108	if PendingAdmin() != zero {109		t.Fatal("pending admin not zero")110	}111	if FeeBps() != 0 || NumPlans() != 0 || NumSubs() != 0 {112		t.Fatal("initial counters not zero")113	}114}115116func TestCreatePlanValidation(cur realm, t *testing.T) {117	testing.SetRealm(testing.NewUserRealm(prov1))118	testing.SetOriginCaller(prov1)119	testing.SetOriginSend(ugnot(5))120	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {121		CreatePlan(cross(cur), "x", "d", 1, MinPeriodBlocks, MaxFeeBps)122	})123124	testing.SetRealm(testing.NewUserRealm(prov1))125	testing.SetOriginCaller(prov1)126	testing.SetOriginSend(nil)127	uassert.AbortsContains(t, cur, "title must be", func() {128		CreatePlan(cross(cur), "", "d", 1, MinPeriodBlocks, MaxFeeBps)129	})130	uassert.AbortsContains(t, cur, "title must be", func() {131		CreatePlan(cross(cur), strings.Repeat("t", MaxTitleLen+1), "d", 1, MinPeriodBlocks, MaxFeeBps)132	})133	uassert.AbortsContains(t, cur, "description too long", func() {134		CreatePlan(cross(cur), "x", strings.Repeat("d", MaxDescLen+1), 1, MinPeriodBlocks, MaxFeeBps)135	})136	uassert.AbortsContains(t, cur, "price must be at least", func() {137		CreatePlan(cross(cur), "x", "d", 0, MinPeriodBlocks, MaxFeeBps)138	})139	uassert.AbortsContains(t, cur, "periodBlocks must be in", func() {140		CreatePlan(cross(cur), "x", "d", 1, MinPeriodBlocks-1, MaxFeeBps)141	})142	uassert.AbortsContains(t, cur, "periodBlocks must be in", func() {143		CreatePlan(cross(cur), "x", "d", 1, MaxPeriodBlocks+1, MaxFeeBps)144	})145}146147func TestFeeConsentCeiling(cur realm, t *testing.T) {148	testing.SetRealm(testing.NewUserRealm(testAdmin))149	testing.SetOriginCaller(testAdmin)150	testing.SetOriginSend(nil)151	SetFeeBps(cross(cur), 250)152153	// A provider who signed for at most 100 bps is refused while the154	// fee is 250.155	testing.SetRealm(testing.NewUserRealm(prov1))156	testing.SetOriginCaller(prov1)157	testing.SetOriginSend(nil)158	uassert.AbortsContains(t, cur, "exceeds the caller's maximum", func() {159		CreatePlan(cross(cur), "capped", "d", 100, MinPeriodBlocks, 100)160	})161162	// A consenting provider snapshots 250 into the plan; a later fee163	// change does not touch it.164	id := planAs(cur, prov1, "snap", 1000, MinPeriodBlocks)165	testing.SetRealm(testing.NewUserRealm(testAdmin))166	testing.SetOriginCaller(testAdmin)167	testing.SetOriginSend(nil)168	SetFeeBps(cross(cur), 0)169	_, _, _, _, planFee, _, _ := PlanInfo(id)170	if planFee != 250 {171		t.Fatalf("plan feeBps = %d, want the 250 snapshot", planFee)172	}173174	// The subscription charges the SNAPSHOT, not the current fee.175	b := begin()176	subscribeAs(cur, alice, id, 1000)177	if got := FeesAccrued() - b.fees; got != 25 {178		t.Fatalf("fee charged = %d, want 25 (250 bps of 1000)", got)179	}180	if got := BalanceOf(prov1); got == 0 {181		t.Fatal("provider not credited")182	}183	b.conserved(t, 0)184}185186func TestPlanQuota(cur realm, t *testing.T) {187	for i := 0; i < MaxPlansPerProvider; i++ {188		planAs(cur, prov2, "q", 1, MinPeriodBlocks)189	}190	testing.SetRealm(testing.NewUserRealm(prov2))191	testing.SetOriginCaller(prov2)192	testing.SetOriginSend(nil)193	uassert.AbortsWithMessage(t, cur, "per-provider plan limit reached", func() {194		CreatePlan(cross(cur), "q", "d", 1, MinPeriodBlocks, MaxFeeBps)195	})196	// Retiring one frees the slot.197	RetirePlan(cross(cur), NumPlans()-1)198	planAs(cur, prov2, "q2", 1, MinPeriodBlocks)199}200201func TestRetirePlanAuthority(cur realm, t *testing.T) {202	id := planAs(cur, prov1, "mine", 5, MinPeriodBlocks)203	testing.SetRealm(testing.NewUserRealm(mallory))204	testing.SetOriginCaller(mallory)205	testing.SetOriginSend(nil)206	uassert.AbortsWithMessage(t, cur, "only the provider may retire a plan", func() {207		RetirePlan(cross(cur), id)208	})209	testing.SetRealm(testing.NewUserRealm(prov1))210	testing.SetOriginCaller(prov1)211	testing.SetOriginSend(nil)212	RetirePlan(cross(cur), id)213	uassert.AbortsWithMessage(t, cur, "plan is not active", func() {214		RetirePlan(cross(cur), id)215	})216	// No new subscriptions on a retired plan.217	testing.SetRealm(testing.NewUserRealm(alice))218	testing.SetOriginCaller(alice)219	testing.SetOriginSend(ugnot(5))220	testing.IssueCoins(Address(), ugnot(5))221	uassert.AbortsWithMessage(t, cur, "plan is not active", func() {222		Subscribe(cross(cur), id)223	})224}225226func TestSubscribeLifecycle(cur realm, t *testing.T) {227	id := planAs(cur, prov1, "basic", 100, 50)228	b := begin()229	h0 := runtime.ChainHeight()230	subID := subscribeAs(cur, alice, id, 100)231232	planID, subscriber, provider, price, paidThrough, periods, status := SubInfo(subID)233	if planID != id || subscriber != alice || provider != prov1 || price != 100 ||234		periods != 1 || status != SubActive {235		t.Fatal("subscription fields wrong")236	}237	if paidThrough != h0+50 {238		t.Fatalf("paidThrough = %d, want %d", paidThrough, h0+50)239	}240	if !Entitled(subID) || !EntitledFor(id, alice) {241		t.Fatal("fresh subscription not entitled")242	}243	if got, ok := ActiveSubID(id, alice); !ok || got != subID {244		t.Fatal("active index wrong")245	}246	b.conserved(t, 0)247248	// Exact envelope: under- and overpayment refused.249	for _, bad := range []int64{99, 101} {250		testing.SetRealm(testing.NewUserRealm(bob))251		testing.SetOriginCaller(bob)252		testing.SetOriginSend(ugnot(bad))253		testing.IssueCoins(Address(), ugnot(bad))254		uassert.AbortsContains(t, cur, "send exactly the plan price", func() {255			Subscribe(cross(cur), id)256		})257	}258259	// A second live subscription to the same plan is refused — the260	// identity-level duplicate-payment guard.261	testing.SetRealm(testing.NewUserRealm(alice))262	testing.SetOriginCaller(alice)263	testing.SetOriginSend(ugnot(100))264	testing.IssueCoins(Address(), ugnot(100))265	uassert.AbortsContains(t, cur, "renew it instead", func() {266		Subscribe(cross(cur), id)267	})268}269270func TestRenewalWindow(cur realm, t *testing.T) {271	id := planAs(cur, prov1, "window", 100, 50)272	subID := subscribeAs(cur, bob, id, 100)273	_, _, _, _, pt0, _, _ := SubInfo(subID)274275	from, until := RenewableFrom(subID)276	if from != pt0-50 || until != pt0+49 {277		t.Fatalf("window [%d,%d], want [%d,%d]", from, until, pt0-50, pt0+49)278	}279280	// Straight after Subscribe, remaining entitlement equals exactly281	// one period (the running one), so ONE prepay renewal is inside282	// the early bound — and extension is FROM paidThrough.283	b := begin()284	renewAs(cur, bob, subID, 100)285	_, _, _, _, pt1, periods, _ := SubInfo(subID)286	if pt1 != pt0+50 || periods != 2 {287		t.Fatalf("paidThrough = %d periods = %d, want %d and 2", pt1, periods, pt0+50)288	}289	b.conserved(t, 0)290291	// A SECOND renewal in the same block is the accidental duplicate,292	// and the early bound refuses it: more than one unstarted period293	// would be prepaid.294	testing.SetRealm(testing.NewUserRealm(bob))295	testing.SetOriginCaller(bob)296	testing.SetOriginSend(ugnot(100))297	testing.IssueCoins(Address(), ugnot(100))298	uassert.AbortsContains(t, cur, "too early", func() {299		Renew(cross(cur), subID)300	})301302	// Wrong payer: a third party cannot extend someone else's303	// subscription even inside the window.304	testing.SkipHeights(50)305	testing.SetRealm(testing.NewUserRealm(mallory))306	testing.SetOriginCaller(mallory)307	testing.SetOriginSend(ugnot(100))308	testing.IssueCoins(Address(), ugnot(100))309	uassert.AbortsWithMessage(t, cur, "only the subscriber may renew", func() {310		Renew(cross(cur), subID)311	})312313	// Wrong amount inside the window.314	testing.SetRealm(testing.NewUserRealm(bob))315	testing.SetOriginCaller(bob)316	testing.SetOriginSend(ugnot(99))317	testing.IssueCoins(Address(), ugnot(99))318	uassert.AbortsContains(t, cur, "send exactly the subscription price", func() {319		Renew(cross(cur), subID)320	})321}322323func TestGraceBoundary(cur realm, t *testing.T) {324	id := planAs(cur, prov1, "grace", 100, 50)325	subID := subscribeAs(cur, alice, id, 100)326	_, _, _, _, pt, _, _ := SubInfo(subID)327328	// Move to the LAST renewable height: h == paidThrough +329	// periodBlocks - 1 (the late bound is exclusive — audit Y2).330	testing.SkipHeights(pt + 49 - runtime.ChainHeight())331	if Entitled(subID) {332		t.Fatal("entitlement must have lapsed past paidThrough")333	}334	// Renewal at the boundary is accepted, extends FROM paidThrough —335	// and buys at least one block: the Y2 regression.336	renewAs(cur, alice, subID, 100)337	_, _, _, _, pt1, _, _ := SubInfo(subID)338	if pt1 != pt+50 {339		t.Fatalf("paidThrough = %d, want %d (extension from paidThrough)", pt1, pt+50)340	}341	if !Entitled(subID) {342		t.Fatal("a boundary renewal must buy at least one block of entitlement")343	}344345	// At the grace end itself renewal is refused, Expire opens: the346	// two sets partition exactly.347	testing.SkipHeights(pt1 + 50 - runtime.ChainHeight())348	testing.SetRealm(testing.NewUserRealm(alice))349	testing.SetOriginCaller(alice)350	testing.SetOriginSend(ugnot(100))351	testing.IssueCoins(Address(), ugnot(100))352	uassert.AbortsContains(t, cur, "grace window over", func() {353		Renew(cross(cur), subID)354	})355356	// Expire is permissionless: mallory may.357	testing.SetRealm(testing.NewUserRealm(mallory))358	testing.SetOriginCaller(mallory)359	testing.SetOriginSend(nil)360	Expire(cross(cur), subID)361	_, _, _, _, _, _, status := SubInfo(subID)362	if status != SubExpired {363		t.Fatal("not expired")364	}365	if EntitledFor(id, alice) {366		t.Fatal("expired subscription still indexed")367	}368	// Terminal: renewal refused by status.369	testing.SetRealm(testing.NewUserRealm(alice))370	testing.SetOriginCaller(alice)371	testing.SetOriginSend(ugnot(100))372	testing.IssueCoins(Address(), ugnot(100))373	uassert.AbortsContains(t, cur, "subscription is expired", func() {374		Renew(cross(cur), subID)375	})376	// The slot is free: a fresh Subscribe works.377	subscribeAs(cur, alice, id, 100)378}379380func TestExpireGuards(cur realm, t *testing.T) {381	id := planAs(cur, prov1, "expguard", 100, 50)382	subID := subscribeAs(cur, bob, id, 100)383	testing.SetRealm(testing.NewUserRealm(mallory))384	testing.SetOriginCaller(mallory)385	testing.SetOriginSend(nil)386	uassert.AbortsContains(t, cur, "not expirable", func() {387		Expire(cross(cur), subID)388	})389	// One block before the grace end it is still not expirable...390	_, _, _, _, pt, _, _ := SubInfo(subID)391	testing.SkipHeights(pt + 49 - runtime.ChainHeight())392	testing.SetRealm(testing.NewUserRealm(mallory))393	testing.SetOriginCaller(mallory)394	testing.SetOriginSend(nil)395	uassert.AbortsContains(t, cur, "not expirable", func() {396		Expire(cross(cur), subID)397	})398	// ...and AT the grace end it is: the sets partition exactly.399	testing.SkipHeights(1)400	testing.SetRealm(testing.NewUserRealm(mallory))401	testing.SetOriginCaller(mallory)402	testing.SetOriginSend(nil)403	Expire(cross(cur), subID)404	testing.SetRealm(testing.NewUserRealm(mallory))405	testing.SetOriginCaller(mallory)406	testing.SetOriginSend(nil)407	uassert.AbortsContains(t, cur, "subscription is expired", func() {408		Expire(cross(cur), subID)409	})410}411412func TestSubscribeCollapsesExpiredIncumbent(cur realm, t *testing.T) {413	id := planAs(cur, prov1, "collapse", 100, 50)414	oldID := subscribeAs(cur, alice, id, 100)415	_, _, _, _, pt, _, _ := SubInfo(oldID)416	testing.SkipHeights(pt + 50 - runtime.ChainHeight())417418	// No Expire call happened; Subscribe collapses the incumbent419	// itself, at the first expirable height.420	newID := subscribeAs(cur, alice, id, 100)421	if newID == oldID {422		t.Fatal("expected a fresh subscription id")423	}424	_, _, _, _, _, _, oldStatus := SubInfo(oldID)425	if oldStatus != SubExpired {426		t.Fatalf("incumbent status = %q, want expired", oldStatus)427	}428	if got, ok := ActiveSubID(id, alice); !ok || got != newID {429		t.Fatal("index does not point at the fresh subscription")430	}431}432433func TestCancel(cur realm, t *testing.T) {434	id := planAs(cur, prov1, "cancel", 100, 50)435	subID := subscribeAs(cur, bob, id, 100)436437	testing.SetRealm(testing.NewUserRealm(mallory))438	testing.SetOriginCaller(mallory)439	testing.SetOriginSend(nil)440	uassert.AbortsWithMessage(t, cur, "only the subscriber may cancel", func() {441		Cancel(cross(cur), subID)442	})443444	testing.SetRealm(testing.NewUserRealm(bob))445	testing.SetOriginCaller(bob)446	testing.SetOriginSend(nil)447	Cancel(cross(cur), subID)448	_, _, _, _, _, _, status := SubInfo(subID)449	if status != SubCancelled {450		t.Fatal("not cancelled")451	}452	// Paid entitlement survives cancellation until paidThrough — on453	// both surfaces (audit Y1)...454	if !Entitled(subID) || !EntitledFor(id, bob) {455		t.Fatal("cancelled subscription lost its paid entitlement")456	}457	// ...but the ACTIVE slot is gone and renewal is refused forever.458	if _, ok := ActiveSubID(id, bob); ok {459		t.Fatal("cancelled subscription still holds the active slot")460	}461	testing.SetRealm(testing.NewUserRealm(bob))462	testing.SetOriginCaller(bob)463	testing.SetOriginSend(ugnot(100))464	testing.IssueCoins(Address(), ugnot(100))465	uassert.AbortsContains(t, cur, "subscription is cancelled", func() {466		Renew(cross(cur), subID)467	})468	testing.SetRealm(testing.NewUserRealm(bob))469	testing.SetOriginCaller(bob)470	testing.SetOriginSend(nil)471	uassert.AbortsContains(t, cur, "subscription is cancelled", func() {472		Cancel(cross(cur), subID)473	})474	// The slot freed: bob may start a fresh subscription at once.475	subscribeAs(cur, bob, id, 100)476}477478func TestRenewRefusedOnRetiredPlan(cur realm, t *testing.T) {479	id := planAs(cur, prov1, "retire-mid", 100, 50)480	subID := subscribeAs(cur, alice, id, 100)481	testing.SetRealm(testing.NewUserRealm(prov1))482	testing.SetOriginCaller(prov1)483	testing.SetOriginSend(nil)484	RetirePlan(cross(cur), id)485	// Entitlement continues...486	if !Entitled(subID) {487		t.Fatal("entitlement must survive plan retirement")488	}489	// ...but renewal is refused even inside the window.490	_, _, _, _, pt, _, _ := SubInfo(subID)491	testing.SkipHeights(pt - runtime.ChainHeight())492	testing.SetRealm(testing.NewUserRealm(alice))493	testing.SetOriginCaller(alice)494	testing.SetOriginSend(ugnot(100))495	testing.IssueCoins(Address(), ugnot(100))496	uassert.AbortsContains(t, cur, "plan is retired", func() {497		Renew(cross(cur), subID)498	})499}500501func TestSubscriberQuota(cur realm, t *testing.T) {502	// Fill carol's quota with one-plan-each subscriptions, then refuse.503	// A dedicated provider: prov2's plan quota is already saturated by504	// TestPlanQuota, and realm globals persist across tests.505	carol := testutils.TestAddress("subcarol")506	provQ := testutils.TestAddress("subprovq")507	var lastPlan int64508	for i := 0; i < MaxSubsPerSubscriber; i++ {509		lastPlan = planAs(cur, provQ, "quota", 1, MinPeriodBlocks)510		subscribeAs(cur, carol, lastPlan, 1)511		// Free the provider quota slot for the next plan.512		testing.SetRealm(testing.NewUserRealm(provQ))513		testing.SetOriginCaller(provQ)514		testing.SetOriginSend(nil)515		RetirePlan(cross(cur), lastPlan)516	}517	extra := planAs(cur, provQ, "quota-x", 1, MinPeriodBlocks)518	testing.SetRealm(testing.NewUserRealm(carol))519	testing.SetOriginCaller(carol)520	testing.SetOriginSend(ugnot(1))521	testing.IssueCoins(Address(), ugnot(1))522	uassert.AbortsWithMessage(t, cur, "per-subscriber subscription limit reached", func() {523		Subscribe(cross(cur), extra)524	})525	// Cancelling one frees a slot.526	sid, ok := ActiveSubID(lastPlan, carol)527	if !ok {528		t.Fatal("expected an active sub to free")529	}530	testing.SetRealm(testing.NewUserRealm(carol))531	testing.SetOriginCaller(carol)532	testing.SetOriginSend(nil)533	Cancel(cross(cur), sid)534	subscribeAs(cur, carol, extra, 1)535	testing.SetRealm(testing.NewUserRealm(provQ))536	testing.SetOriginCaller(provQ)537	testing.SetOriginSend(nil)538	RetirePlan(cross(cur), extra)539}540541func TestClaimsAndFees(cur realm, t *testing.T) {542	testing.SetRealm(testing.NewUserRealm(testAdmin))543	testing.SetOriginCaller(testAdmin)544	testing.SetOriginSend(nil)545	SetFeeBps(cross(cur), 500) // 5% into the next plan546	id := planAs(cur, prov1, "money", 1000, 50)547	testing.SetRealm(testing.NewUserRealm(testAdmin))548	testing.SetOriginCaller(testAdmin)549	testing.SetOriginSend(nil)550	SetFeeBps(cross(cur), 0)551552	b := begin()553	subscribeAs(cur, alice, id, 1000)554	if FeesAccrued()-b.fees != 50 {555		t.Fatalf("fee = %d, want 50", FeesAccrued()-b.fees)556	}557	credited := BalanceOf(prov1)558559	// Mallory has no balance: claims fail.560	testing.SetRealm(testing.NewUserRealm(mallory))561	testing.SetOriginCaller(mallory)562	testing.SetOriginSend(nil)563	uassert.AbortsContains(t, cur, "insufficient balance", func() { Claim(cross(cur), 1) })564	testing.SetRealm(testing.NewUserRealm(mallory))565	testing.SetOriginCaller(mallory)566	testing.SetOriginSend(nil)567	uassert.AbortsWithMessage(t, cur, "nothing to claim", func() { ClaimAll(cross(cur)) })568569	// Provider claims all; coins actually move.570	before := coinsOf(prov1)571	testing.SetRealm(testing.NewUserRealm(prov1))572	testing.SetOriginCaller(prov1)573	testing.SetOriginSend(nil)574	ClaimAll(cross(cur))575	if coinsOf(prov1)-before != credited {576		t.Fatalf("provider received %d, want %d", coinsOf(prov1)-before, credited)577	}578	if BalanceOf(prov1) != 0 {579		t.Fatal("balance not drained")580	}581582	// Fees: only the recipient, and only the pot.583	testing.SetRealm(testing.NewUserRealm(mallory))584	testing.SetOriginCaller(mallory)585	testing.SetOriginSend(nil)586	uassert.AbortsWithMessage(t, cur, "fee recipient only", func() { WithdrawFees(cross(cur)) })587	potBefore := coinsOf(testAdmin)588	testing.SetRealm(testing.NewUserRealm(testAdmin))589	testing.SetOriginCaller(testAdmin)590	testing.SetOriginSend(nil)591	WithdrawFees(cross(cur))592	if coinsOf(testAdmin)-potBefore == 0 {593		t.Fatal("fee pot did not move")594	}595	testing.SetRealm(testing.NewUserRealm(testAdmin))596	testing.SetOriginCaller(testAdmin)597	testing.SetOriginSend(nil)598	uassert.AbortsWithMessage(t, cur, "no fees accrued", func() { WithdrawFees(cross(cur)) })599	b.conserved(t, 0)600}601602func TestSweepReserve(cur realm, t *testing.T) {603	id := planAs(cur, prov1, "sweep", 500, 50)604	begin()605	subscribeAs(cur, bob, id, 500)606607	// Nothing above the reserve: sweep refuses.608	testing.SetRealm(testing.NewUserRealm(testAdmin))609	testing.SetOriginCaller(testAdmin)610	testing.SetOriginSend(nil)611	uassert.AbortsContains(t, cur, "no surplus to sweep", func() {612		SweepDenom(cross(cur), Denom)613	})614	// Out-of-band surplus lands; only the surplus is sweepable.615	testing.IssueCoins(Address(), ugnot(77))616	liabBefore := Liabilities()617	got := coinsOf(testAdmin)618	testing.SetRealm(testing.NewUserRealm(testAdmin))619	testing.SetOriginCaller(testAdmin)620	testing.SetOriginSend(nil)621	SweepDenom(cross(cur), Denom)622	if coinsOf(testAdmin)-got != 77 {623		t.Fatalf("swept %d, want 77", coinsOf(testAdmin)-got)624	}625	if Liabilities() != liabBefore {626		t.Fatal("sweep touched the reserve")627	}628	testing.SetRealm(testing.NewUserRealm(mallory))629	testing.SetOriginCaller(mallory)630	testing.SetOriginSend(nil)631	uassert.AbortsWithMessage(t, cur, "fee recipient only", func() {632		SweepDenom(cross(cur), Denom)633	})634}635636func TestAdminHandover(cur realm, t *testing.T) {637	testing.SetRealm(testing.NewUserRealm(mallory))638	testing.SetOriginCaller(mallory)639	testing.SetOriginSend(nil)640	uassert.AbortsWithMessage(t, cur, "admin only", func() {641		TransferAdmin(cross(cur), mallory)642	})643	testing.SetRealm(testing.NewUserRealm(testAdmin))644	testing.SetOriginCaller(testAdmin)645	testing.SetOriginSend(nil)646	TransferAdmin(cross(cur), prov2)647	// Wrong acceptor refused; authority has not moved yet.648	testing.SetRealm(testing.NewUserRealm(mallory))649	testing.SetOriginCaller(mallory)650	testing.SetOriginSend(nil)651	uassert.AbortsWithMessage(t, cur, "only the staged successor may accept", func() {652		AcceptAdmin(cross(cur))653	})654	if Admin() != testAdmin {655		t.Fatal("authority moved before acceptance")656	}657	testing.SetRealm(testing.NewUserRealm(prov2))658	testing.SetOriginCaller(prov2)659	testing.SetOriginSend(nil)660	AcceptAdmin(cross(cur))661	if Admin() != prov2 {662		t.Fatal("authority did not move")663	}664	// The former admin is locked out.665	testing.SetRealm(testing.NewUserRealm(testAdmin))666	testing.SetOriginCaller(testAdmin)667	testing.SetOriginSend(nil)668	uassert.AbortsWithMessage(t, cur, "admin only", func() {669		SetFeeBps(cross(cur), 1)670	})671	// Hand it back for the remaining tests.672	testing.SetRealm(testing.NewUserRealm(prov2))673	testing.SetOriginCaller(prov2)674	testing.SetOriginSend(nil)675	TransferAdmin(cross(cur), testAdmin)676	testing.SetRealm(testing.NewUserRealm(testAdmin))677	testing.SetOriginCaller(testAdmin)678	testing.SetOriginSend(nil)679	AcceptAdmin(cross(cur))680}681682func TestFeeBounds(cur realm, t *testing.T) {683	testing.SetRealm(testing.NewUserRealm(testAdmin))684	testing.SetOriginCaller(testAdmin)685	testing.SetOriginSend(nil)686	uassert.AbortsContains(t, cur, "fee must be in", func() {687		SetFeeBps(cross(cur), MaxFeeBps+1)688	})689	testing.SetRealm(testing.NewUserRealm(testAdmin))690	testing.SetOriginCaller(testAdmin)691	testing.SetOriginSend(nil)692	uassert.AbortsContains(t, cur, "fee must be in", func() {693		SetFeeBps(cross(cur), -1)694	})695	var zero address696	testing.SetRealm(testing.NewUserRealm(testAdmin))697	testing.SetOriginCaller(testAdmin)698	testing.SetOriginSend(nil)699	uassert.AbortsWithMessage(t, cur, "fee recipient must not be the zero address", func() {700		SetFeeRecipient(cross(cur), zero)701	})702	testing.SetRealm(testing.NewUserRealm(testAdmin))703	testing.SetOriginCaller(testAdmin)704	testing.SetOriginSend(nil)705	uassert.AbortsWithMessage(t, cur, "successor must not be the zero address", func() {706		TransferAdmin(cross(cur), zero)707	})708}709710func TestStraySendRejected(cur realm, t *testing.T) {711	id := planAs(cur, prov1, "stray", 100, 50)712	subID := subscribeAs(cur, alice, id, 100)713	arm := func(from address) {714		testing.SetRealm(testing.NewUserRealm(from))715		testing.SetOriginCaller(from)716		testing.SetOriginSend(ugnot(3))717	}718	arm(prov1)719	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {720		RetirePlan(cross(cur), id)721	})722	arm(alice)723	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {724		Cancel(cross(cur), subID)725	})726	arm(mallory)727	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {728		Expire(cross(cur), subID)729	})730	arm(prov1)731	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {732		ClaimAll(cross(cur))733	})734	arm(testAdmin)735	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {736		WithdrawFees(cross(cur))737	})738	arm(testAdmin)739	uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {740		SetFeeBps(cross(cur), 0)741	})742}743744func TestRenderSanitizes(cur realm, t *testing.T) {745	planAs(cur, prov1, "[evil](https://x) <script>alert(1)</script>", 1, MinPeriodBlocks)746	out := Render("")747	if strings.Contains(out, "<script>") {748		t.Fatal("unsanitized title reached Render")749	}750	if !strings.Contains(out, "plans:") {751		t.Fatal("render missing counters")752	}753	if Render("nope") == renderHome() {754		t.Fatal("unknown path fell through to home")755	}756}757758func TestUnknownIDs(t *testing.T) {759	defer func() {760		if recover() == nil {761			t.Fatal("expected panic")762		}763	}()764	PlanInfo(99999)765}766767// Y1 regression: EntitledFor follows the most recent subscription and768// honors paid entitlement across cancellation.769func TestEntitledForSurvivesCancel(cur realm, t *testing.T) {770	id := planAs(cur, prov1, "y1", 100, 50)771	subID := subscribeAs(cur, alice, id, 100)772	testing.SetRealm(testing.NewUserRealm(alice))773	testing.SetOriginCaller(alice)774	testing.SetOriginSend(nil)775	Cancel(cross(cur), subID)776	if !EntitledFor(id, alice) {777		t.Fatal("cancelled-but-paid subscriber lost EntitledFor")778	}779	// A fresh Subscribe repoints the surface at the new subscription.780	// Skip a few blocks first so ptNew > ptOld: at a height in781	// [ptOld, ptNew) a STALE pointer would answer false while the782	// repointed one answers true — the distinguishing assertion.783	_, _, _, _, ptOld, _, _ := SubInfo(subID)784	testing.SkipHeights(5)785	newID := subscribeAs(cur, alice, id, 100)786	_, _, _, _, ptNew, _, _ := SubInfo(newID)787	if ptNew <= ptOld {788		t.Fatal("fixture broken: ptNew must exceed ptOld")789	}790	if !EntitledFor(id, alice) || !Entitled(newID) || !Entitled(subID) {791		t.Fatal("both paid entitlements should be live right after re-subscribe")792	}793	testing.SkipHeights(ptOld - runtime.ChainHeight())794	if Entitled(subID) {795		t.Fatal("old span should have run out")796	}797	if !EntitledFor(id, alice) {798		t.Fatal("EntitledFor answered the stale id, not the repointed one")799	}800	// After the new paid span runs out too, EntitledFor goes false.801	testing.SkipHeights(ptNew - runtime.ChainHeight())802	if EntitledFor(id, alice) {803		t.Fatal("EntitledFor true past paidThrough")804	}805}806807// Y2 companion: a lapsed-in-grace incumbent blocks Subscribe with a808// message that states both options.809func TestSubscribeMessageInGrace(cur realm, t *testing.T) {810	id := planAs(cur, prov1, "y2msg", 100, 50)811	subID := subscribeAs(cur, bob, id, 100)812	_, _, _, _, pt, _, _ := SubInfo(subID)813	testing.SkipHeights(pt + 10 - runtime.ChainHeight())814	testing.SetRealm(testing.NewUserRealm(bob))815	testing.SetOriginCaller(bob)816	testing.SetOriginSend(ugnot(100))817	testing.IssueCoins(Address(), ugnot(100))818	uassert.AbortsContains(t, cur, "lapsed but renewable", func() {819		Subscribe(cross(cur), id)820	})821	// Cancel + Subscribe is the documented fresh-start path.822	testing.SetRealm(testing.NewUserRealm(bob))823	testing.SetOriginCaller(bob)824	testing.SetOriginSend(nil)825	Cancel(cross(cur), subID)826	subscribeAs(cur, bob, id, 100)827}828

Functions

  • AcceptAdmin(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})

  • ActiveSubID(planID int64, subscriber string) (int64, bool)

  • Address() string

  • Admin() string

  • BalanceOf(a string) int64

  • Cancel(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, subID int64)

  • Claim(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, amount int64)

  • ClaimAll(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})

  • CreatePlan(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, title string, description string, price int64, periodBlocks int64, maxFeeBps int64) int64

  • Entitled(subID int64) bool

  • EntitledFor(planID int64, subscriber string) bool

  • Expire(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, subID int64)

  • FeeBps() int64

  • FeeRecipient() string

  • FeesAccrued() int64

  • Held() int64

  • Liabilities() int64

  • NumPlans() int64

  • NumSubs() int64

  • PaidThrough(subID int64) int64

  • PendingAdmin() string

  • PlanInfo(planID int64) (provider string, title string, price int64, periodBlocks int64, planFeeBps int64, status string, lifetimeSubs int64)

  • Render(path string) string

  • Renew(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, subID int64)

  • RenewableFrom(subID int64) (from int64, until int64)

  • RetirePlan(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, planID int64)

  • SetFeeBps(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, bps int64)

  • SetFeeRecipient(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, recipient string)

  • SubInfo(subID int64) (planID int64, subscriber string, provider string, price int64, paidThrough int64, periods int64, status string)

  • Subscribe(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, planID int64) int64

  • SweepDenom(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, denom string)

  • TransferAdmin(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, successor string)

  • UsersTotal() int64

  • WithdrawFees(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.