diff --git a/packages/common/src/adapters/accessConditionsFromSDK.ts b/packages/common/src/adapters/accessConditionsFromSDK.ts index 18d6f0e9b68..b325955007e 100644 --- a/packages/common/src/adapters/accessConditionsFromSDK.ts +++ b/packages/common/src/adapters/accessConditionsFromSDK.ts @@ -1,7 +1,7 @@ import type { AccessGate } from '@audius/sdk' import { - instanceOfExtendedPurchaseGate, instanceOfFollowGate, + instanceOfPurchaseGate, instanceOfTokenGate } from '@audius/sdk' @@ -13,26 +13,6 @@ export const accessConditionsFromSDK = ( ): AccessConditions | null => { if (instanceOfFollowGate(input)) { return { follow_user_id: input.followUserId } - } else if (instanceOfExtendedPurchaseGate(input)) { - const purchase = input.usdcPurchase - const splits = Array.isArray(purchase.splits) - ? purchase.splits.map((s) => ({ - user_id: s.userId, - percentage: s.percentage, - payout_wallet: s.payoutWallet, - amount: s.amount, - ...(s.ethWallet != null && { eth_wallet: s.ethWallet }) - })) - : [] - const albumTrackPrice = (purchase as { albumTrackPrice?: number }) - .albumTrackPrice - return { - usdc_purchase: { - price: purchase.price, - ...(albumTrackPrice != null && { albumTrackPrice }), - splits - } - } } else if (instanceOfTokenGate(input)) { return { token_gate: { @@ -40,8 +20,16 @@ export const accessConditionsFromSDK = ( token_amount: input.tokenGate.tokenAmount } } - } else if ('nftCollection' in input && input.nftCollection != null) { - return null + } else if (instanceOfPurchaseGate(input)) { + return { + usdc_purchase: { + price: input.usdcPurchase.price, + splits: input.usdcPurchase.splits.map((s) => ({ + user_id: s.userId, + percentage: s.percentage + })) + } + } } else { throw new Error(`Unsupported access gate type: ${JSON.stringify(input)}`) } diff --git a/packages/common/src/adapters/accessConditionsToSDK.ts b/packages/common/src/adapters/accessConditionsToSDK.ts index 936001bde3a..9fdabb7a9bf 100644 --- a/packages/common/src/adapters/accessConditionsToSDK.ts +++ b/packages/common/src/adapters/accessConditionsToSDK.ts @@ -28,7 +28,7 @@ export const usdcPurchaseConditionsToSDK = ( ethWallet?: string } ) => ({ - userId: s.user_id ?? s.userId, + userId: s.user_id, percentage: s.percentage, payoutWallet: s.payout_wallet ?? s.payoutWallet ?? '', amount: s.amount, diff --git a/packages/common/src/api/tan-query/upload/usePublishCollection.ts b/packages/common/src/api/tan-query/upload/usePublishCollection.ts index df33253da97..c0756744add 100644 --- a/packages/common/src/api/tan-query/upload/usePublishCollection.ts +++ b/packages/common/src/api/tan-query/upload/usePublishCollection.ts @@ -36,7 +36,6 @@ type PublishCollectionContext = Pick< 'audiusSdk' | 'analytics' | 'dispatch' | 'reportToSentry' > & { userId: number - wallet: string } type PublishCollectionParams = { @@ -52,15 +51,11 @@ type PublishCollectionParams = { const getPublishCollectionOptions = (context: PublishCollectionContext) => mutationOptions({ mutationFn: async (params: PublishCollectionParams) => { - const { audiusSdk, userId, wallet } = context + const { audiusSdk, userId } = context const sdk = await audiusSdk() - if (!userId || !wallet) { + if (!userId) { throw new Error('User ID and wallet are required to publish collection') } - const userBank = await sdk.services.claimableTokensClient.deriveUserBank({ - ethWallet: wallet, - mint: 'USDC' - }) // If the collection is a premium album, this will populate the premium metadata (price/splits/etc) let albumTrackPrice: number | undefined @@ -73,7 +68,7 @@ const getPublishCollectionOptions = (context: PublishCollectionContext) => params.collectionMetadata.stream_conditions?.usdc_purchase .albumTrackPrice ?? undefined params.collectionMetadata.stream_conditions = getUSDCMetadata( - userBank.toString(), + userId, params.collectionMetadata.stream_conditions ) } @@ -81,7 +76,7 @@ const getPublishCollectionOptions = (context: PublishCollectionContext) => // Combine collection metadata into each track's metadata for (const track of params.tracks) { track.metadata = combineMetadata( - userBank.toString(), + userId, track.metadata, params.collectionMetadata, albumTrackPrice @@ -145,14 +140,12 @@ export const usePublishCollection = ( const { data: account = null } = useCurrentAccount() const { data: accountUser } = useCurrentAccountUser() const userId = account?.userId ?? undefined - const wallet = account?.walletAddresses.currentUser ?? undefined return useMutation({ ...options, ...getPublishCollectionOptions({ audiusSdk, userId: userId!, - wallet: wallet!, dispatch, analytics, reportToSentry @@ -214,7 +207,7 @@ export const usePublishCollection = ( * taking the metadata from the playlist when the track is missing it. */ function combineMetadata( - userBank: string, + userId: number, trackMetadata: TrackMetadataForUpload, collectionMetadata: CollectionValues, albumTrackPrice?: number @@ -269,7 +262,7 @@ function combineMetadata( usdc_purchase: { price: albumTrackPrice, splits: [] } } // Add splits to stream & download conditions - addPremiumMetadata(userBank, metadata) + addPremiumMetadata(userId, metadata) } return metadata } diff --git a/packages/common/src/api/tan-query/upload/usePublishTracks.ts b/packages/common/src/api/tan-query/upload/usePublishTracks.ts index 77b1a634e42..11b55975092 100644 --- a/packages/common/src/api/tan-query/upload/usePublishTracks.ts +++ b/packages/common/src/api/tan-query/upload/usePublishTracks.ts @@ -1,4 +1,3 @@ -import { USDC } from '@audius/fixed-decimal' import { HashId, Id, type UploadResponse } from '@audius/sdk' import { useMutation, useQueryClient } from '@tanstack/react-query' @@ -29,7 +28,6 @@ type PublishTracksContext = Pick< 'audiusSdk' | 'analytics' | 'dispatch' | 'reportToSentry' > & { userId: number - wallet: string kind?: 'tracks' | 'album' | 'playlist' } @@ -47,7 +45,6 @@ export const publishTracks = async ( ) => { const { userId, - wallet, kind, audiusSdk, dispatch, @@ -55,21 +52,15 @@ export const publishTracks = async ( analytics: { make, track } } = context - if (!context.userId || !context.wallet) { + if (!context.userId) { throw new Error('User ID and wallet are required to publish tracks') } const sdk = await audiusSdk() - const userBank = await sdk.services.claimableTokensClient.deriveUserBank({ - ethWallet: wallet, - mint: 'USDC' - }) + return await Promise.all( params.map(async (param) => { - const snakeMetadata = addPremiumMetadata( - userBank.toString(), - param.metadata - ) + const snakeMetadata = addPremiumMetadata(userId, param.metadata) const trackId = await sdk.tracks.generateTrackId() const camelMetadata = trackMetadataForUploadToSdk({ @@ -191,7 +182,6 @@ export const usePublishTracks = ( const { data: account } = useCurrentAccount() const { data: accountUser } = useCurrentAccountUser() const userId = account?.userId ?? undefined - const wallet = account?.walletAddresses.currentUser ?? undefined const kind = options?.kind ?? 'tracks' return useMutation({ @@ -199,7 +189,6 @@ export const usePublishTracks = ( ...getPublishTracksOptions({ ...queryContext, userId: userId!, - wallet: wallet!, kind }), onSuccess: async (data) => { @@ -235,11 +224,10 @@ export const usePublishTracks = ( * returns updated conditions with price in WEI and splits in the new array format. */ export function getUSDCMetadata( - userBank: string, + userId: number, stream_conditions: USDCPurchaseConditions ): USDCPurchaseConditions { const priceCents = stream_conditions.usdc_purchase.price - const priceWei = Number(USDC(priceCents / 100).value.toString()) return { usdc_purchase: { price: priceCents, @@ -248,9 +236,8 @@ export function getUSDCMetadata( }), splits: [ { - payout_wallet: userBank?.toString() ?? '', - percentage: 100, - amount: priceWei + user_id: userId, + percentage: 100 } ] } @@ -262,24 +249,21 @@ export function getUSDCMetadata( * Converts prices to WEI and adds splits for USDC purchasable content. */ export function addPremiumMetadata( - userBank: string, + userId: number, track: T ) { // download_conditions could be set separately from stream_conditions, so we check for them first if (isContentUSDCPurchaseGated(track.download_conditions)) { track.download_conditions = getUSDCMetadata( - userBank, + userId, track.download_conditions ) } if (isContentUSDCPurchaseGated(track.stream_conditions)) { - track.stream_conditions = getUSDCMetadata(userBank, track.stream_conditions) + track.stream_conditions = getUSDCMetadata(userId, track.stream_conditions) // If stream_conditions are set, download_conditions should always match - track.download_conditions = getUSDCMetadata( - userBank, - track.stream_conditions - ) + track.download_conditions = getUSDCMetadata(userId, track.stream_conditions) } return track diff --git a/packages/common/src/models/Track.ts b/packages/common/src/models/Track.ts index 069f4fc53cf..f617b4810b8 100644 --- a/packages/common/src/models/Track.ts +++ b/packages/common/src/models/Track.ts @@ -66,10 +66,10 @@ export type NftGatedConditions = { /** Single split in USDC purchase conditions (matches API extended_payment_split). */ export type PaymentSplit = { - user_id?: number + user_id: number percentage: number - payout_wallet: string - amount: number + payout_wallet?: string + amount?: number eth_wallet?: string } diff --git a/packages/common/src/schemas/upload/uploadFormSchema.ts b/packages/common/src/schemas/upload/uploadFormSchema.ts index 3d52f6cd64d..3537e9e4534 100644 --- a/packages/common/src/schemas/upload/uploadFormSchema.ts +++ b/packages/common/src/schemas/upload/uploadFormSchema.ts @@ -37,10 +37,10 @@ const TokenGatedConditionsSchema = z /** Same as API extended_payment_split (snake-cased) */ const PaymentSplitSchema = z.object({ - user_id: z.optional(z.number()), + user_id: z.number(), percentage: z.number().min(0).max(100), - payout_wallet: z.string(), - amount: z.number().nonnegative(), + payout_wallet: z.string().optional(), + amount: z.number().nonnegative().optional(), eth_wallet: z.optional(z.string()) }) diff --git a/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES b/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES index cee05b583c2..cfb055e06a1 100644 --- a/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES +++ b/packages/sdk/src/sdk/api/generated/default/.openapi-generator/FILES @@ -209,6 +209,7 @@ models/NftGate.ts models/Notification.ts models/Notifications.ts models/NotificationsResponse.ts +models/PaymentSplit.ts models/PinCommentRequestBody.ts models/Playlist.ts models/PlaylistAddedTimestamp.ts diff --git a/packages/sdk/src/sdk/api/generated/default/models/AccessGate.ts b/packages/sdk/src/sdk/api/generated/default/models/AccessGate.ts index 5f47f67fd71..022e3e2b0bf 100644 --- a/packages/sdk/src/sdk/api/generated/default/models/AccessGate.ts +++ b/packages/sdk/src/sdk/api/generated/default/models/AccessGate.ts @@ -20,13 +20,6 @@ import { FollowGateFromJSONTyped, FollowGateToJSON, } from './FollowGate'; -import { - NftGate, - instanceOfNftGate, - NftGateFromJSON, - NftGateFromJSONTyped, - NftGateToJSON, -} from './NftGate'; import { PurchaseGate, instanceOfPurchaseGate, @@ -54,7 +47,7 @@ import { * * @export */ -export type AccessGate = FollowGate | NftGate | PurchaseGate | TipGate | TokenGate; +export type AccessGate = FollowGate | PurchaseGate | TipGate | TokenGate; export function AccessGateFromJSON(json: any): AccessGate { return AccessGateFromJSONTyped(json, false); @@ -64,7 +57,7 @@ export function AccessGateFromJSONTyped(json: any, ignoreDiscriminator: boolean) if ((json === undefined) || (json === null)) { return json; } - return { ...FollowGateFromJSONTyped(json, true), ...NftGateFromJSONTyped(json, true), ...PurchaseGateFromJSONTyped(json, true), ...TipGateFromJSONTyped(json, true), ...TokenGateFromJSONTyped(json, true) }; + return { ...FollowGateFromJSONTyped(json, true), ...PurchaseGateFromJSONTyped(json, true), ...TipGateFromJSONTyped(json, true), ...TokenGateFromJSONTyped(json, true) }; } export function AccessGateToJSON(value?: AccessGate | null): any { @@ -78,9 +71,6 @@ export function AccessGateToJSON(value?: AccessGate | null): any { if (instanceOfFollowGate(value)) { return FollowGateToJSON(value as FollowGate); } - if (instanceOfNftGate(value)) { - return NftGateToJSON(value as NftGate); - } if (instanceOfPurchaseGate(value)) { return PurchaseGateToJSON(value as PurchaseGate); } diff --git a/packages/sdk/src/sdk/api/generated/default/models/PaymentSplit.ts b/packages/sdk/src/sdk/api/generated/default/models/PaymentSplit.ts new file mode 100644 index 00000000000..5fb3f174be9 --- /dev/null +++ b/packages/sdk/src/sdk/api/generated/default/models/PaymentSplit.ts @@ -0,0 +1,76 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * API + * Audius V1 API + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface PaymentSplit + */ +export interface PaymentSplit { + /** + * + * @type {number} + * @memberof PaymentSplit + */ + userId: number; + /** + * + * @type {number} + * @memberof PaymentSplit + */ + percentage: number; +} + +/** + * Check if a given object implements the PaymentSplit interface. + */ +export function instanceOfPaymentSplit(value: object): value is PaymentSplit { + let isInstance = true; + isInstance = isInstance && "userId" in value && value["userId"] !== undefined; + isInstance = isInstance && "percentage" in value && value["percentage"] !== undefined; + + return isInstance; +} + +export function PaymentSplitFromJSON(json: any): PaymentSplit { + return PaymentSplitFromJSONTyped(json, false); +} + +export function PaymentSplitFromJSONTyped(json: any, ignoreDiscriminator: boolean): PaymentSplit { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'userId': json['user_id'], + 'percentage': json['percentage'], + }; +} + +export function PaymentSplitToJSON(value?: PaymentSplit | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'user_id': value.userId, + 'percentage': value.percentage, + }; +} + diff --git a/packages/sdk/src/sdk/api/generated/default/models/UsdcGate.ts b/packages/sdk/src/sdk/api/generated/default/models/UsdcGate.ts index a259488e079..4333d7da359 100644 --- a/packages/sdk/src/sdk/api/generated/default/models/UsdcGate.ts +++ b/packages/sdk/src/sdk/api/generated/default/models/UsdcGate.ts @@ -14,6 +14,13 @@ */ import { exists, mapValues } from '../runtime'; +import type { PaymentSplit } from './PaymentSplit'; +import { + PaymentSplitFromJSON, + PaymentSplitFromJSONTyped, + PaymentSplitToJSON, +} from './PaymentSplit'; + /** * * @export @@ -21,17 +28,17 @@ import { exists, mapValues } from '../runtime'; */ export interface UsdcGate { /** - * - * @type {{ [key: string]: number; }} + * The price in USDC needed to unlock + * @type {number} * @memberof UsdcGate */ - splits: { [key: string]: number; }; + price: number; /** * - * @type {number} + * @type {Array} * @memberof UsdcGate */ - price: number; + splits: Array; } /** @@ -39,8 +46,8 @@ export interface UsdcGate { */ export function instanceOfUsdcGate(value: object): value is UsdcGate { let isInstance = true; - isInstance = isInstance && "splits" in value && value["splits"] !== undefined; isInstance = isInstance && "price" in value && value["price"] !== undefined; + isInstance = isInstance && "splits" in value && value["splits"] !== undefined; return isInstance; } @@ -55,8 +62,8 @@ export function UsdcGateFromJSONTyped(json: any, ignoreDiscriminator: boolean): } return { - 'splits': json['splits'], 'price': json['price'], + 'splits': ((json['splits'] as Array).map(PaymentSplitFromJSON)), }; } @@ -69,8 +76,8 @@ export function UsdcGateToJSON(value?: UsdcGate | null): any { } return { - 'splits': value.splits, 'price': value.price, + 'splits': ((value.splits as Array).map(PaymentSplitToJSON)), }; } diff --git a/packages/sdk/src/sdk/api/generated/default/models/index.ts b/packages/sdk/src/sdk/api/generated/default/models/index.ts index e8c1b3d3312..9b774e08134 100644 --- a/packages/sdk/src/sdk/api/generated/default/models/index.ts +++ b/packages/sdk/src/sdk/api/generated/default/models/index.ts @@ -188,6 +188,7 @@ export * from './NftGate'; export * from './Notification'; export * from './Notifications'; export * from './NotificationsResponse'; +export * from './PaymentSplit'; export * from './PinCommentRequestBody'; export * from './Playlist'; export * from './PlaylistAddedTimestamp'; diff --git a/packages/sdk/src/sdk/api/tracks/types.ts b/packages/sdk/src/sdk/api/tracks/types.ts index c29bacba0af..94dae51d026 100644 --- a/packages/sdk/src/sdk/api/tracks/types.ts +++ b/packages/sdk/src/sdk/api/tracks/types.ts @@ -84,10 +84,8 @@ export const USDCPurchaseConditions = z price: z.number().positive(), splits: z.array( z.object({ - userId: z.number().optional(), - percentage: z.number().min(0).max(100), - payoutWallet: z.string(), - amount: z.number().positive() + userId: z.number(), + percentage: z.number().min(0).max(100) }) ) }) @@ -103,6 +101,7 @@ export const UploadStemMetadataSchema = z.object({ export const UploadTrackMetadataSchema = z.object({ trackId: z.optional(HashId), + ownerId: z.optional(z.number()), aiAttributionUserId: z.optional(HashId), description: z.optional(z.string().max(MAX_DESCRIPTION_LENGTH).nullable()), fieldVisibility: z.optional( diff --git a/packages/web/src/common/store/upload/sagaHelpers.ts b/packages/web/src/common/store/upload/sagaHelpers.ts index d3d9721b848..e946ba4ecc4 100644 --- a/packages/web/src/common/store/upload/sagaHelpers.ts +++ b/packages/web/src/common/store/upload/sagaHelpers.ts @@ -6,12 +6,7 @@ import { isContentUSDCPurchaseGated, USDCPurchaseConditions } from '@audius/common/models' -import { - getOrCreateUSDCUserBank, - TrackForUpload, - TrackMetadataForUpload -} from '@audius/common/store' -import { USDC } from '@audius/fixed-decimal' +import { TrackForUpload, TrackMetadataForUpload } from '@audius/common/store' import { all, call, put } from 'typed-redux-saga' import { make } from 'common/store/analytics/actions' @@ -97,11 +92,7 @@ export function* recordGatedTracks( export function* getUSDCMetadata(stream_conditions: USDCPurchaseConditions) { const ownerAccount = yield* call(queryAccountUser) - const wallet = ownerAccount?.erc_wallet ?? ownerAccount?.wallet - const ownerUserbank = yield* call(getOrCreateUSDCUserBank, wallet) const priceCents = stream_conditions.usdc_purchase.price - const priceWei = Number(USDC(priceCents / 100).value.toString()) - const payoutWallet = ownerUserbank?.toString() ?? '' const conditionsWithMetadata: USDCPurchaseConditions = { usdc_purchase: { price: priceCents, @@ -110,9 +101,8 @@ export function* getUSDCMetadata(stream_conditions: USDCPurchaseConditions) { }), splits: [ { - payout_wallet: payoutWallet, - percentage: 100, - amount: priceWei + user_id: ownerAccount!.user_id!, + percentage: 100 } ] }