diff --git a/src/i18n/en-US/index.ts b/src/i18n/en-US/index.ts index 0ed517f7f..ce6284efe 100644 --- a/src/i18n/en-US/index.ts +++ b/src/i18n/en-US/index.ts @@ -852,6 +852,7 @@ export default { era: 'Era', day: 'Day', numberOfDapps: 'Number of dApps', + numberOfParticipants: 'Number of participants', general: 'General', totalValueLocked: 'Total Value Locked ({token})', tvl: 'TVL', diff --git a/src/staking-v3/components/data/DataList.vue b/src/staking-v3/components/data/DataList.vue index 3634bcfce..7420abc34 100644 --- a/src/staking-v3/components/data/DataList.vue +++ b/src/staking-v3/components/data/DataList.vue @@ -14,6 +14,9 @@ {{ protocolState?.era }} + + {{ numberOfParticipants }} +
{{ $t('stakingV3.tvl') }}
@@ -80,8 +83,12 @@ export default defineComponent({ const { protocolState, currentEraInfo, dAppTiers, tiersConfiguration } = useDappStaking(); const { registeredDapps } = useDapps(); const { periodName, periodDuration, periodCurrentDay } = usePeriod(); - const { tvlPercentage, totalVolumeOfVotesPercentage, bonusEligibleTokens } = - useDataCalculations(); + const { + tvlPercentage, + totalVolumeOfVotesPercentage, + bonusEligibleTokens, + numberOfParticipants, + } = useDataCalculations(); const { activeInflationConfiguration } = useInflation(); const totalDapps = computed(() => registeredDapps.value?.length ?? 0); @@ -110,6 +117,7 @@ export default defineComponent({ totalVolumeOfVotesPercentage, bonusEligibleTokens, activeInflationConfiguration, + numberOfParticipants, nativeTokenSymbol, }; }, diff --git a/src/staking-v3/hooks/useDapps.ts b/src/staking-v3/hooks/useDapps.ts index 2d34098a6..669517acc 100644 --- a/src/staking-v3/hooks/useDapps.ts +++ b/src/staking-v3/hooks/useDapps.ts @@ -6,6 +6,7 @@ import { DappState, IDappStakingRepository, IDappStakingService, + TokenApiProviderRepository, } from '../logic'; import { Symbols } from 'src/v2/symbols'; import { useNetworkInfo } from 'src/hooks'; @@ -15,6 +16,9 @@ import { useStore } from 'src/store'; export function useDapps() { const store = useStore(); const { currentNetworkName } = useNetworkInfo(); + const tokenApiProviderRepository = container.get( + Symbols.TokenApiProviderRepository + ); const registeredDapps = computed( () => store.getters['stakingV3/getRegisteredDapps'] @@ -39,6 +43,11 @@ export function useDapps() { store.commit('stakingV3/addNewDapps', dApps.chainInfo); // Memo: this can a heavy operations since we are querying all dapps stakes for a chain. await fetchStakeAmountsToStore(); + + const numberOfParticipants = await tokenApiProviderRepository.getNumberOfParticipants( + currentNetworkName.value.toLowerCase() + ); + store.commit('stakingV3/setNumberOfParticipants', numberOfParticipants); } finally { aggregator.publish(new BusyMessage(false)); } diff --git a/src/staking-v3/hooks/useDataCalculations.ts b/src/staking-v3/hooks/useDataCalculations.ts index 3fb4ac841..d127fe362 100644 --- a/src/staking-v3/hooks/useDataCalculations.ts +++ b/src/staking-v3/hooks/useDataCalculations.ts @@ -2,10 +2,12 @@ import { computed } from 'vue'; import { useDappStaking } from './useDappStaking'; import { useTokenCirculation } from 'src/hooks/useTokenCirculation'; import { ethers } from 'ethers'; +import { useStore } from 'src/store'; export function useDataCalculations() { const { totalSupply } = useTokenCirculation(); const { currentEraInfo } = useDappStaking(); + const store = useStore(); const tvlPercentage = computed(() => { if (!currentEraInfo.value || !totalSupply.value) { @@ -44,5 +46,9 @@ export function useDataCalculations() { : currentEraInfo.value.currentStakeAmount.voting; }); - return { tvlPercentage, totalVolumeOfVotesPercentage, bonusEligibleTokens }; + const numberOfParticipants = computed( + () => store.getters['stakingV3/getNumberOfParticipants'] + ); + + return { tvlPercentage, totalVolumeOfVotesPercentage, bonusEligibleTokens, numberOfParticipants }; } diff --git a/src/staking-v3/hooks/useLeaderboard.ts b/src/staking-v3/hooks/useLeaderboard.ts index 23e5935d4..bd3a19a2f 100644 --- a/src/staking-v3/hooks/useLeaderboard.ts +++ b/src/staking-v3/hooks/useLeaderboard.ts @@ -24,7 +24,7 @@ export function useLeaderboard() { ); const sortedDapps = computed(() => - registeredDapps.value.sort((a, b) => { + [...registeredDapps.value].sort((a, b) => { const valueA = a.chain?.totalStake ?? BigInt(0); const valueB = b.chain?.totalStake ?? BigInt(0); diff --git a/src/staking-v3/logic/interfaces/DappStakingV3.ts b/src/staking-v3/logic/interfaces/DappStakingV3.ts index 2a04719b8..1d1b8bb82 100644 --- a/src/staking-v3/logic/interfaces/DappStakingV3.ts +++ b/src/staking-v3/logic/interfaces/DappStakingV3.ts @@ -58,7 +58,6 @@ export interface PalletDappStakingV3ProtocolState extends Struct { export interface PalletDappStakingV3DAppInfo extends Struct { readonly owner: AccountId32; readonly id: Compact; - readonly state: PalletDappStakingV3DAppState; readonly rewardBeneficiary: Option; } diff --git a/src/staking-v3/logic/models/DappStaking.ts b/src/staking-v3/logic/models/DappStaking.ts index c5b3197b6..d98ba9d0d 100644 --- a/src/staking-v3/logic/models/DappStaking.ts +++ b/src/staking-v3/logic/models/DappStaking.ts @@ -1,4 +1,4 @@ -import { DappInfo, ProtocolState } from './Node'; +import { DappInfo, DappState, ProtocolState } from './Node'; import { Community } from '@astar-network/astar-sdk-core'; /** @@ -198,6 +198,15 @@ export interface ProviderDappData { registrationBlockNumber: number; unregisteredAt?: number; unregistrationBlockNumber?: number; + owner: string; + beneficiary?: string; + state: DappState; + dappId: number; +} + +export interface NumberOfParticipantsData { + timestamp: string; + participants: number; } export interface StakerRewards { diff --git a/src/staking-v3/logic/repositories/DappStakingRepository.ts b/src/staking-v3/logic/repositories/DappStakingRepository.ts index e0e5e96d5..4d00ef693 100644 --- a/src/staking-v3/logic/repositories/DappStakingRepository.ts +++ b/src/staking-v3/logic/repositories/DappStakingRepository.ts @@ -517,7 +517,7 @@ export class DappStakingRepository implements IDappStakingRepository { address, owner: dapp.owner.toString(), id: dapp.id.toNumber(), - state: dapp.state.isUnregistered ? DappState.Unregistered : DappState.Registered, + state: DappState.Registered, // All dApss from integratedDApps are registered. rewardDestination: dapp.rewardBeneficiary.unwrapOr(undefined)?.toString(), }; } diff --git a/src/staking-v3/logic/repositories/IDataProviderRepository.ts b/src/staking-v3/logic/repositories/IDataProviderRepository.ts index 5fbad22c7..3670ce156 100644 --- a/src/staking-v3/logic/repositories/IDataProviderRepository.ts +++ b/src/staking-v3/logic/repositories/IDataProviderRepository.ts @@ -5,4 +5,5 @@ import { ProviderDappData } from '../models'; */ export interface IDataProviderRepository { getDapps(network: string): Promise; + getNumberOfParticipants(network: string): Promise; } diff --git a/src/staking-v3/logic/repositories/TokenApiProviderRepository.ts b/src/staking-v3/logic/repositories/TokenApiProviderRepository.ts index ed04c28b9..b90f2406c 100644 --- a/src/staking-v3/logic/repositories/TokenApiProviderRepository.ts +++ b/src/staking-v3/logic/repositories/TokenApiProviderRepository.ts @@ -1,6 +1,6 @@ import { injectable } from 'inversify'; import { IDataProviderRepository } from './IDataProviderRepository'; -import { ProviderDappData } from '../models'; +import { ProviderDappData, NumberOfParticipantsData } from '../models'; import { TOKEN_API_URL } from '@astar-network/astar-sdk-core'; import { Guard } from 'src/v2/common'; import axios from 'axios'; @@ -25,4 +25,28 @@ export class TokenApiProviderRepository implements IDataProviderRepository { return []; } + + async getNumberOfParticipants(network: string): Promise { + Guard.ThrowIfUndefined(network, 'network'); + + const numberOfParticipantsUrl = `${TOKEN_API_URL}/v3/${network.toLowerCase()}/dapps-staking/stakerscount-total/1 day`; + try { + const numberOfParticipants = await axios.get>>( + numberOfParticipantsUrl + ); + + const transformedData: NumberOfParticipantsData[] = numberOfParticipants.data.map((item) => { + return { + timestamp: item[0] as string, + participants: item[1] as number, + }; + }); + + return transformedData.length > 0 ? transformedData[0].participants : 0; + } catch (error) { + console.error(error); + } + + return 0; + } } diff --git a/src/staking-v3/logic/services/DappStakingService.ts b/src/staking-v3/logic/services/DappStakingService.ts index 94157c5c5..8a44e75ae 100644 --- a/src/staking-v3/logic/services/DappStakingService.ts +++ b/src/staking-v3/logic/services/DappStakingService.ts @@ -3,6 +3,7 @@ import { CombinedDappInfo, DappInfo, DappStakeInfo, + DappState, SingularStakingInfo, StakeAmount, StakerRewards, @@ -37,7 +38,7 @@ export class DappStakingService implements IDappStakingService { this.tokenApiRepository.getDapps(network.toLowerCase()), ]); - // Map on chain and in store dApps + // Map on chain and in store dApps (registered only) const dApps: CombinedDappInfo[] = []; const onlyChain: DappInfo[] = []; chainDapps.forEach((chainDapp) => { @@ -58,6 +59,27 @@ export class DappStakingService implements IDappStakingService { } }); + // Map unregistered dApps + tokenApiDapps + .filter((x) => x.state === 'Unregistered') + .forEach((dapp) => { + const storeDapp = storeDapps.find( + (x) => x.address.toLowerCase() === dapp.contractAddress.toLowerCase() + ); + if (storeDapp) { + dApps.push({ + basic: storeDapp, + dappDetails: dapp, + chain: { + address: dapp.contractAddress, + id: dapp.dappId, + owner: dapp.owner, + state: DappState.Unregistered, + }, + }); + } + }); + return { fullInfo: dApps, chainInfo: onlyChain }; } diff --git a/src/staking-v3/store/getters.ts b/src/staking-v3/store/getters.ts index b6b1af3d3..d62198a6c 100644 --- a/src/staking-v3/store/getters.ts +++ b/src/staking-v3/store/getters.ts @@ -37,6 +37,7 @@ const getters: GetterTree & DappStakingGetters getVersion: (state) => state.version, getDapps: (state) => state.dapps, getNewDapps: (state) => state.newDapps, + getNumberOfParticipants: (state) => state.numberOfParticipants, getRegisteredDapps: (state) => state.dapps.filter((x) => x.chain.state === DappState.Registered), getProtocolState: (state) => state.protocolState, getLedger: (state) => state.ledger, diff --git a/src/staking-v3/store/mutations.ts b/src/staking-v3/store/mutations.ts index 585446abf..e6b3e6af0 100644 --- a/src/staking-v3/store/mutations.ts +++ b/src/staking-v3/store/mutations.ts @@ -23,6 +23,7 @@ export interface DappStakingMutations { updateDappExtended(state: DappStakingState, dapp: Dapp): void; updateDappChain(state: DappStakingState, dapp: DappInfo): void; updateDappDetails(state: DappStakingState, dapp: ProviderDappData): void; + setNumberOfParticipants(state: DappStakingState, numberOfParticipants: number): void; setProtocolState(state: DappStakingState, protocolState: ProtocolState): void; setLedger(state: DappStakingState, ledger: AccountLedger): void; setStakerInfo(state: DappStakingState, stakerInfo: Map): void; @@ -73,6 +74,9 @@ const mutations: MutationTree & DappStakingMutations = { updateDappDetails(state: DappStakingState, dapp: ProviderDappData): void { updateDapp(state, dapp.contractAddress, dapp, 'dappDetails'); }, + setNumberOfParticipants(state, numberOfParticipants) { + state.numberOfParticipants = numberOfParticipants; + }, setProtocolState(state, protocolState) { state.protocolState = protocolState; }, diff --git a/src/staking-v3/store/state.ts b/src/staking-v3/store/state.ts index 94c8e471c..6df35c051 100644 --- a/src/staking-v3/store/state.ts +++ b/src/staking-v3/store/state.ts @@ -16,6 +16,7 @@ export interface DappStakingState { version: string; dapps: CombinedDappInfo[]; newDapps: DappInfo[]; + numberOfParticipants: number; protocolState: ProtocolState | undefined; ledger: AccountLedger | undefined; stakerInfo: Map | undefined; @@ -33,6 +34,7 @@ function state(): DappStakingState { version: '3.0.0', dapps: [], newDapps: [], + numberOfParticipants: 0, protocolState: undefined, ledger: undefined, stakerInfo: undefined,