Mobile playback is not supported. This demo is mobile friendly for reading, but the streaming audio path works best in a desktop browser.
No session — click Play to open escrow
Chunks paid
0
Total spent (SBC)
0.000
Buffer ahead
0.0s

    
Audio: J.S. Bach — Goldberg Variations BWV 988, Aria. Performed by Bradley Lehman. Public Domain via Wikimedia Commons.

The escrow contract

SessionEscrow is a minimal MPP-style escrow on Radius. Two onchain transactions per session bookend an arbitrary number of free, offchain EIP-712 vouchers. SBC is pulled in via EIP-2612 permit on open; only the final cumulative voucher is settled on close.

protocol · payer.open(sessionId, payee, amount, …) → sign vouchers offchain → payee.close(sessionId, finalCumulativeAmount, nonce, v, r, s)
// SessionEscrow.sol — Radius testnet, chain 72344
bytes32 public constant VOUCHER_TYPEHASH = keccak256(
    "Voucher(bytes32 sessionId,uint256 cumulativeAmount,uint256 nonce)"
);

struct Session {
    address payer; address payee;
    uint128 deposited; uint128 spent;
    uint64  expiry;    bool    closed;
}

// tx 1 · payer pulls funds in via EIP-2612 permit
function open(
    bytes32 sessionId, address payee, uint128 amount, uint64 duration,
    uint256 permitDeadline, uint8 pv, bytes32 pr, bytes32 ps
) external;

// tx 2 · payee submits final voucher; contract pays + refunds atomically
function close(
    bytes32 sessionId, uint256 cumulativeAmount, uint256 nonce,
    uint8 v, bytes32 r, bytes32 s
) external; // require(signer == payer); transfer(payee, cum); refund(payer)

// liveness escape · payer reclaims full deposit if payee never closes
function reclaim(bytes32 sessionId) external;