Cosmic Bull

Realm on pearl-1

market

gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/market

realmapplicationmarketplace

RenderedSourceCall builderState

curated

Multi-domain listing/offer marketplace composing coinio + feeledger + avl/v0 + sanitize/v0; seven attack shapes rejected live.

Identity

Import pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/market
Kindrealm (/r/)
Chainpearl-1
Namespaceg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Realm addressg1y8nzwrv7ufe8c5r747vfpjm8jvayhgvddqwl2g derived, never confirmed against the realm

Provenance

chain-attested
Deployed at height585,791
Deploy transaction76293576775be9db30ab097944990e9c5836d00e52a84b979d3284b7707f82d9 look it up on the RPC
Deployerg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Gas used34,983,448
Storage35,356 bytes, deposit 3535600ugnot
Files on chaingnomod.toml market.gno
Deployed bytesmarket.gno — 18,476 bytes
sha25643cece28779b7d4c081c2bf6dc70c7fb5b6e80776792b8f0a6ee606696e10fd4

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/market$download&file=market.gno' | shasum -a 256

Expected: 43cece28779b7d4c081c2bf6dc70c7fb5b6e80776792b8f0a6ee606696e10fd4 — 18,476 bytes. This was checked for all 21 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 23 exported functions.

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

AcceptAdminBalanceOfBuyCancelListingClaimClaimAllCreateListingDescriptionFeeBpsFeesAccruedHeldLiabilitiesListingInfoNumListingsQuoteRenderSetFeeBpsSetFeeRecipientSurplusSweepDenomTransferAdminUsersTotalWithdrawFees

Overview

Realm market is a custodial GNOT marketplace for goods listings: sellers list (title, description, price), a buyer purchases by paying the exact price, the marketplace holds the value until the seller claims their proceeds (price minus a transparent, snapshotted protocol fee).

COMPOSITION (per the recorded DISCOVERY / REUSE ANALYSIS): balance accounting is feeledger, coin movement is coinio, free-text render safety is the ecosystem sanitizer p/nt/markdown/sanitize/v0. This realm owns only the listing state machine. Two patterns are adopted from inspected ecosystem marketplaces: non-payable entrypoints REFUSE accidental -send instead of stranding it as surplus (nsmarket/v4's assertNoSend), and admin handoff is 2-STEP (memba_appstore_v2's TransferOwnership/AcceptOwnership), closing the one-step-transfer trade-off carried by earlier realms.

LIFECYCLE (terminal states are frozen; one transition per listing):

CreateListing (anyone, no coins) : status Active; the fee bps is SNAPSHOTTED, subject to the seller's own maxFeeBps ceiling Buy (EOA + -send == price) : Active -> Sold, atomically: proceeds (price - snapshot fee) credit the seller's claimable balance, the fee accrues to the pot, the buyer is recorded CancelListing (seller only) : Active -> Cancelled (no funds are involved; listings hold no value) Claim / ClaimAll (anyone) : pays out the caller's own claimable proceeds WithdrawFees (fee recipient) : pays out the fee pot

LISTINGS ARE IMMUTABLE: there is no price update — cancel and relist (new id). Together with Buy's EXACT-envelope rule this closes the listing-manipulation race twice over: a cancelled/relisted listing fails Buy's status check, and any price change fails the envelope check — either way the buyer's coins revert with the transaction. Buyers are structurally indifferent to fee changes: they pay the listed price; the fee comes out of the seller's proceeds at the bps snapshotted when the SELLER listed (with the seller's own ceiling — the creation-time fee race is closed the same way grants closes it).

AUTHORIZATION: every identity derives from the crossing entrypoint's cur.Previous().Address(); no function takes a caller identity as a parameter. Sellers may be EOAs or realms (they claim under their own address); buyers must be EOAs (coinio.Receive is the receipt-guaranteed shape). Self-purchase is rejected.

REALM-SELLER CAVEAT (audit Y1): assertNoSend reads the ORIGIN transaction's send envelope, so a realm seller must call CreateListing/CancelListing/Claim* in a transaction whose origin carried no -send — otherwise the guard fails closed even though this realm received nothing. Not third-party triggerable (nobody can attach a send to someone else's transaction); the workaround is a separate transaction.

MONETARY INVARIANT (conservation): listings hold NO value, so with H = ugnot held at the realm address, U = claimable seller proceeds, F = the fee pot, S >= 0 out-of-band surplus:

H == U + F + S

Buy raises H by exactly price and U+F by exactly price (feeledger guarantees credited + fee == amount); Claim*/WithdrawFees debit the ledger before coinio.Payout moves the identical amount out; any panic aborts the whole transaction; this realm never issues or removes coins. Surplus is recoverable only via SweepDenom (fee recipient), which reserves Liabilities() = U + F.

APPLICATION INVARIANT: status transitions Active -> {Sold, Cancelled} exactly once; Sold if and only if a buyer is recorded; for every sold listing, proceeds + fee == price at the snapshotted bps.

Imports

Constants and variables

Listing status values.

const (
	StatusActive    = "active"
	StatusSold      = "sold"
	StatusCancelled = "cancelled"
)

Input bounds.

const (
	MaxTitleLen = 80
	MaxDescLen  = 2000
	MinPrice    = int64(1)
)

Denom is the only asset this realm accepts.

const Denom = "ugnot"

MaxFeeBps is the hard protocol-fee cap: 1000 bps = 10%.

const MaxFeeBps = int64(1000)

Functions

AcceptAdmin

func AcceptAdmin(cur realm)

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

AcceptAdmin completes a staged admin handoff. Only the staged address may call it.

BalanceOf

func BalanceOf(addr address) int64

BalanceOf returns addr's claimable proceeds.

Buy

func Buy(cur realm, id int64)

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

Buy purchases an active listing. The buyer must be a direct EOA caller and attach EXACTLY the listed price in ugnot — any mismatch (including a price the seller changed by cancel-and-relist) aborts and the coins revert with the transaction. Settlement is atomic: the seller's proceeds (price minus the snapshotted fee) become claimable, the fee accrues to the pot, and the buyer is recorded. Terminal.

CancelListing

func CancelListing(cur realm, id int64)

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

CancelListing withdraws an active listing. Only the seller may cancel; no funds are involved. Terminal.

Claim

func Claim(cur realm, amount int64)

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

Claim sends amount ugnot of the caller's claimable proceeds back to the caller.

ClaimAll

func ClaimAll(cur realm)

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

ClaimAll sends the caller's entire claimable proceeds back to the caller. Fails if there is nothing to claim.

CreateListing

func CreateListing(cur realm, title, description string, price, maxFeeBps int64) int64

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

CreateListing publishes an immutable listing and returns its id. No coins are accepted (the storage deposit the caller pays is the anti-spam). The current protocol fee is snapshotted into the listing and must not exceed maxFeeBps, the ceiling the seller signed for; pass MaxFeeBps to accept any legal fee. Sellers may be EOAs or realms.

Description

func Description(id int64) string

Description returns a listing's raw description text.

FeeBps

func FeeBps() int64

FeeBps returns the fee that will be snapshotted into newly created listings (existing listings keep their own snapshot).

FeesAccrued

func FeesAccrued() int64

FeesAccrued returns the fee pot (the F term).

Held

func Held() int64

Held returns the ugnot actually held at the realm address (H).

Liabilities

func Liabilities() int64

Liabilities returns everything this realm owes: UsersTotal + FeesAccrued (listings hold no value by construction).

ListingInfo

func ListingInfo(id int64) (seller address, title string, price, feeBps int64, status string, buyer address)

ListingInfo returns a listing's fields by value: seller, title, price, snapshotted fee bps, status, and buyer (zero unless sold).

NumListings

func NumListings() int64

NumListings returns how many listings have ever been created.

Quote

func Quote(id int64) (price, fee, toSeller int64)

Quote returns what a buyer pays and what the seller would receive for a listing, at its SNAPSHOTTED fee — the same arithmetic Buy performs (pattern from nsmarket/v4: a fee discovered after signing is a fee the seller was not told about).

Render

func Render(path string) string

Render shows the market at "" and a listing detail at "<id>". Titles are charset-restricted; descriptions pass through the ecosystem sanitizer.

SetFeeBps

func SetFeeBps(cur realm, bps int64)

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

SetFeeBps sets the protocol fee snapshotted into FUTURE listings. Existing listings keep the fee they were created under. Admin only; bounded by [0, MaxFeeBps].

SetFeeRecipient

func SetFeeRecipient(cur realm, next address)

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

SetFeeRecipient re-points the fee/surplus role, including the pot accrued so far. Admin only; zero address rejected.

Surplus

func Surplus() int64

Surplus returns Held() - Liabilities() (the S term).

SweepDenom

func SweepDenom(cur realm, denom string)

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

SweepDenom sends the surplus of a single denomination to the fee recipient. For ugnot only the excess over Liabilities() moves; other denoms move wholly. Only the fee recipient may call it.

TransferAdmin

func TransferAdmin(cur realm, next address)

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

TransferAdmin STAGES a successor admin; the handoff completes only when that address calls AcceptAdmin (2-step, so a typo cannot brick administration — pattern adopted from memba_appstore_v2). Admin only; zero address rejected. Re-staging overwrites a previous stage.

UsersTotal

func UsersTotal() int64

UsersTotal returns the sum of all claimable proceeds (the U term).

WithdrawFees

func WithdrawFees(cur realm)

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

WithdrawFees sends the accrued fee pot to the fee recipient. Only the fee recipient may call it.


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

Dependencies

chain-attested
Importschain, chain/runtime/unsafe, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger, gno.land/p/nt/avl/v0, gno.land/p/nt/markdown/sanitize/v0, strconv
First-party dependenciesgno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/coinio, gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/feeledger
Used bynone

Known limitations

curated

The manifest records no limitation for this package. That is an absence of a recorded caveat, not a proof that none exists — the deployment record below is the fuller account, and it always carries its own "what was NOT verified live" section.

Source and records

Source filepearl/r/market/market.gno at commit 6a510c665a53 in the project repository (not public — the digest command above is the check that needs no repository)
Matches the deployed bytesyes — byte-identical
Recordscatalog/primitives.md#pre-pipeline-realms
pearl/DEPLOYMENT.md