1package service_market23import (4 "chain"5 "chain/banker"6 "strings"7 "testing"89 "gno.land/p/nt/testutils/v0"10 "gno.land/p/nt/uassert/v0"11)1213var (14 testAdmin = testutils.TestAddress("smadmin")15 prov1 = testutils.TestAddress("smprov1")16 prov2 = testutils.TestAddress("smprov2")17 cust1 = testutils.TestAddress("smcust1")18 cust2 = testutils.TestAddress("smcust2")19 mallory = testutils.TestAddress("smmallory")20)2122// Established harness facts, carried from the sibling realms' suites:23// init runs with an empty origin context (the real deploy captures the24// origin caller); the banker resets between tests while realm globals25// persist, so conservation is asserted in DELTA form after re-seeding26// carried liabilities; testing.SetRealm affects only the frame that27// calls it; and testing.SkipHeights WIPES the origin/realm context, so28// every caller is re-armed after a skip.29func init() {30 admin = testAdmin31 feeRecipient = testAdmin32 self = chain.PackageAddress("gno.land/r/g1qp5pt8cdq2f6kfdamn3yuxwg6quqnfpyewzz39/service_market")33}3435type baseline struct{ held, escrow, users, fees int64 }3637func begin() baseline {38 if l := Liabilities(); l > 0 {39 testing.IssueCoins(Address(), ugnot(l))40 }41 return snap()42}4344func snap() baseline {45 return baseline{held: Held(), escrow: EscrowTotal(), users: UsersTotal(), fees: FeesAccrued()}46}4748// conserved asserts ΔH == ΔE + ΔU + ΔF + extraSurplus, the realm's49// stated monetary invariant in delta form.50func (b baseline) conserved(t *testing.T, extraSurplus int64) {51 t.Helper()52 dH := Held() - b.held53 dE := EscrowTotal() - b.escrow54 dU := UsersTotal() - b.users55 dF := FeesAccrued() - b.fees56 if dH != dE+dU+dF+extraSurplus {57 t.Fatalf("conservation violated: ΔH=%d ΔE=%d ΔU=%d ΔF=%d ΔS=%d", dH, dE, dU, dF, extraSurplus)58 }59 if Liabilities() != EscrowTotal()+UsersTotal()+FeesAccrued() {60 t.Fatalf("Liabilities() = %d, want E+U+F", Liabilities())61 }62}6364// appInvariant re-derives the escrow pool from the orders themselves.65// EscrowTotal is a running counter; this proves it still equals Σ amount66// over non-terminal orders, which is the claim SweepDenom's reserve67// rests on.68func appInvariant(t *testing.T) {69 t.Helper()70 var sum int6471 for id := int64(0); id < NumOrders(); id++ {72 _, _, _, amount, _, status := OrderInfo(id)73 switch status {74 case OrderPurchased, OrderDelivered:75 sum += amount76 case OrderReleased, OrderRefunded:77 default:78 t.Fatalf("order %d has unknown status %q", id, status)79 }80 }81 if sum != EscrowTotal() {82 t.Fatalf("EscrowTotal() = %d, but Σ open orders = %d", EscrowTotal(), sum)83 }84}8586func coinsOf(addr address) int64 {87 return banker.NewReadonlyBanker().GetCoin(addr, Denom)88}8990func ugnot(n int64) chain.Coins {91 return chain.NewCoins(chain.NewCoin(Denom, n))92}9394// NOTE ON THE HARNESS. testing.SetRealm applies to the frame that CALLS95// it, so the caller identity must be armed in the SAME frame as the96// entrypoint invocation. A nested `as(from)` helper is silently97// ineffective: the realm reverts when that helper returns, and the call98// lands as the default test caller instead of `from` — which is a test99// that quietly stops testing what it names. Hence the three lines100// inline at every site, matching the sibling suites.101102// registerAs publishes a service (non-payable: envelope explicitly cleared).103func registerAs(cur realm, from address, title, desc string, price, delivery int64) int64 {104 testing.SetRealm(testing.NewUserRealm(from))105 testing.SetOriginCaller(from)106 testing.SetOriginSend(nil)107 return RegisterService(cross(cur), title, desc, price, delivery, MaxFeeBps)108}109110// purchaseAs performs a chain-faithful purchase: envelope staged AND landed.111func purchaseAs(cur realm, from address, serviceID, pay int64) int64 {112 testing.SetRealm(testing.NewUserRealm(from))113 testing.SetOriginCaller(from)114 testing.SetOriginSend(ugnot(pay))115 testing.IssueCoins(Address(), ugnot(pay))116 return PurchaseService(cross(cur), serviceID)117}118119func TestInitialConfig(t *testing.T) {120 if Admin() != testAdmin || FeeRecipient() != testAdmin {121 t.Fatal("seeded roles mismatch")122 }123 var zero address124 if PendingAdmin() != zero {125 t.Fatal("pending admin not zero")126 }127 if FeeBps() != 0 || NumServices() != 0 || NumOrders() != 0 {128 t.Fatal("initial counters not zero")129 }130 if Held() != 0 || Liabilities() != 0 || EscrowTotal() != 0 {131 t.Fatal("initial accounting not zero")132 }133 if Address() == zero {134 t.Fatal("realm address is zero")135 }136}137138func TestRegisterService(cur realm, t *testing.T) {139 b := begin()140 id := registerAs(cur, prov1, "logo design", "two concepts and revisions", 500000, 20000)141142 provider, title, price, delivery, snapBps, status, orderCount := ServiceInfo(id)143 if provider != prov1 || title != "logo design" || price != 500000 ||144 delivery != 20000 || snapBps != 0 || status != ServiceActive || orderCount != 0 {145 t.Fatalf("fields wrong: %v %q %d %d %d %s %d",146 provider, title, price, delivery, snapBps, status, orderCount)147 }148 if ServiceDescription(id) != "two concepts and revisions" {149 t.Fatal("description mismatch")150 }151 if ServicesOf(prov1) != 1 {152 t.Fatalf("ServicesOf = %d, want 1", ServicesOf(prov1))153 }154 p, fee, toProvider := Quote(id)155 if p != 500000 || fee != 0 || toProvider != 500000 {156 t.Fatalf("Quote = %d/%d/%d", p, fee, toProvider)157 }158 appInvariant(t)159 b.conserved(t, 0)160}161162func TestRegisterRejects(cur realm, t *testing.T) {163 b := begin()164165 // Non-payable: an attached envelope is refused, not stranded.166 testing.SetRealm(testing.NewUserRealm(prov1))167 testing.SetOriginCaller(prov1)168 testing.SetOriginSend(ugnot(100))169 uassert.AbortsWithMessage(t, cur, "this function does not accept coins", func() {170 RegisterService(cross(cur), "x", "y", 1, MinDeliveryBlocks, MaxFeeBps)171 })172 testing.SetRealm(testing.NewUserRealm(prov1))173 testing.SetOriginCaller(prov1)174 testing.SetOriginSend(nil)175176 uassert.AbortsContains(t, cur, "title must be", func() {177 RegisterService(cross(cur), "", "d", 1, MinDeliveryBlocks, MaxFeeBps)178 })179 uassert.AbortsContains(t, cur, "title may only contain", func() {180 RegisterService(cross(cur), "bad*title", "d", 1, MinDeliveryBlocks, MaxFeeBps)181 })182 uassert.AbortsContains(t, cur, "description must be", func() {183 RegisterService(cross(cur), "ok", strings.Repeat("x", MaxDescLen+1), 1, MinDeliveryBlocks, MaxFeeBps)184 })185 uassert.AbortsContains(t, cur, "price must be at least", func() {186 RegisterService(cross(cur), "ok", "d", 0, MinDeliveryBlocks, MaxFeeBps)187 })188 uassert.AbortsContains(t, cur, "deliveryBlocks must be", func() {189 RegisterService(cross(cur), "ok", "d", 1, MinDeliveryBlocks-1, MaxFeeBps)190 })191 uassert.AbortsContains(t, cur, "deliveryBlocks must be", func() {192 RegisterService(cross(cur), "ok", "d", 1, MaxDeliveryBlocks+1, MaxFeeBps)193 })194 uassert.AbortsContains(t, cur, "maxFeeBps must be", func() {195 RegisterService(cross(cur), "ok", "d", 1, MinDeliveryBlocks, MaxFeeBps+1)196 })197 appInvariant(t)198 b.conserved(t, 0)199}200201// The provider's published terms cannot be devalued by an admin fee202// change between registration and purchase: registration itself refuses203// a fee above the ceiling the provider signed for. This is the grants Y1204// pattern, applied at the offer rather than the grant.205func TestFeeCeilingAndSnapshot(cur realm, t *testing.T) {206 b := begin()207208 testing.SetRealm(testing.NewUserRealm(testAdmin))209 testing.SetOriginCaller(testAdmin)210 testing.SetOriginSend(nil)211 SetFeeBps(cross(cur), 500)212213 testing.SetRealm(testing.NewUserRealm(prov1))214 testing.SetOriginCaller(prov1)215 testing.SetOriginSend(nil)216 uassert.AbortsContains(t, cur, "exceeds your ceiling", func() {217 RegisterService(cross(cur), "cheap only", "d", 1000, MinDeliveryBlocks, 100)218 })219220 // Registered at 500 bps.221 id := registerAs(cur, prov1, "copywriting", "800 words", 1000000, 20000)222 _, _, _, _, snapBps, _, _ := ServiceInfo(id)223 if snapBps != 500 {224 t.Fatalf("snapshot bps = %d, want 500", snapBps)225 }226227 // Admin raises the fee afterwards; the existing service keeps 500.228 testing.SetRealm(testing.NewUserRealm(testAdmin))229 testing.SetOriginCaller(testAdmin)230 testing.SetOriginSend(nil)231 SetFeeBps(cross(cur), MaxFeeBps)232 _, _, _, _, snapBps, _, _ = ServiceInfo(id)233 if snapBps != 500 {234 t.Fatalf("snapshot bps changed to %d", snapBps)235 }236237 // And an order placed now carries the SERVICE's 500, not the live cap.238 oid := purchaseAs(cur, cust1, id, 1000000)239 _, _, _, _, orderBps, _ := OrderInfo(oid)240 if orderBps != 500 {241 t.Fatalf("order bps = %d, want 500", orderBps)242 }243244 // Clean up: release so later tests start from a settled pool.245 testing.SetRealm(testing.NewUserRealm(prov1))246 testing.SetOriginCaller(prov1)247 testing.SetOriginSend(nil)248 MarkDelivered(cross(cur), oid, "ipfs://copy")249 testing.SetRealm(testing.NewUserRealm(cust1))250 testing.SetOriginCaller(cust1)251 testing.SetOriginSend(nil)252 AcceptDelivery(cross(cur), oid)253254 testing.SetRealm(testing.NewUserRealm(testAdmin))255 testing.SetOriginCaller(testAdmin)256 testing.SetOriginSend(nil)257 SetFeeBps(cross(cur), 0)258 appInvariant(t)259 b.conserved(t, 0)260}261262func TestPurchaseEscrows(cur realm, t *testing.T) {263 b := begin()264 p0 := BalanceOf(prov1)265 sid := registerAs(cur, prov1, "translation", "en to fr", 300000, 20000)266267 oid := purchaseAs(cur, cust1, sid, 300000)268 serviceID, customer, provider, amount, _, status := OrderInfo(oid)269 if serviceID != sid || customer != cust1 || provider != prov1 ||270 amount != 300000 || status != OrderPurchased {271 t.Fatalf("order wrong: %d %v %v %d %s", serviceID, customer, provider, amount, status)272 }273 // The money is in escrow, NOT yet in anyone's claimable balance.274 if EscrowTotal()-b.escrow != 300000 {275 t.Fatalf("ΔE = %d, want 300000", EscrowTotal()-b.escrow)276 }277 if BalanceOf(prov1) != p0 {278 t.Fatalf("provider credited before resolution: %d -> %d", p0, BalanceOf(prov1))279 }280 deliveryDeadline, acceptanceDeadline := OrderDeadlines(oid)281 if deliveryDeadline != Height()+20000 {282 t.Fatalf("delivery deadline = %d", deliveryDeadline)283 }284 if acceptanceDeadline != 0 {285 t.Fatalf("acceptance deadline set before delivery: %d", acceptanceDeadline)286 }287 _, _, _, _, _, _, orderCount := ServiceInfo(sid)288 if orderCount != 1 {289 t.Fatalf("service order count = %d", orderCount)290 }291 appInvariant(t)292 b.conserved(t, 0)293}294295func TestPurchaseRejects(cur realm, t *testing.T) {296 b := begin()297 sid := registerAs(cur, prov1, "editing", "line edit", 250000, 20000)298299 // Wrong amount, in both directions.300 testing.SetRealm(testing.NewUserRealm(cust1))301 testing.SetOriginCaller(cust1)302 testing.SetOriginSend(ugnot(249999))303 testing.IssueCoins(Address(), ugnot(249999))304 uassert.AbortsContains(t, cur, "send exactly the listed price", func() {305 PurchaseService(cross(cur), sid)306 })307 testing.SetOriginSend(ugnot(250001))308 testing.IssueCoins(Address(), ugnot(250001))309 uassert.AbortsContains(t, cur, "send exactly the listed price", func() {310 PurchaseService(cross(cur), sid)311 })312313 // Self-purchase.314 testing.SetRealm(testing.NewUserRealm(prov1))315 testing.SetOriginCaller(prov1)316 testing.SetOriginSend(ugnot(250000))317 testing.IssueCoins(Address(), ugnot(250000))318 uassert.AbortsWithMessage(t, cur, "the provider cannot purchase their own service", func() {319 PurchaseService(cross(cur), sid)320 })321322 // Unknown service.323 testing.SetRealm(testing.NewUserRealm(cust1))324 testing.SetOriginCaller(cust1)325 testing.SetOriginSend(ugnot(250000))326 testing.IssueCoins(Address(), ugnot(250000))327 uassert.AbortsWithMessage(t, cur, "unknown service id", func() {328 PurchaseService(cross(cur), 9999)329 })330 testing.SetRealm(testing.NewUserRealm(cust1))331 testing.SetOriginCaller(cust1)332 testing.SetOriginSend(nil)333334 // Those aborts each landed coins at the realm that the transaction335 // then reverted. In the harness the send is simulated rather than336 // rolled back, so the excess shows up as surplus; assert it is337 // EXACTLY surplus and has not leaked into escrow or a balance.338 appInvariant(t)339 if EscrowTotal() != b.escrow {340 t.Fatalf("a rejected purchase moved escrow: %d -> %d", b.escrow, EscrowTotal())341 }342 if UsersTotal() != b.users {343 t.Fatalf("a rejected purchase credited a balance")344 }345}346347// Retiring stops NEW orders and nothing else. An order already in348// flight keeps its own copy of provider, amount and fee.349func TestRetireService(cur realm, t *testing.T) {350 b := begin()351 n0 := ServicesOf(prov1)352 p0 := BalanceOf(prov1)353 sid := registerAs(cur, prov1, "consulting", "one hour", 400000, 20000)354 oid := purchaseAs(cur, cust1, sid, 400000)355356 testing.SetRealm(testing.NewUserRealm(mallory))357 testing.SetOriginCaller(mallory)358 testing.SetOriginSend(nil)359 uassert.AbortsWithMessage(t, cur, "only the provider may retire this service", func() {360 RetireService(cross(cur), sid)361 })362363 testing.SetRealm(testing.NewUserRealm(prov1))364 testing.SetOriginCaller(prov1)365 testing.SetOriginSend(nil)366 RetireService(cross(cur), sid)367 _, _, _, _, _, status, _ := ServiceInfo(sid)368 if status != ServiceRetired {369 t.Fatalf("status = %s", status)370 }371 if ServicesOf(prov1) != n0 {372 t.Fatalf("retire did not free the provider slot: %d -> %d", n0, ServicesOf(prov1))373 }374375 // Terminal: no un-retire, and no second retire.376 uassert.AbortsWithMessage(t, cur, "service is not active", func() {377 RetireService(cross(cur), sid)378 })379380 // New orders refused...381 testing.SetRealm(testing.NewUserRealm(cust2))382 testing.SetOriginCaller(cust2)383 testing.SetOriginSend(ugnot(400000))384 testing.IssueCoins(Address(), ugnot(400000))385 uassert.AbortsWithMessage(t, cur, "service is not active", func() {386 PurchaseService(cross(cur), sid)387 })388389 // ...but the in-flight order still completes normally.390 testing.SetRealm(testing.NewUserRealm(prov1))391 testing.SetOriginCaller(prov1)392 testing.SetOriginSend(nil)393 MarkDelivered(cross(cur), oid, "notes.pdf")394 testing.SetRealm(testing.NewUserRealm(cust1))395 testing.SetOriginCaller(cust1)396 testing.SetOriginSend(nil)397 AcceptDelivery(cross(cur), oid)398 _, _, _, _, _, ostatus := OrderInfo(oid)399 if ostatus != OrderReleased {400 t.Fatalf("in-flight order broke on retire: %s", ostatus)401 }402 if BalanceOf(prov1) != p0+400000 {403 t.Fatalf("provider credited %d, want %d", BalanceOf(prov1)-p0, 400000)404 }405 appInvariant(t)406 // The refused cust2 purchase landed its 400000 at the realm; on chain407 // the abort reverts that send, but the harness simulates it rather408 // than rolling it back, so it surfaces as out-of-band surplus. It is409 // asserted as surplus precisely to prove it did NOT reach escrow or a410 // balance.411 b.conserved(t, 400000)412}413414func TestServiceCapPerProvider(cur realm, t *testing.T) {415 b := begin()416 ids := make([]int64, 0, MaxServicesPerProvider)417 for i := 0; i < MaxServicesPerProvider; i++ {418 ids = append(ids, registerAs(cur, prov2, "svc", "d", 1000, MinDeliveryBlocks))419 }420 if ServicesOf(prov2) != MaxServicesPerProvider {421 t.Fatalf("ServicesOf = %d", ServicesOf(prov2))422 }423 testing.SetRealm(testing.NewUserRealm(prov2))424 testing.SetOriginCaller(prov2)425 testing.SetOriginSend(nil)426 uassert.AbortsContains(t, cur, "services per provider", func() {427 RegisterService(cross(cur), "one too many", "d", 1000, MinDeliveryBlocks, MaxFeeBps)428 })429430 // Retiring frees exactly one slot.431 RetireService(cross(cur), ids[0])432 ids = append(ids, registerAs(cur, prov2, "replacement", "d", 1000, MinDeliveryBlocks))433 testing.SetRealm(testing.NewUserRealm(prov2))434 testing.SetOriginCaller(prov2)435 testing.SetOriginSend(nil)436 uassert.AbortsContains(t, cur, "services per provider", func() {437 RegisterService(cross(cur), "still too many", "d", 1000, MinDeliveryBlocks, MaxFeeBps)438 })439440 // The cap is per provider, not global.441 registerAs(cur, prov1, "unaffected", "d", 1000, MinDeliveryBlocks)442443 // Teardown: realm globals persist between tests in this harness, so444 // leaving prov2 pinned at the cap would silently break every later445 // test that registers as prov2. Retire everything this test opened.446 testing.SetRealm(testing.NewUserRealm(prov2))447 testing.SetOriginCaller(prov2)448 testing.SetOriginSend(nil)449 for _, id := range ids[1:] {450 RetireService(cross(cur), id)451 }452 if ServicesOf(prov2) != 0 {453 t.Fatalf("teardown left %d services on prov2", ServicesOf(prov2))454 }455 appInvariant(t)456 b.conserved(t, 0)457}458459// ---- the three required protections ----460461// UNAUTHORIZED SETTLEMENT. Nobody but the customer can resolve a462// delivered order early — not the provider who did the work, not the463// admin, not the fee recipient, not a stranger, not another realm.464func TestUnauthorizedSettlement(cur realm, t *testing.T) {465 b := begin()466 p0 := BalanceOf(prov1)467 sid := registerAs(cur, prov1, "audit work", "review the thing", 1000000, 20000)468 oid := purchaseAs(cur, cust1, sid, 1000000)469470 // Only the provider may mark delivered.471 for _, bad := range []address{cust1, testAdmin, mallory, prov2} {472 testing.SetRealm(testing.NewUserRealm(bad))473 testing.SetOriginCaller(bad)474 testing.SetOriginSend(nil)475 uassert.AbortsWithMessage(t, cur, "only the provider may mark this order delivered", func() {476 MarkDelivered(cross(cur), oid, "x")477 })478 }479 // Not even from another code realm.480 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/attacker"))481 testing.SetOriginSend(nil)482 uassert.AbortsWithMessage(t, cur, "only the provider may mark this order delivered", func() {483 MarkDelivered(cross(cur), oid, "x")484 })485486 testing.SetRealm(testing.NewUserRealm(prov1))487 testing.SetOriginCaller(prov1)488 testing.SetOriginSend(nil)489 MarkDelivered(cross(cur), oid, "ipfs://report")490491 // Only the customer may accept. THE key authorization.492 for _, bad := range []address{prov1, testAdmin, mallory, cust2} {493 testing.SetRealm(testing.NewUserRealm(bad))494 testing.SetOriginCaller(bad)495 testing.SetOriginSend(nil)496 uassert.AbortsWithMessage(t, cur, "only the customer may accept this delivery", func() {497 AcceptDelivery(cross(cur), oid)498 })499 }500 testing.SetRealm(testing.NewCodeRealm("gno.land/r/demo/attacker"))501 testing.SetOriginSend(nil)502 uassert.AbortsWithMessage(t, cur, "only the customer may accept this delivery", func() {503 AcceptDelivery(cross(cur), oid)504 })505506 // The timeout valve is permissionless but NOT early: even the507 // provider cannot pull it before the window lapses.508 testing.SetRealm(testing.NewUserRealm(prov1))509 testing.SetOriginCaller(prov1)510 testing.SetOriginSend(nil)511 uassert.AbortsContains(t, cur, "acceptance window has not lapsed", func() {512 ReleaseTimeout(cross(cur), oid)513 })514515 // Nothing has moved.516 if BalanceOf(prov1) != p0 {517 t.Fatalf("provider credited without resolution: %d -> %d", p0, BalanceOf(prov1))518 }519 if EscrowTotal()-b.escrow != 1000000 {520 t.Fatalf("escrow moved: ΔE=%d", EscrowTotal()-b.escrow)521 }522523 // The customer, and only the customer, resolves it.524 testing.SetRealm(testing.NewUserRealm(cust1))525 testing.SetOriginCaller(cust1)526 testing.SetOriginSend(nil)527 AcceptDelivery(cross(cur), oid)528 if BalanceOf(prov1)-p0 != 1000000 {529 t.Fatalf("provider credited %d, want 1000000 at 0 bps", BalanceOf(prov1)-p0)530 }531 appInvariant(t)532 b.conserved(t, 0)533}534535// There is no admin path to escrow at all. The admin's only powers are536// the fee for FUTURE services, the fee recipient, and succession.537func TestAdminCannotTouchEscrow(cur realm, t *testing.T) {538 b := begin()539 sid := registerAs(cur, prov1, "held work", "d", 700000, 20000)540 oid := purchaseAs(cur, cust1, sid, 700000)541542 testing.SetRealm(testing.NewUserRealm(testAdmin))543 testing.SetOriginCaller(testAdmin)544 testing.SetOriginSend(nil)545 uassert.AbortsWithMessage(t, cur, "only the provider may mark this order delivered", func() {546 MarkDelivered(cross(cur), oid, "x")547 })548 uassert.AbortsWithMessage(t, cur, "only the provider may decline this order", func() {549 DeclineOrder(cross(cur), oid)550 })551 uassert.AbortsContains(t, cur, "delivery window has not lapsed", func() {552 ClaimRefund(cross(cur), oid)553 })554555 // And sweep cannot reach live escrow: the reserve covers E too.556 testing.IssueCoins(Address(), ugnot(12345)) // genuine out-of-band surplus557 before := coinsOf(testAdmin)558 SweepDenom(cross(cur), Denom)559 if got := coinsOf(testAdmin) - before; got != 12345 {560 t.Fatalf("swept %d, want exactly the 12345 surplus", got)561 }562 if EscrowTotal() != b.escrow+700000 {563 t.Fatalf("sweep reached escrow: %d", EscrowTotal())564 }565 appInvariant(t)566}567568// DOUBLE PAYMENT. Every terminal transition is reachable at most once,569// and the two terminal outcomes are mutually exclusive.570func TestNoDoublePayment(cur realm, t *testing.T) {571 b := begin()572 sid := registerAs(cur, prov1, "double check", "d", 600000, 20000)573574 // Accept twice.575 oid := purchaseAs(cur, cust1, sid, 600000)576 testing.SetRealm(testing.NewUserRealm(prov1))577 testing.SetOriginCaller(prov1)578 testing.SetOriginSend(nil)579 MarkDelivered(cross(cur), oid, "v1")580 testing.SetRealm(testing.NewUserRealm(cust1))581 testing.SetOriginCaller(cust1)582 testing.SetOriginSend(nil)583 AcceptDelivery(cross(cur), oid)584 credited := BalanceOf(prov1)585 uassert.AbortsWithMessage(t, cur, "order is not awaiting acceptance", func() {586 AcceptDelivery(cross(cur), oid)587 })588 if BalanceOf(prov1) != credited {589 t.Fatalf("second accept paid again: %d -> %d", credited, BalanceOf(prov1))590 }591592 // Released orders cannot then be refunded, timed out, or re-delivered.593 uassert.AbortsWithMessage(t, cur, "order is not awaiting acceptance", func() {594 ReleaseTimeout(cross(cur), oid)595 })596 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {597 ClaimRefund(cross(cur), oid)598 })599 testing.SetRealm(testing.NewUserRealm(prov1))600 testing.SetOriginCaller(prov1)601 testing.SetOriginSend(nil)602 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {603 DeclineOrder(cross(cur), oid)604 })605 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {606 MarkDelivered(cross(cur), oid, "v2")607 })608609 // Decline twice, and a declined order cannot then be released.610 oid2 := purchaseAs(cur, cust2, sid, 600000)611 testing.SetRealm(testing.NewUserRealm(prov1))612 testing.SetOriginCaller(prov1)613 testing.SetOriginSend(nil)614 DeclineOrder(cross(cur), oid2)615 refunded := BalanceOf(cust2)616 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {617 DeclineOrder(cross(cur), oid2)618 })619 if BalanceOf(cust2) != refunded {620 t.Fatalf("second decline refunded again")621 }622 testing.SetRealm(testing.NewUserRealm(cust2))623 testing.SetOriginCaller(cust2)624 testing.SetOriginSend(nil)625 uassert.AbortsWithMessage(t, cur, "order is not awaiting acceptance", func() {626 AcceptDelivery(cross(cur), oid2)627 })628 appInvariant(t)629 b.conserved(t, 0)630}631632// A claim pays out once; the ledger is debited before coins move.633func TestNoDoubleClaim(cur realm, t *testing.T) {634 b := begin()635 p0 := BalanceOf(prov1) // carried in from earlier tests; ClaimAll drains it too636 sid := registerAs(cur, prov1, "claim once", "d", 800000, 20000)637 oid := purchaseAs(cur, cust1, sid, 800000)638 testing.SetRealm(testing.NewUserRealm(prov1))639 testing.SetOriginCaller(prov1)640 testing.SetOriginSend(nil)641 MarkDelivered(cross(cur), oid, "done")642 testing.SetRealm(testing.NewUserRealm(cust1))643 testing.SetOriginCaller(cust1)644 testing.SetOriginSend(nil)645 AcceptDelivery(cross(cur), oid)646647 testing.SetRealm(testing.NewUserRealm(prov1))648 testing.SetOriginCaller(prov1)649 testing.SetOriginSend(nil)650 before := coinsOf(prov1)651 ClaimAll(cross(cur))652 if got := coinsOf(prov1) - before; got != p0+800000 {653 t.Fatalf("claimed %d, want %d", got, p0+800000)654 }655 if BalanceOf(prov1) != 0 {656 t.Fatal("balance not zeroed")657 }658 uassert.AbortsWithMessage(t, cur, "nothing to claim", func() {659 ClaimAll(cross(cur))660 })661 uassert.AbortsContains(t, cur, "insufficient", func() {662 Claim(cross(cur), 1)663 })664 if got := coinsOf(prov1) - before; got != p0+800000 {665 t.Fatalf("a second claim paid out: total %d", got)666 }667 appInvariant(t)668 b.conserved(t, 0)669}670671// STUCK FUNDS, arm 1: the provider abandons the order. Anyone may672// return the escrow to the customer once the delivery window lapses.673func TestStuckFundsProviderAbandons(cur realm, t *testing.T) {674 b := begin()675 sid := registerAs(cur, prov1, "never delivered", "d", 900000, MinDeliveryBlocks)676 oid := purchaseAs(cur, cust1, sid, 900000)677678 // Too early, even for the customer.679 testing.SetRealm(testing.NewUserRealm(cust1))680 testing.SetOriginCaller(cust1)681 testing.SetOriginSend(nil)682 uassert.AbortsContains(t, cur, "delivery window has not lapsed", func() {683 ClaimRefund(cross(cur), oid)684 })685686 testing.SkipHeights(MinDeliveryBlocks)687688 // A total stranger pulls the valve; the money goes to the CUSTOMER,689 // not to the caller.690 testing.SetRealm(testing.NewUserRealm(mallory))691 testing.SetOriginCaller(mallory)692 testing.SetOriginSend(nil)693 mBefore := BalanceOf(mallory)694 ClaimRefund(cross(cur), oid)695 if BalanceOf(mallory) != mBefore {696 t.Fatal("the valve paid its caller")697 }698 if BalanceOf(cust1) != 900000 {699 t.Fatalf("customer refund = %d, want 900000", BalanceOf(cust1))700 }701 if FeesAccrued() != b.fees {702 t.Fatal("a refund accrued a protocol fee")703 }704 _, _, _, _, _, status := OrderInfo(oid)705 if status != OrderRefunded {706 t.Fatalf("status = %s", status)707 }708 // And the customer can actually get the coins out.709 testing.SetRealm(testing.NewUserRealm(cust1))710 testing.SetOriginCaller(cust1)711 testing.SetOriginSend(nil)712 before := coinsOf(cust1)713 ClaimAll(cross(cur))714 if got := coinsOf(cust1) - before; got != 900000 {715 t.Fatalf("customer withdrew %d", got)716 }717 appInvariant(t)718 b.conserved(t, 0)719}720721// STUCK FUNDS, arm 2: the customer goes silent after delivery. Anyone722// may release the escrow to the provider once acceptance lapses. This723// is the valve whose polarity is INVERTED from every sibling realm's,724// and getting it wrong would strand completed work.725func TestStuckFundsCustomerGoesSilent(cur realm, t *testing.T) {726 b := begin()727 sid := registerAs(cur, prov1, "delivered ignored", "d", 1000000, MaxDeliveryBlocks)728 oid := purchaseAs(cur, cust1, sid, 1000000)729 testing.SetRealm(testing.NewUserRealm(prov1))730 testing.SetOriginCaller(prov1)731 testing.SetOriginSend(nil)732 MarkDelivered(cross(cur), oid, "ipfs://final")733734 _, acceptanceDeadline := OrderDeadlines(oid)735 if acceptanceDeadline != Height()+AcceptanceBlocks {736 t.Fatalf("acceptance deadline = %d, want height+%d", acceptanceDeadline, AcceptanceBlocks)737 }738739 testing.SkipHeights(AcceptanceBlocks)740741 testing.SetRealm(testing.NewUserRealm(mallory))742 testing.SetOriginCaller(mallory)743 testing.SetOriginSend(nil)744 mBefore := BalanceOf(mallory)745 ReleaseTimeout(cross(cur), oid)746 if BalanceOf(mallory) != mBefore {747 t.Fatal("the valve paid its caller")748 }749 if BalanceOf(prov1) != 1000000 {750 t.Fatalf("provider = %d, want 1000000", BalanceOf(prov1))751 }752 _, _, _, _, _, status := OrderInfo(oid)753 if status != OrderReleased {754 t.Fatalf("status = %s", status)755 }756 appInvariant(t)757 b.conserved(t, 0)758}759760// The delivery deadline protects the customer, so late delivery is761// allowed while the refund valve is still un-pulled — but the refund762// valve closes the instant delivery lands, and reopening it is not763// possible.764func TestLateDeliveryRace(cur realm, t *testing.T) {765 b := begin()766 p0 := BalanceOf(prov1)767 sid := registerAs(cur, prov1, "late but wanted", "d", 500000, MinDeliveryBlocks)768 oid := purchaseAs(cur, cust1, sid, 500000)769770 testing.SkipHeights(MinDeliveryBlocks + 10)771772 // Provider delivers late; permitted.773 testing.SetRealm(testing.NewUserRealm(prov1))774 testing.SetOriginCaller(prov1)775 testing.SetOriginSend(nil)776 MarkDelivered(cross(cur), oid, "late.zip")777778 // The refund valve is now closed: the order is no longer awaiting779 // delivery, so the lapsed delivery deadline is irrelevant.780 testing.SetRealm(testing.NewUserRealm(mallory))781 testing.SetOriginCaller(mallory)782 testing.SetOriginSend(nil)783 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {784 ClaimRefund(cross(cur), oid)785 })786 testing.SetRealm(testing.NewUserRealm(cust1))787 testing.SetOriginCaller(cust1)788 testing.SetOriginSend(nil)789 uassert.AbortsWithMessage(t, cur, "order is not awaiting delivery", func() {790 ClaimRefund(cross(cur), oid)791 })792793 // The customer still holds the real lever: accept, or wait out the794 // acceptance window.795 AcceptDelivery(cross(cur), oid)796 if BalanceOf(prov1)-p0 != 500000 {797 t.Fatalf("provider credited %d, want 500000", BalanceOf(prov1)-p0)798 }799 appInvariant(t)800 b.conserved(t, 0)801}802803// ---- fees, sweep, administration ----804805func TestFeeSplitAndWithdraw(cur realm, t *testing.T) {806 b := begin()807 p0 := BalanceOf(prov1)808 testing.SetRealm(testing.NewUserRealm(testAdmin))809 testing.SetOriginCaller(testAdmin)810 testing.SetOriginSend(nil)811 SetFeeBps(cross(cur), 250) // 2.5%812813 sid := registerAs(cur, prov1, "fee bearing", "d", 1000000, 20000)814 p, fee, toProvider := Quote(sid)815 if p != 1000000 || fee != 25000 || toProvider != 975000 {816 t.Fatalf("Quote = %d/%d/%d", p, fee, toProvider)817 }818819 oid := purchaseAs(cur, cust1, sid, 1000000)820 testing.SetRealm(testing.NewUserRealm(prov1))821 testing.SetOriginCaller(prov1)822 testing.SetOriginSend(nil)823 MarkDelivered(cross(cur), oid, "x")824 testing.SetRealm(testing.NewUserRealm(cust1))825 testing.SetOriginCaller(cust1)826 testing.SetOriginSend(nil)827 AcceptDelivery(cross(cur), oid)828829 if BalanceOf(prov1)-p0 != 975000 {830 t.Fatalf("provider credited %d, want 975000", BalanceOf(prov1)-p0)831 }832 if FeesAccrued()-b.fees != 25000 {833 t.Fatalf("fee pot ΔF = %d", FeesAccrued()-b.fees)834 }835836 testing.SetRealm(testing.NewUserRealm(mallory))837 testing.SetOriginCaller(mallory)838 testing.SetOriginSend(nil)839 uassert.AbortsWithMessage(t, cur, "only the fee recipient may withdraw fees", func() {840 WithdrawFees(cross(cur))841 })842 testing.SetRealm(testing.NewUserRealm(testAdmin))843 testing.SetOriginCaller(testAdmin)844 testing.SetOriginSend(nil)845 before := coinsOf(testAdmin)846 WithdrawFees(cross(cur))847 if got := coinsOf(testAdmin) - before; got != b.fees+25000 {848 t.Fatalf("withdrew %d", got)849 }850 uassert.AbortsWithMessage(t, cur, "no fees accrued", func() {851 WithdrawFees(cross(cur))852 })853854 testing.SetRealm(testing.NewUserRealm(testAdmin))855 testing.SetOriginCaller(testAdmin)856 testing.SetOriginSend(nil)857 SetFeeBps(cross(cur), 0)858 appInvariant(t)859 b.conserved(t, 0)860}861862func TestSweepReservesEscrow(cur realm, t *testing.T) {863 b := begin()864 sid := registerAs(cur, prov1, "sweep guard", "d", 400000, 20000)865 purchaseAs(cur, cust1, sid, 400000)866867 // No surplus yet. coinio.Sweep aborts rather than sending zero, so868 // the escrow is unreachable by REVERT, not merely by arithmetic —869 // which is the stronger of the two.870 testing.SetRealm(testing.NewUserRealm(testAdmin))871 testing.SetOriginCaller(testAdmin)872 testing.SetOriginSend(nil)873 before := coinsOf(testAdmin)874 uassert.AbortsContains(t, cur, "no surplus to sweep", func() {875 SweepDenom(cross(cur), Denom)876 })877 if coinsOf(testAdmin) != before {878 t.Fatal("swept out of a zero-surplus realm")879 }880 if EscrowTotal() != b.escrow+400000 {881 t.Fatal("sweep reached escrow")882 }883884 // A foreign denom moves wholly.885 testing.IssueCoins(Address(), chain.NewCoins(chain.NewCoin("gjunk", 77)))886 SweepDenom(cross(cur), "gjunk")887 if banker.NewReadonlyBanker().GetCoin(testAdmin, "gjunk") != 77 {888 t.Fatal("foreign denom not swept")889 }890891 testing.SetRealm(testing.NewUserRealm(mallory))892 testing.SetOriginCaller(mallory)893 testing.SetOriginSend(nil)894 uassert.AbortsWithMessage(t, cur, "only the fee recipient may sweep surplus", func() {895 SweepDenom(cross(cur), Denom)896 })897 appInvariant(t)898}899900func TestAdminHandover(cur realm, t *testing.T) {901 b := begin()902 testing.SetRealm(testing.NewUserRealm(mallory))903 testing.SetOriginCaller(mallory)904 testing.SetOriginSend(nil)905 uassert.AbortsWithMessage(t, cur, "admin only", func() {906 TransferAdmin(cross(cur), mallory)907 })908 uassert.AbortsWithMessage(t, cur, "admin only", func() {909 SetFeeBps(cross(cur), 10)910 })911 uassert.AbortsWithMessage(t, cur, "admin only", func() {912 SetFeeRecipient(cross(cur), mallory)913 })914915 testing.SetRealm(testing.NewUserRealm(testAdmin))916 testing.SetOriginCaller(testAdmin)917 testing.SetOriginSend(nil)918 // A malformed nominee is rejected where the typo is made, for parity919 // with SetFeeRecipient. The zero address keeps its documented meaning920 // as the cancel sentinel and must NOT be caught by that check.921 uassert.AbortsWithMessage(t, cur, "invalid admin address", func() {922 TransferAdmin(cross(cur), address("g1notanaddress"))923 })924 TransferAdmin(cross(cur), prov2)925 if Admin() != testAdmin {926 t.Fatal("nomination took effect immediately")927 }928 if PendingAdmin() != prov2 {929 t.Fatalf("pending = %v", PendingAdmin())930 }931 TransferAdmin(cross(cur), "")932 if PendingAdmin() != "" {933 t.Fatalf("zero address did not cancel: %v", PendingAdmin())934 }935 TransferAdmin(cross(cur), prov2)936937 // Wrong acceptor.938 testing.SetRealm(testing.NewUserRealm(mallory))939 testing.SetOriginCaller(mallory)940 testing.SetOriginSend(nil)941 uassert.AbortsWithMessage(t, cur, "only the nominated admin may accept", func() {942 AcceptAdmin(cross(cur))943 })944 testing.SetRealm(testing.NewUserRealm(prov2))945 testing.SetOriginCaller(prov2)946 testing.SetOriginSend(nil)947 AcceptAdmin(cross(cur))948 if Admin() != prov2 {949 t.Fatalf("admin = %v", Admin())950 }951 var zero address952 if PendingAdmin() != zero {953 t.Fatal("pending not cleared")954 }955956 // Authority MOVED: the former admin is now powerless.957 testing.SetRealm(testing.NewUserRealm(testAdmin))958 testing.SetOriginCaller(testAdmin)959 testing.SetOriginSend(nil)960 uassert.AbortsWithMessage(t, cur, "admin only", func() {961 SetFeeBps(cross(cur), 10)962 })963964 // Hand it back so the rest of the suite keeps its seeded roles.965 testing.SetRealm(testing.NewUserRealm(prov2))966 testing.SetOriginCaller(prov2)967 testing.SetOriginSend(nil)968 TransferAdmin(cross(cur), testAdmin)969 testing.SetRealm(testing.NewUserRealm(testAdmin))970 testing.SetOriginCaller(testAdmin)971 testing.SetOriginSend(nil)972 AcceptAdmin(cross(cur))973 if Admin() != testAdmin {974 t.Fatal("handback failed")975 }976 appInvariant(t)977 b.conserved(t, 0)978}979980// ---- render safety ----981982func TestRenderSanitizesUntrustedText(cur realm, t *testing.T) {983 begin()984 evil := "[click](https://evil.example) "985 sid := registerAs(cur, prov1, "render probe", evil, 100000, 20000)986 oid := purchaseAs(cur, cust1, sid, 100000)987 testing.SetRealm(testing.NewUserRealm(prov1))988 testing.SetOriginCaller(prov1)989 testing.SetOriginSend(nil)990 MarkDelivered(cross(cur), oid, evil)991992 sOut := Render("s/" + itoa(sid))993 if strings.Contains(sOut, "](https://evil.example)") {994 t.Fatal("service description rendered an unescaped markdown link")995 }996 oOut := Render("o/" + itoa(oid))997 if strings.Contains(oOut, "](https://evil.example/x.png)") {998 t.Fatal("delivery uri rendered an unescaped markdown image")999 }10001001 // Unknown and malformed ids degrade to a warning, never a panic.1002 for _, p := range []string{"s/abc", "o/abc", "s/999999", "o/999999"} {1003 if !strings.Contains(Render(p), "[!WARNING]") {1004 t.Fatalf("Render(%q) did not warn", p)1005 }1006 }1007 if !strings.Contains(Render(""), "Service marketplace") {1008 t.Fatal("home render broken")1009 }1010 appInvariant(t)1011}10121013// The home page is bounded regardless of catalog size.1014func TestRenderIsBounded(cur realm, t *testing.T) {1015 begin()1016 for i := 0; i < RenderLimit+5; i++ {1017 registerAs(cur, prov2, "bulk svc", "d", 1000, MinDeliveryBlocks)1018 testing.SetRealm(testing.NewUserRealm(prov2))1019 testing.SetOriginCaller(prov2)1020 testing.SetOriginSend(nil)1021 // Retire immediately so the per-provider cap is not the thing1022 // under test here.1023 RetireService(cross(cur), NumServices()-1)1024 }1025 out := Render("")1026 if got := strings.Count(out, "\n- [#"); got > RenderLimit {1027 t.Fatalf("home listed %d services, cap is %d", got, RenderLimit)1028 }1029 appInvariant(t)1030}10311032// ---- guards on every non-payable entrypoint ----10331034func TestNonPayableEntrypointsRefuseCoins(cur realm, t *testing.T) {1035 b := begin()1036 sid := registerAs(cur, prov1, "send guard", "d", 100000, 20000)1037 oid := purchaseAs(cur, cust1, sid, 100000)10381039 stage := func(from address) {1040 testing.SetRealm(testing.NewUserRealm(from))1041 testing.SetOriginCaller(from)1042 testing.SetOriginSend(ugnot(1))1043 }1044 msg := "this function does not accept coins"10451046 stage(prov1)1047 uassert.AbortsWithMessage(t, cur, msg, func() { MarkDelivered(cross(cur), oid, "x") })1048 uassert.AbortsWithMessage(t, cur, msg, func() { DeclineOrder(cross(cur), oid) })1049 uassert.AbortsWithMessage(t, cur, msg, func() { RetireService(cross(cur), sid) })1050 uassert.AbortsWithMessage(t, cur, msg, func() { ClaimAll(cross(cur)) })1051 uassert.AbortsWithMessage(t, cur, msg, func() { Claim(cross(cur), 1) })1052 stage(cust1)1053 uassert.AbortsWithMessage(t, cur, msg, func() { AcceptDelivery(cross(cur), oid) })1054 uassert.AbortsWithMessage(t, cur, msg, func() { ClaimRefund(cross(cur), oid) })1055 uassert.AbortsWithMessage(t, cur, msg, func() { ReleaseTimeout(cross(cur), oid) })1056 stage(testAdmin)1057 uassert.AbortsWithMessage(t, cur, msg, func() { SetFeeBps(cross(cur), 1) })1058 uassert.AbortsWithMessage(t, cur, msg, func() { SetFeeRecipient(cross(cur), prov1) })1059 uassert.AbortsWithMessage(t, cur, msg, func() { TransferAdmin(cross(cur), prov1) })1060 uassert.AbortsWithMessage(t, cur, msg, func() { AcceptAdmin(cross(cur)) })1061 uassert.AbortsWithMessage(t, cur, msg, func() { WithdrawFees(cross(cur)) })1062 uassert.AbortsWithMessage(t, cur, msg, func() { SweepDenom(cross(cur), Denom) })10631064 testing.SetRealm(testing.NewUserRealm(prov1))1065 testing.SetOriginCaller(prov1)1066 testing.SetOriginSend(nil)1067 appInvariant(t)1068 if EscrowTotal() != b.escrow+100000 {1069 t.Fatal("a refused call moved escrow")1070 }1071}10721073func TestUnknownIdsAbort(cur realm, t *testing.T) {1074 begin()1075 testing.SetRealm(testing.NewUserRealm(mallory))1076 testing.SetOriginCaller(mallory)1077 testing.SetOriginSend(nil)1078 uassert.AbortsWithMessage(t, cur, "unknown service id", func() {1079 RetireService(cross(cur), 999999)1080 })1081 uassert.AbortsWithMessage(t, cur, "unknown order id", func() {1082 AcceptDelivery(cross(cur), 999999)1083 })1084 uassert.AbortsWithMessage(t, cur, "unknown order id", func() {1085 ClaimRefund(cross(cur), 999999)1086 })1087 uassert.AbortsWithMessage(t, cur, "unknown order id", func() {1088 ReleaseTimeout(cross(cur), 999999)1089 })1090 // A view is not a crossing call, so its failure is a plain panic1091 // rather than an abort — a different assertion, not a weaker one.1092 uassert.PanicsWithMessage(t, cur, "unknown service id", func() {1093 ServiceDescription(999999)1094 })1095 uassert.PanicsWithMessage(t, cur, "unknown order id", func() {1096 OrderInfo(999999)1097 })1098}10991100func TestMarkDeliveredBoundsURI(cur realm, t *testing.T) {1101 begin()1102 sid := registerAs(cur, prov1, "uri bound", "d", 100000, 20000)1103 oid := purchaseAs(cur, cust1, sid, 100000)1104 testing.SetRealm(testing.NewUserRealm(prov1))1105 testing.SetOriginCaller(prov1)1106 testing.SetOriginSend(nil)1107 uassert.AbortsContains(t, cur, "uri must be at most", func() {1108 MarkDelivered(cross(cur), oid, strings.Repeat("u", MaxURILen+1))1109 })1110 MarkDelivered(cross(cur), oid, strings.Repeat("u", MaxURILen))1111 if len(OrderURI(oid)) != MaxURILen {1112 t.Fatal("uri not stored at the boundary")1113 }1114 appInvariant(t)1115}11161117func TestCheckedAddOverflow(t *testing.T) {1118 const maxInt64 int64 = 1<<63 - 11119 if _, ok := checkedAdd(maxInt64, 1); ok {1120 t.Fatal("overflow not detected")1121 }1122 if v, ok := checkedAdd(maxInt64-1, 1); !ok || v != maxInt64 {1123 t.Fatal("boundary add rejected")1124 }1125 if v, ok := checkedAdd(5, -3); !ok || v != 2 {1126 t.Fatal("negative delta broken")1127 }1128}11291130// A full multi-party run, asserting conservation at every checkpoint —1131// the property that all three protections ultimately rest on.1132func TestFullLifecycleConservation(cur realm, t *testing.T) {1133 b := begin()1134 testing.SetRealm(testing.NewUserRealm(testAdmin))1135 testing.SetOriginCaller(testAdmin)1136 testing.SetOriginSend(nil)1137 SetFeeBps(cross(cur), 100) // 1%11381139 s1 := registerAs(cur, prov1, "alpha", "d", 1000000, MinDeliveryBlocks)1140 s2 := registerAs(cur, prov2, "beta", "d", 2000000, MaxDeliveryBlocks)1141 b.conserved(t, 0)11421143 // Accepted.1144 o1 := purchaseAs(cur, cust1, s1, 1000000)1145 b.conserved(t, 0)1146 testing.SetRealm(testing.NewUserRealm(prov1))1147 testing.SetOriginCaller(prov1)1148 testing.SetOriginSend(nil)1149 MarkDelivered(cross(cur), o1, "a")1150 testing.SetRealm(testing.NewUserRealm(cust1))1151 testing.SetOriginCaller(cust1)1152 testing.SetOriginSend(nil)1153 AcceptDelivery(cross(cur), o1)1154 b.conserved(t, 0)11551156 // Declined.1157 o2 := purchaseAs(cur, cust2, s2, 2000000)1158 testing.SetRealm(testing.NewUserRealm(prov2))1159 testing.SetOriginCaller(prov2)1160 testing.SetOriginSend(nil)1161 DeclineOrder(cross(cur), o2)1162 b.conserved(t, 0)11631164 // Expired to a refund.1165 o3 := purchaseAs(cur, cust1, s1, 1000000)1166 testing.SkipHeights(MinDeliveryBlocks)1167 testing.SetRealm(testing.NewUserRealm(mallory))1168 testing.SetOriginCaller(mallory)1169 testing.SetOriginSend(nil)1170 ClaimRefund(cross(cur), o3)1171 b.conserved(t, 0)11721173 // Timed out to a release.1174 o4 := purchaseAs(cur, cust2, s2, 2000000)1175 testing.SetRealm(testing.NewUserRealm(prov2))1176 testing.SetOriginCaller(prov2)1177 testing.SetOriginSend(nil)1178 MarkDelivered(cross(cur), o4, "b")1179 testing.SkipHeights(AcceptanceBlocks)1180 testing.SetRealm(testing.NewUserRealm(mallory))1181 testing.SetOriginCaller(mallory)1182 testing.SetOriginSend(nil)1183 ReleaseTimeout(cross(cur), o4)1184 b.conserved(t, 0)11851186 if EscrowTotal() != b.escrow {1187 t.Fatalf("escrow not drained: %d -> %d", b.escrow, EscrowTotal())1188 }11891190 // Everyone withdraws; the realm ends holding only what it started1191 // with plus the fee pot it still owes.1192 for _, who := range []address{prov1, prov2, cust1, cust2, testAdmin, mallory} {1193 if BalanceOf(who) == 0 {1194 continue1195 }1196 testing.SetRealm(testing.NewUserRealm(who))1197 testing.SetOriginCaller(who)1198 testing.SetOriginSend(nil)1199 ClaimAll(cross(cur))1200 }1201 // Every counterparty this suite has ever used is in that list, so1202 // draining them must take U to exactly zero — not back to the1203 // baseline, which still carried earlier tests' unclaimed credits.1204 if UsersTotal() != 0 {1205 t.Fatalf("claimable residue: %d", UsersTotal())1206 }1207 appInvariant(t)1208 b.conserved(t, 0)12091210 testing.SetRealm(testing.NewUserRealm(testAdmin))1211 testing.SetOriginCaller(testAdmin)1212 testing.SetOriginSend(nil)1213 SetFeeBps(cross(cur), 0)1214}1215AcceptAdmin(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})
AcceptDelivery(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}, orderID int64)
Address() string
Admin() string
BalanceOf(addr string) 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})
ClaimRefund(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}, orderID int64)
DeclineOrder(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}, orderID int64)
EscrowTotal() int64
FeeBps() int64
FeeRecipient() string
FeesAccrued() int64
Height() int64
Held() int64
Liabilities() int64
MarkDelivered(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}, orderID int64, uri string)
NumOrders() int64
NumServices() int64
OrderDeadlines(id int64) (deliveryDeadline int64, acceptanceDeadline int64)
OrderInfo(id int64) (serviceID int64, customer string, provider string, amount int64, feeBps int64, status string)
OrderURI(id int64) string
PendingAdmin() string
PurchaseService(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}, serviceID int64) int64
Quote(id int64) (price int64, fee int64, toProvider int64)
RegisterService(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, deliveryBlocks int64, maxFeeBps int64) int64
ReleaseTimeout(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}, orderID int64)
Render(path string) string
RetireService(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}, id int64)
ServiceDescription(id int64) string
ServiceInfo(id int64) (provider string, title string, price int64, deliveryBlocks int64, feeBps int64, status string, orderCount int64)
ServicesOf(a string) 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}, next string)
Surplus() 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}, next 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.
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.