Verification Phase
How seeders independently verify payment channels on-chain before serving data.
In the verification phase, the Seeder independently checks the on-chain payment channel before opening a paid session. The Seeder treats the blockchain as the source of truth and MUST NOT rely solely on the channel_opened message contents.
On-Chain Channel Lookup
Upon receiving a channel_opened message, the Seeder performs a read-only lookup using the provided tx_signature. The Seeder MUST:
- Fetch the transaction by
tx_signaturefrom a trusted RPC endpoint - Reject if the transaction cannot be found or hasn't reached at least confirmed status
- Parse the transaction to locate:
- The channel creation instruction
- The escrow account holding deposited funds
- The deposited amount
- The channel state (leecher, seeder, timeout, etc.)
- Any memo instruction attached to the transaction
If any of these steps fail, the Seeder MUST treat the channel as invalid.
Validation Rules
A payment channel is considered valid only if ALL of the following checks pass:
1. Channel State Check
- The channel MUST exist on-chain and be in an
"Open"state - The Seeder's wallet address in the channel state MUST equal the Seeder's configured wallet
2. Deposit Amount Check
- The deposited amount MUST be ≥ the Seeder's
min_prepayment - The Seeder MAY also enforce a maximum deposit policy
3. Token Check
- The escrow MUST hold the expected token (e.g. USDC) on the expected chain
4. Session Binding Check (Privacy-Preserving)
The memo MUST match the SeedPay format:
{
"protocol": "seedpay",
"version": "1.0",
"session_hash": "<hex-string>",
"nonce": 1702700000000
}The Seeder computes expected_hash = SHA-256(Session_UUID) using the Session_UUID derived during ECDH key exchange. The session_hash in the memo MUST equal expected_hash.
This proves the channel is bound to this specific connection without revealing peer_id or IP information.
5. Freshness / Replay Protection
- The channel opening MUST be recent:
nonceor block time within 5–10 minutes - The Seeder MUST maintain a set of already-used channel identifiers and reject duplicates
6. Error-Free Execution
- The transaction metadata MUST indicate success — any failed or reverted transaction is invalid
Seeder Response
On Success
The Seeder:
-
Creates a payment session with initial state:
Field Value channel_idVerified channel identifier channel_depositVerified deposited amount last_check_nonce0 last_check_amount0 bytes_downloaded0 price_per_mbValue from handshake channel_timeoutTimeout from channel state -
Sends a
channel_confirmedmessage:{ "type": "channel_confirmed", "confirmed": true, "channel_id": "<channel_identifier>", "deposit": 0.01, "price_per_mb": 0.0001, "timeout": 1702703600000 } -
Unchokes the Leecher on the BitTorrent wire, allowing piece requests.
On Failure
The Seeder sends a channel_rejected message and keeps the Leecher choked:
{
"type": "channel_rejected",
"confirmed": false,
"reason": "session_mismatch"
}Possible rejection reasons:
| Reason | Description |
|---|---|
tx_not_found | Transaction not found on-chain |
tx_failed | Transaction failed or reverted |
wrong_seeder | Seeder wallet doesn't match |
insufficient_deposit | Below min_prepayment |
session_mismatch | Session hash doesn't match ECDH-derived UUID |
replayed_channel | Channel ID already used |
expired | Channel opening too old |
invalid_channel_state | Channel not in Open state |
The Seeder MAY allow the Leecher to retry with a new channel opening, or MAY close the connection according to local policy.
Once verified, the protocol transitions to Data Transfer.