Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENG-5252 feat(portal): add raw graphql query to quests route for nft points #998

Merged
merged 2 commits into from
Dec 26, 2024
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
3 changes: 2 additions & 1 deletion .github/workflows/deploy_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ jobs:
--build-arg GTM_TRACKING_ID=${{ secrets.GTM_TRACKING_ID }} \
--build-arg FF_FULL_LOCKDOWN_ENABLED=false \
--build-arg FF_GENERIC_BANNER_ENABLED=true \
--build-arg FF_INCIDENT_BANNER_ENABLED=false
--build-arg FF_INCIDENT_BANNER_ENABLED=false \
--build-arg RELIC_API_URL=${{ secrets.RELIC_API_URL }}
docker tag portal ${{ env.ECR_IMAGE }}
docker push ${{ env.ECR_IMAGE }}
rm privy_verification_key.pem
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/deploy_production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ jobs:
--build-arg GTM_TRACKING_ID=${{ secrets.GTM_TRACKING_ID }} \
--build-arg FF_FULL_LOCKDOWN_ENABLED=false \
--build-arg FF_GENERIC_BANNER_ENABLED=false \
--build-arg FF_INCIDENT_BANNER_ENABLED=false
--build-arg FF_INCIDENT_BANNER_ENABLED=false \
--build-arg RELIC_API_URL=${{ secrets.RELIC_API_URL }}
docker tag portal ${{ env.ECR_IMAGE }}
docker push ${{ env.ECR_IMAGE }}
rm privy_verification_key.pem
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/deploy_staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ jobs:
--build-arg GTM_TRACKING_ID=${{ secrets.GTM_TRACKING_ID }} \
--build-arg FF_FULL_LOCKDOWN_ENABLED=false \
--build-arg FF_INCIDENT_BANNER_ENABLED=false \
--build-arg FF_GENERIC_BANNER_ENABLED=false
--build-arg FF_GENERIC_BANNER_ENABLED=false \
--build-arg RELIC_API_URL=${{ secrets.RELIC_API_URL }}
docker tag portal ${{ env.ECR_IMAGE }}
docker push ${{ env.ECR_IMAGE }}
rm privy_verification_key.pem
Expand Down
3 changes: 2 additions & 1 deletion apps/portal/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ARG FF_FULL_LOCKDOWN_ENABLED=${FF_FULL_LOCKDOWN_ENABLED}
ARG FF_INCIDENT_BANNER_ENABLED=${FF_INCIDENT_BANNER_ENABLED}
ARG FF_GENERIC_BANNER_ENABLED=${FF_GENERIC_BANNER_ENABLED}
ARG VITE_DEPLOY_ENV=${VITE_DEPLOY_ENV}
ARG RELIC_API_URL=${RELIC_API_URL}

ENV ALCHEMY_MAINNET_API_KEY=${ALCHEMY_MAINNET_API_KEY}
ENV ALCHEMY_API_KEY=${ALCHEMY_API_KEY}
Expand Down Expand Up @@ -57,7 +58,7 @@ ENV FF_FULL_LOCKDOWN_ENABLED=${FF_FULL_LOCKDOWN_ENABLED}
ENV FF_INCIDENT_BANNER_ENABLED=${FF_INCIDENT_BANNER_ENABLED}
ENV FF_GENERIC_BANNER_ENABLED=${FF_GENERIC_BANNER_ENABLED}
ENV VITE_DEPLOY_ENV=${VITE_DEPLOY_ENV}

ENV RELIC_API_URL=${RELIC_API_URL}
WORKDIR /app

COPY package.json \
Expand Down
115 changes: 115 additions & 0 deletions apps/portal/app/lib/hooks/useRelicCounts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { useQuery } from '@tanstack/react-query'

interface GraphQLResponse<T> {
data?: T
errors?: Array<{ message: string }>
}

const GetMintCountDocument = {
query: `
query GetMintCountUntilDate($address: String!, $cutoff_timestamp: Int!) {
voucherRedeemedEvents(
where: { redeemer: $address, timestamp_lte: $cutoff_timestamp }
) {
totalCount
}
}
`,
} as const

interface GetMintCountQuery {
voucherRedeemedEvents: {
totalCount: number
}
}

const GetRelicHoldingsDocument = {
query: `
query GetRelicHoldings($address: String!) {
account(address: $address) {
tokens {
totalCount
}
voucherRedeemedEvents {
totalCount
}
}
}
`,
} as const

interface GetRelicHoldingsQuery {
account: {
tokens: {
totalCount: number
}
voucherRedeemedEvents: {
totalCount: number
}
}
}

async function fetchGraphQL<T, V>(
document: { query: string },
variables: V,
): Promise<GraphQLResponse<T>> {
const endpoint = process.env.RELIC_GRAPHQL_ENDPOINT
if (!endpoint) {
throw new Error('RELIC_GRAPHQL_ENDPOINT not configured')
}

const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: document.query,
variables,
}),
})

if (!response.ok) {
throw new Error(`GraphQL request failed: ${response.statusText}`)
}

return response.json()
}

export function useRelicCounts(address: string) {
const cutoffTimestamp = 1735516799

const { data: mintCountData } = useQuery({
queryKey: ['relicMintCount', address, cutoffTimestamp],
queryFn: () =>
fetchGraphQL<
GetMintCountQuery,
{ address: string; cutoff_timestamp: number }
>(GetMintCountDocument, {
address,
cutoff_timestamp: cutoffTimestamp,
}),
})

const { data: holdingsData } = useQuery({
queryKey: ['relicHoldCount', address],
queryFn: () =>
fetchGraphQL<GetRelicHoldingsQuery, { address: string }>(
GetRelicHoldingsDocument,
{
address,
},
),
})

const mintCount = mintCountData?.data?.voucherRedeemedEvents?.totalCount ?? 0
const holdCount = holdingsData?.data?.account?.tokens?.totalCount ?? 0

return {
mintCount,
holdCount,
nftMintPoints: mintCount * 2000000,
nftHoldPoints: holdCount * 250000,
totalNftPoints: mintCount * 2000000 + holdCount * 250000,
}
}
25 changes: 2 additions & 23 deletions apps/portal/app/routes/app+/profile+/$wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ import ShareModal from '@components/share-modal'
import StakeModal from '@components/stake/stake-modal'
import TagsModal from '@components/tags/tags-modal'
import { useLiveLoader } from '@lib/hooks/useLiveLoader'
import { useRelicCounts } from '@lib/hooks/useRelicCounts'
import { getIdentityOrPending } from '@lib/services/identities'
import { getPurchaseIntentsByAddress } from '@lib/services/phosphor'
import { getTags } from '@lib/services/tags'
import {
followModalAtom,
Expand All @@ -65,7 +65,6 @@ import { Outlet, useNavigate } from '@remix-run/react'
import { fetchWrapper } from '@server/api'
import { requireUserWallet } from '@server/auth'
import { getVaultDetails } from '@server/multivault'
import { getRelicCount } from '@server/relics'
import {
BLOCK_EXPLORER_URL,
CURRENT_ENV,
Expand Down Expand Up @@ -138,16 +137,6 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
return logger('No user totals found')
}

// TODO: Remove this relic hold/mint count and points calculation when it is stored in BE.
const relicHoldCount = await getRelicCount(wallet as `0x${string}`)

const userCompletedMints = await getPurchaseIntentsByAddress(
wallet,
'CONFIRMED',
)

const relicMintCount = userCompletedMints.data?.total_results

let vaultDetails: VaultDetailsType | null = null

if (!!userIdentity && userIdentity.vault_id) {
Expand Down Expand Up @@ -213,8 +202,6 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
followVaultDetails,
vaultDetails,
isPending,
relicHoldCount: relicHoldCount.toString(),
relicMintCount,
})
}

Expand All @@ -229,8 +216,6 @@ export default function Profile() {
followVaultDetails,
vaultDetails,
isPending,
relicMintCount,
relicHoldCount,
} = useLiveLoader<{
wallet: string
userWallet: string
Expand All @@ -241,12 +226,11 @@ export default function Profile() {
followVaultDetails: VaultDetailsType
vaultDetails: VaultDetailsType
isPending: boolean
relicMintCount: number
relicHoldCount: string
}>(['attest', 'create'])
const navigate = useNavigate()

const { user_assets, assets_sum } = vaultDetails ? vaultDetails : userIdentity
const { totalNftPoints } = useRelicCounts(wallet)

const [stakeModalActive, setStakeModalActive] = useAtom(stakeModalAtom)
const [tagsModalActive, setTagsModalActive] = useAtom(tagsModalAtom)
Expand All @@ -265,11 +249,6 @@ export default function Profile() {
}
}, [saveListModalActive])

// TODO: Remove this relic hold/mint count and points calculation when it is stored in BE.
const nftMintPoints = relicMintCount ? relicMintCount * 2000000 : 0
const nftHoldPoints = relicHoldCount ? +relicHoldCount * 250000 : 0
const totalNftPoints = nftMintPoints + nftHoldPoints

const feePoints = calculatePointsFromFees(userTotals.total_protocol_fee_paid)

const totalPoints =
Expand Down
27 changes: 3 additions & 24 deletions apps/portal/app/routes/app+/profile+/_index+/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import { SegmentedNav } from '@components/segmented-nav'
import StakeModal from '@components/stake/stake-modal'
import TagsModal from '@components/tags/tags-modal'
import { useLiveLoader } from '@lib/hooks/useLiveLoader'
import { useRelicCounts } from '@lib/hooks/useRelicCounts'
import { getIdentityOrPending } from '@lib/services/identities'
import { getPurchaseIntentsByAddress } from '@lib/services/phosphor'
import { getTags } from '@lib/services/tags'
import {
editProfileModalAtom,
Expand Down Expand Up @@ -72,7 +72,6 @@ import {
import { fetchWrapper } from '@server/api'
import { requireUser } from '@server/auth'
import { getVaultDetails } from '@server/multivault'
import { getRelicCount } from '@server/relics'
import {
BLOCK_EXPLORER_URL,
CURRENT_ENV,
Expand All @@ -90,16 +89,6 @@ export async function loader({ request }: LoaderFunctionArgs) {
invariant(user.wallet?.address, 'User wallet not found')
const userWallet = user.wallet?.address

// TODO: Remove this relic hold/mint count and points calculation when it is stored in BE.
const relicHoldCount = await getRelicCount(userWallet as `0x${string}`)

const userCompletedMints = await getPurchaseIntentsByAddress(
userWallet,
'CONFIRMED',
)

const relicMintCount = userCompletedMints.data?.total_results

const userObject = await fetchWrapper(request, {
method: UsersService.getUserByWalletPublic,
args: {
Expand Down Expand Up @@ -201,8 +190,6 @@ export async function loader({ request }: LoaderFunctionArgs) {
vaultDetails,
followClaim,
isPending,
relicHoldCount: relicHoldCount.toString(),
relicMintCount,
})
}

Expand All @@ -216,8 +203,6 @@ export interface ProfileLoaderData {
vaultDetails: VaultDetailsType
followClaim: ClaimPresenter
isPending: boolean
relicMintCount: number
relicHoldCount: string
}

export default function Profile() {
Expand All @@ -230,10 +215,10 @@ export default function Profile() {
userTotals,
vaultDetails,
isPending,
relicMintCount,
relicHoldCount,
} = useLiveLoader<ProfileLoaderData>(['attest', 'create'])

const { totalNftPoints } = useRelicCounts(userWallet)

const { user_assets, assets_sum } = vaultDetails ? vaultDetails : userIdentity

const [userObject, setUserObject] = useState<
Expand Down Expand Up @@ -288,11 +273,6 @@ export default function Profile() {
return null
}

// TODO: Remove this relic hold/mint count and points calculation when it is stored in BE.
const nftMintPoints = relicMintCount ? relicMintCount * 2000000 : 0
const nftHoldPoints = relicHoldCount ? +relicHoldCount * 250000 : 0
const totalNftPoints = nftMintPoints + nftHoldPoints

const feePoints = calculatePointsFromFees(userTotals.total_protocol_fee_paid)

const totalPoints =
Expand All @@ -312,7 +292,6 @@ export default function Profile() {
stats={{
numberOfFollowers: userTotals.follower_count,
numberOfFollowing: userTotals.followed_count,
// TODO: Remove this relic hold/mint count and points calculation when it is stored in BE.
points: totalPoints,
}}
bio={userObject.description ?? ''}
Expand Down
Loading
Loading