From d5026ce23846f18b4e1d82a2783fb1bf3e2076b5 Mon Sep 17 00:00:00 2001 From: belopash Date: Tue, 11 Jun 2024 11:17:14 +0500 Subject: [PATCH] refactor: cleanup squid queries --- src/api/contracts/staking.ts | 4 +- src/api/subsquid-network-squid/api.graphql | 137 ++--- src/api/subsquid-network-squid/graphql.tsx | 480 +++++++++++------- .../subsquid-network-squid/workers-graphql.ts | 373 +++++++------- src/pages/DelegationsPage/DelegationsPage.tsx | 4 +- src/pages/WorkersPage/DelegationCapacity.tsx | 8 +- src/pages/WorkersPage/UptimeGraph.tsx | 8 +- src/pages/WorkersPage/Worker.tsx | 212 +++++++- src/pages/WorkersPage/WorkerCard.tsx | 25 +- src/pages/WorkersPage/WorkerDelegate.tsx | 31 +- src/pages/WorkersPage/WorkerEdit.tsx | 16 +- src/pages/WorkersPage/WorkerName.tsx | 4 +- src/pages/WorkersPage/WorkerStatistics.tsx | 202 -------- src/pages/WorkersPage/WorkerStatus.tsx | 54 +- src/pages/WorkersPage/WorkerUndelegate.tsx | 24 +- src/pages/WorkersPage/WorkerUnregister.tsx | 27 +- src/pages/WorkersPage/WorkerVersion.tsx | 4 +- src/pages/WorkersPage/WorkersPage.tsx | 9 +- 18 files changed, 902 insertions(+), 720 deletions(-) delete mode 100644 src/pages/WorkersPage/WorkerStatistics.tsx diff --git a/src/api/contracts/staking.ts b/src/api/contracts/staking.ts index 6e07a4f..e5f7aab 100644 --- a/src/api/contracts/staking.ts +++ b/src/api/contracts/staking.ts @@ -15,7 +15,7 @@ import { import { useApproveSqd } from '@api/contracts/sqd'; import { VESTING_CONTRACT_ABI } from '@api/contracts/vesting.abi'; -import { AccountType, BlockchainApiWorker, SourceWallet } from '@api/subsquid-network-squid'; +import { AccountType, Worker, SourceWallet } from '@api/subsquid-network-squid'; import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts'; import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; @@ -25,7 +25,7 @@ import { STAKING_CONTRACT_ABI } from './staking.abi'; import { errorMessage, TxResult, isApproveRequiredError, WriteContractRes } from './utils'; type WorkerDepositRequest = { - worker: BlockchainApiWorker; + worker: Pick; amount: string; wallet: Pick; }; diff --git a/src/api/subsquid-network-squid/api.graphql b/src/api/subsquid-network-squid/api.graphql index 1ffa91c..2977aa5 100644 --- a/src/api/subsquid-network-squid/api.graphql +++ b/src/api/subsquid-network-squid/api.graphql @@ -39,38 +39,40 @@ query account($address: String!) { ### WORKERS ### -fragment WorkerFragment on Worker { +fragment WorkerBaseFragment on Worker { id name peerId +} + +fragment WorkerStatusFragment on Worker { status - createdAt - bond - claimableReward - claimedReward - uptime24Hours - uptime90Days - totalDelegation - capedDelegation - delegationCount - apr - stakerApr online jailed dialOk - locked - version jailReason - owner { - id - type - } - realOwner { - id - } +} + +fragment WorkerFragment on Worker { + ...WorkerBaseFragment + ...WorkerStatusFragment + version + createdAt + uptime90Days + apr + stakerApr + totalDelegation + capedDelegation } fragment WorkerFullFragment on Worker { + ...WorkerFragment + bond + claimableReward + claimedReward + uptime24Hours + delegationCount + locked totalDelegationRewards website email @@ -90,6 +92,9 @@ fragment WorkerFullFragment on Worker { id type } + realOwner { + id + } } query allWorkers { @@ -98,17 +103,17 @@ query allWorkers { } } -query workerByPeerId($peerId: String!, $address: String!) { +query workerByPeerId($peerId: String!, $address: String) { workers(where: { peerId_eq: $peerId }, limit: 1) { - ...WorkerFragment ...WorkerFullFragment - myDelegations: delegations(where: { realOwner: { id_eq: $address } }) { + delegations(where: { realOwner: { id_eq: $address } }) { + claimableReward + claimedReward deposit locked owner { id type - balance } } } @@ -124,15 +129,9 @@ query workerDaysUptimeById($id: String!, $from: DateTime!) { query myWorkers($address: String!) { workers(orderBy: id_ASC, where: { realOwner: { id_eq: $address }, status_not_eq: WITHDRAWN }) { ...WorkerFragment - myDelegations: delegations(where: { realOwner: { id_eq: $address } }) { - deposit - locked - owner { - id - type - balance - } - } + uptime24Hours + claimableReward + claimedReward } } @@ -142,22 +141,49 @@ query myWorkersCount($address: String!) { } } -query workerRewardStats($workerId: String!) { +query workerDelegationInfo($workerId: String!) { workerById(id: $workerId) { + bond + totalDelegation + capedDelegation liveness dTenure trafficWeight - bond - capedDelegation - totalDelegation } - + statistics(limit: 1) { utilizedStake baseApr } } +query workerOwner($workerId: String!) { + workerById(id: $workerId) { + owner { + id + type + } + realOwner { + id + } + } +} + +query myWorkerDelegations($address: String!, $workerId: String!) { + workerById(id: $workerId) { + delegations(where: { realOwner: { id_eq: $address } }) { + claimableReward + claimedReward + deposit + locked + owner { + id + type + } + } + } +} + query myAssets($address: String!) { accounts(where: { id_eq: $address }) { balance @@ -167,6 +193,7 @@ query myAssets($address: String!) { } } workers(where: { realOwner: { id_eq: $address } }) { + ...WorkerBaseFragment bond claimableReward } @@ -182,29 +209,27 @@ query myAssets($address: String!) { } query myDelegations($address: String!) { - delegations(where: { realOwner: { id_eq: $address }, deposit_gt: 0 }) { - claimableReward - claimedReward - deposit - locked - worker { - ...WorkerFragment - } - owner { - id - type + workers(where: { delegations_some: { realOwner: { id_eq: $address } } }) { + ...WorkerFragment + delegations(where: { realOwner: { id_eq: $address } }) { + claimableReward + claimedReward + deposit + locked + owner { + id + type + } } } } -query myClaimsAvailable($address: String!) { +query myClaims($address: String!) { delegations(where: { realOwner: { id_eq: $address }, claimableReward_gt: 0 }) { claimableReward deposit worker { - id - name - peerId + ...WorkerBaseFragment } owner { id @@ -212,9 +237,7 @@ query myClaimsAvailable($address: String!) { } } workers(where: { realOwner: { id_eq: $address }, claimableReward_gt: 0 }) { - id - name - peerId + ...WorkerBaseFragment claimableReward owner { id diff --git a/src/api/subsquid-network-squid/graphql.tsx b/src/api/subsquid-network-squid/graphql.tsx index e2ab5ea..8d28b53 100644 --- a/src/api/subsquid-network-squid/graphql.tsx +++ b/src/api/subsquid-network-squid/graphql.tsx @@ -5459,35 +5459,49 @@ export type AccountQuery = { }; }; -export type WorkerFragmentFragment = { +export type WorkerBaseFragmentFragment = { __typename?: 'Worker'; id: string; name?: string; peerId: string; +}; + +export type WorkerStatusFragmentFragment = { + __typename?: 'Worker'; status: WorkerStatus; + online?: boolean; + jailed?: boolean; + dialOk?: boolean; + jailReason?: string; +}; + +export type WorkerFragmentFragment = { + __typename?: 'Worker'; + version?: string; createdAt: string; - bond: string; - claimableReward: string; - claimedReward: string; - uptime24Hours?: number; uptime90Days?: number; - totalDelegation: string; - capedDelegation: string; - delegationCount: number; apr?: number; stakerApr?: number; + totalDelegation: string; + capedDelegation: string; + id: string; + name?: string; + peerId: string; + status: WorkerStatus; online?: boolean; jailed?: boolean; dialOk?: boolean; - locked?: boolean; - version?: string; jailReason?: string; - owner: { __typename?: 'Account'; id: string; type: AccountType }; - realOwner: { __typename?: 'Account'; id: string }; }; export type WorkerFullFragmentFragment = { __typename?: 'Worker'; + bond: string; + claimableReward: string; + claimedReward: string; + uptime24Hours?: number; + delegationCount: number; + locked?: boolean; totalDelegationRewards: string; website?: string; email?: string; @@ -5499,8 +5513,24 @@ export type WorkerFullFragmentFragment = { servedData24Hours?: string; servedData90Days?: string; storedData?: string; + version?: string; + createdAt: string; + uptime90Days?: number; + apr?: number; + stakerApr?: number; + totalDelegation: string; + capedDelegation: string; + id: string; + name?: string; + peerId: string; + status: WorkerStatus; + online?: boolean; + jailed?: boolean; + dialOk?: boolean; + jailReason?: string; dayUptimes?: Array<{ __typename?: 'WorkerDayUptime'; timestamp: string; uptime: number }>; owner: { __typename?: 'Account'; id: string; type: AccountType }; + realOwner: { __typename?: 'Account'; id: string }; }; export type AllWorkersQueryVariables = Exact<{ [key: string]: never }>; @@ -5509,62 +5539,39 @@ export type AllWorkersQuery = { __typename?: 'Query'; workers: Array<{ __typename?: 'Worker'; - id: string; - name?: string; - peerId: string; - status: WorkerStatus; + version?: string; createdAt: string; - bond: string; - claimableReward: string; - claimedReward: string; - uptime24Hours?: number; uptime90Days?: number; - totalDelegation: string; - capedDelegation: string; - delegationCount: number; apr?: number; stakerApr?: number; + totalDelegation: string; + capedDelegation: string; + id: string; + name?: string; + peerId: string; + status: WorkerStatus; online?: boolean; jailed?: boolean; dialOk?: boolean; - locked?: boolean; - version?: string; jailReason?: string; - owner: { __typename?: 'Account'; id: string; type: AccountType }; - realOwner: { __typename?: 'Account'; id: string }; }>; }; export type WorkerByPeerIdQueryVariables = Exact<{ peerId: Scalars['String']['input']; - address: Scalars['String']['input']; + address?: InputMaybe; }>; export type WorkerByPeerIdQuery = { __typename?: 'Query'; workers: Array<{ __typename?: 'Worker'; - id: string; - name?: string; - peerId: string; - status: WorkerStatus; - createdAt: string; bond: string; claimableReward: string; claimedReward: string; uptime24Hours?: number; - uptime90Days?: number; - totalDelegation: string; - capedDelegation: string; delegationCount: number; - apr?: number; - stakerApr?: number; - online?: boolean; - jailed?: boolean; - dialOk?: boolean; locked?: boolean; - version?: string; - jailReason?: string; totalDelegationRewards: string; website?: string; email?: string; @@ -5576,15 +5583,32 @@ export type WorkerByPeerIdQuery = { servedData24Hours?: string; servedData90Days?: string; storedData?: string; - myDelegations: Array<{ + version?: string; + createdAt: string; + uptime90Days?: number; + apr?: number; + stakerApr?: number; + totalDelegation: string; + capedDelegation: string; + id: string; + name?: string; + peerId: string; + status: WorkerStatus; + online?: boolean; + jailed?: boolean; + dialOk?: boolean; + jailReason?: string; + delegations: Array<{ __typename?: 'Delegation'; + claimableReward: string; + claimedReward: string; deposit: string; locked?: boolean; - owner: { __typename?: 'Account'; id: string; type: AccountType; balance: string }; + owner: { __typename?: 'Account'; id: string; type: AccountType }; }>; + dayUptimes?: Array<{ __typename?: 'WorkerDayUptime'; timestamp: string; uptime: number }>; owner: { __typename?: 'Account'; id: string; type: AccountType }; realOwner: { __typename?: 'Account'; id: string }; - dayUptimes?: Array<{ __typename?: 'WorkerDayUptime'; timestamp: string; uptime: number }>; }>; }; @@ -5610,35 +5634,24 @@ export type MyWorkersQuery = { __typename?: 'Query'; workers: Array<{ __typename?: 'Worker'; - id: string; - name?: string; - peerId: string; - status: WorkerStatus; - createdAt: string; - bond: string; + uptime24Hours?: number; claimableReward: string; claimedReward: string; - uptime24Hours?: number; + version?: string; + createdAt: string; uptime90Days?: number; - totalDelegation: string; - capedDelegation: string; - delegationCount: number; apr?: number; stakerApr?: number; + totalDelegation: string; + capedDelegation: string; + id: string; + name?: string; + peerId: string; + status: WorkerStatus; online?: boolean; jailed?: boolean; dialOk?: boolean; - locked?: boolean; - version?: string; jailReason?: string; - myDelegations: Array<{ - __typename?: 'Delegation'; - deposit: string; - locked?: boolean; - owner: { __typename?: 'Account'; id: string; type: AccountType; balance: string }; - }>; - owner: { __typename?: 'Account'; id: string; type: AccountType }; - realOwner: { __typename?: 'Account'; id: string }; }>; }; @@ -5651,24 +5664,57 @@ export type MyWorkersCountQuery = { workersConnection: { __typename?: 'WorkersConnection'; totalCount: number }; }; -export type WorkerRewardStatsQueryVariables = Exact<{ +export type WorkerDelegationInfoQueryVariables = Exact<{ workerId: Scalars['String']['input']; }>; -export type WorkerRewardStatsQuery = { +export type WorkerDelegationInfoQuery = { __typename?: 'Query'; workerById?: { __typename?: 'Worker'; + bond: string; + totalDelegation: string; + capedDelegation: string; liveness?: number; dTenure?: number; trafficWeight?: number; - bond: string; - capedDelegation: string; - totalDelegation: string; }; statistics: Array<{ __typename?: 'Statistics'; utilizedStake: string; baseApr: number }>; }; +export type WorkerOwnerQueryVariables = Exact<{ + workerId: Scalars['String']['input']; +}>; + +export type WorkerOwnerQuery = { + __typename?: 'Query'; + workerById?: { + __typename?: 'Worker'; + owner: { __typename?: 'Account'; id: string; type: AccountType }; + realOwner: { __typename?: 'Account'; id: string }; + }; +}; + +export type MyWorkerDelegationsQueryVariables = Exact<{ + address: Scalars['String']['input']; + workerId: Scalars['String']['input']; +}>; + +export type MyWorkerDelegationsQuery = { + __typename?: 'Query'; + workerById?: { + __typename?: 'Worker'; + delegations: Array<{ + __typename?: 'Delegation'; + claimableReward: string; + claimedReward: string; + deposit: string; + locked?: boolean; + owner: { __typename?: 'Account'; id: string; type: AccountType }; + }>; + }; +}; + export type MyAssetsQueryVariables = Exact<{ address: Scalars['String']['input']; }>; @@ -5680,7 +5726,14 @@ export type MyAssetsQuery = { balance: string; owned: Array<{ __typename?: 'Account'; id: string; balance: string }>; }>; - workers: Array<{ __typename?: 'Worker'; bond: string; claimableReward: string }>; + workers: Array<{ + __typename?: 'Worker'; + bond: string; + claimableReward: string; + id: string; + name?: string; + peerId: string; + }>; delegations: Array<{ __typename?: 'Delegation'; claimableReward: string; deposit: string }>; }; @@ -5690,47 +5743,39 @@ export type MyDelegationsQueryVariables = Exact<{ export type MyDelegationsQuery = { __typename?: 'Query'; - delegations: Array<{ - __typename?: 'Delegation'; - claimableReward: string; - claimedReward: string; - deposit: string; - locked?: boolean; - worker: { - __typename?: 'Worker'; - id: string; - name?: string; - peerId: string; - status: WorkerStatus; - createdAt: string; - bond: string; + workers: Array<{ + __typename?: 'Worker'; + version?: string; + createdAt: string; + uptime90Days?: number; + apr?: number; + stakerApr?: number; + totalDelegation: string; + capedDelegation: string; + id: string; + name?: string; + peerId: string; + status: WorkerStatus; + online?: boolean; + jailed?: boolean; + dialOk?: boolean; + jailReason?: string; + delegations: Array<{ + __typename?: 'Delegation'; claimableReward: string; claimedReward: string; - uptime24Hours?: number; - uptime90Days?: number; - totalDelegation: string; - capedDelegation: string; - delegationCount: number; - apr?: number; - stakerApr?: number; - online?: boolean; - jailed?: boolean; - dialOk?: boolean; + deposit: string; locked?: boolean; - version?: string; - jailReason?: string; owner: { __typename?: 'Account'; id: string; type: AccountType }; - realOwner: { __typename?: 'Account'; id: string }; - }; - owner: { __typename?: 'Account'; id: string; type: AccountType }; + }>; }>; }; -export type MyClaimsAvailableQueryVariables = Exact<{ +export type MyClaimsQueryVariables = Exact<{ address: Scalars['String']['input']; }>; -export type MyClaimsAvailableQuery = { +export type MyClaimsQuery = { __typename?: 'Query'; delegations: Array<{ __typename?: 'Delegation'; @@ -5741,10 +5786,10 @@ export type MyClaimsAvailableQuery = { }>; workers: Array<{ __typename?: 'Worker'; + claimableReward: string; id: string; name?: string; peerId: string; - claimableReward: string; owner: { __typename?: 'Account'; id: string; type: AccountType }; }>; }; @@ -5884,40 +5929,45 @@ export type VestingByAddressQuery = { }; }; -export const WorkerFragmentFragmentDoc = ` - fragment WorkerFragment on Worker { +export const WorkerBaseFragmentFragmentDoc = ` + fragment WorkerBaseFragment on Worker { id name peerId +} + `; +export const WorkerStatusFragmentFragmentDoc = ` + fragment WorkerStatusFragment on Worker { status - createdAt - bond - claimableReward - claimedReward - uptime24Hours - uptime90Days - totalDelegation - capedDelegation - delegationCount - apr - stakerApr online jailed dialOk - locked - version jailReason - owner { - id - type - } - realOwner { - id - } } `; +export const WorkerFragmentFragmentDoc = ` + fragment WorkerFragment on Worker { + ...WorkerBaseFragment + ...WorkerStatusFragment + version + createdAt + uptime90Days + apr + stakerApr + totalDelegation + capedDelegation +} + ${WorkerBaseFragmentFragmentDoc} +${WorkerStatusFragmentFragmentDoc}`; export const WorkerFullFragmentFragmentDoc = ` fragment WorkerFullFragment on Worker { + ...WorkerFragment + bond + claimableReward + claimedReward + uptime24Hours + delegationCount + locked totalDelegationRewards website email @@ -5937,8 +5987,11 @@ export const WorkerFullFragmentFragmentDoc = ` id type } + realOwner { + id + } } - `; + ${WorkerFragmentFragmentDoc}`; export const GatewayFragmentFragmentDoc = ` fragment GatewayFragment on Gateway { id @@ -6115,23 +6168,22 @@ export const useAllWorkersQuery = ( }; export const WorkerByPeerIdDocument = ` - query workerByPeerId($peerId: String!, $address: String!) { + query workerByPeerId($peerId: String!, $address: String) { workers(where: {peerId_eq: $peerId}, limit: 1) { - ...WorkerFragment ...WorkerFullFragment - myDelegations: delegations(where: {realOwner: {id_eq: $address}}) { + delegations(where: {realOwner: {id_eq: $address}}) { + claimableReward + claimedReward deposit locked owner { id type - balance } } } } - ${WorkerFragmentFragmentDoc} -${WorkerFullFragmentFragmentDoc}`; + ${WorkerFullFragmentFragmentDoc}`; export const useWorkerByPeerIdQuery = ( dataSource: { endpoint: string; fetchParams?: RequestInit }, @@ -6187,15 +6239,9 @@ export const MyWorkersDocument = ` where: {realOwner: {id_eq: $address}, status_not_eq: WITHDRAWN} ) { ...WorkerFragment - myDelegations: delegations(where: {realOwner: {id_eq: $address}}) { - deposit - locked - owner { - id - type - balance - } - } + uptime24Hours + claimableReward + claimedReward } } ${WorkerFragmentFragmentDoc}`; @@ -6246,15 +6292,15 @@ export const useMyWorkersCountQuery = ( +export const useWorkerDelegationInfoQuery = ( + dataSource: { endpoint: string; fetchParams?: RequestInit }, + variables: WorkerDelegationInfoQueryVariables, + options?: Omit, 'queryKey'> & { + queryKey?: UseQueryOptions['queryKey']; + }, +) => { + return useQuery({ + queryKey: ['workerDelegationInfo', variables], + queryFn: fetcher( + dataSource.endpoint, + dataSource.fetchParams || {}, + WorkerDelegationInfoDocument, + variables, + ), + ...options, + }); +}; + +export const WorkerOwnerDocument = ` + query workerOwner($workerId: String!) { + workerById(id: $workerId) { + owner { + id + type + } + realOwner { + id + } + } +} + `; + +export const useWorkerOwnerQuery = ( dataSource: { endpoint: string; fetchParams?: RequestInit }, - variables: WorkerRewardStatsQueryVariables, - options?: Omit, 'queryKey'> & { - queryKey?: UseQueryOptions['queryKey']; + variables: WorkerOwnerQueryVariables, + options?: Omit, 'queryKey'> & { + queryKey?: UseQueryOptions['queryKey']; }, ) => { - return useQuery({ - queryKey: ['workerRewardStats', variables], - queryFn: fetcher( + return useQuery({ + queryKey: ['workerOwner', variables], + queryFn: fetcher( dataSource.endpoint, dataSource.fetchParams || {}, - WorkerRewardStatsDocument, + WorkerOwnerDocument, + variables, + ), + ...options, + }); +}; + +export const MyWorkerDelegationsDocument = ` + query myWorkerDelegations($address: String!, $workerId: String!) { + workerById(id: $workerId) { + delegations(where: {realOwner: {id_eq: $address}}) { + claimableReward + claimedReward + deposit + locked + owner { + id + type + } + } + } +} + `; + +export const useMyWorkerDelegationsQuery = ( + dataSource: { endpoint: string; fetchParams?: RequestInit }, + variables: MyWorkerDelegationsQueryVariables, + options?: Omit, 'queryKey'> & { + queryKey?: UseQueryOptions['queryKey']; + }, +) => { + return useQuery({ + queryKey: ['myWorkerDelegations', variables], + queryFn: fetcher( + dataSource.endpoint, + dataSource.fetchParams || {}, + MyWorkerDelegationsDocument, variables, ), ...options, @@ -6292,6 +6407,7 @@ export const MyAssetsDocument = ` } } workers(where: {realOwner: {id_eq: $address}}) { + ...WorkerBaseFragment bond claimableReward } @@ -6302,7 +6418,7 @@ export const MyAssetsDocument = ` deposit } } - `; + ${WorkerBaseFragmentFragmentDoc}`; export const useMyAssetsQuery = ( dataSource: { endpoint: string; fetchParams?: RequestInit }, @@ -6325,17 +6441,17 @@ export const useMyAssetsQuery = ( export const MyDelegationsDocument = ` query myDelegations($address: String!) { - delegations(where: {realOwner: {id_eq: $address}, deposit_gt: 0}) { - claimableReward - claimedReward - deposit - locked - worker { - ...WorkerFragment - } - owner { - id - type + workers(where: {delegations_some: {realOwner: {id_eq: $address}}}) { + ...WorkerFragment + delegations(where: {realOwner: {id_eq: $address}}) { + claimableReward + claimedReward + deposit + locked + owner { + id + type + } } } } @@ -6360,15 +6476,13 @@ export const useMyDelegationsQuery = ( +export const useMyClaimsQuery = ( dataSource: { endpoint: string; fetchParams?: RequestInit }, - variables: MyClaimsAvailableQueryVariables, - options?: Omit, 'queryKey'> & { - queryKey?: UseQueryOptions['queryKey']; + variables: MyClaimsQueryVariables, + options?: Omit, 'queryKey'> & { + queryKey?: UseQueryOptions['queryKey']; }, ) => { - return useQuery({ - queryKey: ['myClaimsAvailable', variables], - queryFn: fetcher( + return useQuery({ + queryKey: ['myClaims', variables], + queryFn: fetcher( dataSource.endpoint, dataSource.fetchParams || {}, - MyClaimsAvailableDocument, + MyClaimsDocument, variables, ), ...options, diff --git a/src/api/subsquid-network-squid/workers-graphql.ts b/src/api/subsquid-network-squid/workers-graphql.ts index 3ae54ef..e232600 100644 --- a/src/api/subsquid-network-squid/workers-graphql.ts +++ b/src/api/subsquid-network-squid/workers-graphql.ts @@ -8,116 +8,118 @@ import { useAccount } from '@network/useAccount.ts'; import { useSquidDataSource } from './datasource'; import { - AccountType, ClaimType, useAllWorkersQuery, - useMyClaimsAvailableQuery, + useMyClaimsQuery, useMyDelegationsQuery, + useMyWorkerDelegationsQuery, useMyWorkersCountQuery, useMyWorkersQuery, useWorkerByPeerIdQuery, - useWorkerDaysUptimeByIdQuery, - useWorkerRewardStatsQuery, - WorkerFragmentFragment, - WorkerFullFragmentFragment, - WorkerStatus, + useWorkerDelegationInfoQuery, + useWorkerOwnerQuery, + Worker, } from './graphql'; import { useNetworkSettings } from './settings-graphql'; // inherit API interface for internal class -export interface BlockchainApiWorker extends Omit { - createdAt: Date; -} - -export class BlockchainApiWorker { - ownedByMe?: boolean; - delegationCapacity?: number; - delegationEnabled: boolean = false; - myDelegations: { - owner: { id: string; type: AccountType }; - deposit: string; - locked?: boolean; - claimableReward: string; - claimedReward: string; - }[] = []; - totalReward: string; - // myDelegationsTotal: BigNumber; - // myDelegationsRewardsTotal: BigNumber; - - constructor({ worker, address }: { worker: WorkerFragmentFragment; address?: `0x${string}` }) { - Object.assign(this, { - ...worker, - createdAt: new Date(worker.createdAt), - delegationEnabled: worker.status === WorkerStatus.Active, - ownedByMe: worker.realOwner?.id === address, - }); - - // this.myDelegationsTotal = this.myDelegations.reduce( - // (t, r) => t.plus(fromSqd(r.deposit)), - // BigNumber(0), - // ); - - // this.myDelegationsRewardsTotal = this.myDelegations.reduce( - // (t, r) => t.plus(fromSqd(r.claimableReward)).plus(fromSqd(r.claimedReward)), - // BigNumber(0), - // ); - - this.totalReward = BigNumber(this.claimedReward).plus(this.claimableReward).toFixed(0); - - if (this.totalDelegation && this.capedDelegation) { - this.delegationCapacity = calculateDelegationCapacity({ - capedDelegation: this.capedDelegation, - totalDelegation: this.totalDelegation, - }); - } - } - - canEdit() { - if (!this.ownedByMe) return false; - - switch (this.status) { - case WorkerStatus.Registering: - case WorkerStatus.Active: - return true; - default: - return false; - } - } - - canUnregister() { - if (!this.ownedByMe) return false; - - switch (this.status) { - case WorkerStatus.Deregistering: - case WorkerStatus.Deregistered: - case WorkerStatus.Withdrawn: - return false; - default: - return true; - } - } - - canWithdraw() { - return this.status === WorkerStatus.Deregistered && !this.locked; - } - - displayStats() { - switch (this.status) { - case WorkerStatus.Registering: - case WorkerStatus.Active: - case WorkerStatus.Deregistering: - return true; - default: - return false; - } - } -} +// export interface BlockchainApiWorker extends Omit { +// createdAt: Date; +// } + +// export class BlockchainApiWorker { +// ownedByMe?: boolean; +// delegationCapacity?: number; +// delegationEnabled: boolean = false; +// myDelegations: { +// owner: { id: string; type: AccountType }; +// deposit: string; +// locked?: boolean; +// claimableReward: string; +// claimedReward: string; +// }[] = []; +// totalReward: string; +// // myDelegationsTotal: BigNumber; +// // myDelegationsRewardsTotal: BigNumber; + +// constructor({ worker, address }: { worker: WorkerFragmentFragment; address?: `0x${string}` }) { +// Object.assign(this, { +// ...worker, +// createdAt: new Date(worker.createdAt), +// delegationEnabled: worker.status === WorkerStatus.Active, +// ownedByMe: worker.realOwner?.id === address, +// }); + +// // this.myDelegationsTotal = this.myDelegations.reduce( +// // (t, r) => t.plus(fromSqd(r.deposit)), +// // BigNumber(0), +// // ); + +// // this.myDelegationsRewardsTotal = this.myDelegations.reduce( +// // (t, r) => t.plus(fromSqd(r.claimableReward)).plus(fromSqd(r.claimedReward)), +// // BigNumber(0), +// // ); + +// this.totalReward = BigNumber(this.claimedReward).plus(this.claimableReward).toFixed(0); + +// if (this.totalDelegation && this.capedDelegation) { +// this.delegationCapacity = calculateDelegationCapacity({ +// capedDelegation: this.capedDelegation, +// totalDelegation: this.totalDelegation, +// }); +// } +// } + +// canEdit() { +// if (!this.ownedByMe) return false; + +// switch (this.status) { +// case WorkerStatus.Registering: +// case WorkerStatus.Active: +// return true; +// default: +// return false; +// } +// } + +// canUnregister() { +// if (!this.ownedByMe) return false; + +// switch (this.status) { +// case WorkerStatus.Deregistering: +// case WorkerStatus.Deregistered: +// case WorkerStatus.Withdrawn: +// return false; +// default: +// return true; +// } +// } + +// canWithdraw() { +// return this.status === WorkerStatus.Deregistered && !this.locked; +// } + +// displayStats() { +// switch (this.status) { +// case WorkerStatus.Registering: +// case WorkerStatus.Active: +// case WorkerStatus.Deregistering: +// return true; +// default: +// return false; +// } +// } +// } // inherit API interface for internal class -export interface BlockchainApiFullWorker extends BlockchainApiWorker, WorkerFullFragmentFragment { - owner: WorkerFullFragmentFragment['owner']; +// export interface BlockchainApiFullWorker extends BlockchainApiWorker, WorkerFullFragmentFragment { +// owner: WorkerFullFragmentFragment['owner']; +// } +// export class BlockchainApiFullWorker extends BlockchainApiWorker {} + +export interface WorkerExtended extends Worker { + delegationCapacity: number; } -export class BlockchainApiFullWorker extends BlockchainApiWorker {} export enum WorkerSortBy { JoinedAt = 'joined_at', @@ -147,7 +149,6 @@ export function useWorkers({ sortDir: SortDir; }) { const dataSource = useSquidDataSource(); - const { address } = useAccount(); const { isPending: isSettingsLoading } = useNetworkSettings(); const { data, isPending } = useAllWorkersQuery(dataSource, {}); @@ -163,11 +164,14 @@ export function useWorkers({ return true; }) - .map(worker => { - return new BlockchainApiWorker({ - worker, - address, - }); + .map(w => { + return { + ...w, + delegationCapacity: calculateDelegationCapacity({ + totalDelegation: w.totalDelegation, + capedDelegation: w.capedDelegation, + }), + }; }) .sort((a, b) => { if (sortDir === SortDir.Desc) { @@ -177,18 +181,14 @@ export function useWorkers({ switch (sortBy) { case WorkerSortBy.Uptime90d: return (a.uptime90Days ?? -1) - (b.uptime90Days ?? -1); - case WorkerSortBy.Uptime24h: - return (a.uptime24Hours ?? -1) - (b.uptime24Hours ?? -1); case WorkerSortBy.DelegationCapacity: return (a.delegationCapacity ?? -1) - (b.delegationCapacity ?? -1); case WorkerSortBy.StakerAPR: - return ( - (a.stakerApr ?? -1) - (b.stakerApr ?? -1) || a.delegationCount - b.delegationCount - ); + return (a.stakerApr ?? -1) - (b.stakerApr ?? -1); case WorkerSortBy.WorkerAPR: return (a.apr ?? -1) - (b.apr ?? -1); default: - return a.createdAt.valueOf() - b.createdAt.valueOf(); + return new Date(a.createdAt).valueOf() - new Date(b.createdAt).valueOf(); } }); @@ -200,7 +200,7 @@ export function useWorkers({ totalPages: Math.floor(filtered.length / perPage), workers: filtered.slice((normalizedPage - 1) * perPage, normalizedPage * perPage), }; - }, [data?.workers, search, sortBy, sortDir, address, page, perPage]); + }, [data?.workers, search, sortBy, sortDir, page, perPage]); return { ...filteredData, @@ -221,13 +221,9 @@ export function useMyWorkers() { }, { select: res => { - return res.workers.map( - w => - new BlockchainApiWorker({ - worker: w, - address, - }), - ); + return res.workers.map(w => { + return w; + }); }, enabled, }, @@ -242,23 +238,24 @@ export function useMyWorkers() { export function useWorkerByPeerId(peerId?: string) { const datasource = useSquidDataSource(); const enabled = !!peerId; - const { address } = useAccount(); const { isPending: isSettingsLoading } = useNetworkSettings(); + const { address } = useAccount(); const { data, isPending } = useWorkerByPeerIdQuery( datasource, - { - peerId: peerId || '', - address: address || '', - }, + { peerId: peerId || '', address }, { select: res => { if (!res.workers.length) return; - - return new BlockchainApiFullWorker({ - worker: res.workers[0], - address, - }); + return res.workers.map(w => { + return { + ...w, + delegationCapacity: calculateDelegationCapacity({ + totalDelegation: w.totalDelegation, + capedDelegation: w.capedDelegation, + }), + }; + })[0]; }, enabled, }, @@ -270,38 +267,11 @@ export function useWorkerByPeerId(peerId?: string) { }; } -// TODO: remove hardcoded date -export function useWorkerDaysUptimeById(workerId?: string) { - const enabled = !!workerId; - const datasource = useSquidDataSource(); - - const { data, isLoading } = useWorkerDaysUptimeByIdQuery( - datasource, - { - id: workerId || '', - from: '2024-01-23T12:00:00.000000Z', - }, - { - select: res => - res.workerSnapshotsByDay.map(({ timestamp, uptime }) => ({ - timestamp, - uptime, - })), - enabled, - }, - ); - - return { - data: data || [], - isLoading: enabled ? isLoading : false, - }; -} - export function useMyClaimsAvailable({ source }: { source?: string } = {}) { const { address } = useAccount(); const datasource = useSquidDataSource(); - const { data, isLoading } = useMyClaimsAvailableQuery(datasource, { + const { data, isLoading } = useMyClaimsQuery(datasource, { address: address || '', }); @@ -380,23 +350,23 @@ export function useMyDelegations() { address: address || '', }); - const delegations: BlockchainApiWorker[] = useMemo(() => { - const workers: Map = new Map(); - for (const d of data?.delegations || []) { - let worker = workers.get(d.worker.id); - if (!worker) { - worker = new BlockchainApiWorker({ worker: d.worker }); - worker.myDelegations = []; - workers.set(worker.id, worker); - } - worker.myDelegations.push(d); - } - return [...workers.values()]; - }, [data?.delegations]); + const workers = useMemo(() => { + return ( + data?.workers.map(w => { + return { + ...w, + delegationCapacity: calculateDelegationCapacity({ + totalDelegation: w.totalDelegation, + capedDelegation: w.capedDelegation, + }), + }; + }) || [] + ); + }, [data]); return { isLoading: isSettingsLoading || isLoading, - delegations, + workers, }; } @@ -421,9 +391,15 @@ export function useIsWorkerOperator() { }; } -export function useWorkerRewardStats(workerId?: string) { +export function useWorkerDelegationInfo({ + workerId, + enabled, +}: { + workerId?: string; + enabled?: boolean; +}) { const datasource = useSquidDataSource(); - const { data, isLoading } = useWorkerRewardStatsQuery( + const { data, isLoading } = useWorkerDelegationInfoQuery( datasource, { workerId: workerId || '', @@ -431,10 +407,61 @@ export function useWorkerRewardStats(workerId?: string) { { select: res => { return { - ...res.workerById, - ...res.statistics[0], + worker: res.workerById, + info: res.statistics[0], }; }, + enabled, + }, + ); + + return { + isLoading: isLoading, + data, + }; +} + +export function useWorkerOwner({ workerId, enabled }: { workerId?: string; enabled?: boolean }) { + const datasource = useSquidDataSource(); + const { data, isLoading } = useWorkerOwnerQuery( + datasource, + { + workerId: workerId || '', + }, + { + select: res => { + return res.workerById; + }, + enabled, + }, + ); + + return { + isLoading: isLoading, + data, + }; +} + +export function useMyWorkerDelegations({ + workerId, + enabled, +}: { + workerId?: string; + enabled?: boolean; +}) { + const { address } = useAccount(); + const datasource = useSquidDataSource(); + const { data, isLoading } = useMyWorkerDelegationsQuery( + datasource, + { + workerId: workerId || '', + address: address || '', + }, + { + select: res => { + return res.workerById; + }, + enabled, }, ); diff --git a/src/pages/DelegationsPage/DelegationsPage.tsx b/src/pages/DelegationsPage/DelegationsPage.tsx index a08338e..dfbf727 100644 --- a/src/pages/DelegationsPage/DelegationsPage.tsx +++ b/src/pages/DelegationsPage/DelegationsPage.tsx @@ -21,14 +21,14 @@ import { WorkerStatus } from '@pages/WorkersPage/WorkerStatus'; import { WorkerUndelegate } from '@pages/WorkersPage/WorkerUndelegate'; export function MyDelegations() { - const { delegations, isLoading } = useMyDelegations(); + const { workers: delegations, isLoading } = useMyDelegations(); const { SQD_TOKEN } = useContracts(); const groupedDelegations = useMemo(() => { return mapValues( keyBy(delegations, w => w.id), w => { - return w.myDelegations.reduce( + return w.delegations.reduce( (s, d) => { s.deposit = s.deposit.plus(d.deposit); s.reward = s.reward.plus(d.claimedReward).plus(d.claimableReward); diff --git a/src/pages/WorkersPage/DelegationCapacity.tsx b/src/pages/WorkersPage/DelegationCapacity.tsx index 03e088a..9f2048b 100644 --- a/src/pages/WorkersPage/DelegationCapacity.tsx +++ b/src/pages/WorkersPage/DelegationCapacity.tsx @@ -2,8 +2,6 @@ import { percentFormatter } from '@lib/formatters/formatters'; import { Box, Stack, styled } from '@mui/material'; import classNames from 'classnames'; -import { BlockchainApiWorker } from '@api/subsquid-network-squid'; - export const Bar = styled(Box)(({ theme }) => ({ width: theme.spacing(0.75), height: theme.spacing(2), @@ -33,11 +31,7 @@ export const BarWrapper = styled(Box)(({ theme }) => ({ const BARS_COUNT = 5; const RANGES = Array.from({ length: BARS_COUNT }, (_, i) => (i * 100) / BARS_COUNT); -export function DelegationCapacity({ - worker, -}: { - worker: Pick; -}) { +export function DelegationCapacity({ worker }: { worker: { delegationCapacity: number } }) { const delegationCapacity = worker.delegationCapacity || 0; const color = delegationCapacity >= 80 ? 'error' : delegationCapacity >= 40 ? 'warning' : 'success'; diff --git a/src/pages/WorkersPage/UptimeGraph.tsx b/src/pages/WorkersPage/UptimeGraph.tsx index c5b24c6..a10ed95 100644 --- a/src/pages/WorkersPage/UptimeGraph.tsx +++ b/src/pages/WorkersPage/UptimeGraph.tsx @@ -5,7 +5,7 @@ import { percentFormatter } from '@lib/formatters/formatters.ts'; import { Box, styled, useMediaQuery, useTheme } from '@mui/material'; import { keyBy } from 'lodash-es'; -import { BlockchainApiFullWorker } from '@api/subsquid-network-squid'; +import { Worker } from '@api/subsquid-network-squid'; import { StatusBar } from './StatusBar'; @@ -31,7 +31,11 @@ const StyledNotes = styled(Box)(({ theme }) => ({ const oneDayInMilliseconds = 24 * 60 * 60 * 1000; -export const UptimeGraph = ({ worker }: { worker: BlockchainApiFullWorker }) => { +export const UptimeGraph = ({ + worker, +}: { + worker: Pick; +}) => { const theme = useTheme(); const w1200 = useMediaQuery(theme.breakpoints.up(1200)); const w1000 = useMediaQuery(theme.breakpoints.up(1000)); diff --git a/src/pages/WorkersPage/Worker.tsx b/src/pages/WorkersPage/Worker.tsx index 8215ccf..879fbc5 100644 --- a/src/pages/WorkersPage/Worker.tsx +++ b/src/pages/WorkersPage/Worker.tsx @@ -1,20 +1,31 @@ -import React from 'react'; - -import { Stack } from '@mui/material'; -import { Box } from '@mui/system'; +import { dateFormat } from '@i18n'; +import { + bytesFormatter, + numberWithSpacesFormatter, + percentFormatter, + tokenFormatter, + urlFormatter, +} from '@lib/formatters/formatters.ts'; +import { fromSqd } from '@lib/network'; +import { Box, Divider, Stack, styled } from '@mui/material'; import { useParams, useSearchParams } from 'react-router-dom'; import { useWorkerByPeerId, WorkerStatus } from '@api/subsquid-network-squid'; import { Card } from '@components/Card'; +import { CopyToClipboard } from '@components/CopyToClipboard'; import { Loader } from '@components/Loader'; import { NotFound } from '@components/NotFound'; import { CenteredPageWrapper, NetworkPageTitle } from '@layouts/NetworkLayout'; +import { useAccount } from '@network/useAccount'; +import { useContracts } from '@network/useContracts'; import { WorkerUnregister } from '@pages/WorkersPage/WorkerUnregister'; +import { DelegationCapacity } from './DelegationCapacity'; +import { UptimeGraph } from './UptimeGraph'; import { WorkerCard } from './WorkerCard'; import { WorkerDelegate } from './WorkerDelegate'; -import { WorkerStatistics } from './WorkerStatistics'; import { WorkerUndelegate } from './WorkerUndelegate'; +import { WorkerVersion } from './WorkerVersion'; // const sx = { // background: '#000', @@ -26,9 +37,56 @@ import { WorkerUndelegate } from './WorkerUndelegate'; // }, // }; +export const WorkerDescLabel = styled(Box, { + name: 'WorkerDescLabel', +})(({ theme }) => ({ + flex: 0.5, + color: theme.palette.text.secondary, + whiteSpace: 'balance', + maxWidth: theme.spacing(25), + fontSize: '1rem', +})); + +export const WorkerColumn = styled(Box, { + name: 'WorkerDescLabel', +})(() => ({ + flex: 1, +})); + +export const WorkerDescTable = styled(Box, { + name: 'WorkerDescTable', +})(() => ({ + flex: 1, +})); + +export const WorkerDescRow = styled(Box, { + name: 'WorkerDescRow', +})(({ theme }) => ({ + display: 'flex', + alignItems: 'flex-start', + margin: theme.spacing(5, 0), + lineHeight: 1.4, +})); + +export const WorkerDescValue = styled(Box, { + name: 'WorkerDescValue', +})(({ theme }) => ({ + flex: 1, + marginLeft: theme.spacing(2), + overflowWrap: 'anywhere', +})); + +export const Title = styled(Box)(({ theme }) => ({ + fontSize: '1.25rem', + lineHeight: 1, + marginBottom: theme.spacing(3), +})); + export const Worker = ({ backPath }: { backPath: string }) => { const { peerId } = useParams<{ peerId: string }>(); const { data: worker, isPending } = useWorkerByPeerId(peerId); + const { address } = useAccount(); + const { SQD_TOKEN } = useContracts(); const [searchParams] = useSearchParams(); @@ -51,12 +109,150 @@ export const Worker = ({ backPath }: { backPath: string }) => { ) : ( <> - + - + }> + + + + Registered + {dateFormat(worker.createdAt, 'dateTime')} + + + Version + + + + + + Website + + {worker.website ? ( + + {urlFormatter(worker.website)} + + ) : ( + '-' + )} + + + + Contact + + {worker.email ? : '-'} + + + + Description + {worker.description || '-'} + + + + + }> + + Bond + + + Bonded + + {tokenFormatter(fromSqd(worker.bond), SQD_TOKEN)} + + + + Worker APR + + {worker.apr != null ? percentFormatter(worker.apr) : '-'} + + + + Total reward + + {tokenFormatter( + fromSqd(worker.claimableReward).plus(worker.claimedReward), + SQD_TOKEN, + )} + + + + + + + Delegation + + + Delegators + {worker.delegationCount} + + + Total delegation + + {tokenFormatter(fromSqd(worker.totalDelegation), SQD_TOKEN)} + + + + Delegation capacity + + + + + + Delegator APR + + {worker.stakerApr != null ? percentFormatter(worker.stakerApr) : '-'} + + + + Total reward + + {tokenFormatter(fromSqd(worker.totalDelegationRewards), SQD_TOKEN)} + + + + + + + Statistics + + + Uptime, 24h / 90d + + {percentFormatter(worker.uptime24Hours)} /{' '} + {percentFormatter(worker.uptime90Days)} + + + + Queries, 24h / 90d + + {numberWithSpacesFormatter(worker.queries24Hours)} /{' '} + {numberWithSpacesFormatter(worker.queries90Days)} + + + + Data served, 24h / 90d + + {bytesFormatter(worker.servedData24Hours)} /{' '} + {bytesFormatter(worker.servedData90Days)} + + + + Data stored + {bytesFormatter(worker.storedData)} + + + + + + - {worker.ownedByMe && worker.status !== WorkerStatus.Withdrawn ? ( + {worker.realOwner.id === address && worker.status !== WorkerStatus.Withdrawn ? ( diff --git a/src/pages/WorkersPage/WorkerCard.tsx b/src/pages/WorkersPage/WorkerCard.tsx index f154485..332dd07 100644 --- a/src/pages/WorkersPage/WorkerCard.tsx +++ b/src/pages/WorkersPage/WorkerCard.tsx @@ -1,10 +1,8 @@ -import React from 'react'; - import { IconButton, Stack, styled, useMediaQuery, useTheme } from '@mui/material'; import { Box } from '@mui/system'; import { Link } from 'react-router-dom'; -import { BlockchainApiFullWorker } from '@api/subsquid-network-squid'; +import { Worker, WorkerStatusFragmentFragment } from '@api/subsquid-network-squid'; import { Avatar } from '@components/Avatar'; import { CopyToClipboard } from '@components/CopyToClipboard'; import { shortPeerId } from '@components/PeerId'; @@ -21,13 +19,19 @@ export const PeerIdRow = styled(Box, { overflowWrap: 'anywhere', })); -function WorkerTitle({ worker }: { worker: BlockchainApiFullWorker }) { +function WorkerTitle({ + worker, + canEdit, +}: { + worker: Pick; + canEdit: boolean; +}) { return ( {worker.name || worker.peerId} - {worker.canEdit() ? ( + {canEdit ? ( @@ -36,7 +40,13 @@ function WorkerTitle({ worker }: { worker: BlockchainApiFullWorker }) { ); } -export const WorkerCard = ({ worker }: { worker: BlockchainApiFullWorker }) => { +export const WorkerCard = ({ + worker, + canEdit, +}: { + worker: Pick & WorkerStatusFragmentFragment; + canEdit: boolean; +}) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('xs')); @@ -49,7 +59,7 @@ export const WorkerCard = ({ worker }: { worker: BlockchainApiFullWorker }) => { size={100} /> - + { - {/* {worker.description} */} ); }; diff --git a/src/pages/WorkersPage/WorkerDelegate.tsx b/src/pages/WorkersPage/WorkerDelegate.tsx index 492d372..77972d1 100644 --- a/src/pages/WorkersPage/WorkerDelegate.tsx +++ b/src/pages/WorkersPage/WorkerDelegate.tsx @@ -9,7 +9,7 @@ import { useFormik } from 'formik'; import { useDebounce } from 'use-debounce'; import { useCapedStakeAfterDelegation, useWorkerDelegate } from '@api/contracts/staking'; -import { BlockchainApiWorker, useWorkerRewardStats } from '@api/subsquid-network-squid'; +import { Worker, WorkerStatus, useWorkerDelegationInfo } from '@api/subsquid-network-squid'; import { BlockchainContractError } from '@components/BlockchainContractError'; import { ContractCallDialog } from '@components/ContractCallDialog'; import { Form, FormikSelect, FormikTextInput, FormRow } from '@components/Form'; @@ -40,7 +40,7 @@ export function WorkerDelegate({ worker, disabled, }: { - worker?: BlockchainApiWorker; + worker?: Pick; disabled?: boolean; }) { const { delegateToWorker, error, isLoading } = useWorkerDelegate(); @@ -112,7 +112,7 @@ export function WorkerDelegate({ return ( <>