From 1a30331db1b90b019fe3271033a6df027132ee27 Mon Sep 17 00:00:00 2001 From: Nikita Polyakov <53777036+Nikita-Polyakov@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:12:45 +0300 Subject: [PATCH] [Point System] add support for versions (#1593) * point systems query * update v2 component --- src/indexer/queries/pointSystem.ts | 133 +++++++++++++++++++++++++---- src/types/pointSystem.ts | 14 ++- src/utils/index.ts | 4 +- src/utils/pointSystem.ts | 8 ++ src/views/PointSystemV2.vue | 76 ++++++++++------- 5 files changed, 183 insertions(+), 52 deletions(-) diff --git a/src/indexer/queries/pointSystem.ts b/src/indexer/queries/pointSystem.ts index d52acf3d1..cbe009235 100644 --- a/src/indexer/queries/pointSystem.ts +++ b/src/indexer/queries/pointSystem.ts @@ -3,6 +3,8 @@ import { getCurrentIndexer, WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web' import { SubqueryIndexer, SubsquidIndexer } from '@soramitsu/soraneo-wallet-web/lib/services/indexer'; import { gql } from '@urql/core'; +import { AccountPointSystems, AccountPointsVersioned, AccountPointsCalculation } from '@/types/pointSystem'; + import type { QueryData, ConnectionQueryResponse, @@ -261,6 +263,21 @@ type AccountMetaEntity = { deposit: AccountMetaDeposit; }; +type AccountPointSystemEntity = { + id: string; + accountId: string; + version: number; + startedAtBlock: number; + // points + xorFees: AccountMetaAssetVolume; + xorBurned: AccountMetaAssetVolume; + xorStakingValRewards: AccountMetaAssetVolume; + orderBook: AccountMetaEventCounter; + vault: AccountMetaEventCounter; + governance: AccountMetaGovernance; + deposit: AccountMetaDeposit; +}; + const SubqueryAccountMetaQuery = gql>` query AccountMetaQuery($id: String = "") { data: accountMeta(id: $id) { @@ -277,6 +294,32 @@ const SubqueryAccountMetaQuery = gql>` } `; +const SubqueryAccountPointSystemsQuery = gql>` + query AccountPointSystemsQuery($id: String = "", $after: Cursor) { + data: accountPointSystems(orderBy: ID_ASC, after: $after, filter: { accountId: { equalTo: $id } }) { + pageInfo { + hasNextPage + endCursor + } + edges { + node { + id + accountId + version + startedAtBlock + xorFees + xorBurned + xorStakingValRewards + orderBook + vault + governance + deposit + } + } + } + } +`; + const parseVolume = (data: AccountMetaAssetVolume | AccountMetaGovernance) => { return { amount: new FPNumber(data.amount), @@ -292,24 +335,10 @@ const parseCounter = (data: AccountMetaEventCounter) => { }; }; -const parseAccountMeta = (item: QueryData) => { - const { - createdAtTimestamp, - createdAtBlock, - xorFees, - xorBurned, - xorStakingValRewards, - orderBook, - vault, - governance, - deposit, - } = item.data; +const parseAccountPoints = (item: AccountMetaEntity | AccountPointSystemEntity): AccountPointsCalculation => { + const { xorFees, xorBurned, xorStakingValRewards, orderBook, vault, governance, deposit } = item; return { - createdAt: { - block: Number(createdAtBlock), - timestamp: Number(createdAtTimestamp) * 1000, - }, fees: parseVolume(xorFees), burned: parseVolume(xorBurned), staking: parseVolume(xorStakingValRewards), @@ -326,7 +355,36 @@ const parseAccountMeta = (item: QueryData) => { }; }; -export async function fetchAccountMeta(accountAddress: string) { +const parseAccountMeta = (item: AccountMetaEntity): AccountPointSystems => { + const { createdAtTimestamp, createdAtBlock } = item; + const startedAtBlock = Number(createdAtBlock); + + return { + createdAt: { + block: startedAtBlock, + timestamp: Number(createdAtTimestamp) * 1000, + }, + points: [ + { + version: 1, + startedAtBlock, + ...parseAccountPoints(item), + }, + ], + }; +}; + +const parseAccountPointSystem = (item: AccountPointSystemEntity): AccountPointsVersioned => { + const { version, startedAtBlock } = item; + + return { + version, + startedAtBlock, + ...parseAccountPoints(item), + }; +}; + +export async function fetchAccountMeta(accountAddress: string): Promise { const indexer = getCurrentIndexer(); const variables = { id: accountAddress }; @@ -334,13 +392,52 @@ export async function fetchAccountMeta(accountAddress: string) { if (indexer.type === IndexerType.SUBQUERY) { const subqueryIndexer = indexer as SubqueryIndexer; const response = await subqueryIndexer.services.explorer.request(SubqueryAccountMetaQuery, variables); + + if (!response) return null; + + return parseAccountMeta(response.data); + } + + return null; + } catch (error) { + console.error(error); + return null; + } +} + +export async function fetchAccountPointSystems(accountAddress: string): Promise { + const indexer = getCurrentIndexer(); + const variables = { id: accountAddress }; + + try { + if (indexer.type === IndexerType.SUBQUERY) { + const subqueryIndexer = indexer as SubqueryIndexer; + const response = await subqueryIndexer.services.explorer.fetchAllEntities( + SubqueryAccountPointSystemsQuery, + variables, + parseAccountPointSystem + ); + if (!response) return null; - return parseAccountMeta(response); + return response; } + return null; } catch (error) { console.error(error); return null; } } + +export async function fetchAccountPoints(accountAddress: string): Promise { + const meta = await fetchAccountMeta(accountAddress); + const points = await fetchAccountPointSystems(accountAddress); + + if (!meta) return null; + + return { + createdAt: meta.createdAt, + points: Array.isArray(points) ? points : meta.points, + }; +} diff --git a/src/types/pointSystem.ts b/src/types/pointSystem.ts index 0815ca51e..637a11f17 100644 --- a/src/types/pointSystem.ts +++ b/src/types/pointSystem.ts @@ -79,5 +79,17 @@ export interface AccountPointsCalculation { incomingUSD: FPNumber; outgoingUSD: FPNumber; }; - createdAt: { timestamp: number; block: number }; +} + +export interface AccountPointsVersioned extends AccountPointsCalculation { + version: number; + startedAtBlock: number; +} + +export interface AccountPointSystems { + createdAt: { + timestamp: number; + block: number; + }; + points: AccountPointsVersioned[]; } diff --git a/src/utils/index.ts b/src/utils/index.ts index 1952dd2f7..c7f61fea4 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -357,8 +357,8 @@ export const formatAmountWithSuffix = (value: FPNumber, precision = 2): AmountWi }; }; -export const convertFPNumberToNumber = (fpValue: FPNumber, precision = 2): number => { - return parseFloat(fpValue.toFixed(precision)); +export const convertFPNumberToNumber = (fpValue: Nullable, precision = 2): number => { + return parseFloat((fpValue ?? FPNumber.ZERO).toFixed(precision)); }; export const formatDecimalPlaces = (value: FPNumber | number, asPercent = false): string => { diff --git a/src/utils/pointSystem.ts b/src/utils/pointSystem.ts index 313e4988e..3c4fbe401 100644 --- a/src/utils/pointSystem.ts +++ b/src/utils/pointSystem.ts @@ -41,6 +41,14 @@ class PointsService { }; } + public getEraCoefficient(era: number): number { + if (era === 1) { + return 0.5; + } + + return 1; + } + public calculateCategoryPoints(categoryValues: CategoryValues): { [key: string]: CalculateCategoryPointResult } { const results: { [key: string]: CalculateCategoryPointResult } = {}; const firstTxAccountResult: { [key: string]: CalculateCategoryPointResult } = {}; diff --git a/src/views/PointSystemV2.vue b/src/views/PointSystemV2.vue index 2fe7da991..d2855f826 100644 --- a/src/views/PointSystemV2.vue +++ b/src/views/PointSystemV2.vue @@ -99,7 +99,7 @@ import { fetchAccountMeta } from '@/indexer/queries/pointSystem'; import type { ReferrerRewards } from '@/indexer/queries/referrals'; import { lazyComponent } from '@/router'; import { action, getter, state } from '@/store/decorators'; -import { AccountPointsCalculation, CalculateCategoryPointResult, CategoryPoints } from '@/types/pointSystem'; +import { AccountPointSystems, CalculateCategoryPointResult, CategoryPoints } from '@/types/pointSystem'; import { convertFPNumberToNumber } from '@/utils'; import { pointsService } from '@/utils/pointSystem'; @@ -124,7 +124,6 @@ export default class PointSystemV2 extends Mixins( readonly LogoSize = WALLET_CONSTS.LogoSize; @state.referrals.referralRewards private referralRewards!: Nullable; - @state.wallet.settings.blockNumber private blockNumber!: number; @state.wallet.account.accountAssets private accountAssets!: Array; @state.pool.accountLiquidity private accountLiquidity!: Array; @@ -179,41 +178,57 @@ export default class PointSystemV2 extends Mixins( return fiatBalanceFloat; } - getPointsForCategories(accountDataForPointsCalculation: AccountPointsCalculation): CategoryPoints { + private getPointsForCategories(pointSystems: AccountPointSystems): CategoryPoints { + const firstTxAccount = pointSystems.createdAt.timestamp ?? 0; + const liquidityProvision = this.getTotalLiquidityFiatValue(); - const VXORHoldings = this.getCurrentFiatBalanceForToken(VXOR.symbol); - const referralRewards = convertFPNumberToNumber(this.referralRewards?.rewards ?? this.Zero); - const depositVolumeBridges = - convertFPNumberToNumber(accountDataForPointsCalculation?.bridge.incomingUSD ?? this.Zero) + - convertFPNumberToNumber(accountDataForPointsCalculation?.bridge.outgoingUSD ?? this.Zero); - const networkFeeSpent = convertFPNumberToNumber(accountDataForPointsCalculation?.fees.amountUSD ?? this.Zero); - const XORBurned = convertFPNumberToNumber(accountDataForPointsCalculation?.burned.amountUSD ?? this.Zero); const XORHoldings = this.getCurrentFiatBalanceForToken(XOR.symbol); - const kensetsuVolumeRepaid = convertFPNumberToNumber( - accountDataForPointsCalculation?.kensetsu.amountUSD ?? this.Zero - ); + const VXORHoldings = this.getCurrentFiatBalanceForToken(VXOR.symbol); const KUSDHoldings = this.getCurrentFiatBalanceForToken(KUSD.symbol); - const orderbookVolume = convertFPNumberToNumber(accountDataForPointsCalculation?.orderBook.amountUSD ?? this.Zero); - const governanceLockedXOR = convertFPNumberToNumber( - accountDataForPointsCalculation?.governance.amountUSD ?? this.Zero + const referralRewards = convertFPNumberToNumber(this.referralRewards?.rewards); + + const points = pointSystems.points.reduce( + (acc, era) => { + const eraCoefficient = pointsService.getEraCoefficient(era.version); + + const depositVolumeBridges = + convertFPNumberToNumber(era.bridge.incomingUSD) + convertFPNumberToNumber(era.bridge.outgoingUSD); + const networkFeeSpent = convertFPNumberToNumber(era.fees.amountUSD); + const XORBurned = convertFPNumberToNumber(era.burned.amountUSD); + const kensetsuVolumeRepaid = convertFPNumberToNumber(era.kensetsu.amountUSD); + const orderbookVolume = convertFPNumberToNumber(era.orderBook.amountUSD); + const governanceLockedXOR = convertFPNumberToNumber(era.governance.amountUSD); + const nativeXorStaking = convertFPNumberToNumber(era.staking.amountUSD); + + acc.depositVolumeBridges += depositVolumeBridges * eraCoefficient; + acc.networkFeeSpent += networkFeeSpent * eraCoefficient; + acc.XORBurned += XORBurned * eraCoefficient; + acc.kensetsuVolumeRepaid += kensetsuVolumeRepaid * eraCoefficient; + acc.orderbookVolume += orderbookVolume * eraCoefficient; + acc.governanceLockedXOR += governanceLockedXOR * eraCoefficient; + acc.nativeXorStaking += nativeXorStaking * eraCoefficient; + + return acc; + }, + { + depositVolumeBridges: 0, + networkFeeSpent: 0, + XORBurned: 0, + kensetsuVolumeRepaid: 0, + orderbookVolume: 0, + governanceLockedXOR: 0, + nativeXorStaking: 0, + } ); - const nativeXorStaking = convertFPNumberToNumber(accountDataForPointsCalculation?.staking.amountUSD ?? this.Zero); - const firstTxAccount = accountDataForPointsCalculation?.createdAt.timestamp ?? 0; const pointsForCategories = { + firstTxAccount, liquidityProvision, - VXORHoldings, - referralRewards, - depositVolumeBridges, - networkFeeSpent, - XORBurned, XORHoldings, - governanceLockedXOR, - kensetsuVolumeRepaid, - orderbookVolume, - nativeXorStaking, + VXORHoldings, KUSDHoldings, - firstTxAccount, + referralRewards, + ...points, }; return pointsForCategories; } @@ -222,11 +237,10 @@ export default class PointSystemV2 extends Mixins( if (this.isLoggedIn) { // Referral rewards await this.getAccountReferralRewards(); - const account = this.account.address; - const end = this.blockNumber; - if (!(account && end)) return; + const account = this.account.address; const accountMeta = await fetchAccountMeta(account); + if (accountMeta) { this.pointsForCards = pointsService.calculateCategoryPoints(this.getPointsForCategories(accountMeta)); }