Skip to content

Add Solana wallet middleware for coin-gated streams#738

Merged
raymondjacobson merged 5 commits intomainfrom
ray/solana-wallet-stream-auth
Mar 26, 2026
Merged

Add Solana wallet middleware for coin-gated streams#738
raymondjacobson merged 5 commits intomainfrom
ray/solana-wallet-stream-auth

Conversation

@raymondjacobson
Copy link
Copy Markdown
Member

Summary

  • New solanaWalletMiddleware verifies ed25519 signatures from X-Solana-Wallet, X-Solana-Message, X-Solana-Signature headers
  • New checkSolanaWalletTokenAccess helper performs real-time on-chain token balance checks via Solana RPC (derives ATA, calls GetTokenAccountBalance)
  • Stream endpoint (v1TrackStream) falls back to Solana wallet balance check when standard access check fails, enabling coin-gated streaming for non-Audius wallets
  • Exported BuildMediaLink from dbv1 package to support building stream URLs in the fallback path
  • Companion example app in Add coin-gated tracks example app apps#14012

Test plan

  • Verify existing stream endpoint works unchanged for OAuth-authenticated users
  • Test Solana wallet headers with valid ed25519 signature → stream succeeds for wallets holding sufficient tokens
  • Test invalid/missing signature headers → 401 error
  • Test wallet with insufficient token balance → 403 error
  • Verify middleware is no-op when no Solana headers are present

🤖 Generated with Claude Code

New middleware verifies ed25519 signatures from X-Solana-Wallet,
X-Solana-Message, and X-Solana-Signature headers. When standard
access check fails, the stream endpoint falls back to real-time
on-chain token balance verification via Solana RPC for wallets
that hold the required artist coin.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zap.Bool("hasAccess", int64(balance) >= scaledRequired),
)

return int64(balance) >= scaledRequired, nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nice

raymondjacobson and others added 4 commits March 26, 2026 12:05
A valid PKCE access token already proves the user authorized the
client app during the OAuth consent flow. The on-chain grant check
is redundant for these requests and fails for read-only apps that
don't have a grant registered in the grants table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move token gate checks for Solana wallets from the stream endpoint
into GetBulkTrackAccess via a TokenBalanceFetcher callback. Balances
are looked up from the indexed sol_token_account_balances table
instead of Solana RPC, removing the RPC dependency entirely.

- Add TokenBalanceFetcher type and optional param to GetBulkTrackAccess
- Replace RPC-based checkSolanaWalletTokenAccess with DB-backed fetcher
- Remove inline fallback in v1TrackStream — access is now pre-calculated
- Remove unused BuildMediaLink export
- Add middleware test for Solana wallet signature verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the TokenBalanceFetcher abstraction with a plain solanaWallet
string parameter. When present, a parallel query against
sol_token_account_balances runs alongside the existing sol_user_balances
lookup, merging the higher balance per mint after both complete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@raymondjacobson raymondjacobson merged commit 8e6b030 into main Mar 26, 2026
5 checks passed
@raymondjacobson raymondjacobson deleted the ray/solana-wallet-stream-auth branch March 26, 2026 19:51
raymondjacobson added a commit to AudiusProject/apps that referenced this pull request Mar 26, 2026
## Summary
- New example web app at `packages/web/examples/coin-gated/`
demonstrating token-gated track browsing and streaming using artist
coins
- Supports two auth paths: Audius OAuth (PKCE) and direct Solana wallet
signing (Phantom)
- Uses `sdk.coins.getCoinByTicker()` to look up coins,
`sdk.users.getTracksByUser()` with `gateCondition: ['token']` to list
gated tracks, and `sdk.tracks.streamTrack()` for authenticated streaming
- Companion API changes in AudiusProject/api#738

## Test plan
- [x] `cd packages/web/examples/coin-gated && npm install && npm run
dev`
- [x] Enter a coin ticker (e.g. `YAK`) and verify coin info + gated
tracks load
- [x] Sign in with Audius OAuth and verify access status updates on
tracks
- [x] Connect Phantom wallet and verify wallet-based streaming works
- [x] Verify locked tracks show disabled play button when not
authenticated

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants