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-5262 feat(portal): update protocol points from legacy api to graphql #1007

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions .github/workflows/deploy_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ jobs:
--build-arg PHOSPHOR_COLLECTION_ID=${{ secrets.PHOSPHOR_COLLECTION_ID }} \
--build-arg GTM_TRACKING_ID=${{ secrets.GTM_TRACKING_ID }} \
--build-arg RELIC_GRAPHQL_ENDPOINT=${{ secrets.RELIC_GRAPHQL_ENDPOINT }} \
--build-arg I7N_GRAPHQL_ENDPOINT=${{ secrets.I7N_GRAPHQL_ENDPOINT }} \
--build-arg FF_FULL_LOCKDOWN_ENABLED=false \
--build-arg FF_GENERIC_BANNER_ENABLED=true \
--build-arg FF_INCIDENT_BANNER_ENABLED=false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy_production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ jobs:
--build-arg PHOSPHOR_COLLECTION_ID=${{ secrets.PHOSPHOR_COLLECTION_ID }} \
--build-arg GTM_TRACKING_ID=${{ secrets.GTM_TRACKING_ID }} \
--build-arg RELIC_GRAPHQL_ENDPOINT=${{ secrets.RELIC_GRAPHQL_ENDPOINT }} \
--build-arg I7N_GRAPHQL_ENDPOINT=${{ secrets.I7N_GRAPHQL_ENDPOINT }} \
--build-arg FF_FULL_LOCKDOWN_ENABLED=false \
--build-arg FF_GENERIC_BANNER_ENABLED=false \
--build-arg FF_INCIDENT_BANNER_ENABLED=false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy_staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ jobs:
--build-arg PHOSPHOR_COLLECTION_ID=${{ secrets.PHOSPHOR_COLLECTION_ID }} \
--build-arg GTM_TRACKING_ID=${{ secrets.GTM_TRACKING_ID }} \
--build-arg RELIC_GRAPHQL_ENDPOINT=${{ secrets.RELIC_GRAPHQL_ENDPOINT }} \
--build-arg I7N_GRAPHQL_ENDPOINT=${{ secrets.I7N_GRAPHQL_ENDPOINT }} \
--build-arg FF_FULL_LOCKDOWN_ENABLED=false \
--build-arg FF_INCIDENT_BANNER_ENABLED=false \
--build-arg FF_GENERIC_BANNER_ENABLED=false
Expand Down
3 changes: 2 additions & 1 deletion apps/portal/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ 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_GRAPHQL_ENDPOINT=${RELIC_GRAPHQL_ENDPOINT}
ARG I7N_GRAPHQL_ENDPOINT=${I7N_GRAPHQL_ENDPOINT}

ENV ALCHEMY_MAINNET_API_KEY=${ALCHEMY_MAINNET_API_KEY}
ENV ALCHEMY_API_KEY=${ALCHEMY_API_KEY}
Expand Down Expand Up @@ -59,7 +60,7 @@ 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_GRAPHQL_ENDPOINT=${RELIC_GRAPHQL_ENDPOINT}

ENV I7N_GRAPHQL_ENDPOINT=${I7N_GRAPHQL_ENDPOINT}
WORKDIR /app

COPY package.json \
Expand Down
109 changes: 109 additions & 0 deletions apps/portal/app/lib/services/protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
interface GraphQLResponse<T> {
data?: T
errors?: Array<{ message: string }>
}

const GetFeeTransfersDocument = {
query: `
query GetFeeTransfers($address: String!, $cutoff_timestamp: numeric) {
before_cutoff: feeTranfers_aggregate(
where: { blockTimestamp: { _lte: $cutoff_timestamp }, senderId: { _eq: $address } }
) {
aggregate {
sum {
amount
}
}
}
after_cutoff: feeTranfers_aggregate(
where: { blockTimestamp: { _gt: $cutoff_timestamp }, senderId: { _eq: $address } }
) {
aggregate {
sum {
amount
}
}
}
}
`,
} as const

interface GetFeeTransfersQuery {
before_cutoff: {
aggregate: {
sum: {
amount: string
}
}
}
after_cutoff: {
aggregate: {
sum: {
amount: string
}
}
}
}

interface GetFeeTransfersQueryVariables {
address: string
cutoff_timestamp: number
}

async function fetchGraphQL<T, V>(
document: { query: string },
variables: V,
): Promise<GraphQLResponse<T>> {
const endpoint = process.env.I7N_GRAPHQL_ENDPOINT
if (!endpoint) {
throw new Error('I7N_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 async function fetchProtocolFees(address: string) {
const cutoffTimestamp = 1733356800

const feeData = await fetchGraphQL<
GetFeeTransfersQuery,
GetFeeTransfersQueryVariables
>(GetFeeTransfersDocument, {
address,
cutoff_timestamp: cutoffTimestamp,
})

const beforeCutoffAmount =
feeData?.data?.before_cutoff?.aggregate?.sum?.amount ?? '0'
const afterCutoffAmount =
feeData?.data?.after_cutoff?.aggregate?.sum?.amount ?? '0'

const beforeCutoffPoints =
(BigInt(beforeCutoffAmount) * BigInt(10000000)) / BigInt(1e18)
const afterCutoffPoints =
(BigInt(afterCutoffAmount) * BigInt(1000000)) / BigInt(1e18)
const totalPoints = beforeCutoffPoints + afterCutoffPoints

return {
beforeCutoffAmount,
afterCutoffAmount,
beforeCutoffPoints: beforeCutoffPoints.toString(),
afterCutoffPoints: afterCutoffPoints.toString(),
totalPoints: totalPoints.toString(),
}
}
18 changes: 13 additions & 5 deletions apps/portal/app/routes/app+/profile+/$wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ import { getSpecialPredicate } from '@lib/utils/app'
import logger from '@lib/utils/logger'
import {
calculatePercentageOfTvl,
calculatePointsFromFees,
formatBalance,
getAtomImage,
getAtomLabel,
Expand All @@ -73,6 +72,7 @@ import {
userIdentityRouteOptions,
} from 'app/consts'
import TwoPanelLayout from 'app/layouts/two-panel-layout'
import { fetchProtocolFees } from 'app/lib/services/protocol'
import { fetchRelicCounts } from 'app/lib/services/relic'
import { VaultDetailsType } from 'app/types/vault'
import { useAtom } from 'jotai'
Expand Down Expand Up @@ -137,7 +137,10 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
return logger('No user totals found')
}

const relicCounts = await fetchRelicCounts(wallet.toLowerCase())
const [relicCounts, protocolFees] = await Promise.all([
fetchRelicCounts(wallet.toLowerCase()),
fetchProtocolFees(wallet.toLowerCase()),
])

let vaultDetails: VaultDetailsType | null = null

Expand Down Expand Up @@ -206,6 +209,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
isPending,
relicHoldCount: relicCounts.holdCount,
relicMintCount: relicCounts.mintCount,
protocolFees,
})
}

Expand All @@ -222,6 +226,7 @@ export default function Profile() {
isPending,
relicMintCount,
relicHoldCount,
protocolFees,
} = useLiveLoader<{
wallet: string
userWallet: string
Expand All @@ -234,6 +239,11 @@ export default function Profile() {
isPending: boolean
relicMintCount: number
relicHoldCount: number
protocolFees: {
beforeCutoffPoints: string
afterCutoffPoints: string
totalPoints: string
}
}>(['attest', 'create'])
const navigate = useNavigate()

Expand All @@ -260,13 +270,11 @@ export default function Profile() {
const nftHoldPoints = relicHoldCount ? relicHoldCount * 250000 : 0
const totalNftPoints = nftMintPoints + nftHoldPoints

const feePoints = calculatePointsFromFees(userTotals.total_protocol_fee_paid)

const totalPoints =
userTotals.referral_points +
userTotals.quest_points +
totalNftPoints +
feePoints
parseInt(protocolFees.totalPoints)

const leftPanel = (
<div className="flex-col justify-start items-start gap-5 inline-flex max-lg:w-full">
Expand Down
18 changes: 13 additions & 5 deletions apps/portal/app/routes/app+/profile+/_index+/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import { getSpecialPredicate } from '@lib/utils/app'
import logger from '@lib/utils/logger'
import {
calculatePercentageOfTvl,
calculatePointsFromFees,
formatBalance,
getAtomImage,
getAtomLabel,
Expand All @@ -79,6 +78,7 @@ import {
userIdentityRouteOptions,
} from 'app/consts'
import TwoPanelLayout from 'app/layouts/two-panel-layout'
import { fetchProtocolFees } from 'app/lib/services/protocol'
import { fetchRelicCounts } from 'app/lib/services/relic'
import { VaultDetailsType } from 'app/types/vault'
import { useAtom } from 'jotai'
Expand All @@ -89,7 +89,10 @@ export async function loader({ request }: LoaderFunctionArgs) {
invariant(user.wallet?.address, 'User wallet not found')
const userWallet = user.wallet?.address

const relicCounts = await fetchRelicCounts(userWallet.toLowerCase())
const [relicCounts, protocolFees] = await Promise.all([
fetchRelicCounts(userWallet.toLowerCase()),
fetchProtocolFees(userWallet.toLowerCase()),
])

const userObject = await fetchWrapper(request, {
method: UsersService.getUserByWalletPublic,
Expand Down Expand Up @@ -194,6 +197,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
isPending,
relicHoldCount: relicCounts.holdCount,
relicMintCount: relicCounts.mintCount,
protocolFees,
})
}

Expand All @@ -209,6 +213,11 @@ export interface ProfileLoaderData {
isPending: boolean
relicMintCount: number
relicHoldCount: number
protocolFees: {
beforeCutoffPoints: string
afterCutoffPoints: string
totalPoints: string
}
}

export default function Profile() {
Expand All @@ -223,6 +232,7 @@ export default function Profile() {
isPending,
relicMintCount,
relicHoldCount,
protocolFees,
} = useLiveLoader<ProfileLoaderData>(['attest', 'create'])

const { user_assets, assets_sum } = vaultDetails ? vaultDetails : userIdentity
Expand Down Expand Up @@ -284,13 +294,11 @@ export default function Profile() {
const nftHoldPoints = relicHoldCount * 250000
const totalNftPoints = nftMintPoints + nftHoldPoints

const feePoints = calculatePointsFromFees(userTotals.total_protocol_fee_paid)

const totalPoints =
userTotals.referral_points +
userTotals.quest_points +
totalNftPoints +
feePoints
parseInt(protocolFees.totalPoints)

const leftPanel = (
<div className="flex-col justify-start items-start gap-5 inline-flex max-lg:w-full">
Expand Down
27 changes: 17 additions & 10 deletions apps/portal/app/routes/app+/quest+/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { PointsEarnedCard } from '@components/points-card/points-card'
import { QuestSetProgressCard } from '@components/quest/quest-set-progress-card'
import { ReferralCard } from '@components/referral-card/referral-card'
import RelicPointCard from '@components/relic-point-card/relic-point-card'
import { calculatePointsFromFees, invariant } from '@lib/utils/misc'
import { invariant } from '@lib/utils/misc'
import { LoaderFunctionArgs } from '@remix-run/node'
import { Await, useLoaderData } from '@remix-run/react'
import { fetchWrapper } from '@server/api'
Expand All @@ -31,14 +31,18 @@ import {
HEADER_BANNER_HELP_CENTER,
STANDARD_QUEST_SET,
} from 'app/consts'
import { fetchProtocolFees } from 'app/lib/services/protocol'
import { fetchRelicCounts } from 'app/lib/services/relic'
import { isAddress } from 'viem'

export async function loader({ request }: LoaderFunctionArgs) {
const userWallet = await requireUserWallet(request)
invariant(userWallet, 'Unauthorized')

const relicCounts = await fetchRelicCounts(userWallet.toLowerCase())
const [relicCounts, protocolFees] = await Promise.all([
fetchRelicCounts(userWallet.toLowerCase()),
fetchProtocolFees(userWallet.toLowerCase()),
])

const userProfile = await fetchWrapper(request, {
method: UsersService.getUserByWalletPublic,
Expand Down Expand Up @@ -76,12 +80,19 @@ export async function loader({ request }: LoaderFunctionArgs) {
inviteCodes: inviteCodes.invite_codes,
relicHoldCount: relicCounts.holdCount,
mintCount: relicCounts.mintCount,
protocolFees,
}
}

export default function Quests() {
const { userTotals, inviteCodes, mintCount, relicHoldCount, details } =
useLoaderData<typeof loader>()
const {
userTotals,
inviteCodes,
mintCount,
relicHoldCount,
protocolFees,
details,
} = useLoaderData<typeof loader>()

const nftMintPoints = mintCount * 2000000
const nftHoldPoints = relicHoldCount * 250000
Expand Down Expand Up @@ -131,9 +142,7 @@ export default function Quests() {
resolvedUserTotals.referral_points +
resolvedUserTotals.quest_points +
totalNftPoints +
calculatePointsFromFees(
resolvedUserTotals.total_protocol_fee_paid,
)
parseInt(protocolFees.totalPoints)
}
activities={[
{
Expand All @@ -142,9 +151,7 @@ export default function Quests() {
},
{
name: 'Protocol',
points: calculatePointsFromFees(
resolvedUserTotals.total_protocol_fee_paid,
),
points: parseInt(protocolFees.totalPoints),
},
{
name: 'NFT',
Expand Down
Loading
Loading