Nine Anchor programs. Seven frontend verticals. One fee rail. Every upgrade path, pause switch, and chat message is signed on-chain or in a wallet.
This page is for VCs doing technical DD and developers skimming scope. Snapshots show devnet state. Mainnet architecture is the same minus: audited programs, Squads multisig signers on hardware keys, and staged position caps.
Live on-chain counts — refresh on page load. Full activity feed at /stats.
On-chain — nine Anchor programs
All nine compile on Anchor 1.0 with Solana 2.x tooling. 110+ LiteSVM tests pass locally; every program publishes a security.txt metadata section for contact on disclosure. Seven handle value flows and carry a global paused kill-switch admin instruction.
tip_jarCreator tipssubscriptionRecurring billingeventsLegacy PDA ticketsevent_ticketsCompressed NFT ticketsrwa_registryLicenced issuer listrwa_mintAsset tokenisationmarketplacePublic listingsotc_dealsBilateral escrowauctionsSealed-bid auctionsShared on-chain patterns
Config PDA per program
Single authority-gated admin surface: initialize_config, update_fee_bps, update_treasury, update_config_authority, update_pause. Treasury is a USDC ATA; authority will be a Squads multisig on mainnet. Backward-compat layout — new paused flag slots into reserved bytes.
Fee split on every value flow
fee = amount × fee_bps / 10_000. Stats track creator-share (not gross) so analytics stay accurate. Fee cap 1000 bps (10%) enforced on-chain.
Escrow vault PDA
Used by marketplace, otc_deals, auctions, event_tickets resale. Tokens park in a program-owned ATA. Settlement is a single transaction — no custodian window. Programmatic signer seeds prevent any path to drain-by-authority.
Permissionless cranks
Subscription charges, auction settlement, OTC deal expiry, and tier-seat GC (pg_cron) all crank on demand from any wallet. No central scheduler.
Keccak256 commit / reveal
Used by private-price ticket resale and sealed-bid auctions. Hides price / bid until reveal. Bonus: MEV-resistant for auctions.
Emergency pause (new)
Every fund-moving instruction gated on config.paused. Squads multisig can pause a program in one transaction while a patch rolls out. Withdraw-type instructions stay open so creators can drain their vaults.
Frontend — seven marketplace surfaces
/marketplaceRWA tile browse/marketplace/assets/[mint]Asset detail/marketplace/eventsEvent browse/marketplace/auctionsSealed-bid auctions/marketplace/rentalsRental plans/marketplace/otcBilateral deals/marketplace/portfolioWallet-aware dashboardChat — signed, persisted, rate-limited
In-app chat runs on Supabase with strict RLS gated by wallet-signed JWTs. Nothing mutates on the server without a valid wallet signature. Three thread kinds cover every conversation surface:
otc_deallisting_dmgroupWrites go through an Edge Function that verifies an ed25519 signature over a challenge tied to the thread and a ~15-minute timestamp. Reads use a short-lived JWT (15 min TTL) minted after a separate signed challenge. Both artefacts cache in localStorage per-wallet so one wallet interaction bootstraps an hour of browsing without further popups.
Security posture
Upgrade authority
All nine programs' upgrade authority live on a Squads 2-of-3 multisig. Every deploy is a proposal that needs two independent signatures. Single-key compromise no longer hijacks programs. Runbook at docs/SECURITY_RUNBOOK.md.
Emergency pause
Authority-gated update_pause instruction on seven programs freezes all fund-moving entry points in a single Squads proposal. Withdraw / close paths stay open so users can still drain vaults. No custodian flag-flip.
Signed chat auth
Every chat write is an ed25519 signature over a thread-bound, time-bound challenge. Reads are gated by a Supabase JWT minted only after a separate signature. JWT is rotatable in minutes.
Turnstile + rate limit
Group chat writes gate on Cloudflare Turnstile (managed mode; invisible for trusted traffic) plus a per-wallet 30-messages-per-5-minutes cap. Sybil requires funded wallets — not free.
Security event telemetry
security_events table logs sig_verify_fail, challenge_expired, rate_limit_hit, turnstile_fail, jwt_issued. Two convenience views for hot-wallet burst detection and 24h abuse triage. Service-role only.
security.txt
All nine programs embed the Squads security.txt format with disclosure contact (security@nodosol.com). Lets researchers reach us without guessing.
Pending, in order of priority: external audit (OtterSec / Neodyme / Zellic, 4-8 week wait list), mainnet multisig with hardware signers, staged rollout with position caps. Bug bounty program post-audit.
Stack & infrastructure
What shipped since last update
- In-app chat: OTC threads, per-listing DMs, and seven public channels. Signed ed25519 writes, JWT-gated reads, localStorage persistence.
- Asset detail page: gallery + video + location + attributes + OTC activity + self-list flow + edit/cancel for own listings + Contact owner DM.
- Marketplace jurisdictions filter: joins issuer PDAs into the listing index, filters by ISO code, compliance chips on cards.
- Emergency pause across 7 programs: update_pause admin ix gated on Config authority (Squads multisig).
- Squads multisig migration: upgrade authority of all 9 programs moved to 2-of-3 Squads vault on devnet.
- Security event log: security_events table + Edge Function writes + hot-wallet views.
- UX hardening: toast system + friendly error decoder, unified dark theme, responsive stat grids, search + chat in sidebar nav, 65+ alerts migrated to toasts.
- Chat session persistence: JWT + per-thread sig cached per-wallet in localStorage — one wallet popup per hour of active chat instead of per page load.