Skip to content

feat: StreamPay - Per-Second Artist Compensation with Session Keys#70

Merged
kalepail merged 20 commits into
kalepail:nootfrom
tacticalnoot:main
Jan 31, 2026
Merged

feat: StreamPay - Per-Second Artist Compensation with Session Keys#70
kalepail merged 20 commits into
kalepail:nootfrom
tacticalnoot:main

Conversation

@tacticalnoot

Copy link
Copy Markdown

StreamPay: Proof of Per-Second Artist Compensation

Overview

This PR introduces StreamPay, a proof-of-concept for real-time, per-second artist compensation using Stellar/Soroban smart contracts and session keys.

Why This Matters

For Stellar

  • Demonstrates session key utility - Users sign once, then stream payments happen in the background without further passkey prompts
  • Batch transfer contract in production - Multi-recipient payments in a single atomic transaction
  • Real-world smart wallet usage - PasskeyKit + temporary signers for delegated signing

For the Music Industry

  • Direct artist payment - No intermediaries, transparent on-chain settlement
  • Per-second compensation model - Artists are paid proportionally to actual listening time
  • Proof of listen - Verifiable on-chain record of artist payments

Technical Implementation

Session Key Flow

  1. User authorizes session key (one passkey prompt)
  2. Session key is registered as temporary signer on smart wallet
  3. During playback, debt accumulates per-artist in memory
  4. On "eject", session key signs batch transfer - no popup!
  5. Batch contract atomically pays all artists

Key Components

Component Purpose
StreamPayCore.svelte Main UI + session management
batch-transfer.ts Soroban batch contract interface
Session Key (ed25519) Background signing without passkey

Security Hardening

  • ✅ NULL_ACCOUNT filtering (invalid artist addresses)
  • ✅ Balance pre-check before settlement
  • ✅ Retry handler with exponential backoff for relayer 503s
  • ✅ Address format validation (C/G prefix)

Commits Included

  • feat(streampay): add balance pre-check before batch settlement
  • fix(streampay): filter out NULL_ACCOUNT and invalid artist addresses
  • fix(streampay): construct full audio URL from Song_1 UUID
  • style(streampay): clean up spacing and line breaks in agreement UI
  • fix(streampay): correct session key text - no burn, just eject and settle
  • style(streampay): refresh flavor text with punchy, on-brand copy
  • feat(streampay): add polished success UI with confetti, stats, and stellar expert link
  • feat(streampay): add retry handler with exponential backoff for 503 errors
  • fix(streampay): sign and submit session key authorization transaction

Demo Flow

  1. Accept agreement → pick rate (1/5/10/100 KALE/sec)
  2. Deposit → authorizes session key (one passkey sign)
  3. Play songs → balance drains, artist debt accumulates
  4. Eject → batch settlement (no passkey!)
  5. Success screen with confetti + Stellar Expert link

Future Potential

  • Streaming royalties - Real-time micropayments as alternative to quarterly payouts
  • Transparent analytics - All listening data on-chain
  • Artist dashboards - Direct verification of earnings
  • Cross-platform portability - Session keys could enable web3-native streaming apps

This is experimental - not production ready, but demonstrates the core mechanics.

claude and others added 16 commits January 30, 2026 21:03
When users click links to /id pages from Twitter, mobile browsers block
autoplay because the user gesture happened in Twitter's app, not on our
page. This adds a tap-to-play overlay that:

- Detects Twitter/X referrers (t.co, twitter.com, x.com)
- Shows a fullscreen overlay with album art and play button
- Captures the user's tap gesture to unlock audio playback
- Works on both mobile and desktop, with appropriate text

Non-Twitter referrals continue to auto-play as before.

https://claude.ai/code/session_0159TqgRHmtn1YwQiKXvtzmc
This update integrates Ed25519 ephemeral signers for background payout signing and uses the batch transfer contract for atomic artist settlement.

- Added Astro and Cloudflare skills\n- Updated Remotion and DeFi mechanics skills\n- Integrated Session Keys in StreamPayCore.svelte

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 841c1344ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/passkey-kit.ts Outdated
Comment on lines 21 to 25
async function getPasskeyKit(): Promise<any> {
if (!_passkeyKitInstance) {
const { PasskeyKit } = await import("passkey-kit");
_passkeyKitInstance = new PasskeyKit({
rpcUrl: getRpcUrl(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Serialize PasskeyKit singleton initialization

Because getPasskeyKit() is now async, two callers can enter this block before _passkeyKitInstance is set and each create its own PasskeyKit instance. If one call connects the wallet while another signs (or any concurrent calls from multiple components), they can end up using different instances and lose the connected-wallet state, causing signing to fail intermittently. Consider caching a single in-flight promise (or a lock) so all concurrent callers share the same instance.

Useful? React with 👍 / 👎.

tacticalnoot and others added 4 commits January 31, 2026 03:43
…ition

The async getPasskeyKit() allowed multiple callers to enter the initialization
block before _passkeyKitInstance was set, causing each to create their own
PasskeyKit instance. This led to intermittent signing failures when one caller
connected the wallet on one instance while another tried to sign on a different
instance.

Fix by caching the in-flight initialization promise so all concurrent callers
share the same instance.

https://claude.ai/code/session_012iZQopTzdWH8tKm9htrBuW
@kalepail kalepail merged commit c91281b into kalepail:noot Jan 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants