Skip to content

Commit

Permalink
ENG-5252 feat(portal): add raw graphql query to quests route for nft …
Browse files Browse the repository at this point in the history
…points (#998)

## Affected Packages

Apps

- [ ] data populator
- [x] portal
- [ ] template

Packages

- [ ] 1ui
- [ ] api
- [ ] graphql
- [ ] protocol
- [ ] sdk

Tools

- [ ] tools

## Overview

Swaps out the Phosphor and RPC calls used for NFT Relic points to use
the new GraphQL ponder endpoint.

## Screen Captures

If applicable, add screenshots or screen captures of your changes.

## Declaration

- [x] I hereby declare that I have abided by the rules and regulations
as outlined in the
[CONTRIBUTING.md](https://github.com/0xIntuition/intuition-ts/blob/main/CONTRIBUTING.md)
  • Loading branch information
Vitalsine85 authored Dec 26, 2024
1 parent 12816db commit 8d810a5
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 134 deletions.
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

0 comments on commit 8d810a5

Please sign in to comment.