Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/auto-follow-artist-coin-purchase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@audius/common": patch
"@audius/mobile": patch
"@audius/web": patch
---

Automatically follow an artist when a user successfully purchases their artist coin
82 changes: 82 additions & 0 deletions packages/common/src/api/tan-query/jupiter/useSwapCoins.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useDispatch } from 'react-redux'

import { coinFromSdk } from '~/adapters/coin'
import {
getUserCoinQueryKey,
getUserQueryKey,
Expand All @@ -12,10 +14,15 @@ import {
import { QUERY_KEYS } from '~/api/tan-query/queryKeys'
import type { QueryContextType } from '~/api/tan-query/utils/QueryContext'
import { Feature } from '~/models'
import { FollowSource } from '~/models/Analytics'
import type { User } from '~/models/User'
import { JupiterQuoteResult } from '~/services/Jupiter'
import { NON_ARTIST_COIN_MINTS } from '~/store/ui/shared/tokenConstants'

import { getArtistCoinQueryFn } from '../coins/useArtistCoin'
import { useTradeableCoins } from '../coins/useTradeableCoins'
import { useFollowUser } from '../users/useFollowUser'
import { entityCacheOptions } from '../utils/entityCacheOptions'

import { SwapOrchestrator } from './orchestrator'
import {
Expand Down Expand Up @@ -213,6 +220,70 @@ export const optimisticallyUpdateSwapBalances = (
})
}

/**
* Auto-follows the owning artist of a coin after a successful purchase.
* Skips if the output mint is not an artist coin, the user already follows
* the artist, or the coin's owner can't be resolved.
*/
const autoFollowArtistOnCoinPurchase = async ({
outputMint,
queryClient,
audiusSdk,
dispatch,
followUser,
reportToSentry
}: {
outputMint: string
queryClient: ReturnType<typeof useQueryClient>
audiusSdk: QueryContextType['audiusSdk']
dispatch: ReturnType<typeof useDispatch>
followUser: ReturnType<typeof useFollowUser>['mutate']
reportToSentry: QueryContextType['reportToSentry']
}) => {
if (!outputMint || NON_ARTIST_COIN_MINTS.includes(outputMint)) {
return
}

try {
const coin = await queryClient.fetchQuery({
queryKey: getArtistCoinQueryKey(outputMint),
queryFn: async () => {
const sdk = await audiusSdk()
const rawCoin = await getArtistCoinQueryFn(
outputMint,
queryClient,
sdk,
dispatch
)
return coinFromSdk(rawCoin)
},
...entityCacheOptions
})

if (!coin?.ownerId) {
return
}

// Skip if the current user already follows the artist
const artistUser = queryClient.getQueryData(getUserQueryKey(coin.ownerId))
if (artistUser?.does_current_user_follow) {
return
}

followUser({
followeeUserId: coin.ownerId,
source: FollowSource.ARTIST_COIN_PURCHASE
})
} catch (error) {
reportToSentry({
name: 'AutoFollowArtistOnCoinPurchaseError',
error: error as Error,
feature: Feature.TanQuery,
additionalInfo: { outputMint }
})
}
}

/**
* Hook for executing coin swaps using Jupiter.
* Swaps any supported SPL token (or SOL) for another.
Expand All @@ -223,6 +294,8 @@ export const useSwapCoins = () => {
useQueryContext()
const { data: user } = useCurrentAccountUser()
const { coins } = useTradeableCoins()
const dispatch = useDispatch()
const { mutate: followUser } = useFollowUser()

return useMutation<SwapTokensResult, Error, SwapTokensParams>({
mutationFn: async (params): Promise<SwapTokensResult> => {
Expand Down Expand Up @@ -304,6 +377,15 @@ export const useSwapCoins = () => {
},
onSuccess: (result, params) => {
optimisticallyUpdateSwapBalances(params, result, queryClient, user, env)
// Auto-follow the artist whose coin was just purchased
autoFollowArtistOnCoinPurchase({
outputMint: params.outputMint,
queryClient,
audiusSdk,
dispatch,
followUser,
reportToSentry
})
},
onMutate: () => {
return { status: SwapStatus.SENDING_TRANSACTION }
Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/models/Analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,8 @@ export enum FollowSource {
EMPTY_FEED = 'empty feed',
HOW_TO_UNLOCK_TRACK_PAGE = 'how to unlock track page',
HOW_TO_UNLOCK_MODAL = 'how to unlock modal',
SIGN_UP = 'sign up'
SIGN_UP = 'sign up',
ARTIST_COIN_PURCHASE = 'artist coin purchase'
}

type Share = {
Expand Down
Loading