From 482875acbe0438d864c827422e50dfbd192bbc7d Mon Sep 17 00:00:00 2001 From: Dawid Sowa Date: Tue, 1 Oct 2024 13:12:47 +0200 Subject: [PATCH 1/7] refactor: use native_resource_details for summary creation part 1 --- apps/dashboard/src/lib/summary/summary.ts | 79 +++++++++++-------- .../resource/[resource]/+layout.ts | 5 +- .../src/routes/(search-pages)/utils.ts | 5 +- .../utils/entities/resource/fungible/index.ts | 3 +- .../src/api/utils/entities/resource/index.ts | 3 +- .../non-fungible/claim-nft-collection.ts | 11 +-- .../entities/resource/non-fungible/index.ts | 19 +++-- .../package-owner-badge-collection.ts | 32 ++------ packages/ui/src/api/utils/staking.ts | 45 +++++++---- 9 files changed, 109 insertions(+), 93 deletions(-) diff --git a/apps/dashboard/src/lib/summary/summary.ts b/apps/dashboard/src/lib/summary/summary.ts index 798208dc8..962d36c06 100644 --- a/apps/dashboard/src/lib/summary/summary.ts +++ b/apps/dashboard/src/lib/summary/summary.ts @@ -58,9 +58,17 @@ const getEntityTypes = async ( const getEntityDetailsFn = (stateVersion: number) => (addresses: string[]) => pipe( () => - callApi('getEntityDetailsVaultAggregated', addresses, undefined, { - state_version: stateVersion - }), + callApi( + 'getEntityDetailsVaultAggregated', + addresses, + { + dappTwoWayLinks: true, + nativeResourceDetails: true + }, + { + state_version: stateVersion + } + ), handleGatewayResult((_) => ERROR_MSG) )() @@ -87,7 +95,10 @@ const getPoolUnitData = callApi( 'getEntityDetailsVaultAggregated', poolAddresses as string[], - undefined, + { + dappTwoWayLinks: true, + nativeResourceDetails: true + }, { state_version: stateVersion } ), handleGatewayResult((_) => ERROR_MSG) @@ -102,7 +113,10 @@ const getPoolUnitData = pools.flatMap( (pool) => pool.metadata.expected.pool_resources.typed.values ), - undefined, + { + dappTwoWayLinks: true, + nativeResourceDetails: true + }, { state_version: stateVersion } ), handleGatewayResult((_) => ERROR_MSG) @@ -165,29 +179,31 @@ export const produceSummary = ( () => callApi( 'getEntityDetailsVaultAggregated', - acc.resources.fungible.map((token) => token.address) + acc.resources.fungible.map((token) => token.address), + { + dappTwoWayLinks: true, + nativeResourceDetails: true + } ), handleGatewayResult((_) => ERROR_MSG), andThen(map(transformFungibleResource)) )() ) - const nonFungibleResources = Promise.all([account, validatorResponse]).then( - ([acc, { validators }]) => - pipe( - () => - callApi( - 'getEntityDetailsVaultAggregated', - acc.resources.nonFungible.map((token) => token.address) - ), - handleGatewayResult((_) => ERROR_MSG), - andThen( - pipe( - map((entity) => transformNonFungibleResource(entity, validators)), - (x) => Promise.all(x) - ) - ) - )() + const nonFungibleResources = account.then((acc) => + pipe( + () => + callApi( + 'getEntityDetailsVaultAggregated', + acc.resources.nonFungible.map((token) => token.address), + { + dappTwoWayLinks: true, + nativeResourceDetails: true + } + ), + handleGatewayResult((_) => ERROR_MSG), + andThen(map(transformNonFungibleResource)) + )() ) const nfts = Promise.all([account, nonFungibleResources]).then( @@ -228,16 +244,15 @@ export const produceSummary = ( fungibleResources, nfts ]) - .then( - ([response, accountData, fungibles, nonFungibles]) => - [ - getStakedInfo(response.validators, fungibles)(accountData), - getUnstakeAndClaimInfo(response.validators)(nonFungibles)( - accountData, - response.ledger_state.epoch - ) - ] as const - ) + .then(([response, accountData, fungibles, nonFungibles]) => { + return [ + getStakedInfo(response.validators, fungibles)(accountData), + getUnstakeAndClaimInfo(response.validators)(nonFungibles)( + accountData, + response.ledger_state.epoch + ) + ] as const + }) .then(([staked, unstakeAndClaim]) => { let totalStaked = BigNumber(0) let totalUnstaking = BigNumber(0) diff --git a/apps/dashboard/src/routes/(search-pages)/resource/[resource]/+layout.ts b/apps/dashboard/src/routes/(search-pages)/resource/[resource]/+layout.ts index 70df5147a..30f7d872a 100644 --- a/apps/dashboard/src/routes/(search-pages)/resource/[resource]/+layout.ts +++ b/apps/dashboard/src/routes/(search-pages)/resource/[resource]/+layout.ts @@ -33,7 +33,10 @@ const getEntityDetails = (stateVersion?: number) => (addresses: string[]) => callApi( 'getEntityDetailsVaultAggregated', addresses, - undefined, + { + dappTwoWayLinks: true, + nativeResourceDetails: true + }, stateVersion ? { state_version: stateVersion diff --git a/apps/dashboard/src/routes/(search-pages)/utils.ts b/apps/dashboard/src/routes/(search-pages)/utils.ts index d9923d1cf..0b718d0ce 100644 --- a/apps/dashboard/src/routes/(search-pages)/utils.ts +++ b/apps/dashboard/src/routes/(search-pages)/utils.ts @@ -40,7 +40,10 @@ export const getLookupEntity = ( callApi( 'getEntityDetailsVaultAggregated', [address], - options, + options || { + dappTwoWayLinks: true, + nativeResourceDetails: true, + }, ledgerState ).andThen((entities) => entities.length === 0 diff --git a/packages/ui/src/api/utils/entities/resource/fungible/index.ts b/packages/ui/src/api/utils/entities/resource/fungible/index.ts index 411fa9772..1bc4c260c 100644 --- a/packages/ui/src/api/utils/entities/resource/fungible/index.ts +++ b/packages/ui/src/api/utils/entities/resource/fungible/index.ts @@ -20,6 +20,7 @@ export const transformFungibleResource = ( resourceType: 'fungible', divisibility: ( entity.details as StateEntityDetailsResponseFungibleResourceDetails - ).divisibility + ).divisibility, + nativeResourceDetails: entity.details.native_resource_details } as const) )() diff --git a/packages/ui/src/api/utils/entities/resource/index.ts b/packages/ui/src/api/utils/entities/resource/index.ts index b9b589799..b839052c2 100644 --- a/packages/ui/src/api/utils/entities/resource/index.ts +++ b/packages/ui/src/api/utils/entities/resource/index.ts @@ -1,5 +1,6 @@ import type { EntityMetadataItem, + NativeResourceDetails, StateEntityDetailsVaultResponseItem } from '@common/gateway-sdk' import { transformEntity, type _Entity } from '..' @@ -21,7 +22,6 @@ import { transformNonFungibleResource } from './non-fungible' import { createStandardMetadata, type ExpectedMetadata, - type SystemMetadata } from '@api/utils/metadata' type ResourceType = 'fungible' | 'non-fungible' @@ -37,6 +37,7 @@ export type Resource< } behaviors: 'simple' | Behavior[] displayName: string + nativeResourceDetails?: NativeResourceDetails } export const standardMetadata = createStandardMetadata({ diff --git a/packages/ui/src/api/utils/entities/resource/non-fungible/claim-nft-collection.ts b/packages/ui/src/api/utils/entities/resource/non-fungible/claim-nft-collection.ts index ed3e81056..98da1ddf7 100644 --- a/packages/ui/src/api/utils/entities/resource/non-fungible/claim-nft-collection.ts +++ b/packages/ui/src/api/utils/entities/resource/non-fungible/claim-nft-collection.ts @@ -34,16 +34,11 @@ const getEntityDetails = (address: string) => export const isClaimNftCollection = ( resourceEntity: StateEntityDetailsVaultResponseItem, - validators: (ValidatorListItem | Validator)[] ) => { - const validator = validators.find( - (validator) => - validator.address === - getStringMetadata('validator')(resourceEntity.metadata) && - validator.unstakeClaimResourceAddress === resourceEntity.address + return ( + resourceEntity.details?.type === 'NonFungibleResource' && + resourceEntity.details.native_resource_details?.kind === 'ValidatorClaimNft' ) - - return validator !== undefined } export const resourceToClaimNftCollection = ( diff --git a/packages/ui/src/api/utils/entities/resource/non-fungible/index.ts b/packages/ui/src/api/utils/entities/resource/non-fungible/index.ts index 7fc871c19..fd2284ac8 100644 --- a/packages/ui/src/api/utils/entities/resource/non-fungible/index.ts +++ b/packages/ui/src/api/utils/entities/resource/non-fungible/index.ts @@ -1,6 +1,5 @@ import { transformResource, type Resource } from '..' import type { StateEntityDetailsVaultResponseItem } from '@common/gateway-sdk' -import type { Validator, ValidatorListItem } from '../../component/validator' import { systemMetadata as claimNftSystemMetadata, type ClaimNftCollection, @@ -21,22 +20,27 @@ export type NonFungibleResource = | ClaimNftCollection | PackageOwnerBadgeCollection -export const transformNonFungibleResource = async ( - entity: StateEntityDetailsVaultResponseItem, - validators?: (ValidatorListItem | Validator)[] -): Promise => { - if (validators && isClaimNftCollection(entity, validators)) { +export const transformNonFungibleResource = ( + entity: StateEntityDetailsVaultResponseItem +): NonFungibleResource => { + if (entity.details?.type !== 'NonFungibleResource') { + throw new Error('Invalid resource type') + } + + if (isClaimNftCollection(entity)) { return { ...transformResource(entity, claimNftSystemMetadata), resourceType: 'non-fungible', + nativeResourceDetails: entity.details.native_resource_details, nonFungibleType: 'claim-nft-collection' } as const } - if (await isPackageOwnerBadgeCollection(entity.address)) { + if (isPackageOwnerBadgeCollection(entity)) { return { ...transformResource(entity, PackageOwnerSystemMetadata), resourceType: 'non-fungible', + nativeResourceDetails: entity.details.native_resource_details, nonFungibleType: 'package-owner-badge-collection' } as const } @@ -44,6 +48,7 @@ export const transformNonFungibleResource = async ( return { ...transformResource(entity), resourceType: 'non-fungible', + nativeResourceDetails: entity.details.native_resource_details, nonFungibleType: 'default' } as const } diff --git a/packages/ui/src/api/utils/entities/resource/non-fungible/package-owner-badge-collection.ts b/packages/ui/src/api/utils/entities/resource/non-fungible/package-owner-badge-collection.ts index d520ae28a..3eadc3d75 100644 --- a/packages/ui/src/api/utils/entities/resource/non-fungible/package-owner-badge-collection.ts +++ b/packages/ui/src/api/utils/entities/resource/non-fungible/package-owner-badge-collection.ts @@ -1,6 +1,6 @@ import { createSystemMetadata } from '@api/utils/metadata' import type { Resource, standardMetadata } from '..' -import { networkConfiguration } from '@stores' +import type { StateEntityDetailsResponseItem } from '@common/gateway-sdk' export const systemMetadata = createSystemMetadata({ name: 'String', @@ -17,29 +17,7 @@ export type PackageOwnerBadgeCollection = Resource< } export const isPackageOwnerBadgeCollection = ( - nonFungibleResourceAddress: string -) => { - let resolve: (value: boolean) => void - - const promise = new Promise((res) => { - resolve = res - }) - - let unsub = networkConfiguration.subscribe((config) => { - if (config) { - if ( - config?.well_known_addresses.package_owner_badge === - nonFungibleResourceAddress - ) { - resolve(true) - } else { - resolve(false) - } - } - }) - - return promise.then((result) => { - unsub() - return result - }) -} + entity: StateEntityDetailsResponseItem +) => + entity.details?.type === 'NonFungibleResource' && + entity.details.native_resource_details?.kind === 'PackageOwnerBadge' diff --git a/packages/ui/src/api/utils/staking.ts b/packages/ui/src/api/utils/staking.ts index d59a60d94..71413d918 100644 --- a/packages/ui/src/api/utils/staking.ts +++ b/packages/ui/src/api/utils/staking.ts @@ -5,9 +5,9 @@ import type { ClaimNft } from './nfts/claim-nft' import type { Account } from './entities/component/account' import type { NonFungible } from './nfts' import type { FungibleResource } from './entities/resource/fungible' -import { isNil } from 'ramda' import type { Component } from './entities/component' import type { standardMetadata } from './metadata' +import type { NativeResourceValidatorLiquidStakeUnitValue } from '@common/gateway-sdk' type CommonStakeInfo = { type: T @@ -89,27 +89,41 @@ export const getUnstakeAndClaimInfo = export const getStakedInfo = (validators: ValidatorListItem[], fungibles: FungibleResource[]) => - (account: Account | Component) => - account.resources.fungible - .filter((token) => - validators.some( - (validator) => validator.stakeUnitResourceAddress === token.address - ) + (account: Account | Component) => { + const stakeUnits: Map = + new Map( + fungibles + .filter( + (token) => + token.nativeResourceDetails && + token.nativeResourceDetails.kind === 'ValidatorLiquidStakeUnit' + ) + .map((token) => { + return [ + token.address, + token.nativeResourceDetails as NativeResourceValidatorLiquidStakeUnitValue + ] + }) ) + + return account.resources.fungible + .filter((token) => stakeUnits.has(token.address)) .map((stakeUnitToken) => { + const stakeUnitNativeResourceDetails = stakeUnits.get( + stakeUnitToken.address + )! + const multiplier = + stakeUnitNativeResourceDetails.unit_redemption_value[0].amount + + const xrdAmount = new BigNumber(stakeUnitToken.value) + .multipliedBy(new BigNumber(multiplier!)) + .toFixed(RET_DECIMAL_PRECISION) + const validator = validators.find( (validator) => validator.stakeUnitResourceAddress === stakeUnitToken.address )! - const xrdAmount = validator.totalStakeInXRD - .multipliedBy(stakeUnitToken.value) - .dividedBy( - fungibles.find((token) => token.address === stakeUnitToken.address)! - .totalSupply - ) - .toFixed(RET_DECIMAL_PRECISION) - return { type: 'staked', account: account.address, @@ -119,3 +133,4 @@ export const getStakedInfo = } as StakedInfo }) .filter((stakeInfo) => !new BigNumber(stakeInfo.xrdAmount).eq(0)) + } From b953b0bf678e76710551cbad3b0ba87720f35a8d Mon Sep 17 00:00:00 2001 From: Dawid Sowa Date: Tue, 1 Oct 2024 14:24:00 +0200 Subject: [PATCH 2/7] refactor: remove `/validators/list` call from preview pages --- .../staking-card/StakedValidatorCard.svelte | 169 ++++++++++-------- apps/dashboard/src/lib/summary/summary.ts | 46 ++--- .../lib/token-pages/StakingPageWrapper.svelte | 11 ++ .../src/routes/(search-pages)/utils.ts | 2 +- .../[validator]/staking/+page.svelte | 11 ++ .../src/api/utils/entities/resource/index.ts | 2 +- .../non-fungible/claim-nft-collection.ts | 2 +- packages/ui/src/api/utils/nfts/claim-nft.ts | 4 +- packages/ui/src/api/utils/nfts/index.ts | 9 + .../ui/src/api/utils/resource-cache-client.ts | 1 - packages/ui/src/api/utils/staking.ts | 22 +-- .../src/api/utils/validators-cache-module.ts | 51 ++++++ 12 files changed, 206 insertions(+), 124 deletions(-) create mode 100644 packages/ui/src/api/utils/validators-cache-module.ts diff --git a/apps/dashboard/src/lib/staking-card/StakedValidatorCard.svelte b/apps/dashboard/src/lib/staking-card/StakedValidatorCard.svelte index 451caf074..f0733a8ce 100644 --- a/apps/dashboard/src/lib/staking-card/StakedValidatorCard.svelte +++ b/apps/dashboard/src/lib/staking-card/StakedValidatorCard.svelte @@ -6,89 +6,110 @@ import { formatXRDValue, formatTokenValue } from '@utils' import BigNumber from 'bignumber.js' import ValueBox from './ValueBox.svelte' - import ValidatorPlaceholder from '@icons/validator-placeholder.svg' - export let validatorStakes: any - + import type { AccumulatedStakeInfo } from '../summary/summary' + import { onMount } from 'svelte' + import { validatorsCacheModule } from '@api/utils/validators-cache-module' -
- -
- -
-
-

- {validatorStakes.validator.metadata.expected.name?.typed.value || - ''} -

-
-
+ export let validatorStakes: AccumulatedStakeInfo -
- Staked {formatXRDValue(validatorStakes.accumulatedStakes)} -
-
-
- -
-
- - Liquid Stake Units - {formatTokenValue(validatorStakes.accumulatedLiquidStakeUnits) - .displayValue} -
+ let isLoading: boolean - -
- - {#if validatorStakes.unstaking.length || validatorStakes.readyToClaim.length} -
-
- + onMount(() => { + const subscription = validatorsCacheModule.isLoading$.subscribe((data) => { + isLoading = data + }) + + return () => { + subscription.unsubscribe() + } + }) + - Stake Claims +{#key isLoading} + {#if validatorsCacheModule} + {@const validator = validatorsCacheModule.validators.get( + validatorStakes.validatorAddress + )} +
+ +
+ +
+
+

+ {validator?.name || ''} +

+
+
+ +
+ Staked {formatXRDValue(validatorStakes.accumulatedStakes)} +
- {#each validatorStakes.unstaking as stakeEntry} - - {/each} +
+ +
+
+ + Liquid Stake Units + {formatTokenValue(validatorStakes.accumulatedLiquidStakeUnits) + .displayValue} +
- {#each validatorStakes.readyToClaim as stakeEntry} - {/each} -
- {/if} -
-
-
+
+ + {#if validatorStakes.unstaking.length || validatorStakes.readyToClaim.length} +
+
+ + + Stake Claims +
+ {#each validatorStakes.unstaking as stakeEntry} + + {/each} + + {#each validatorStakes.readyToClaim as stakeEntry} + + {/each} +
+ {/if} + + +
+ {/if} +{/key}