Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
95aeb9a
Adapt Dotify for Product DevNet
knzeng-e Jul 26, 2026
b9d4302
Use dotify-test01 Product domain
knzeng-e Jul 26, 2026
fc2a2ce
feat: extract runtime contract ports
knzeng-e Jul 26, 2026
00f1d93
feat: add Product CDM runtime adapter
knzeng-e Jul 26, 2026
5e41931
feat: add Product signature scheme
knzeng-e Jul 28, 2026
aaffb9d
feat: wire Product key signatures in frontend
knzeng-e Jul 28, 2026
cb17803
fix: accept Product host signing envelopes and reject EVM-derived keys
knzeng-e Jul 29, 2026
65e7650
docs: correct Product protected-playback claims
knzeng-e Jul 29, 2026
9164b2c
chore: bound runtime catalog reads and record CDM adapter gaps
knzeng-e Jul 29, 2026
1ef3117
feat: generate the Product CDM manifest and contract types
knzeng-e Jul 29, 2026
8bd9220
feat: wire the Product CDM runtime adapter behind a build-time flag
knzeng-e Jul 29, 2026
ed701e6
docs: record the CDM manifest slice and its remaining gate
knzeng-e Jul 29, 2026
9246537
fix: target the devnet preset, the only chain holding Dotify runtimes
knzeng-e Jul 29, 2026
b587bd7
feat: prove the DevNet endpoint set with a read-only smoke check
knzeng-e Jul 29, 2026
1476208
docs: correct the stale CDM prerequisite in the deploy runbook
knzeng-e Jul 29, 2026
10a4a59
perf: bound and hedge the legacy IPFS gateway reads
knzeng-e Jul 29, 2026
0f7438e
fix: keep one API machine warm for first sound
knzeng-e Jul 29, 2026
072e9f9
feat: explain why a room connection was refused
knzeng-e Jul 29, 2026
b06e765
docs: warn that flyctl -c does not set the Docker build context
knzeng-e Jul 29, 2026
7e64f10
fix: keep a raced gateway read cancellable after the winner returns
knzeng-e Jul 29, 2026
3254cec
fix: admit the Product host container origin to the API allowlist
knzeng-e Jul 29, 2026
cb41c26
docs: assess Dotify against the official Product stack
knzeng-e Jul 29, 2026
1c89fb1
feat: read personhood from the Individuality precompile
knzeng-e Jul 29, 2026
ab75467
feat: register @dotify/* in the CDM registry without redeploying
knzeng-e Jul 29, 2026
acc13f8
docs: record why cdm deploy is blocked by the Asset Hub size limit
knzeng-e Jul 30, 2026
3bea7ce
feat: generate CDM metadata blobs and wire their CIDs into publishing
knzeng-e Jul 30, 2026
ef36c2c
feat: add the Bulletin upload step and fix a wrong CID multihash
knzeng-e Jul 30, 2026
1aa84dc
fix: sign cdm:publish with the configured hardhat account
knzeng-e Jul 30, 2026
185748c
chore: publish CDM names and refresh Product icon
knzeng-e Jul 30, 2026
bf3b1ec
feat: announce hosted rooms on the Statement Store
knzeng-e Jul 31, 2026
4c951db
fix: address review on room beacons
knzeng-e Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ dist/
.playwright*
!.env.example
!web/.env.example
!web/.env.product-devnet
!contracts/evm/.env.example

web/node_modules/
web/dist/
web/dist-bulletin*
web/dist-product/
web/*.car
web/.playwright*
web/playwright-report/
web/test-results/
Expand Down
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,14 @@ cd web
npm run smoke:production-env
```

When Product DevNet endpoints, `deployments.json`, or the DevNet build profile
change, also run the read-only endpoint check:

```bash
cd web
npm run smoke:devnet
```

For deployment-sensitive work, add the relevant read-only health, chain,
contract, IPFS gateway, and wrong-network checks. Record the environment and
evidence without exposing credentials.
Expand Down
39 changes: 26 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,28 @@ aura lights the whole field (`web/src/styles/aura.css`).
creates one personal `SmartRuntime` per artist, and `ArtistDirectory` indexes
artist addresses to their runtimes.

**Frontend**: Static React + Vite web app deployed to dot.li.
**Frontend**: Static React + Vite web app deployed to Netlify and, through the
Product profile, Bulletin/DotNS at `dotify-test01.dot`.

**WebRTC**: real-time music streaming.

**Socket.IO**: signaling for room discovery and SDP/ICE exchange. A future
iteration can move signaling to statement-store style infrastructure.

**Product SDK direction**: Dotify remains a standalone web app first. Product
SDK / Playground / Humanity work is a progressive-enhancement track documented
in
[`docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md`](docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md).
The current SDK snapshot is prototype/reference/unaudited and must be proven
against Dotify's Host, key-delivery, room, and contract constraints before it
becomes a production dependency.
**Product SDK direction**: Dotify now has an adaptive Product DevNet build for
`dotify-test01.dot`. It keeps standalone link-first rooms and Free listening intact,
adds explicit app-scoped Product identity, and publishes through
Bulletin/DotNS. The runtime hooks now sit behind typed ports with the current
viem implementation and an experimental Product CDM/PAPI adapter boundary.
The backend key-delivery protocol now has an explicit Product sr25519
signature scheme that binds the Product account public key to the derived H160
requester before access checks. The Product frontend can now submit that
Product proof after explicit host-account connection; contract writes remain
passkey/EVM until CDM-installed runtime packages and host-signed transaction
evidence are proven. See
[`docs/explanation/product-devnet-architecture.md`](docs/explanation/product-devnet-architecture.md)
and the
[`Product roadmap`](docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md).

## Deployed

Expand All @@ -69,7 +77,7 @@ becomes a production dependency.

**Gateway URL** — <https://paseo-ipfs.polkadot.io/ipfs/bafkr4ibynaanfrddyjgpmut2qrcu6vdttocbp4feyw6vkgxkkhqndjksny>

**DotNS name** — `dotify.dot.li`
**DotNS name** — `dotify-test01.dev-dot.li`

## How to run end-to-end (locally)

Expand Down Expand Up @@ -118,7 +126,8 @@ npm run dev

| Variable | Required | Purpose |
| --------------------------- | ---------------- | -------------------------------------------------------- |
| `API_ORIGIN` | Production | Frontend origin allowed by API CORS |
| `API_ORIGIN` | Compatibility | Singular frontend CORS origin fallback |
| `API_ORIGINS` | Production | Comma-separated exact frontend CORS origins |
| `PASEO_ASSET_HUB_RPC` | Key requests | Paseo Asset Hub EVM RPC used for access checks |
| `DOTIFY_DIRECTORY_ADDRESS` | Key requests | ArtistDirectory address used to resolve artist runtimes |
| `DOTIFY_CHAIN_ID` | Key requests | Chain ID expected in wallet-signed key requests |
Expand Down Expand Up @@ -298,6 +307,10 @@ releasing it. Gated tracks use a signed session or signed key request; the
backend verifies the requester, resolves the artist runtime, and calls
`musicAccCanAccess` before releasing a per-track key. If access is denied, the
UI shows the action needed to unlock the track and plays no protected audio.
Standalone clients sign with the default `eip191` scheme. Product-host clients
can use `product-sr25519-v1` by signing the same canonical Dotify message bytes
with the app-scoped Product account and sending `productPublicKey`; the backend
derives the H160 requester from that public key before any nonce is consumed.

For registered artist tracks, users without a connected wallet can play Free
tracks. For gated tracks, they see a sign-in/unlock gate. Dev-account fallback
Expand Down Expand Up @@ -430,9 +443,9 @@ handle:
and decide whether a backend read-through gateway is needed.
4. Keep demo-mode browser-exposed Pinata/content secrets out of public
deployments.
5. Run Product SDK feasibility spikes: Host detection, Product account signing,
resource allocation, Playground/Bulletin/DotNS deployment, and PolkaVM/CDM
contract portability.
5. Validate the Product host/account and Bulletin/DotNS deployment baseline,
then wire frontend Product-signed key/session requests, resource allocation,
and PolkaVM/CDM contract portability.
6. Add a production artist dashboard on `/artists`: release drafts, edit
metadata, royalty analytics, and profile verification state.
7. Deploy and monitor a public signaling server for DotNS / Bulletin builds.
Expand Down
37 changes: 37 additions & 0 deletions contracts/evm/.cdm/cdm.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Auto-generated by cdm install -- do not edit
import type { HexString, SizedHex } from "polkadot-api";

declare module "@parity/cdm-codegen" {
interface CdmContracts {
"@dotify/artist-directory": {
methods: {
artistAtIndex: { args: [index: bigint]; response: HexString };
artistCount: { args: []; response: bigint };
artistsPage: { args: [offset: bigint, limit: bigint]; response: { artists: HexString[]; runtimes: HexString[] } };
deployer: { args: []; response: HexString };
factory: { args: []; response: HexString };
register: { args: [artist: HexString, runtime: HexString]; response: undefined };
runtimeOf: { args: [arg0: HexString]; response: HexString };
setFactory: { args: [_factory: HexString]; response: undefined };
};
};
"@dotify/artist-runtime-factory": {
methods: {
accessPallet: { args: []; response: HexString };
createRuntime: { args: []; response: HexString };
cutPallet: { args: []; response: HexString };
directory: { args: []; response: HexString };
initContract: { args: []; response: HexString };
installRuntimeStep: { args: []; response: number };
loupePallet: { args: []; response: HexString };
nftPallet: { args: []; response: HexString };
ownershipPallet: { args: []; response: HexString };
pendingRuntimeOf: { args: [arg0: HexString]; response: HexString };
pendingRuntimeStageOf: { args: [arg0: HexString]; response: number };
registryPallet: { args: []; response: HexString };
royaltiesPallet: { args: []; response: HexString };
runtimeOf: { args: [artist: HexString]; response: HexString };
};
};
}
}
37 changes: 37 additions & 0 deletions contracts/evm/.cdm/contracts.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Auto-generated by cdm install -- do not edit
import type { HexString, SizedHex } from "polkadot-api";

declare module "@parity/product-sdk-contracts" {
interface Contracts {
"@dotify/artist-directory": {
methods: {
artistAtIndex: { args: [index: bigint]; response: HexString };
artistCount: { args: []; response: bigint };
artistsPage: { args: [offset: bigint, limit: bigint]; response: { artists: HexString[]; runtimes: HexString[] } };
deployer: { args: []; response: HexString };
factory: { args: []; response: HexString };
register: { args: [artist: HexString, runtime: HexString]; response: undefined };
runtimeOf: { args: [arg0: HexString]; response: HexString };
setFactory: { args: [_factory: HexString]; response: undefined };
};
};
"@dotify/artist-runtime-factory": {
methods: {
accessPallet: { args: []; response: HexString };
createRuntime: { args: []; response: HexString };
cutPallet: { args: []; response: HexString };
directory: { args: []; response: HexString };
initContract: { args: []; response: HexString };
installRuntimeStep: { args: []; response: number };
loupePallet: { args: []; response: HexString };
nftPallet: { args: []; response: HexString };
ownershipPallet: { args: []; response: HexString };
pendingRuntimeOf: { args: [arg0: HexString]; response: HexString };
pendingRuntimeStageOf: { args: [arg0: HexString]; response: number };
registryPallet: { args: []; response: HexString };
royaltiesPallet: { args: []; response: HexString };
runtimeOf: { args: [artist: HexString]; response: HexString };
};
};
}
}
176 changes: 176 additions & 0 deletions contracts/evm/.cdm/contracts/@dotify/artist-directory/0/abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "artist",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "runtime",
"type": "address"
}
],
"name": "ArtistRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "factory",
"type": "address"
}
],
"name": "FactorySet",
"type": "event"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "artistAtIndex",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "artistCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "offset",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit",
"type": "uint256"
}
],
"name": "artistsPage",
"outputs": [
{
"internalType": "address[]",
"name": "artists",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "runtimes",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "deployer",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "artist",
"type": "address"
},
{
"internalType": "address",
"name": "runtime",
"type": "address"
}
],
"name": "register",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "runtimeOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_factory",
"type": "address"
}
],
"name": "setFactory",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@dotify/artist-directory",
"version": 0,
"address": "0xcf1534C6e2B0E43B9436c1e86A076466dC0F2108",
"metadataCid": "bafk2bzacebiynqo7tjvxa3xlvf6pphgq3nzatqjbn3yo2fszrlvxibtsr4ce6"
}
Loading
Loading