Publish media to Shelby, register ownership and access policy on Aptos, and give buyers wallet-scoped access to creator media.
Open live app | Repository | Move package
Shelby media storage
Aptos on-chain registry
Payby is a Web3-native creator media vault for publishing premium media, creator archives, gated drops, and wallet-aware buyer access. Shelby stores the media bytes and metadata blobs. Aptos stores the ownership, listing, access, purchase, revenue, and creator-profile records that define the application state.
The product has two connected surfaces:
- Creator workspace: publish media, manage a Shelby vault, maintain a creator profile, inspect network routes, and review sales and activity.
- Buyer surface: discover creators, open public media pages, purchase paid listings, and recover unlocked media from a wallet-scoped library.
Payby is designed to be inspectable. A user can see the active Shelby route, Aptos fullnode, contract address, transaction links, Shelby blob routes, and the metadata commitment associated with a listing.
- Connect an Aptos wallet.
- Select a Shelby route and confirm that the wallet network matches it.
- Select media files and define title, description, category, tags, visibility, access policy, price, currency, and retention.
- Sign the Shelby blob-registration transaction.
- Upload the media blob and a Payby metadata blob to Shelby.
- Sign the Aptos owner-listing transaction that records the access policy.
- After listing finality, sign the metadata-commitment transaction that records the Shelby URI and SHA-256 hash.
- Wait for Aptos finality and Shelby indexing before the listing is marked complete.
- Share the public media or creator URL.
- Open a public creator or media page.
- Connect the buyer wallet.
- Read the listing and access policy from the Aptos registry.
- Open free media when the policy permits it, or sign
purchase_fromfor a paid listing. - Wait for the purchase transaction to reach finality.
- Retrieve the Shelby blob and recover the purchase from the buyer library.
| Data | System of record | Purpose |
|---|---|---|
| Media bytes | Shelby | Durable media storage and retrieval route |
| Payby metadata blob | Shelby | Recoverable metadata payload for a listing |
| Listing owner and state | Aptos Move registry | Ownership, title, policy, price, asset, and active state |
| Metadata commitment | Aptos Move registry | metadata_uri and SHA-256 metadata_hash |
| Purchase receipt | Aptos Move registry | Buyer, creator, blob, price, payment asset, and timestamp |
| Creator sales | Aptos Move registry | Sale count and creator revenue summary |
| Creator profile | Aptos Move registry | Public creator identity and profile update timestamp |
| UI recovery data | Browser cache | Non-canonical local recovery and optimistic UI state |
LocalStorage is not treated as the canonical source of ownership, access, or purchase state. Chain reads are used to recover listings and receipts when the browser cache is empty or stale.
| Layer | Implementation | Responsibility |
|---|---|---|
| Shelby React SDK | @shelby-protocol/react@4.1.0 |
Upload mutations and blob registration |
| Shelby browser SDK | @shelby-protocol/sdk@0.7.0 |
Browser client and direct storage operations |
| Aptos wallet adapter | @aptos-labs/wallet-adapter-react |
Wallet discovery, connection, network changes, and signing |
| Aptos TypeScript SDK | @aptos-labs/ts-sdk |
Fullnode reads, transaction building, submission, and finality checks |
| Payby Move package | contracts/payby_marketplace |
Owner listings, metadata commitments, profiles, purchases, and sales |
| React frontend | src/ |
Creator, buyer, public, and network inspection workflows |
The Shelby upload path uses the official wallet adapter flow. The Aptos access registry is built against the selected fullnode and submitted only after the wallet/network preflight passes. The application also checks the live fullnode chain ID before opening a publish or registry retry prompt, so a stale wallet network cannot silently create an invalid transaction.
Owner-scoped listing, metadata, purchase, and listing-sales indexes use flat
Move table keys such as (owner, blob_name). This preserves creator namespace
isolation without nested tables, which the Shelbynet transaction simulator
cannot evaluate reliably. Listing and metadata writes are separate,
idempotent transactions so a rejected second approval can be retried without
re-uploading media to Shelby.
| Route | Aptos wallet network | Shelby RPC | Aptos fullnode | Product role |
|---|---|---|---|---|
| Shelbynet | Network.SHELBYNET |
https://api.shelbynet.shelby.xyz/shelby |
https://api.shelbynet.shelby.xyz/v1 |
Primary Shelby community route |
| Shelby Testnet | Network.TESTNET |
https://api.testnet.shelby.xyz/shelby |
https://api.testnet.aptoslabs.com/v1 |
Early Access validation route |
Shelbynet is a developer prototype network and may be wiped roughly weekly or faster. It must not be treated as permanent archival storage. Network URLs, contract addresses, payment assets, and API keys are route-specific and are configured through environment variables.
The current application does not hardcode a permanent Shelbynet chain ID. It reads the active chain from the configured fullnode during the publish preflight. This is important for a prototype network whose infrastructure can be rebuilt.
Official references:
The Move package is located at:
contracts/payby_marketplace/
The current Payby marketplace deployment is:
0x962ebbcf81cbc5dc0950a8ca036d54828481043f1df8960a2ec4d50fae8c3a12
- Module:
payby_marketplace - Package:
PaybyMarketplace - Open account on Aptos Explorer
Because Shelbynet can be wiped, this address should be treated as the current deployment for the active route, not as a permanent production address.
The registry exposes entry functions for:
initializeupsert_listingupsert_listing_with_metadataupsert_listing_for_ownerupsert_listing_for_owner_with_metadataupsert_listing_metadataupsert_listing_metadata_for_ownerupsert_creator_profileupsert_creator_profile_v2create_listingupdate_listingpurchasepurchase_fromdelistdelist_for_owner
The frontend uses view functions for wallet-scoped and public reads:
get_listingandget_listing_for_ownerget_listing_metadataandget_listing_metadata_for_ownerget_listing_countandget_listing_count_for_ownerget_listing_keyandget_listing_key_for_ownerget_purchasesandget_purchases_from_ownerget_purchase_record_countandget_purchase_recordget_sales_summaryandget_listing_sales_summaryget_creator_profileandget_creator_profile_v2can_accessandcan_access_for_owner
The paid purchase path transfers the configured fungible asset through Aptos and records a buyer purchase index, receipt record, creator sale count, and listing-level sale summary.
Payment assets are route- and currency-specific. Payby never uses the generic
APT metadata address as a ShelbyUSD fallback: a ShelbyUSD listing must carry
the ShelbyUSD metadata object on-chain, and a buyer transaction is stopped when
the committed currency and the listing payment asset disagree. The current
Shelbynet ShelbyUSD metadata object is
0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1, matching
the asset shown in the Shelby account balance documentation.
Creator profile drafts are browser recovery data keyed by network and wallet address. The public profile remains sourced from the Aptos Move registry; a wallet cannot inherit another wallet's local profile draft.
| Route | Surface |
|---|---|
/ |
Landing page |
/app/vault |
Creator vault |
/app/publish |
Publish media and access policy |
/app/analytics |
Creator sales and revenue |
/app/discover |
Creator discovery and browsing |
/app/library |
Buyer purchases and unlocked media |
/app/network |
Shelby and Aptos route inspection |
/app/profile |
Creator profile editor |
/app/activity |
Wallet-scoped activity and transaction history |
/app/blob/<owner>/<blob-name> |
Workspace media detail |
/creator/<wallet-address> |
Public creator page |
/media/<owner>/<blob-name> |
Public media page |
The landing page is intentionally separate from the workspace. Workspace navigation uses route-level code splitting and browser view transitions when the platform supports them.
.
├── contracts/
│ └── payby_marketplace/ Aptos Move package
├── docs/ Product direction and quality gates
├── public/ Browser icon and public assets
├── scripts/
│ ├── deploy-payby-marketplace.ps1
│ ├── deploy-payby-marketplace.mjs
│ └── readiness-check.mjs
├── src/
│ ├── app/ Route parsing and navigation
│ ├── components/ Shared UI and workspace components
│ ├── config/ Network and wallet configuration
│ ├── domain/ Application models
│ ├── hooks/ Wallet-scoped stores and data hooks
│ ├── pages/public/ Public creator and media pages
│ ├── pages/workspace/ Vault, publish, analytics, and system pages
│ ├── services/aptos/ Fullnode and wallet boundaries
│ ├── services/payby/ Move registry reads and transaction history
│ ├── services/shelby/ Shelby URI, retrieval, and explorer helpers
│ ├── services/storage/ Browser cache utilities
│ ├── landing.css Landing page styles; kept separate
│ ├── styles.css Shared application styles
│ └── workspace-*.css Workspace design system layers
├── tests/ Deterministic route, wallet, storage, and state tests
├── assets/readme/ README screenshot and integration marks
├── .env.example Environment variable template
├── vercel.json Vite build and SPA rewrites
└── vite.config.ts Vite and Shelby Clay WASM configuration
The landing page boundary is deliberate. Workspace design changes must not
modify src/landing.css, src/main.tsx, assets/readme/payby-landing-page.png,
or public/payby-icon.svg without an explicit product decision.
- Node.js 20 LTS recommended
- npm 10 or newer
- An Aptos-compatible browser wallet for interactive flows
- Aptos CLI only when compiling or deploying the Move package
- Shelby and Aptos API keys for routes that require authenticated access
npm ci
Copy-Item .env.example .envOpen .env and set the route-specific API keys, marketplace address, and
payment asset metadata addresses required by the flow you want to exercise.
npm run devThe Vite server uses 127.0.0.1 and defaults to port 5173. If that port is
occupied, Vite selects another available port; use the URL printed by the
terminal so the wallet origin matches the active browser tab.
npm run test
npm run build
npm run check:readiness
git diff --checkThe current deterministic suite covers 22 tests for route serialization,
wallet and network handling, transaction scoping, cache recovery, Shelby path
encoding, Move view behavior, and fullnode response mapping.
check:readiness verifies that configured marketplace view functions are
callable and that payment asset metadata is present. It cannot prove a wallet
extension will approve a transaction, nor can it prove Shelby storage survives
a network wipe.
Start from .env.example. The most important variables are:
# Frontend route selection
VITE_PAYBY_DEFAULT_NETWORK=shelbynet
# Shelby credentials
VITE_SHELBYNET_API_KEY=
VITE_SHELBY_TESTNET_API_KEY=
VITE_SHELBYNET_LOCATION_HINT=shelbynet-1
VITE_SHELBY_TESTNET_LOCATION_HINT=
# Aptos fullnode credentials
VITE_APTOS_SHELBYNET_API_KEY=
VITE_APTOS_TESTNET_API_KEY=
# Marketplace deployments
VITE_PAYBY_SHELBYNET_MARKETPLACE_ADDRESS=0x962ebbcf81cbc5dc0950a8ca036d54828481043f1df8960a2ec4d50fae8c3a12
VITE_PAYBY_TESTNET_MARKETPLACE_ADDRESS=
# Payment asset metadata addresses
VITE_PAYBY_PAYMENT_ASSET_METADATA=
VITE_PAYBY_APT_PAYMENT_ASSET_METADATA=
VITE_PAYBY_SHELBYUSD_PAYMENT_ASSET_METADATA=
VITE_PAYBY_SHELBYNET_PAYMENT_ASSET_METADATA=
VITE_PAYBY_TESTNET_PAYMENT_ASSET_METADATA=
VITE_PAYBY_SHELBYNET_APT_PAYMENT_ASSET_METADATA=
VITE_PAYBY_SHELBYNET_SHELBYUSD_PAYMENT_ASSET_METADATA=0x1b18363a9f1fe5e6ebf247daba5cc1c18052bb232efdc4c50f556053922d98e1
VITE_PAYBY_TESTNET_APT_PAYMENT_ASSET_METADATA=
VITE_PAYBY_TESTNET_SHELBYUSD_PAYMENT_ASSET_METADATA=The readiness script also accepts server-side aliases for deployment checks:
PAYBY_SHELBYNET_MARKETPLACE_ADDRESS=
PAYBY_TESTNET_MARKETPLACE_ADDRESS=
PAYBY_APTOS_SHELBYNET_API_KEY=
PAYBY_APTOS_TESTNET_API_KEY=
PAYBY_SHELBYNET_FULLNODE_URL=https://api.shelbynet.shelby.xyz/v1
PAYBY_TESTNET_FULLNODE_URL=https://api.testnet.aptoslabs.com/v1VITE_* values are bundled into a browser application. Use public or
restricted API keys only. Never commit .env, private keys, wallet recovery
phrases, or deployment credentials.
The deployment helper supports a dedicated Aptos profile or an explicitly provided local private-key file. A profile from another project must not be used.
powershell -ExecutionPolicy Bypass -File .\scripts\deploy-payby-marketplace.ps1 `
-Network shelbynet `
-Profile payby-shelbynet `
-UpdateEnvpowershell -ExecutionPolicy Bypass -File .\scripts\deploy-payby-marketplace.ps1 `
-Network shelbynet `
-PrivateKeyFile C:\secure\payby-shelbynet.key `
-Address 0x... `
-UpdateEnvThe key file must remain outside Git. The deployment script compiles the Move package, publishes it, initializes the registry, and can write the resulting address into the local environment file.
powershell -ExecutionPolicy Bypass -File .\scripts\deploy-payby-marketplace.ps1 `
-Network testnet `
-Profile payby-testnet `
-UpdateEnvFund the selected deployer on the selected network before publishing. A Shelbynet deployment address and transaction history should be considered ephemeral because the network can be rebuilt.
The repository is configured as a Vite SPA in vercel.json:
- Install command:
npm ci - Build command:
npm run build - Output directory:
dist - SPA rewrites for
/app/*,/media/*, and/ - WASM content type handling for Shelby Clay assets
Set the same VITE_* variables in the Vercel project environment before
deploying. A push to the configured branch can trigger the project deployment;
the deployment URL must be tested with a wallet extension from the same
browser profile.
- Wallets approve every user-authorized Aptos transaction.
- Payby does not store private keys or recovery phrases.
- Listing ownership and purchase state are read from the Aptos registry.
- Media bytes are retrieved from Shelby using the route recorded for the listing.
- Metadata URI and hash commitments are checked before a listing is treated as complete.
- Wallet-scoped caches are keyed by wallet and network to prevent one account from inheriting another account's activity or purchases.
- API keys in a Vite client are public to the browser; scope and rotate them at the infrastructure layer.
- Paid access depends on the configured payment asset metadata and the deployed Move registry. An empty payment asset configuration is not a valid paid-release setup.
- Shelby media and metadata blob upload integration.
- Aptos Move marketplace package deployed and initialized on the current Shelbynet route.
- Owner-scoped listings and metadata commitments.
- Free, allowlist, and paid policy data model in the Move registry.
- Paid purchase and buyer purchase records through
purchase_from. - Creator sales, listing sales, and revenue views.
- On-chain creator profile V2 fields, including X handle and verification flag.
- Creator vault, publish, analytics, discover, buyer library, network, profile, activity, public creator, and public media pages.
- Wallet-scoped transaction history and pagination-oriented UI states.
- Direct Shelby retrieval while a hardened gateway retrieval layer remains deferred until after Early Access validation.
- Automated build, deterministic tests, readiness checks, and landing-page boundary checks.
- Complete a funded browser publish with a supported wallet and verify Shelby upload, Aptos registry finality, retrieval, and vault indexing together.
- Complete a separate buyer purchase with a second wallet and verify the purchase receipt, creator revenue, and buyer library recovery.
- Validate the active wallet's chain ID against the live Shelbynet fullnode. On the currently observed environment, the installed Petra native profile and live Shelbynet endpoint reported different chain IDs; Payby correctly stops before opening a doomed prompt rather than hardcoding a stale value.
- Repeat the creator and buyer flows after a Shelbynet wipe.
- Configure and validate the Shelby Testnet marketplace and payment assets after Early Access access is available.
- Run browser accessibility, responsive, wallet-extension, and console-error QA with the deployed application.
- Replace the X verification flag with a verified OAuth/attestation flow before treating creator verification as a trust signal.
Payby is therefore an active integration candidate, not a claim of completed community release. The remaining work is primarily funded wallet E2E, network-specific validation, and operational verification.
Use this checklist before inviting external users:
- Set production Vercel environment variables without exposing secrets.
- Publish a small free media item from creator wallet A.
- Confirm the Shelby blob and Aptos listing are both finalized.
- Open the public media page from a clean browser session.
- Purchase a paid item from buyer wallet B.
- Confirm the buyer receipt and unlocked media in wallet B's library.
- Confirm wallet A sees the sale and updated revenue.
- Confirm wallet A's activity is not visible in wallet B's activity feed.
- Open
/creator/<wallet-address>and verify the public creator profile. - Test delisting, failed transactions, retry states, and expired retention.
- Repeat the supported flow on Shelby Testnet after Early Access is granted.
- Record transaction hashes and Shelby explorer links for the release report.
Keep changes scoped to the relevant boundary:
- Use
src/pages/publicfor public creator and media experiences. - Use
src/pages/workspacefor authenticated creator and buyer workflows. - Put chain reads and writes in
src/services/paybyorsrc/services/aptos. - Put Shelby route and URI behavior in
src/services/shelby. - Keep browser cache behavior in
src/services/storageand never promote it to canonical state. - Update
tasks.md,memory.md, andsoul.mdwhen a tracked integration or product decision changes. - Preserve the landing-page boundary unless the change explicitly targets the landing experience.
Before opening a pull request:
npm run test
npm run build
npm run check:readiness
git diff --checkNo license has been declared for this repository yet. Do not reuse the code outside the repository until a license is added by the project owner.