Yora is a time-locked encrypted capsule dApp built with Aptos wallets and Shelby decentralized hot storage.
Yora lets a sender create a private message or file capsule for a specific recipient wallet. The payload is encrypted in the browser, stored as an encrypted Shelby blob, and can only be unsealed by the recipient wallet after the selected unlock time.
| Resource | URL |
|---|---|
| Live dApp | https://yora-nine.vercel.app |
| GitHub repository | https://github.com/Immomoo/Yora |
| Shelby docs | https://docs.shelby.xyz |
| Aptos docs | https://aptos.dev |
Most private content apps solve storage and access as separate problems. Yora treats them as one flow:
- The sender seals a payload for one recipient wallet.
- The browser encrypts the payload before anything is written to storage.
- Shelby stores the encrypted capsule as hot decentralized object storage.
- The recipient wallet can discover the capsule through Shelby.
- The capsule stays locked until the unlock timestamp.
- After unlock, the recipient signs the release request and decrypts locally in the browser.
The result is a simple primitive for private delayed delivery: messages, files, launch notes, community drops, sealed announcements, personal handoffs, and time-based access experiments.
| Feature | Status | Notes |
|---|---|---|
| Time-locked capsules | Implemented | Each capsule has a title, recipient wallet, payload, and unlock timestamp. |
| Message payloads | Implemented | Text capsules are encrypted and previewed after unseal. |
| File payloads | Implemented | File capsules are encrypted, downloaded after unseal, and image files can be previewed in the unseal modal. |
| Browser-side encryption | Implemented | Uses Web Crypto AES-GCM before Shelby storage. |
| Shelby blob storage | Implemented | New capsules are written as encrypted Shelby capsule envelopes. |
| Shelbynet Devnet route | Implemented and manually validated | A fresh post-SDK Shelbynet flow was validated on 2026-08-07, including Shelby blob write, recipient discovery, remote release, and unseal. |
| Shelby Testnet route | Retired in current SDK | Shelby SDK 0.6.0 does not expose a supported Testnet client; Yora keeps the route visible but disables writes until Shelby publishes a supported replacement. |
| Aptos wallet connection | Implemented | Uses the Aptos wallet adapter and supports wallet selection. |
| Recipient discovery | Implemented | Connected wallets load capsules addressed to them from Shelby. |
| Sender history | Implemented | Sent capsules are separated from received capsules. |
| Remote key release | Implemented and live-validated | Vercel API routes escrow and release capsule keys after wallet-signature validation; the production flow was manually exercised on Shelbynet. |
| Cross-browser unseal | Implemented and manually tested | Recipient can unseal from a different browser when the production remote key-release service is configured. |
| Aptos Move registry | Implemented as optional receipt layer | Registers capsule metadata and records release markers on the configured Shelbynet deployment; it is not yet the sole release-enforcement authority. |
| Registry verification | Implemented | Discovered capsules show verified, released, missing, mismatch, unavailable, or not-enabled states. |
| Explorer links | Implemented | Shelby blob links and Aptos transaction links are shown where available. |
| Production UI | Implemented | Landing page, dashboard, create flow, capsule vault, transactions, profile, wallet picker, responsive layout, and motion polish. |
| Area | Shelbynet Devnet | Shelby Testnet |
|---|---|---|
| Network switching | Tested | Implemented |
| Wallet connection | Tested | Implemented |
| Message capsule create | Manually validated 2026-08-07 | Not supported by current SDK |
| File capsule create | Manually validated 2026-08-07 | Not supported by current SDK |
| Shelby blob write | Manually validated 2026-08-07 | Not supported by current SDK |
| Recipient discovery | Manually validated 2026-08-07 | Not supported by current SDK |
| Different browser unseal | Manually validated 2026-08-07 | Not supported by current SDK |
| Text preview after unseal | Manually validated 2026-08-07 | Not supported by current SDK |
| Image preview after unseal | Manually validated 2026-08-07 | Not supported by current SDK |
| Remote key release | Manually validated 2026-08-07 | Not supported by current SDK |
| Optional Aptos registry UI | Manually validated on configured Shelbynet route | Not supported by current SDK |
flowchart LR
Sender[Sender wallet] --> Compose[Compose capsule]
Compose --> Encrypt[Encrypt payload in browser]
Encrypt --> Shelby[Write encrypted capsule blob to Shelby]
Encrypt --> Escrow[Escrow decrypt key with remote key-release API]
Shelby --> Index[Load capsule through Shelby index]
Index --> Recipient[Recipient wallet]
Recipient --> Time{Unlock time reached?}
Time -- No --> Locked[Keep locked]
Time -- Yes --> Sign[Recipient signs release request]
Sign --> Release[Release decrypt key]
Release --> Decrypt[Decrypt Shelby payload in browser]
Decrypt --> Preview[Preview text or file]
flowchart TB
subgraph Browser
UI[React + TypeScript UI]
Wallet[Aptos Wallet Adapter]
Crypto[Web Crypto AES-GCM]
Runtime[Yora capsule runtime]
end
subgraph Shelby
BlobStorage[Shelby encrypted blob storage]
BlobIndex[Shelby blob index]
end
subgraph YoraAPI[Yora API on Vercel]
EscrowAPI[POST /api/v1/capsules/escrow]
ReleaseAPI[POST /api/v1/capsules/release]
KV[(KV key records)]
end
subgraph Aptos
Registry[Optional Move registry]
end
UI --> Runtime
Runtime --> Wallet
Runtime --> Crypto
Runtime --> BlobStorage
BlobStorage --> BlobIndex
BlobIndex --> Runtime
Runtime --> EscrowAPI
ReleaseAPI --> KV
EscrowAPI --> KV
Runtime -. optional register and release marker .-> Registry
Each Shelby blob stores an encrypted Yora envelope:
- capsule version
- title and recipient metadata
- creator address
- unlock timestamp
- selected Shelby route
- payload type and payload size
- blob name and digest
- encrypted ciphertext
Plaintext message and file bytes are not written to Shelby.
Yora is designed around a clear trust boundary:
- Payload encryption happens in the browser before Shelby writes.
- Shelby stores encrypted capsule envelopes, not plaintext payloads.
- The recipient wallet must match the capsule recipient before unseal.
- The unlock timestamp is checked before key release.
- Remote key release requires wallet-signed escrow and release messages.
- The key-release API returns the decrypt key only after validating capsule id, key id, recipient, route, blob owner, blob name, digest, and unlock time.
- Unsealed payloads are decrypted in the browser, not by the key-release service.
- If Shelby rejects the write, Yora does not create a capsule.
Important production note:
Vite exposes every VITE_ variable to the browser bundle. If a Shelby API key must be treated as a private secret, Shelby writes should be moved behind a backend or proxy before a mainnet-grade deployment.
Yora is not claiming full decentralization of key release yet. The current implementation includes a remote key-release service, but the long-term hardening path is to connect release decisions more deeply to on-chain registry state or a decentralized/threshold key management layer.
Current limitations:
- Shelby Testnet is currently retired in Shelby SDK 0.6.0; Yora does not claim Testnet writes until Shelby publishes a supported route.
- Key release is service-backed, not threshold or fully decentralized.
- The key-release service validates stored capsule metadata, signatures, route, digest, and unlock time, but deeper registry-backed release enforcement is still a hardening target.
- Automated browser smoke coverage is included; the live wallet flow remains opt-in because it requires a configured wallet test session and real Shelby access.
- Aptos wallet dependencies create a large production chunk; bundle splitting is a future optimization.
See Phase 4 key release for the production hardening plan.
For a dedicated trust model, metadata exposure notes, key-release assumptions, and disclosure guidance, see SECURITY.md.
Yora supports two selectable Shelby routes.
| Route | Purpose | Frontend env |
|---|---|---|
| Shelbynet Devnet | Supported write route; live validation confirmed 2026-08-07 | VITE_SHELBYNET_API_KEY |
| Shelby Testnet | Testnet route retained for visibility; writes are disabled | VITE_SHELBY_TESTNET_API_KEY |
The selected route controls:
- Shelby client configuration
- Shelby blob base URL
- Aptos wallet network expectation
- registry address lookup
- explorer links
- dashboard status labels
npm install
npm run devOpen the local Vite URL shown in the terminal.
npm run buildThe compiled app is generated in dist/.
Copy .env.example to .env for local development.
VITE_YORA_NETWORK=shelbynet
VITE_APTOS_API_KEY=
VITE_SHELBYNET_APTOS_API_KEY=
VITE_SHELBY_API_KEY=
VITE_SHELBYNET_API_KEY=
VITE_SHELBY_TESTNET_API_KEY=
VITE_YORA_KEY_RELEASE_URL=
VITE_YORA_KEY_RELEASE_PUBLIC_KEY=
VITE_YORA_REGISTRY_ADDRESS=
VITE_YORA_SHELBYNET_REGISTRY_ADDRESS=
VITE_YORA_TESTNET_REGISTRY_ADDRESS=
YORA_KEY_RELEASE_PRIVATE_KEY=
YORA_KV_REST_API_URL=
YORA_KV_REST_API_TOKEN=Do not commit .env or real API keys. Local environment files are ignored by the repository.
| Variable | Purpose |
|---|---|
| VITE_YORA_NETWORK | Default route when the app opens. Yora currently starts on Shelbynet. |
VITE_APTOS_API_KEY |
Aptos API key used by the wallet adapter on Shelbynet. |
VITE_SHELBYNET_APTOS_API_KEY |
Optional Aptos API key override for Shelbynet. |
VITE_SHELBY_API_KEY |
Shared Shelby API key fallback for both Shelby routes. |
VITE_SHELBYNET_API_KEY |
Shelby API key for Shelbynet writes. |
VITE_SHELBY_TESTNET_API_KEY |
Reserved for a future Shelby Testnet replacement route. |
VITE_YORA_KEY_RELEASE_URL |
Enables remote key release when set, for example https://yora-nine.vercel.app/api. |
VITE_YORA_KEY_RELEASE_PUBLIC_KEY |
RSA-OAEP public key used by the browser to encrypt capsule keys before escrow. |
VITE_YORA_REGISTRY_ADDRESS |
Optional fallback Aptos Move registry address. |
VITE_YORA_SHELBYNET_REGISTRY_ADDRESS |
Optional Shelbynet registry address. |
VITE_YORA_TESTNET_REGISTRY_ADDRESS |
Reserved Shelby Testnet registry address; route currently disabled. |
| Variable | Purpose |
|---|---|
YORA_KEY_RELEASE_PRIVATE_KEY |
RSA-OAEP private key used by the API to decrypt escrowed capsule keys after validation. |
YORA_KV_REST_API_URL / STORAGE_KV_REST_API_URL |
REST endpoint for durable key-release storage. The STORAGE_ form matches the Vercel Upstash integration prefix. |
YORA_KV_REST_API_TOKEN / STORAGE_KV_REST_API_TOKEN |
Token for durable key-release storage. |
Yora includes Vercel API routes for remote key escrow and release:
POST /api/v1/capsules/escrow
POST /api/v1/capsules/release
Generate the RSA-OAEP keypair:
npm run key-release:keysSet the public key in the frontend environment:
VITE_YORA_KEY_RELEASE_PUBLIC_KEY=<generated-public-key>
VITE_YORA_KEY_RELEASE_URL=https://yora-nine.vercel.app/apiSet the private key and KV credentials as server-only Vercel environment variables:
YORA_KEY_RELEASE_PRIVATE_KEY=<generated-private-key>
YORA_KV_REST_API_URL=<kv-rest-url>
YORA_KV_REST_API_TOKEN=<kv-rest-token>The key-release API verifies wallet-signed messages with Aptos Ed25519 signatures. It records encrypted key material in KV and appends release events when a recipient successfully unseals a capsule.
The optional Move registry package lives in move/.
It records metadata only:
- capsule id
- creator
- recipient
- unlock timestamp
- Shelby route
- blob owner
- blob name
- ciphertext digest
- payload kind and size
- release marker
The encrypted payload remains on Shelby.
Compile:
npm run move:compile -- --named-addresses yora=<publisher-address>Publish:
npm run move:publish -- --named-addresses yora=<publisher-address>Initialize once on the same network:
aptos move run --function-id <publisher-address>::yora_registry::initializeThen set the matching frontend variable:
VITE_YORA_SHELBYNET_REGISTRY_ADDRESS=<shelbynet-publisher-address>
VITE_YORA_TESTNET_REGISTRY_ADDRESS=<testnet-publisher-address>VITE_YORA_REGISTRY_ADDRESS remains available as a fallback when both routes share the same publisher address.
Yora is deployed on Vercel:
https://yora-nine.vercel.app
For production deployments:
- Configure the same frontend variables from
.env.example. - Configure server-only key-release variables in Vercel project settings.
- Confirm the durable KV integration used by the key-release API is active and attached to the deployment.
- Set the correct registry address for the selected route if registry writes should be active.
- Run
npm run buildbefore deploying.
Use this short, non-secret checklist after each production deployment:
- Open https://yora-nine.vercel.app and confirm the selected route is Shelbynet.
- Connect the sender wallet and create a small text capsule for a second wallet with a short future unlock time.
- Confirm the progress reaches Shelby storage and, when enabled, the Aptos registry receipt. A local success record is not sufficient.
- Switch to the recipient wallet, reload the app, and confirm the capsule appears under received capsules rather than sent capsules.
- After the unlock time, sign the release request and confirm the text preview opens.
- Repeat the unseal from a different browser or device to verify the production remote key-release path.
- If the flow fails, record the selected route, wallet network, deployment URL, timestamp, and redacted error. Never paste private keys, KV tokens, decrypt keys, or plaintext payloads into an issue.
This checklist validates the deployed integration; it is not a security audit. Shelby Testnet is currently retired in the SDK and is excluded from this health check.
The following flow has been manually validated on Shelbynet:
- Connect sender wallet.
- Select Shelbynet route.
- Create text capsule for recipient wallet.
- Create image/file capsule for recipient wallet.
- Confirm Shelby blob write succeeds.
- Confirm optional registry status appears when configured.
- Switch to recipient wallet.
- Confirm dashboard and capsule page show only capsules for the active wallet.
- Unseal after unlock time.
- Confirm text preview appears.
- Confirm image preview appears for image payloads.
- Confirm unseal works from a different browser when remote key release is configured.
Automated checks in this repository:
- npm run test:api — API signature, recipient, unlock, digest, network, timestamp, and duplicate escrow coverage
- npm run check:secrets — tracked-file secret scan
- npm run build — TypeScript and production Vite build
- npm run move:compile — Aptos Move registry compilation
- npm run test:e2e:smoke — Playwright landing, app-shell, and image-upload preview smoke test
- npm run test:e2e:flow — opt-in wallet flow for create, discover, unlock, and text preview; image unseal remains part of the manual checklist until a wallet fixture is available
.github/
workflows/quality.yml Build, test, Move compile, smoke, and secret checks
api/
_keyRelease.js Shared key-release API helpers
v1/capsules/escrow.js Remote key escrow endpoint
v1/capsules/release.js Remote key release endpoint
docs/
PHASE_4_KEY_RELEASE.md Production key-release hardening notes
assets/ README screenshots
move/
sources/yora_registry.move Optional Aptos Move registry module
public/
favicon.svg Yora favicon
og-image.png Social preview image
scripts/
generate-key-release-keys.mjs
check-secrets.mjs Tracked-file secret scan
tests/
api-key-release.test.mjs Remote key-release API tests
e2e/yora.spec.mjs Playwright smoke and opt-in wallet flow
LICENSE MIT license
src/
App.tsx Main application shell and dApp flows
main.tsx Aptos wallet provider and React entry
styles.css Product UI, responsive layout, and motion
types.ts Capsule and registry types
lib/
address.ts Address normalization helpers
aptosRegistry.ts Registry transactions and verification reads
bytes.ts Encoding helpers
crypto.ts AES-GCM encryption and decryption
keyRelease.ts Browser and remote key-release adapter
shelby.ts Shelby route configuration
shelbyCapsules.ts Capsule envelope encoding and Shelby discovery
storage.ts Shelby blob reading helpers
- React 18
- TypeScript
- Vite
- Aptos TypeScript SDK
- Aptos Wallet Adapter
- Shelby Protocol SDK
- Shelby React SDK
- Web Crypto API
- Vercel API routes
- KV-style REST storage for key records
- Aptos Move for optional registry metadata
Near-term:
- Revisit Shelby Testnet only after Shelby publishes a supported SDK/network route and Early Access validation is available.
- Expand the opt-in wallet E2E harness with a dedicated wallet-extension fixture and CI-safe Shelby test environment.
- Improve bundle splitting around Aptos wallet and SDK dependencies.
- Add deeper API observability for key-release failures and release events.
Production hardening:
- Connect key-release decisions to registry state before returning keys.
- Add stricter replay protection and operational key rotation.
- Evaluate decentralized or threshold key management for future release guarantees.
- Add a documented threat model and independent security review before broader use.
Yora has a working Shelbynet product flow with encrypted Shelby storage, recipient discovery, remote key release, file preview, and optional Aptos registry receipts. A fresh production flow was manually validated on 2026-08-07 after the SDK 0.6.0 migration, including seal, recipient discovery, cross-browser unseal, and release receipts. The current wallet upload path uses the official Shelby React hook v4.1.0 and sends shelbynet-1 as the write location. Shelby Testnet is kept as an explicit unavailable route because the current SDK marks it retired.
Yora is released under the MIT License. See LICENSE for the full text.


