solisting explorer

This commit is contained in:
thesn10
2026-06-24 23:02:54 +02:00
parent e326bfee51
commit 45e5c5267e
3 changed files with 2903 additions and 0 deletions

293
docs/solisting-explorer.md Normal file
View File

@@ -0,0 +1,293 @@
# Solisting Explorer — Frontend Design Brief
Build a dark, polished blockchain explorer frontend for the **Solisting** Solana program ecosystem — similar in style to Solscan or Jupiter (dark backgrounds, colored state badges, card-based layout). The primary accent color is Solana purple (`#9945FF`) with green (`#14F195`) for active/success states.
The app is called **Solisting Explorer**. It's a debug/inspection tool like mempool.space or Etherscan, but specifically for the solisting + descro program ecosystem. Users can browse all on-chain data and, if they connect their wallet, execute instructions they're authorized for.
---
## What Solisting Is
Solisting is a Solana on-chain program (Anchor framework) that provides a coordination layer for product listings and order consent. It sits on top of a separate escrow program called **descro**.
- Sellers create **Listings** advertising goods or services with a price in SOL (or SPL tokens).
- Buyers create **Orders** against a listing. This triggers the creation of a **descro Escrow** — a trustless SOL vault holding the buyer's funds until the seller confirms.
- The seller then accepts or rejects. Disputes are resolved by a **Resolver** (a registered third party).
- Solisting never holds funds itself — all money flows through descro's vault accounts.
---
## Programs and IDs
| Program | Role | Program ID |
|---|---|---|
| `solisting` | Listings + Orders | `DzwUAbpRvqcbA8QsEkRbZeXG4TEho5782cMySodrUHBU` |
| `descro` | Escrow vault engine | `DjVR4EuYV6USMJFfsGZwhZ3y8rtWsmG8EvDY96GTqqi3` |
| `descro_ext_resolvers` | Resolver registry | `GwUPAKs3HHzCpj8uhet4NAnxk9GWNwfrYbpihu5DyFp` |
The app needs a **network selector dropdown** in the top navigation: **localnet / devnet / mainnet-beta**. The selected network determines the RPC endpoint for all account fetches and transaction submissions.
---
## On-Chain Accounts
### ListingAccount (solisting program)
PDA seeds: `["listing", seller_pubkey_bytes, listing_id_as_u64_le_bytes]`
```
seller: Pubkey // wallet that created the listing
listing_id: u64 // unique ID chosen by seller
canonical_currency: Currency // Sol | Spl { mint: Pubkey, decimals: u8 }
price: u64 // in smallest unit of canonical_currency
canonical_oracle: Option<Pubkey> // Pyth V2 feed (TOKEN/USD). None = stablecoin ($1)
alt_currencies: Vec<AltCurrencyConfig> // max 3. each has { currency, usd_oracle: Option<Pubkey> }
accepted_resolvers: Vec<Pubkey> // max 4. empty = any resolver is accepted
quantity: u32 // total units (includes reserved)
quantity_reserved: u32 // locked by pending orders
metadata_uri: String // max 256 chars. IPFS or HTTPS link to listing metadata JSON
is_active: bool // whether new orders are accepted
bump: u8
```
Derived: `available = quantity quantity_reserved`
### OrderAccount (solisting program)
PDA seeds: `["order", listing_account_pubkey_bytes, buyer_pubkey_bytes, order_id_as_u64_le_bytes]`
```
listing: Pubkey // the ListingAccount this order belongs to
buyer: Pubkey
seller: Pubkey // copied from listing at creation
resolver: Pubkey // chosen dispute resolver
payment_currency: Currency
amount: u64 // final payment amount (oracle-converted if paying in alt currency)
escrow_account: Pubkey // linked descro EscrowAccount PDA
escrow_id: u64 // first 8 bytes of this order's PDA address as u64 little-endian
order_id: u64
created_at: i64 // unix timestamp
bump: u8
```
### EscrowAccount (descro program)
PDA seeds: `["escrow", seller_pubkey_bytes, escrow_id_as_u64_le_bytes]`
```
seller: Pubkey
buyer: Pubkey
amount: u64 // lamports held in the vault
dispute_resolver: Option<Pubkey>
state: EscrowState // see lifecycle below
escrow_id: u64
dispute_raised_at: Option<i64> // unix timestamp, set when dispute is raised
bump: u8
vault_bump: u8
```
The **vault** is a separate bare system account (no data, just holds SOL):
PDA seeds: `["vault", escrow_account_pubkey_bytes]` (in the descro program)
### EscrowState lifecycle
```
AwaitingSellerConfirm → buyer deposited, waiting for seller
Active → seller confirmed, delivery in progress
Disputed → dispute raised by buyer or seller
Complete → funds released to seller
Cancelled → funds refunded to buyer
```
State transitions:
- `AwaitingSellerConfirm``Active`: seller accepts (via solisting `accept_order`)
- `AwaitingSellerConfirm``Cancelled`: seller rejects, buyer cancels (via solisting or directly on descro)
- `Active``Complete`: buyer calls `complete` on descro (marks delivery received, vault goes to seller)
- `Active``Disputed`: buyer or seller raises dispute on descro
- `Disputed``Complete` or `Cancelled`: resolver calls `resolve(Winner)` on descro
State badge color suggestions: `AwaitingSellerConfirm` = amber, `Active` = green, `Disputed` = red/orange, `Complete` = blue/teal, `Cancelled` = gray.
### ResolverEntry (descro_ext_resolvers program)
PDA seeds: `["resolver", resolver_pubkey_bytes]`
```
authority: Pubkey
resolver_type: ResolverType // CentralAuthority | JuryDAO | MAD | Algorithmic | Multisig
acceptance_policy: AcceptancePolicy // Open | SignatureGated | ProgramGated
name: String // max 64 chars
description: String // max 256 chars
fee_bps: u16 // fee in basis points (100 bps = 1%)
fee_recipient: Pubkey
metadata_uri: String // max 256 chars
total_resolved: u64
ruled_for_buyer: u64
ruled_for_seller: u64
registered_at: i64
```
---
## Instructions
### Solisting: create_listing
Signer: seller
Creates a new `ListingAccount`.
Params: `listing_id`, `canonical_currency`, `price`, `canonical_oracle`, `alt_currencies` (max 3), `accepted_resolvers` (max 4), `quantity`, `metadata_uri`
### Solisting: update_listing
Signer: seller (must own the listing, listing must be active)
Updates all mutable fields on an existing `ListingAccount` (not the listing_id).
### Solisting: close_listing
Signer: seller
Closes the `ListingAccount`. Rent returned to seller.
### Solisting: create_order
Signer: buyer
Creates an `OrderAccount` and CPIs into descro to create + fund an escrow vault with the buyer's SOL.
Params: `order_id`, `escrow_id` (= first 8 bytes of order PDA as u64 LE), `resolver`, `payment_currency`, `expected_amount`, `max_slippage_bps`
Constraints: listing must be active, must have available quantity, currency must be in listing's accepted currencies, resolver must be in listing's accepted resolvers (if list is non-empty).
Note: only `Currency::Sol` works currently. SPL token payment is not yet implemented (`SplNotImplemented` error).
### Solisting: accept_order
Signer: seller
CPIs `descro::seller_confirm` → escrow moves to `Active`. Decrements `quantity_reserved` and `quantity`. Closes `OrderAccount` (rent to seller).
### Solisting: reject_order
Signer: seller
Defensive: reads escrow state first; only CPIs `descro::cancel` if escrow is still `AwaitingSellerConfirm`. Decrements `quantity_reserved`. Closes `OrderAccount`. Buyer gets vault refund.
### Solisting: cancel_order
Signer: buyer
Same as reject_order but initiated by the buyer. Closes `OrderAccount` (rent to buyer).
### Solisting: close_stale_order
Signer: anyone (permissionless cleanup)
Closes an `OrderAccount` whose linked descro escrow is already in a terminal state (`Complete` or `Cancelled`) or has already been closed (account data empty). Rent goes to the caller.
### Descro: complete
Signer: buyer
Constraint: escrow must be `Active`.
Releases vault funds to seller. Escrow → `Complete`. Closes escrow account.
### Descro: dispute
Signer: buyer or seller
Constraint: escrow must be `Active`.
Escrow → `Disputed`. Records `dispute_raised_at` timestamp.
### Descro: resolve
Signer: resolver (must match `escrow.dispute_resolver`)
Constraint: escrow must be `Disputed`.
Param: `winner: Winner` (Buyer or Seller).
Releases vault to winner. Escrow → `Complete`.
### Descro: cancel (direct)
Signer: buyer or seller
Constraint: escrow must be `AwaitingDeposit` or `AwaitingSellerConfirm`.
Refunds vault to buyer. Closes escrow.
---
## Error Codes (Solisting)
| Name | Message |
|---|---|
| `ListingNotActive` | Listing is not active |
| `OutOfStock` | No quantity available |
| `Unauthorized` | Signer is not authorized |
| `CurrencyNotAccepted` | Currency not accepted by this listing |
| `ResolverNotAccepted` | Resolver not accepted by this listing |
| `OracleRequired` | Oracle account required but not provided |
| `OracleMismatch` | Oracle key doesn't match listing |
| `OraclePriceUnavailable` | Oracle price stale or confidence too wide |
| `SlippageExceeded` | Oracle rate moved unfavorably |
| `SplNotImplemented` | SPL payment not yet implemented |
| `EscrowStateUnexpected` | Escrow not in expected state |
| `InvalidDescroProgram` | Descro program address mismatch |
---
## Oracle / Price Conversion
Solisting uses **Pyth V2** price feeds for multi-currency support.
- Prices must be no older than 60 seconds.
- Conversion formula (canonical currency → alt currency):
`target = price × canonical_price_raw / target_price_raw × 10^(canonical_exponent target_exponent + target_decimals canonical_decimals)`
- A currency with `usd_oracle = None` is treated as a $1.00 USD stablecoin.
- Slippage check: `|computed expected| ≤ expected × max_slippage_bps / 10_000`
---
## Relationships Between Accounts
```
ResolverEntry (descro_ext_resolvers)
↑ pubkey referenced in
ListingAccount.accepted_resolvers[] ←── one listing has many orders
↑ pubkey stored in
OrderAccount.listing
OrderAccount.resolver → can look up ResolverEntry for display
OrderAccount.escrow_account → EscrowAccount (descro)
EscrowAccount → Vault (bare SOL account, descro)
```
---
## Pages and Features
### Listings page (no wallet required)
Browse all `ListingAccount` PDAs on-chain. Show: listing ID, seller (abbreviated address), canonical price + currency, available qty / total qty, number of pending orders, active/inactive badge. Filterable by active status and seller address. Clicking a row goes to the listing detail page.
### Listing detail page (no wallet required)
Show all fields of the `ListingAccount`. Quantity displayed as a gauge or three numbers (available / reserved / total). Alt currencies listed with their oracle addresses. Accepted resolvers listed — if a `ResolverEntry` exists for that pubkey, show the resolver name. Metadata URI shown with a link and optional fetch of the JSON to show name/description/image. Below: table of all `OrderAccount`s for this listing with their escrow state.
If connected wallet = seller: show "Update Listing" and "Close Listing" buttons.
If connected wallet is not the seller and has no open order: show "Place Order" button.
### Order detail page (no wallet required)
Show all fields of the `OrderAccount`. Show the linked `EscrowAccount` data inline: state badge, vault balance in SOL (raw lamports on hover), `dispute_raised_at` if applicable. Show the escrow state machine with the current state highlighted.
Action buttons depend on the connected wallet's role:
- Seller: "Accept Order" and "Reject Order" (when escrow is `AwaitingSellerConfirm`)
- Buyer: "Cancel Order" (when escrow is `AwaitingSellerConfirm`), "Complete" (when `Active`), "Dispute" (when `Active`)
- Anyone: "Close Stale Order" (when escrow is terminal or closed)
### All escrows page (no wallet required)
Browse all `descro::EscrowAccount` PDAs. Filterable by state. Columns: escrow ID, seller, buyer, amount in SOL, state badge, resolver (if any).
### Resolver registry page (no wallet required)
Browse all `ResolverEntry` PDAs. Show name, type, acceptance policy, fee %, total disputes, buyer win %, seller win %. Clicking goes to resolver detail page.
### Resolver detail page (no wallet required)
All fields of a `ResolverEntry`. Show dispute stats as numbers and ratios.
### My Dashboard (wallet required)
Two tabs: "My Listings" and "My Orders (as Buyer)".
My Listings: all `ListingAccount`s where `seller == connected_wallet`. Quick stats per listing. Buttons: Update, Close, + a link to its orders.
My Orders: all `OrderAccount`s where `buyer == connected_wallet`. Show current escrow state per order with available action buttons.
Prominent "Create Listing" button on this page.
### Create / Edit Listing form (wallet required)
Fields: canonical currency (SOL or SPL mint address), price, canonical oracle pubkey (optional), up to 3 alt currencies (each: currency + oracle pubkey), up to 4 accepted resolver pubkeys, quantity, metadata URI.
### Global search
Search box in the top nav. Input any pubkey. The frontend determines what account type it is and redirects to the relevant detail page (listing, order, escrow, resolver, or wallet).
---
## Display Conventions
- **Addresses:** always show as `ABCD...WXYZ` (first 4 + last 4 chars). Copy-to-clipboard button. Link to the relevant detail page within the explorer.
- **SOL amounts:** show as SOL (divide lamports by 1,000,000,000). Show raw lamport value on hover.
- **SPL token amounts:** show in token units using the `decimals` stored in the `Currency::Spl` variant. Optionally show token symbol if resolvable via token metadata.
- **Timestamps:** show as relative time ("2 hours ago"). Show exact UTC datetime on hover.
- **`quantity_reserved`:** always show all three numbers — available / reserved / total.
- **Resolver pubkeys in listings:** if a `ResolverEntry` exists, show name. Otherwise show abbreviated pubkey.
- **`metadata_uri`:** show as a clickable link. Optionally fetch the JSON and show name/description/image from it.

File diff suppressed because it is too large Load Diff

1513
prototype-app/support.js vendored Normal file

File diff suppressed because it is too large Load Diff