Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Conceptual documents that help you understand why Dotify works the way it does.
| [Architecture Overview](./explanation/architecture-overview.md) | All | How the six system layers (identity, IPFS, EVM, Bulletin, WebRTC, frontend) connect |
| [Access Control Model](./explanation/access-control-model.md) | All | Human free vs Classic — what they mean for artists and listeners |
| [Content Protection](./explanation/content-protection.md) | All | Audio encryption pipeline, what it protects, and what it does not |
| [Royalty Settlement](./explanation/royalty-settlement.md) | All | How DOT payments flow from listener wallet to artist wallet |
| [Royalty Settlement](./explanation/royalty-settlement.md) | All | How native runtime payments flow from listener wallet to artist wallet, and why Product CASH settlement remains a separate rail |
| [Listening Rooms](./explanation/listening-rooms.md) | All | WebRTC peer-to-peer streaming, signaling protocol, known limitations |
| [Product DevNet Architecture](./explanation/product-devnet-architecture.md) | Maintainers | Dual-host boundaries, Product account capabilities, rooms, storage, and the proposed contract port |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ Goal: deepen the delivered Product mode one adapter at a time.
hook. The tracked Product deployment still defaults to viem, but a
`product-cdm` build now changes the runtime write adapter at the same seam as
reads.
- Delivered on the next follow-up branch: make Classic unlock payments a typed
native runtime payment intent before they reach `RuntimeWritePort`. The code
now has an explicit unsupported `product-cash` rail, so future CASH work can
add receipt/bridge settlement without pretending CASH is already executable
through `msg.value`.
- Settled: the chain question. Product DevNet is a preset over the Paseo system
parachains (Asset Hub 1000, People 1004, Bulletin 1010) at EVM chain
420420417, not a separate network. Dotify's contracts are already there,
Expand All @@ -201,8 +206,10 @@ Goal: deepen the delivered Product mode one adapter at a time.
The SDK's `paseo` preset is Paseo Next (1500/1502), a different network, so
`devnet` is the only environment Dotify can serve a catalog from.
- Next: `pallet-revive` account mapping plus real host-signed transaction smoke
tests before Product writes can replace the EVM wallet path. This is now the
only gate left for Product contract mode.
tests before Product writes can replace the EVM wallet path.
- Next: confirm the Product-supported CASH settlement model before exposing any
native/CASH conversion, bridge, or receipt UI. Dotify must keep runtime access
grants tied to verifiable settlement evidence.
- Next: run real Product host smoke tests for protected playback and capture the
Product sr25519 request evidence.
- Keep backend key delivery authoritative unless a Product-host design proves a
Expand Down
10 changes: 6 additions & 4 deletions docs/design/dotify-product-stack-alignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,12 @@ host-signed payment receipt the runtime verifies, or an Asset-Hub-side
entitlement credited from an attested People-chain transfer. Both need design
work. Do not ship a payment path until this is settled.

Interim implementation note: Classic unlock now goes through Dotify's
`RuntimeWritePort`, so a build can switch from viem to Product CDM contract
handles without changing the listener UI. That is still native-value runtime
payment, not Product-native CASH settlement.
Interim implementation note: Classic unlock now creates a typed native runtime
payment intent and sends that through Dotify's `RuntimeWritePort`, so a build
can switch from viem to Product CDM contract handles without changing the
listener UI. That is still native-value runtime payment, not Product-native
CASH settlement. CASH is modeled as a separate unsupported rail until Product
confirms how People-chain CASH can settle Asset-Hub runtime entitlement.

**Catalog metadata to Bulletin.** Release metadata, artwork, and manifests are
small, immutable, and public. Exactly Bulletin's shape. The Fly read model
Expand Down
11 changes: 6 additions & 5 deletions docs/explanation/access-control-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@ level, it can access the track without paying.

> "Pay once, play forever."

In Classic mode, a listener pays a fixed amount of DOT to unlock full playback.
The payment goes directly and immediately to the artist's wallet - no
intermediary, no payout schedule, no platform cut.
In Classic mode, a listener pays a fixed amount of the configured chain's
native token to unlock full playback. On the current Product DevNet/Paseo Asset
Hub runtime rail, that token is PAS. The payment goes directly and immediately
to the artist's wallet - no intermediary, no payout schedule, no platform cut.

Once a listener has paid for a track, their wallet is recorded on-chain. They
can return and play the track at any time without paying again, even if the
track later flips away from Classic and back.

**When to choose Classic:**

- You want to monetize your releases directly in DOT.
- You want to monetize your releases directly through the runtime-native token.
- You prefer familiar pay-to-play economics.

---
Expand All @@ -88,7 +89,7 @@ track later flips away from Classic and back.
3. An access gate is shown with the appropriate action:
- **Signin gate** - listener has no wallet connected. They must connect first.
- **Personhood gate** - wallet is connected but lacks the required PoP level.
- **Payment gate** - wallet is connected; DOT payment is required.
- **Payment gate** - wallet is connected; a runtime-native payment is required.

The listener can choose a Free track, join a room hosted by someone with access,
or satisfy the required gate.
Expand Down
2 changes: 1 addition & 1 deletion docs/explanation/architecture-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Track selected → access checked
└── No access? ──► Unlock/personhood gate shown, no protected audio
├── Pay DOT → musicRoyPayAccess() → access granted
├── Pay native → musicRoyPayAccess() → access granted
└── Prove PoP → registrar confirms personhood → access granted
```

Expand Down
20 changes: 18 additions & 2 deletions docs/explanation/product-devnet-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Socket.IO, and WebRTC signaling.
| Join room link | No wallet | No wallet | Same |
| Host room | Socket.IO + WebRTC | Product Desktop/web host: same. Product Mobile iOS: external-browser continuation until the host exposes Product WebRTC. | Keep until a multiparty replacement proves equivalent UX |
| Product identity | Not applicable | App-scoped SS58/H160 | Host identity with explicit capability grants |
| Classic payment | Passkey/EVM wallet through `RuntimeWritePort` | Passkey/EVM wallet in the tracked build; Product CDM writer only when `VITE_DOTIFY_RUNTIME_ADAPTER=product-cdm` is explicitly enabled | CASH settlement after the Product payment rail is designed |
| Classic payment | Native runtime payment intent through `RuntimeWritePort`; the asset label is derived from the connected EVM `chainId` (`PAS` on Product DevNet/Paseo, `DOT` on a DOT-backed Polkadot Hub EVM chain) | Passkey/EVM wallet in the tracked build; Product CDM writer only when `VITE_DOTIFY_RUNTIME_ADAPTER=product-cdm` is explicitly enabled | CASH settlement after the Product payment rail is designed |
| Protected key request | EIP-191 or session token | `product-sr25519-v1` when a Product account is connected; EIP-191 or session token otherwise | Frontend-host signed Product key/session requests, with captured host signing evidence |
| Artist publication | viem/EVM | viem/EVM | Generated CDM contract adapter |
| Personhood | Current on-chain policy source | No new claim | Privacy-preserving Product proof after verification |
Expand Down Expand Up @@ -177,7 +177,7 @@ RuntimeWritePort
registerTrack()
setAccessMode()
setReleaseActive()
payForAccess()
payForAccess(nativeRuntimeIntent)
```

Adapters:
Expand All @@ -193,6 +193,22 @@ Adapters:
- `CatalogApiAdapter`: the existing server-side read model, shared by both
frontends.

Classic unlock no longer passes a loose `(runtimeAddress, contentHash, value)`
triple into runtime writers. The catalog hook creates a typed native runtime
payment intent first: asset symbol derived from the configured EVM chain
(`PAS` on the current Product DevNet/Paseo Asset Hub chain), rail
`runtime-native`, runtime address, content hash, and 18-decimal native amount.
The amount comes from the runtime or catalog API `pricePlanck` value when
available; `priceDot` is only the rounded display string. The viem and Product
CDM adapters both submit that same intent as `musicRoyPayAccess(contentHash)`
plus `msg.value`.

CASH is represented separately as an unsupported `product-cash` rail. That is
intentional. CASH lives on People chain while Dotify entitlements live in Asset
Hub runtimes, so the Product-native path needs an explicit receipt or bridge
model before any listener payment can execute. Dotify must not silently convert
CASH to native runtime value or mark access paid without runtime evidence.

The CDM adapter has one deliberate gap: royalty payment history is not read
through Product contract handles because the current SDK surface exposes
method queries and transactions, not the viem-style historical log query used
Expand Down
21 changes: 17 additions & 4 deletions docs/explanation/royalty-settlement.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

## How royalties work for artists

When a listener pays to unlock a Classic-access track, the DOT goes directly from their wallet to yours. There is no platform account, no holding period, and no payout schedule. The smart contract distributes the payment the moment the transaction is confirmed.
When a listener pays to unlock a Classic-access track, the configured chain's
native token goes directly from their wallet to yours. On the current Product
DevNet/Paseo Asset Hub runtime rail, that token is PAS. There is no platform
account, no holding period, and no payout schedule. The smart contract
distributes the payment the moment the transaction is confirmed.

You can also split royalties with collaborators. When you register a track, you specify a list of recipient addresses and a share for each (expressed in basis points, where 10,000 = 100 %). The contract distributes the payment proportionally in the same transaction.

Expand All @@ -22,7 +26,7 @@ SmartRuntime. For each entry you can see:

- The track that was unlocked.
- The listener's wallet address.
- The amount paid in DOT.
- The amount paid in the configured runtime-native token.
- The date and time of the transaction.
- A link to the transaction receipt on Blockscout.

Expand Down Expand Up @@ -63,8 +67,17 @@ When a listener calls `musicRoyPayAccess(contentHash)`, the contract:
5. Emits `MusicRoyAccessPaid(contentHash, listener, amount)`.

The `pricePlanck` field name is historical. The active EVM path stores and pays
prices as 18-decimal native token units, so the frontend uses `parseEther()` for
DOT input and `formatEther()` for display.
prices as 18-decimal native token units. The frontend uses `parseEther()` for
artist price input and `formatEther()` for display, but unlock payments are
built from the catalog's authoritative `pricePlanck` when present. `priceDot`
is never used as the source of truth for an on-chain Classic payment. The
frontend derives the payment symbol from the configured chain and wraps the
native amount as a typed runtime payment intent before submitting
`musicRoyPayAccess`.

Product CASH settlement is deliberately not executable through this path. CASH
lives on People chain while Dotify runtime entitlements live on Asset Hub, so
that future flow needs an explicit Product-confirmed receipt or bridge design.

### Royalty event structure

Expand Down
10 changes: 6 additions & 4 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1432,7 +1432,9 @@ <h3>Doors the artist can define</h3>
<h3>Rights and splits that can be audited</h3>
<p>
Runtime rules keep royalties, collaborator shares, and access decisions inspectable
without making chain mechanics the listener's first experience.
without making chain mechanics the listener's first experience. Classic payments now
move through an explicit native runtime intent, while Product CASH remains a separate
settlement rail until the cross-chain receipt model is verified.
</p>
</dd>
</div>
Expand Down Expand Up @@ -1545,9 +1547,9 @@ <h3>Product DevNet now, sovereignty adapters next</h3>
current viem implementation, API-side Product sr25519 verification with frontend Product
proof submission for protected key/session requests, and an opt-in CDM/PAPI path that can
route runtime reads and write submissions through the Product host signer. The tracked
deployment still defaults to viem until account mapping, native value payment forwarding,
and host-signed transaction evidence are verified. Product Mobile in-app live audio pending
a host-exposed WebRTC capability, CASH settlement design, Humanity/Individuality proofs,
deployment still defaults to viem until account mapping, native payment forwarding,
host-signed transaction evidence, and Product CASH receipt design are verified. Product
Mobile in-app live audio pending a host-exposed WebRTC capability, Humanity/Individuality proofs,
consented provenance, and ambassador mechanics remain sequenced behind verified security
and privacy boundaries.
</p>
Expand Down
11 changes: 11 additions & 0 deletions docs/product/ux-signature-flows.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ sequenceDiagram
participant API as Dotify Backend

L->>UI: Click unlock full track
UI->>UI: Build native runtime payment intent
UI->>L: Confirm Classic payment transaction
L->>RT: musicRoyPayAccess(contentHash) + value
RT-->>UI: Transaction confirmed
Expand All @@ -125,6 +126,16 @@ sequenceDiagram
UI-->>L: Full playback
```

Classic unlock intentionally uses a native runtime payment intent today. The
visible asset symbol is derived from the connected EVM `chainId` and Dotify's
explicit Polkadot Hub native-currency metadata table (`PAS` on the current
Product DevNet/Paseo Asset Hub rail, `DOT` on a DOT-backed Polkadot Hub EVM
chain), not hard-coded as DOT. This is not an on-chain metadata fetch: standard
EVM JSON-RPC exposes `eth_chainId`, not native-token symbol metadata.
Product CASH settlement is a separate future rail; it must not be treated as
executable until Dotify has a Product-confirmed receipt or bridge model between
People chain CASH and Asset Hub runtime entitlement.

## Human Free flow

```mermaid
Expand Down
16 changes: 14 additions & 2 deletions docs/reference/contracts-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All contracts are deployed on **Paseo Asset Hub** (`chainId 420420417`). Source lives in `Dotify/contracts/evm/contracts/`.

Classic unlock payments settle through the runtime's native EVM `msg.value`
rail. The frontend fetches the connected EVM `chainId`, then derives the
displayed native asset from an explicit Polkadot Hub metadata table because
standard EVM JSON-RPC does not expose a native-currency symbol/decimals method.
The current Product DevNet/Paseo runtime rail displays `PAS`; a DOT-backed
Polkadot Hub EVM chain displays `DOT`.

> **Pre-fix deployment warning (2026-07-12):** this reference describes the
> current source contract. The configured Paseo factory and indexed runtimes
> still use the registry facet deployed before `musicRegRegister` became
Expand Down Expand Up @@ -325,6 +332,10 @@ Pay for access to a Classic-mode track.
field name is historical; Dotify now stores the price as 18-decimal Asset Hub
EVM native units.

Frontend writes build an explicit native runtime payment intent before calling
this function. CASH is not passed through this runtime method; Product-native
CASH settlement requires a future receipt or bridge model.

On success:

1. Distributes `msg.value` across royalty splits (basis points).
Expand Down Expand Up @@ -404,11 +415,12 @@ Introspection: `facets()`, `facetFunctionSelectors(address)`, `facetAddresses()`
The Solidity field is still named `pricePlanck` for historical/Substrate
context, but the active EVM path stores prices directly as 18-decimal native
token units. The frontend uses viem's `parseEther()` and `formatEther()` helpers
for DOT display and `msg.value`.
for display and `msg.value`; the payment symbol comes from the configured EVM
chain's native currency (`PAS` on chain `420420417`).

| Format | Example |
| ------------------------------ | ------------------------- |
| DOT (display) | `0.5` |
| Native display amount | `0.5` |
| Stored value / EVM `msg.value` | `500_000_000_000_000_000` |

Frontend conversion: `src/utils/format.ts` → `dotToPlanck()` for input and
Expand Down
Loading
Loading