Skip to content

Repository files navigation

Stash

A decentralized dataset and AI model marketplace on Aptos.

Stash is a wallet-native marketplace for publishing, buying, and accessing datasets or model artifacts without centralized custody. Files and metadata live on Shelby decentralized hot storage, while ownership, payments, revenue, and access control are enforced on Aptos.

Aptos Move Shelby React CI


Why Stash

AI datasets and model artifacts are valuable assets. Most platforms still depend on centralized hosting, account-level permissions, platform fees, and opaque takedown rules. Stash takes a different route:

  • Creators own the listing through Aptos accounts and Move resources.
  • Files stay decentralized through Shelby hot storage.
  • Access policies are enforced on-chain for public, creator-approved, and paid listings.
  • Paid listings settle in APT or ShelbyUSD with a 2.5% protocol fee encoded in Move.
  • APT proceeds accrue in escrow for creator claims; ShelbyUSD settles directly after the protocol fee is applied.
  • The UI is built for trust: clear wallet states, transaction stages, and real loading/error states.

Product Status

Stash is live as a Shelbinet review build. It is suitable for test-network evaluation, not mainnet production use.

Area Status
Frontend shell Built
Wallet connection Working with Petra
Upload flow UI Built
Shelby SDK browser integration Integrated
Move contracts Deployed on Shelbinet
Marketplace pages Built
Dashboard pages Built
Creator upload/listing E2E Verified on Shelbinet
Paid APT purchase/indexer E2E Verified on Shelbinet
Public, gated, and ShelbyUSD flows Functional E2E verified in the current wallet-bound recovery model
Wallet-bound encrypted key recovery Verified by the creator across four isolated browser contexts for a new protected dataset
Key lifecycle hardening Live on Shelbynet; creator-confirmed rotation/revocation E2E evidence is recorded, while independent audit remains pending
Review deployment Live

Current review boundary: new protected datasets carry wallet-encrypted recovery material. The creator confirmed recovery and delivery across four isolated browser contexts, using the same creator and buyer wallet accounts in fresh contexts. Datasets created before this change may not contain a recoverable backup and should be republished before relying on cross-browser recovery. A representative application-level transaction set is recorded in the Shelbinet review evidence; internal Shelby blob transactions are intentionally omitted from the concise submission set.

Known Limitations

Limitation Owner Intended resolution
Gated and paid downloads require creator approval or key delivery after the buyer request or purchase. Stash protocol team Define and implement an explicit delivery workflow before mainnet.
Cross-browser recovery requires the same wallet account and a wallet message signature; changing accounts cannot unlock the backup. Stash protocol team Add explicit recovery UX and account-change handling; the initial four-context E2E has been confirmed.
Legacy protected datasets created before wallet-backed backups were added may not contain portable recovery material. Dataset creator Republish those datasets with the current upload flow before clearing the publishing browser.
Key rotation and revocation cannot recall plaintext or files already downloaded before the state change. Stash protocol team Keep the lifecycle evidence and explain this boundary during review; complete an independent security audit before mainnet.
The contracts and frontend have not undergone an independent security audit. Stash protocol team Obtain independent Move and application security review before mainnet.

For the exact Shelbinet addresses, transaction evidence, verification commands, and current review boundary, see the review evidence.

Architecture

flowchart LR
  creator[Creator Wallet] --> ui[Stash React dApp]
  buyer[Buyer Wallet] --> ui

  ui --> wallet[Aptos Wallet Adapter]
  wallet --> petra[Petra / Aptos Wallets]

  ui --> shelby[Shelby SDK]
  shelby --> hot[Decentralized Hot Storage]

  ui --> aptos[Aptos Fullnode]
  aptos --> move[Move Contracts]

  move --> marketplace[marketplace.move]
  move --> payment[payment.move]
  move --> access[access.move]

  move --> indexer[Aptos Indexer GraphQL]
  indexer --> ui
Loading

Storage Layer

Shelby stores encrypted dataset payloads and metadata manifests. Stash keeps a storage identifier on-chain, not the raw file.

Contract Layer

Move modules define the marketplace behavior:

Module Responsibility
marketplace.move Listing lifecycle plus Public, Gated, and Paid policies
payment.move APT escrow/claims, direct ShelbyUSD settlement, and 2.5% protocol fee
access.move Access requests, grants, verification, and buyer-specific key envelopes

access.move keeps the deployed V2 resource layout intact and stores lifecycle state in a separate AccessV3Store. rotate_buyer_key invalidates the previous envelope and requires a new creator delivery. revoke_access removes the current envelope and blocks future access checks. These controls cannot recall plaintext that a buyer already downloaded.

Indexing Layer

Aptos Indexer GraphQL is used for marketplace search, dataset pages, dashboard analytics, and event-driven state.

Core Flows

Creator Publish Flow

sequenceDiagram
  actor Creator
  participant UI as Stash dApp
  participant Shelby as Shelby Storage
  participant Wallet as Petra Wallet
  participant Aptos as Aptos Move Contracts
  participant Indexer as Aptos Indexer

  Creator->>UI: Select files and metadata
  UI->>UI: Encrypt gated or paid payloads
  UI->>Shelby: Prepare blob commitments
  UI->>Wallet: Request Shelby registration signature
  Wallet->>Aptos: Submit blob registration
  UI->>Shelby: Upload encrypted blob and manifest
  UI->>Wallet: Request listing transaction
  Wallet->>Aptos: create_listing_v2()
  Aptos->>Indexer: Emit listing events
  Indexer->>UI: Listing appears in marketplace
Loading

Buyer Access Flow

sequenceDiagram
  actor Buyer
  participant UI as Stash dApp
  participant Wallet as Petra Wallet
  participant Aptos as Payment + Access Contracts
  participant Shelby as Shelby Storage

  Buyer->>UI: Open dataset detail
  UI->>Wallet: Submit request or purchase with buyer public key
  UI->>Wallet: Sign recovery message for encrypted buyer-key backup
  Wallet->>Aptos: request_access() or purchase_v2()
  Aptos->>Aptos: Record request or paid access
  Creator->>Aptos: Publish buyer-specific key envelope
  UI->>Aptos: Read access and delivery state
  UI->>Wallet: Sign recovery message when restoring the buyer key
  UI->>Shelby: Download encrypted file
  UI->>UI: Decrypt with the recovered buyer key
Loading

Tech Stack

Layer Technology
Frontend Vite, React, TypeScript
Styling Tailwind CSS, custom design tokens
Motion Framer Motion, GSAP
Wallet Aptos Wallet Adapter, Petra
Blockchain Aptos, Move
Storage Shelby SDK
Indexing Aptos Indexer GraphQL
Build Vite production build with Shelby WASM handling

Application Routes

Route Purpose
/ Landing page and protocol overview
/marketplace Dataset discovery, filters, sorting, indexer-backed grid
/upload Creator upload and publish flow
/dataset/:id Dataset detail, purchase, access, download
/dashboard Creator listings, revenue, transactions, analytics
/purchases Buyer library with purchased and approved datasets, delivery status, and return links

Access Modes

Mode Storage On-chain behavior Delivery
Public Plain Shelby blob Active listing is immediately accessible Direct download without a wallet
Gated AES-GCM encrypted Buyer requests access; creator approves Creator publishes a key envelope encrypted to the buyer; the buyer key backup is wallet-bound
Paid / APT AES-GCM encrypted One-time APT purchase; creator proceeds accrue in escrow Creator publishes the buyer key envelope; creator claims APT revenue; the buyer key backup is wallet-bound
Paid / ShelbyUSD AES-GCM encrypted One-time ShelbyUSD purchase; 97.5% creator and 2.5% treasury settle atomically Creator publishes the buyer key envelope; no revenue claim is required; the buyer key backup is wallet-bound

Local Development

Requirements

  • Node.js 20.19.0 or newer
  • npm
  • Aptos CLI wrapper (installed in the Move validation section)
  • Petra wallet for browser E2E testing

Install

npm ci

Run Dev Server

npm run dev

Typecheck

npm run typecheck

Production Build

npm run build

Browser smoke tests

The repository includes a Playwright smoke suite for the route shell. It verifies that the landing page boots, direct navigation to the main routes does not produce a blank screen, and the upload flow does not overflow a mobile viewport. Wallet-extension transactions and live Shelby data remain manual E2E checks because they require a real wallet and review-network state.

Install the browser once, then run the suite:

npx playwright install chromium
npm run test:e2e

Move Compile / Test

Install the exact Aptos CLI wrapper used by CI before running contract commands:

npm install --no-save @aptos-labs/aptos-cli@3.0.0
npx aptos --install
npx aptos move compile --dev --skip-fetch-latest-git-deps
npx aptos move test --dev --skip-fetch-latest-git-deps

Access lifecycle upgrade

The current Shelbynet review package predates AccessV3Store. After publishing a compatible package upgrade from the real deployer profile, initialize the new resource once:

.\scripts\initialize-shelbynet-v3.ps1 -Address 0xYOUR_PACKAGE_ADDRESS -Profile shelbynet

Do not run the initializer against the old package or a development address. The command is intentionally separate from publish-shelbynet.ps1 because an existing package must be upgraded first and the initializer is one-time state setup.

Environment Variables

Create .env.local for local dApp configuration.

VITE_APTOS_NETWORK=shelbynet
VITE_APTOS_FULLNODE_URL=https://api.shelbynet.shelby.xyz/v1
VITE_APTOS_INDEXER_URL=https://api.shelbynet.shelby.xyz/v1/graphql
VITE_SHELBY_RPC_URL=https://api.shelbynet.shelby.xyz/shelby
VITE_STASH_MODULE_ADDRESS=0x2d82e8802ab2a3fcce32df2f663a05efcbba9ae00d755b76d242dffb087a4a83

# Optional, depending on network/provider requirements
VITE_APTOS_API_KEY=
VITE_SHELBY_API_KEY=

Supported network names in the frontend:

  • shelbynet
  • testnet
  • devnet
  • mainnet
  • local

When no network is configured, Stash defaults to shelbynet.

Shelby Browser Notes

The Shelby SDK depends on browser-compatible polyfills and a WASM asset for erasure coding. This repo includes handling for:

  • Buffer and process browser compatibility
  • Shelby clay.wasm serving through Vite middleware
  • Vite dependency optimization exclusions for Shelby packages
  • Upload cancellation and non-retryable wallet rejection handling
  • Bounded retry handling for transient Aptos/Shelby 429 and 5xx responses

Reliability Rules

Stash treats transaction and storage flows as first-class UX:

  • Wallet rejection must stop the flow immediately.
  • Validation/config errors must not retry silently.
  • Aptos and Shelby transient 429/5xx errors retry with bounded backoff and Retry-After support.
  • React Query must not add a second retry layer on top of transport retries.
  • Upload state must be cancellable and resettable.
  • Public UI should not present mock data as real marketplace state.

Project Structure

sources/
  marketplace.move       Move listing module
  payment.move           Move purchase and revenue module
  access.move            Move access-control module

src/
  components/            Shared UI, layout, wallet, tx components
  hooks/                 dApp hooks for Shelby and marketplace actions
  lib/                   Aptos, Shelby, network, format, wallet utilities
  pages/                 Landing, marketplace, upload, detail, dashboard
  styles/                Design tokens and global styling

Deployment Checklist

Before public release:

  • Deploy Move modules to the target Aptos network.
  • Set VITE_STASH_MODULE_ADDRESS to the deployed package address.
  • Verify Shelby upload on the target network with a small file.
  • Confirm Aptos Indexer events for listing, purchase, access, and claims.
  • Run creator E2E: upload, register listing, view listing.
  • Run buyer E2E: purchase, verify access, download/decrypt.
  • Run production build and route smoke checks.
  • Verify no fallback/mock data appears as public marketplace truth.

License

This repository is proprietary and provided for technical review and evaluation. No license is granted to copy, modify, distribute, sublicense, or use the code without written permission from the project owner. See LICENSE.


Stash is built for data ownership, on-chain access, and decentralized distribution.

Current Shelbinet Deployment

The Stash Move package is deployed on Shelbinet.

Item Value
Network shelbynet
Package address 0x2d82e8802ab2a3fcce32df2f663a05efcbba9ae00d755b76d242dffb087a4a83
Publish transaction 0x005794789e05b80ae3dbb91bd0027180bd4f754b633fa3b82e9c8ad5faf7153c
Access/payment v2 upgrade 0x5ac5dd1027bcedebb640aee9fe20193aef777ac5677e2d21cd4ce18e2ee7032a
Compatible V3 package upgrade 0x6e7858299788cd5d2a9771dc78636a4e1216ca9ab70930452380b32270c6b817
Access V3 initializer 0x3243367ff49ae0af24d9e561be3afeacf170485de6062c9f12a572b04548acfb
ShelbyUSD metadata 0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1
Review app https://stash-stash2.vercel.app/
Fullnode https://api.shelbynet.shelby.xyz/v1
Indexer https://api.shelbynet.shelby.xyz/v1/graphql
Shelby RPC https://api.shelbynet.shelby.xyz/shelby

The frontend includes this package address as the default Shelbinet module address. VITE_STASH_MODULE_ADDRESS can still override it for future redeployments.

Shelbinet Launch Runbook

Stash targets Shelbinet by default and includes the current package address. Browser upload, listing creation, paid APT purchase, indexer materialization, and dashboard analytics have been exercised on Shelbinet. The connected wallet still needs the network assets and permissions required by Shelby's active early-access policy.

1. Create a Shelbinet Aptos CLI profile

Use the deploy wallet you want to own the Stash Move package. Do not commit private keys.

npx aptos init --network custom `
  --rest-url https://api.shelbynet.shelby.xyz/v1 `
  --skip-faucet `
  --profile shelbynet

If you already have the deploy key, initialize with --private-key or --private-key-file. The account must have enough gas on Shelbinet before publishing.

2. Publish the Move package

Replace <deployer-address> with the account address from the shelbynet profile.

.\scripts\publish-shelbynet.ps1 -Address <deployer-address> -Profile shelbynet

The script compiles the Move package with stash=<deployer-address>, runs Move tests, then publishes against the Shelbinet fullnode.

3. Set frontend environment

Create .env.local locally and mirror the same values in the hosting provider.

VITE_APTOS_NETWORK=shelbynet
VITE_APTOS_FULLNODE_URL=https://api.shelbynet.shelby.xyz/v1
VITE_APTOS_INDEXER_URL=https://api.shelbynet.shelby.xyz/v1/graphql
VITE_SHELBY_RPC_URL=https://api.shelbynet.shelby.xyz/shelby
VITE_STASH_MODULE_ADDRESS=0x2d82e8802ab2a3fcce32df2f663a05efcbba9ae00d755b76d242dffb087a4a83
VITE_SHELBY_API_KEY=
VITE_APTOS_API_KEY=

VITE_STASH_MODULE_ADDRESS is mandatory for marketplace, dashboard, upload publish, purchase, claim revenue, and access verification. 0xcafe is intentionally rejected by the frontend because it is only the dev-test address from Move.toml.

4. Verify Shelby storage

A real Shelbinet upload was completed with the Shelby CLI using the deployed package wallet.

Item Value
CLI context shelbynet
Write location shelbynet-1
Upload transaction 0x9fcd01ba1721359c22543a7bb00a06b214c45e6b93afb0c3e1d3928ca9fdc8be
Explorer https://explorer.shelby.xyz/shelbynet/account/0x2d82e8802ab2a3fcce32df2f663a05efcbba9ae00d755b76d242dffb087a4a83

If browser upload fails before the Petra signature, confirm the connected wallet has ShelbyUSD and a Shelby write location. The CLI validation used shelbynet-1 explicitly.

5. Verify the app

.\scripts\check-shelbynet.ps1
npm.cmd run build

Manual E2E checklist:

  1. Connect Petra on Shelbinet.
  2. Upload a small file from /upload.
  3. Confirm the Shelby blob registration popup appears.
  4. Confirm the Stash listing registration popup appears.
  5. Confirm the listing appears in /marketplace from Aptos Indexer events.
  6. Purchase from another wallet.
  7. Confirm access::verify_access returns true.
  8. Download and decrypt the Shelby file.

Current delivery note: buyer-specific key wrapping is implemented on-chain. New protected uploads also store encrypted recovery material: the creator backup is embedded in the Shelby manifest, while the buyer backup is carried in the existing on-chain buyer-key field. Recovery requires a signature from the same wallet account and never stores the wallet signature itself. The creator still approves or delivers each protected request manually. The buyer library at /purchases is derived from indexed purchase, access, and delivery events. Cross-browser recovery for a new protected dataset was creator-confirmed across four isolated browser contexts; legacy datasets without a backup remain device-bound.

About

Decentralized dataset and AI model marketplace on Aptos Shelbynet, using Shelby hot storage with on-chain payments, access control, and provenance.

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages