Skip to content

Commit 8c2b99d

Browse files
rickyromboclaude
andauthored
Auto-create USDC userbank on gated track upload/edit (#14227)
## Summary - When a user uploads or edits a track with USDC stream/download gating, fire `createUserBankIfNeeded(mint: 'USDC')` in parallel with the SDK call so the seller's userbank exists as a side effect of listing gated content — not just after they open Add Cash, withdraw, or claim flows. - Best-effort: errors are logged but never block the save. Underlying `getOrCreateUserBank` is idempotent, so duplicate triggers (e.g. album publish that fans out to `publishTracks`) are safe. ## Scope - `useUpdateTrack` (track edit) — `packages/common/src/api/tan-query/tracks/useUpdateTrack.ts` - `publishTracks` (track upload, also reused by album upload) — `packages/common/src/api/tan-query/upload/usePublishTracks.ts` ## Why not the album-level hooks - `usePublishCollection` already delegates to `publishTracks` for each child track of a premium album, so the trigger fires there. - `useUpdateCollection` only edits the album's price metadata; the album was already gated at upload time, so the userbank trigger has already fired via the original track publish. ## Test plan - [ ] Upload a track with USDC download gating → seller's USDC userbank exists after upload (verify via Solana account lookup or a follow-up purchase) - [ ] Edit an existing non-gated track to enable USDC downloads → userbank exists after save - [ ] Edit a USDC-gated track's price (no gate change) → no error, userbank trigger short-circuits via `didExist` - [ ] Upload a premium album → seller userbank exists once, even with multiple child tracks - [ ] Upload/edit a non-USDC (free / follow-gated / token-gated) track → no userbank call fires - [ ] Network failure on userbank creation → upload/edit still succeeds; warning logged 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent c712104 commit 8c2b99d

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

packages/common/src/api/tan-query/tracks/useUpdateTrack.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
isContentTokenGated,
1919
isContentUSDCPurchaseGated
2020
} from '~/models/Track'
21+
import { createUserBankIfNeeded } from '~/services/audius-backend'
2122
import { CommonState } from '~/store/commonStore'
2223
import { stemsUploadSelectors } from '~/store/stems-upload'
2324
import { replaceTrackProgressModalActions } from '~/store/ui/modals/replace-track-progress-modal'
@@ -29,6 +30,7 @@ import { formatMusicalKey } from '~/utils/musicalKeys'
2930
import { TQTrack } from '../models'
3031
import { QUERY_KEYS } from '../queryKeys'
3132
import { addPremiumMetadata } from '../upload/usePublishTracks'
33+
import { useCurrentAccountUser } from '../users/account/accountSelectors'
3234
import { useCurrentUserId } from '../users/account/useCurrentUserId'
3335
import { getUserQueryKey } from '../users/useUser'
3436
import { handleStemUpdates } from '../utils/handleStemUpdates'
@@ -107,6 +109,7 @@ export const useUpdateTrack = () => {
107109
const store = useStore()
108110
const { mutate: deleteTrack } = useDeleteTrack()
109111
const { data: userId } = useCurrentUserId()
112+
const { data: accountUser } = useCurrentAccountUser()
110113

111114
return useMutation({
112115
mutationFn: async ({
@@ -134,6 +137,26 @@ export const useUpdateTrack = () => {
134137
)
135138
const sdkMetadata = trackMetadataForUploadToSdk(metadataWithSplits)
136139

140+
const ethAddress = accountUser?.wallet
141+
if (
142+
ethAddress &&
143+
(isContentUSDCPurchaseGated(metadataWithSplits.stream_conditions) ||
144+
isContentUSDCPurchaseGated(metadataWithSplits.download_conditions))
145+
) {
146+
createUserBankIfNeeded(sdk, {
147+
mint: 'USDC',
148+
ethAddress,
149+
recordAnalytics: analytics.track
150+
}).catch((error) => {
151+
reportToSentry({
152+
error,
153+
additionalInfo: { trackId, userId, ethAddress },
154+
feature: Feature.Edit,
155+
name: 'Ensure USDC userbank on track edit'
156+
})
157+
})
158+
}
159+
137160
const response = await sdk.tracks.updateTrack({
138161
audioFile,
139162
imageFile,

packages/common/src/api/tan-query/upload/usePublishTracks.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
Name,
99
Feature
1010
} from '~/models'
11+
import { createUserBankIfNeeded } from '~/services/audius-backend'
1112
import { ProgressStatus, uploadActions } from '~/store'
1213
import type { TrackMetadataForUpload } from '~/store'
1314

@@ -28,6 +29,7 @@ type PublishTracksContext = Pick<
2829
'audiusSdk' | 'analytics' | 'dispatch' | 'reportToSentry'
2930
> & {
3031
userId: number
32+
ethAddress?: string | null
3133
kind?: 'tracks' | 'album' | 'playlist'
3234
}
3335

@@ -45,6 +47,7 @@ export const publishTracks = async (
4547
) => {
4648
const {
4749
userId,
50+
ethAddress,
4851
kind,
4952
audiusSdk,
5053
dispatch,
@@ -58,6 +61,28 @@ export const publishTracks = async (
5861

5962
const sdk = await audiusSdk()
6063

64+
if (
65+
ethAddress &&
66+
params.some(
67+
(p) =>
68+
isContentUSDCPurchaseGated(p.metadata.stream_conditions) ||
69+
isContentUSDCPurchaseGated(p.metadata.download_conditions)
70+
)
71+
) {
72+
createUserBankIfNeeded(sdk, {
73+
mint: 'USDC',
74+
ethAddress,
75+
recordAnalytics: track
76+
}).catch((error) => {
77+
reportToSentry({
78+
error,
79+
additionalInfo: { userId, ethAddress },
80+
feature: Feature.Upload,
81+
name: 'Ensure USDC userbank on track upload'
82+
})
83+
})
84+
}
85+
6186
return await Promise.all(
6287
params.map(async (param) => {
6388
const snakeMetadata = addPremiumMetadata(userId, param.metadata)
@@ -189,6 +214,7 @@ export const usePublishTracks = (
189214
...getPublishTracksOptions({
190215
...queryContext,
191216
userId: userId!,
217+
ethAddress: accountUser?.wallet,
192218
kind
193219
}),
194220
onSuccess: async (data) => {

0 commit comments

Comments
 (0)