diff --git a/src/api/contracts/soft-cap.abi.ts b/src/api/contracts/soft-cap.abi.ts new file mode 100644 index 0000000..2f3a6f8 --- /dev/null +++ b/src/api/contracts/soft-cap.abi.ts @@ -0,0 +1,26 @@ +export const SOFT_CAP_ABI = [ + { + type: 'function', + name: 'cap', + inputs: [{ name: 'x', type: 'uint256', internalType: 'UD60x18' }], + outputs: [{ name: '', type: 'uint256', internalType: 'UD60x18' }], + stateMutability: 'pure', + }, + { + type: 'function', + name: 'capedStake', + inputs: [{ name: 'workerId', type: 'uint256', internalType: 'uint256' }], + outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }], + stateMutability: 'view', + }, + { + type: 'function', + name: 'capedStakeAfterDelegation', + inputs: [ + { name: 'workerId', type: 'uint256', internalType: 'uint256' }, + { name: 'delegationAmount', type: 'int256', internalType: 'int256' }, + ], + outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }], + stateMutability: 'view', + }, +] as const; diff --git a/src/api/contracts/staking.ts b/src/api/contracts/staking.ts index edfc828..14263ee 100644 --- a/src/api/contracts/staking.ts +++ b/src/api/contracts/staking.ts @@ -1,10 +1,10 @@ -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { logger } from '@logger'; import Decimal from 'decimal.js'; import { encodeFunctionData } from 'viem'; import { waitForTransactionReceipt } from 'viem/actions'; -import { useWriteContract, usePublicClient, useClient } from 'wagmi'; +import { useWriteContract, usePublicClient, useClient, useReadContract } from 'wagmi'; import { useApproveSqd } from '@api/contracts/sqd'; import { @@ -19,6 +19,7 @@ import { useSquidNetworkHeightHooks } from '@hooks/useSquidNetworkHeightHooks.ts import { useAccount } from '@network/useAccount'; import { useContracts } from '@network/useContracts.ts'; +import { SOFT_CAP_ABI } from './soft-cap.abi'; import { STAKING_CONTRACT_ABI } from './staking.abi'; type WorkerDepositRequest = { @@ -232,3 +233,29 @@ export function useWorkerUndelegate() { error, }; } + +export function useCapedStake({ workerId }: { workerId?: string }) { + const contracts = useContracts(); + const { currentHeight, isLoading: isHeightLoading } = useSquidNetworkHeightHooks(); + + const { data, isLoading } = useReadContract({ + address: contracts.SOFT_CAP, + abi: SOFT_CAP_ABI, + functionName: 'capedStake', + args: [BigInt(workerId || -1)], + blockNumber: BigInt(currentHeight), + query: { + enabled: !!workerId && !isHeightLoading, + }, + }); + + const res = useRef(undefined); + useEffect(() => { + if (!isLoading) res.current = data?.toString(); + }, [data, isLoading]); + + return { + data: res.current, + isLoading: !res.current, + }; +} diff --git a/src/api/contracts/vesting.ts b/src/api/contracts/vesting.ts index 23dc352..415a611 100644 --- a/src/api/contracts/vesting.ts +++ b/src/api/contracts/vesting.ts @@ -13,9 +13,9 @@ import { VESTING_CONTRACT_ABI } from './vesting.abi'; export function useVestingContracts({ addresses }: { addresses: `0x${string}`[] }) { const contracts = useContracts(); - const { currentHeight, isLoading: isHeightLoading } = useSquidNetworkHeightHooks(); + const { currentHeight, isLoading: isSquidHeightLoading } = useSquidNetworkHeightHooks(); - const { data: res } = useReadContracts({ + const { data, isLoading } = useReadContracts({ contracts: addresses.flatMap(address => { const vestingContract = { abi: VESTING_CONTRACT_ABI, address } as const; return [ @@ -60,48 +60,48 @@ export function useVestingContracts({ addresses }: { addresses: `0x${string}`[] allowFailure: true, blockNumber: BigInt(currentHeight), query: { - enabled: !isHeightLoading && !!addresses.length, + enabled: !isSquidHeightLoading && !!addresses.length, + select: r => { + if (r?.some(r => r.status === 'success')) { + return chunk(r, 8).map(ch => ({ + start: Number(unwrapResult(ch[0])) * 1000, + end: Number(unwrapResult(ch[1])) * 1000, + deposited: unwrapResult(ch[2])?.toString(), + releasable: unwrapResult(ch[3])?.toString(), + released: unwrapResult(ch[4])?.toString(), + balance: unwrapResult(ch[5])?.toString(), + initialRelease: Number(unwrapResult(ch[6]) || 0) / 100, + expectedTotal: unwrapResult(ch[7])?.toString(), + })); + } else { + return res.current; + } + }, }, }); - const data = useRef< + const res = useRef< | { start?: number; end?: number; - deposited?: string | undefined; - releasable?: string | undefined; - released?: string | undefined; - balance?: string | undefined; + deposited?: string; + releasable?: string; + released?: string; + balance?: string; initialRelease?: number; - expectedTotal?: string | undefined; + expectedTotal?: string; }[] | undefined >(undefined); - useEffect(() => { - if (res?.some(r => r.status === 'success')) { - data.current = chunk(res, 8).map(ch => ({ - start: Number(unwrapResult(ch[0])) * 1000, - end: Number(unwrapResult(ch[1])) * 1000, - deposited: unwrapResult(ch[2])?.toString(), - releasable: unwrapResult(ch[3])?.toString(), - released: unwrapResult(ch[4])?.toString(), - balance: unwrapResult(ch[5])?.toString(), - initialRelease: Number(unwrapResult(ch[6]) || 0) / 100, - expectedTotal: unwrapResult(ch[7])?.toString(), - })); - } - }, [res]); - - return addresses.length - ? { - data: data.current, - isLoading: !data.current, - } - : { - data: [], - isLoading: false, - }; + if (!addresses.length) res.current = []; + if (!isLoading) res.current = data; + }, [addresses, data, isLoading]); + + return { + data: res.current, + isLoading: !res.current, + }; } export function useVestingContract({ address }: { address?: `0x${string}` }) { diff --git a/src/api/subsquid-network-squid/api.graphql b/src/api/subsquid-network-squid/api.graphql index 023b5f2..1102f6a 100644 --- a/src/api/subsquid-network-squid/api.graphql +++ b/src/api/subsquid-network-squid/api.graphql @@ -40,18 +40,16 @@ query account($address: String!) { fragment WorkerFragment on Worker { id name - email peerId - website status createdAt - description bond claimableReward claimedReward uptime24Hours uptime90Days totalDelegation + capedDelegation delegationCount apr stakerApr @@ -71,6 +69,10 @@ fragment WorkerFragment on Worker { } fragment WorkerFullFragment on Worker { + totalDelegationRewards + website + email + description queries24Hours queries90Days scannedData24Hours diff --git a/src/api/subsquid-network-squid/graphql.tsx b/src/api/subsquid-network-squid/graphql.tsx index f4ecb4e..cb847e8 100644 --- a/src/api/subsquid-network-squid/graphql.tsx +++ b/src/api/subsquid-network-squid/graphql.tsx @@ -650,6 +650,12 @@ export enum ClaimOrderByInput { WorkerBondDesc = 'worker_bond_DESC', WorkerBondDescNullsFirst = 'worker_bond_DESC_NULLS_FIRST', WorkerBondDescNullsLast = 'worker_bond_DESC_NULLS_LAST', + WorkerCapedDelegationAsc = 'worker_capedDelegation_ASC', + WorkerCapedDelegationAscNullsFirst = 'worker_capedDelegation_ASC_NULLS_FIRST', + WorkerCapedDelegationAscNullsLast = 'worker_capedDelegation_ASC_NULLS_LAST', + WorkerCapedDelegationDesc = 'worker_capedDelegation_DESC', + WorkerCapedDelegationDescNullsFirst = 'worker_capedDelegation_DESC_NULLS_FIRST', + WorkerCapedDelegationDescNullsLast = 'worker_capedDelegation_DESC_NULLS_LAST', WorkerClaimableRewardAsc = 'worker_claimableReward_ASC', WorkerClaimableRewardAscNullsFirst = 'worker_claimableReward_ASC_NULLS_FIRST', WorkerClaimableRewardAscNullsLast = 'worker_claimableReward_ASC_NULLS_LAST', @@ -800,6 +806,12 @@ export enum ClaimOrderByInput { WorkerStoredDataDesc = 'worker_storedData_DESC', WorkerStoredDataDescNullsFirst = 'worker_storedData_DESC_NULLS_FIRST', WorkerStoredDataDescNullsLast = 'worker_storedData_DESC_NULLS_LAST', + WorkerTotalDelegationRewardsAsc = 'worker_totalDelegationRewards_ASC', + WorkerTotalDelegationRewardsAscNullsFirst = 'worker_totalDelegationRewards_ASC_NULLS_FIRST', + WorkerTotalDelegationRewardsAscNullsLast = 'worker_totalDelegationRewards_ASC_NULLS_LAST', + WorkerTotalDelegationRewardsDesc = 'worker_totalDelegationRewards_DESC', + WorkerTotalDelegationRewardsDescNullsFirst = 'worker_totalDelegationRewards_DESC_NULLS_FIRST', + WorkerTotalDelegationRewardsDescNullsLast = 'worker_totalDelegationRewards_DESC_NULLS_LAST', WorkerTotalDelegationAsc = 'worker_totalDelegation_ASC', WorkerTotalDelegationAscNullsFirst = 'worker_totalDelegation_ASC_NULLS_FIRST', WorkerTotalDelegationAscNullsLast = 'worker_totalDelegation_ASC_NULLS_LAST', @@ -1168,6 +1180,12 @@ export enum DelegationOrderByInput { WorkerBondDesc = 'worker_bond_DESC', WorkerBondDescNullsFirst = 'worker_bond_DESC_NULLS_FIRST', WorkerBondDescNullsLast = 'worker_bond_DESC_NULLS_LAST', + WorkerCapedDelegationAsc = 'worker_capedDelegation_ASC', + WorkerCapedDelegationAscNullsFirst = 'worker_capedDelegation_ASC_NULLS_FIRST', + WorkerCapedDelegationAscNullsLast = 'worker_capedDelegation_ASC_NULLS_LAST', + WorkerCapedDelegationDesc = 'worker_capedDelegation_DESC', + WorkerCapedDelegationDescNullsFirst = 'worker_capedDelegation_DESC_NULLS_FIRST', + WorkerCapedDelegationDescNullsLast = 'worker_capedDelegation_DESC_NULLS_LAST', WorkerClaimableRewardAsc = 'worker_claimableReward_ASC', WorkerClaimableRewardAscNullsFirst = 'worker_claimableReward_ASC_NULLS_FIRST', WorkerClaimableRewardAscNullsLast = 'worker_claimableReward_ASC_NULLS_LAST', @@ -1318,6 +1336,12 @@ export enum DelegationOrderByInput { WorkerStoredDataDesc = 'worker_storedData_DESC', WorkerStoredDataDescNullsFirst = 'worker_storedData_DESC_NULLS_FIRST', WorkerStoredDataDescNullsLast = 'worker_storedData_DESC_NULLS_LAST', + WorkerTotalDelegationRewardsAsc = 'worker_totalDelegationRewards_ASC', + WorkerTotalDelegationRewardsAscNullsFirst = 'worker_totalDelegationRewards_ASC_NULLS_FIRST', + WorkerTotalDelegationRewardsAscNullsLast = 'worker_totalDelegationRewards_ASC_NULLS_LAST', + WorkerTotalDelegationRewardsDesc = 'worker_totalDelegationRewards_DESC', + WorkerTotalDelegationRewardsDescNullsFirst = 'worker_totalDelegationRewards_DESC_NULLS_FIRST', + WorkerTotalDelegationRewardsDescNullsLast = 'worker_totalDelegationRewards_DESC_NULLS_LAST', WorkerTotalDelegationAsc = 'worker_totalDelegation_ASC', WorkerTotalDelegationAscNullsFirst = 'worker_totalDelegation_ASC_NULLS_FIRST', WorkerTotalDelegationAscNullsLast = 'worker_totalDelegation_ASC_NULLS_LAST', @@ -3526,6 +3550,7 @@ export type Worker = { __typename?: 'Worker'; apr?: Maybe; bond: Scalars['BigInt']['output']; + capedDelegation: Scalars['BigInt']['output']; claimableReward: Scalars['BigInt']['output']; claimedReward: Scalars['BigInt']['output']; claims: Array; @@ -3561,6 +3586,7 @@ export type Worker = { statusHistory: Array; storedData?: Maybe; totalDelegation: Scalars['BigInt']['output']; + totalDelegationRewards: Scalars['BigInt']['output']; uptime24Hours?: Maybe; uptime90Days?: Maybe; version?: Maybe; @@ -3627,6 +3653,12 @@ export enum WorkerOrderByInput { BondDesc = 'bond_DESC', BondDescNullsFirst = 'bond_DESC_NULLS_FIRST', BondDescNullsLast = 'bond_DESC_NULLS_LAST', + CapedDelegationAsc = 'capedDelegation_ASC', + CapedDelegationAscNullsFirst = 'capedDelegation_ASC_NULLS_FIRST', + CapedDelegationAscNullsLast = 'capedDelegation_ASC_NULLS_LAST', + CapedDelegationDesc = 'capedDelegation_DESC', + CapedDelegationDescNullsFirst = 'capedDelegation_DESC_NULLS_FIRST', + CapedDelegationDescNullsLast = 'capedDelegation_DESC_NULLS_LAST', ClaimableRewardAsc = 'claimableReward_ASC', ClaimableRewardAscNullsFirst = 'claimableReward_ASC_NULLS_FIRST', ClaimableRewardAscNullsLast = 'claimableReward_ASC_NULLS_LAST', @@ -3825,6 +3857,12 @@ export enum WorkerOrderByInput { StoredDataDesc = 'storedData_DESC', StoredDataDescNullsFirst = 'storedData_DESC_NULLS_FIRST', StoredDataDescNullsLast = 'storedData_DESC_NULLS_LAST', + TotalDelegationRewardsAsc = 'totalDelegationRewards_ASC', + TotalDelegationRewardsAscNullsFirst = 'totalDelegationRewards_ASC_NULLS_FIRST', + TotalDelegationRewardsAscNullsLast = 'totalDelegationRewards_ASC_NULLS_LAST', + TotalDelegationRewardsDesc = 'totalDelegationRewards_DESC', + TotalDelegationRewardsDescNullsFirst = 'totalDelegationRewards_DESC_NULLS_FIRST', + TotalDelegationRewardsDescNullsLast = 'totalDelegationRewards_DESC_NULLS_LAST', TotalDelegationAsc = 'totalDelegation_ASC', TotalDelegationAscNullsFirst = 'totalDelegation_ASC_NULLS_FIRST', TotalDelegationAscNullsLast = 'totalDelegation_ASC_NULLS_LAST', @@ -3916,6 +3954,12 @@ export enum WorkerRewardOrderByInput { WorkerBondDesc = 'worker_bond_DESC', WorkerBondDescNullsFirst = 'worker_bond_DESC_NULLS_FIRST', WorkerBondDescNullsLast = 'worker_bond_DESC_NULLS_LAST', + WorkerCapedDelegationAsc = 'worker_capedDelegation_ASC', + WorkerCapedDelegationAscNullsFirst = 'worker_capedDelegation_ASC_NULLS_FIRST', + WorkerCapedDelegationAscNullsLast = 'worker_capedDelegation_ASC_NULLS_LAST', + WorkerCapedDelegationDesc = 'worker_capedDelegation_DESC', + WorkerCapedDelegationDescNullsFirst = 'worker_capedDelegation_DESC_NULLS_FIRST', + WorkerCapedDelegationDescNullsLast = 'worker_capedDelegation_DESC_NULLS_LAST', WorkerClaimableRewardAsc = 'worker_claimableReward_ASC', WorkerClaimableRewardAscNullsFirst = 'worker_claimableReward_ASC_NULLS_FIRST', WorkerClaimableRewardAscNullsLast = 'worker_claimableReward_ASC_NULLS_LAST', @@ -4066,6 +4110,12 @@ export enum WorkerRewardOrderByInput { WorkerStoredDataDesc = 'worker_storedData_DESC', WorkerStoredDataDescNullsFirst = 'worker_storedData_DESC_NULLS_FIRST', WorkerStoredDataDescNullsLast = 'worker_storedData_DESC_NULLS_LAST', + WorkerTotalDelegationRewardsAsc = 'worker_totalDelegationRewards_ASC', + WorkerTotalDelegationRewardsAscNullsFirst = 'worker_totalDelegationRewards_ASC_NULLS_FIRST', + WorkerTotalDelegationRewardsAscNullsLast = 'worker_totalDelegationRewards_ASC_NULLS_LAST', + WorkerTotalDelegationRewardsDesc = 'worker_totalDelegationRewards_DESC', + WorkerTotalDelegationRewardsDescNullsFirst = 'worker_totalDelegationRewards_DESC_NULLS_FIRST', + WorkerTotalDelegationRewardsDescNullsLast = 'worker_totalDelegationRewards_DESC_NULLS_LAST', WorkerTotalDelegationAsc = 'worker_totalDelegation_ASC', WorkerTotalDelegationAscNullsFirst = 'worker_totalDelegation_ASC_NULLS_FIRST', WorkerTotalDelegationAscNullsLast = 'worker_totalDelegation_ASC_NULLS_LAST', @@ -4259,6 +4309,12 @@ export enum WorkerSnapshotOrderByInput { WorkerBondDesc = 'worker_bond_DESC', WorkerBondDescNullsFirst = 'worker_bond_DESC_NULLS_FIRST', WorkerBondDescNullsLast = 'worker_bond_DESC_NULLS_LAST', + WorkerCapedDelegationAsc = 'worker_capedDelegation_ASC', + WorkerCapedDelegationAscNullsFirst = 'worker_capedDelegation_ASC_NULLS_FIRST', + WorkerCapedDelegationAscNullsLast = 'worker_capedDelegation_ASC_NULLS_LAST', + WorkerCapedDelegationDesc = 'worker_capedDelegation_DESC', + WorkerCapedDelegationDescNullsFirst = 'worker_capedDelegation_DESC_NULLS_FIRST', + WorkerCapedDelegationDescNullsLast = 'worker_capedDelegation_DESC_NULLS_LAST', WorkerClaimableRewardAsc = 'worker_claimableReward_ASC', WorkerClaimableRewardAscNullsFirst = 'worker_claimableReward_ASC_NULLS_FIRST', WorkerClaimableRewardAscNullsLast = 'worker_claimableReward_ASC_NULLS_LAST', @@ -4409,6 +4465,12 @@ export enum WorkerSnapshotOrderByInput { WorkerStoredDataDesc = 'worker_storedData_DESC', WorkerStoredDataDescNullsFirst = 'worker_storedData_DESC_NULLS_FIRST', WorkerStoredDataDescNullsLast = 'worker_storedData_DESC_NULLS_LAST', + WorkerTotalDelegationRewardsAsc = 'worker_totalDelegationRewards_ASC', + WorkerTotalDelegationRewardsAscNullsFirst = 'worker_totalDelegationRewards_ASC_NULLS_FIRST', + WorkerTotalDelegationRewardsAscNullsLast = 'worker_totalDelegationRewards_ASC_NULLS_LAST', + WorkerTotalDelegationRewardsDesc = 'worker_totalDelegationRewards_DESC', + WorkerTotalDelegationRewardsDescNullsFirst = 'worker_totalDelegationRewards_DESC_NULLS_FIRST', + WorkerTotalDelegationRewardsDescNullsLast = 'worker_totalDelegationRewards_DESC_NULLS_LAST', WorkerTotalDelegationAsc = 'worker_totalDelegation_ASC', WorkerTotalDelegationAscNullsFirst = 'worker_totalDelegation_ASC_NULLS_FIRST', WorkerTotalDelegationAscNullsLast = 'worker_totalDelegation_ASC_NULLS_LAST', @@ -4560,6 +4622,12 @@ export enum WorkerStatusChangeOrderByInput { WorkerBondDesc = 'worker_bond_DESC', WorkerBondDescNullsFirst = 'worker_bond_DESC_NULLS_FIRST', WorkerBondDescNullsLast = 'worker_bond_DESC_NULLS_LAST', + WorkerCapedDelegationAsc = 'worker_capedDelegation_ASC', + WorkerCapedDelegationAscNullsFirst = 'worker_capedDelegation_ASC_NULLS_FIRST', + WorkerCapedDelegationAscNullsLast = 'worker_capedDelegation_ASC_NULLS_LAST', + WorkerCapedDelegationDesc = 'worker_capedDelegation_DESC', + WorkerCapedDelegationDescNullsFirst = 'worker_capedDelegation_DESC_NULLS_FIRST', + WorkerCapedDelegationDescNullsLast = 'worker_capedDelegation_DESC_NULLS_LAST', WorkerClaimableRewardAsc = 'worker_claimableReward_ASC', WorkerClaimableRewardAscNullsFirst = 'worker_claimableReward_ASC_NULLS_FIRST', WorkerClaimableRewardAscNullsLast = 'worker_claimableReward_ASC_NULLS_LAST', @@ -4710,6 +4778,12 @@ export enum WorkerStatusChangeOrderByInput { WorkerStoredDataDesc = 'worker_storedData_DESC', WorkerStoredDataDescNullsFirst = 'worker_storedData_DESC_NULLS_FIRST', WorkerStoredDataDescNullsLast = 'worker_storedData_DESC_NULLS_LAST', + WorkerTotalDelegationRewardsAsc = 'worker_totalDelegationRewards_ASC', + WorkerTotalDelegationRewardsAscNullsFirst = 'worker_totalDelegationRewards_ASC_NULLS_FIRST', + WorkerTotalDelegationRewardsAscNullsLast = 'worker_totalDelegationRewards_ASC_NULLS_LAST', + WorkerTotalDelegationRewardsDesc = 'worker_totalDelegationRewards_DESC', + WorkerTotalDelegationRewardsDescNullsFirst = 'worker_totalDelegationRewards_DESC_NULLS_FIRST', + WorkerTotalDelegationRewardsDescNullsLast = 'worker_totalDelegationRewards_DESC_NULLS_LAST', WorkerTotalDelegationAsc = 'worker_totalDelegation_ASC', WorkerTotalDelegationAscNullsFirst = 'worker_totalDelegation_ASC_NULLS_FIRST', WorkerTotalDelegationAscNullsLast = 'worker_totalDelegation_ASC_NULLS_LAST', @@ -4820,6 +4894,15 @@ export type WorkerWhereInput = { bond_lte?: InputMaybe; bond_not_eq?: InputMaybe; bond_not_in?: InputMaybe>; + capedDelegation_eq?: InputMaybe; + capedDelegation_gt?: InputMaybe; + capedDelegation_gte?: InputMaybe; + capedDelegation_in?: InputMaybe>; + capedDelegation_isNull?: InputMaybe; + capedDelegation_lt?: InputMaybe; + capedDelegation_lte?: InputMaybe; + capedDelegation_not_eq?: InputMaybe; + capedDelegation_not_in?: InputMaybe>; claimableReward_eq?: InputMaybe; claimableReward_gt?: InputMaybe; claimableReward_gte?: InputMaybe; @@ -5085,6 +5168,15 @@ export type WorkerWhereInput = { storedData_lte?: InputMaybe; storedData_not_eq?: InputMaybe; storedData_not_in?: InputMaybe>; + totalDelegationRewards_eq?: InputMaybe; + totalDelegationRewards_gt?: InputMaybe; + totalDelegationRewards_gte?: InputMaybe; + totalDelegationRewards_in?: InputMaybe>; + totalDelegationRewards_isNull?: InputMaybe; + totalDelegationRewards_lt?: InputMaybe; + totalDelegationRewards_lte?: InputMaybe; + totalDelegationRewards_not_eq?: InputMaybe; + totalDelegationRewards_not_in?: InputMaybe>; totalDelegation_eq?: InputMaybe; totalDelegation_gt?: InputMaybe; totalDelegation_gte?: InputMaybe; @@ -5201,18 +5293,16 @@ export type WorkerFragmentFragment = { __typename?: 'Worker'; id: string; name?: string; - email?: string; peerId: string; - website?: string; status: WorkerStatus; createdAt: any; - description?: string; bond: any; claimableReward: any; claimedReward: any; uptime24Hours?: number; uptime90Days?: number; totalDelegation: any; + capedDelegation: any; delegationCount: number; apr?: number; stakerApr?: number; @@ -5228,6 +5318,10 @@ export type WorkerFragmentFragment = { export type WorkerFullFragmentFragment = { __typename?: 'Worker'; + totalDelegationRewards: any; + website?: string; + email?: string; + description?: string; queries24Hours?: any; queries90Days?: any; scannedData24Hours?: any; @@ -5247,18 +5341,16 @@ export type AllWorkersQuery = { __typename?: 'Worker'; id: string; name?: string; - email?: string; peerId: string; - website?: string; status: WorkerStatus; createdAt: any; - description?: string; bond: any; claimableReward: any; claimedReward: any; uptime24Hours?: number; uptime90Days?: number; totalDelegation: any; + capedDelegation: any; delegationCount: number; apr?: number; stakerApr?: number; @@ -5284,18 +5376,16 @@ export type WorkerByPeerIdQuery = { __typename?: 'Worker'; id: string; name?: string; - email?: string; peerId: string; - website?: string; status: WorkerStatus; createdAt: any; - description?: string; bond: any; claimableReward: any; claimedReward: any; uptime24Hours?: number; uptime90Days?: number; totalDelegation: any; + capedDelegation: any; delegationCount: number; apr?: number; stakerApr?: number; @@ -5305,6 +5395,10 @@ export type WorkerByPeerIdQuery = { locked?: boolean; version?: string; jailReason?: string; + totalDelegationRewards: any; + website?: string; + email?: string; + description?: string; queries24Hours?: any; queries90Days?: any; scannedData24Hours?: any; @@ -5344,18 +5438,16 @@ export type MyWorkersQuery = { __typename?: 'Worker'; id: string; name?: string; - email?: string; peerId: string; - website?: string; status: WorkerStatus; createdAt: any; - description?: string; bond: any; claimableReward: any; claimedReward: any; uptime24Hours?: number; uptime90Days?: number; totalDelegation: any; + capedDelegation: any; delegationCount: number; apr?: number; stakerApr?: number; @@ -5416,18 +5508,16 @@ export type MyDelegationsQuery = { __typename?: 'Worker'; id: string; name?: string; - email?: string; peerId: string; - website?: string; status: WorkerStatus; createdAt: any; - description?: string; bond: any; claimableReward: any; claimedReward: any; uptime24Hours?: number; uptime90Days?: number; totalDelegation: any; + capedDelegation: any; delegationCount: number; apr?: number; stakerApr?: number; @@ -5606,18 +5696,16 @@ export const WorkerFragmentFragmentDoc = ` fragment WorkerFragment on Worker { id name - email peerId - website status createdAt - description bond claimableReward claimedReward uptime24Hours uptime90Days totalDelegation + capedDelegation delegationCount apr stakerApr @@ -5638,6 +5726,10 @@ export const WorkerFragmentFragmentDoc = ` `; export const WorkerFullFragmentFragmentDoc = ` fragment WorkerFullFragment on Worker { + totalDelegationRewards + website + email + description queries24Hours queries90Days scannedData24Hours diff --git a/src/api/subsquid-network-squid/workers-graphql.ts b/src/api/subsquid-network-squid/workers-graphql.ts index 86514fe..12e214d 100644 --- a/src/api/subsquid-network-squid/workers-graphql.ts +++ b/src/api/subsquid-network-squid/workers-graphql.ts @@ -28,17 +28,17 @@ export interface BlockchainApiWorker extends WorkerFragmentFragment {} export class BlockchainApiWorker { ownedByMe?: boolean; - totalDelegations: { - limit: Decimal; - total: Decimal; - capacity: Decimal; - utilizedPercent: Decimal; - } = { - limit: new Decimal(0), - total: new Decimal(0), - capacity: new Decimal(0), - utilizedPercent: new Decimal(0), - }; + // totalDelegations: { + // limit: Decimal; + // total: Decimal; + // capacity: Decimal; + // } = { + // limit: new Decimal(0), + // total: new Decimal(0), + // capacity: new Decimal(0), + // utilizedPercent: new Decimal(0), + // }; + utilizedPercent?: number; delegationEnabled: boolean = false; myDelegations: { owner: { id: string; type: AccountType }; @@ -75,6 +75,16 @@ export class BlockchainApiWorker { ); this.totalReward = new Decimal(this.claimedReward).add(this.claimableReward).toFixed(0); + + if (this.totalDelegation && this.bond) { + const up = new Decimal(this.totalDelegation) // (total / (bond / 3)) * (caped / total) + .div(this.bond) + .mul(3) + .div(this.capedDelegation) + .mul(this.totalDelegation) + .mul(100); + this.utilizedPercent = up.isNaN() ? 0 : up.toNumber(); + } } canEdit() { @@ -187,7 +197,7 @@ export function useWorkers({ case WorkerSortBy.Uptime24h: return (a.uptime24Hours ?? -1) - (b.uptime24Hours ?? -1); case WorkerSortBy.DelegationCapacity: - return a.totalDelegations.capacity.minus(b.totalDelegations.capacity).toNumber(); + return (a.utilizedPercent ?? -1) - (b.utilizedPercent ?? -1); case WorkerSortBy.StakerAPR: return ( (a.stakerApr ?? -1) - (b.stakerApr ?? -1) || a.delegationCount - b.delegationCount diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 20c3476..ab620d6 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -49,7 +49,10 @@ export const Avatar = ({ return ( - + {name.slice(0, 2).toUpperCase()} {/*{typeof online !== 'undefined' ? : null}*/} diff --git a/src/components/StyledTooltip/StyledTooltip.tsx b/src/components/StyledTooltip/StyledTooltip.tsx index 4448833..783788e 100644 --- a/src/components/StyledTooltip/StyledTooltip.tsx +++ b/src/components/StyledTooltip/StyledTooltip.tsx @@ -6,7 +6,7 @@ export const StyledTooltip = styled(({ className, ...props }: TooltipProps) => ( ))(({ theme }) => ({ [`& .${tooltipClasses.tooltip}`]: { - borderRadius: 8, + borderRadius: 6, color: theme.palette.text.default, }, })); diff --git a/src/components/Table/BorderedTable.tsx b/src/components/Table/BorderedTable.tsx index 51725a6..b0ee7e3 100644 --- a/src/components/Table/BorderedTable.tsx +++ b/src/components/Table/BorderedTable.tsx @@ -1,6 +1,6 @@ import React, { PropsWithChildren, SyntheticEvent } from 'react'; -import { Stack, styled, Table, TableCell } from '@mui/material'; +import { Stack, styled, Table, TableCell, Tooltip } from '@mui/material'; import { Box } from '@mui/system'; import { SortDir } from '@api/subsquid-network-squid'; @@ -35,6 +35,23 @@ export const BorderedTable = styled(Table)(({ theme }) => ({ }, }, + '& td:last-of-type.pinned, & th:last-of-type.pinned': { + boxShadow: '0px 0px 0px 0px rgba(0, 0, 0, 0.1)', + position: 'sticky', + right: 0, + [theme.breakpoints.down('sm')]: { + position: 'relative', + }, + }, + + '& td:first-of-type.pinned, & th:first-of-type.pinned': { + position: 'sticky', + left: 0, + [theme.breakpoints.down('sm')]: { + position: 'relative', + }, + }, + '& th': { color: theme.palette.text.secondary, fontWeight: 'normal', @@ -66,17 +83,31 @@ const ClickableStack = styled(Stack)(({ theme }) => ({ userSelect: 'none', })); +export function HeaderCell({ + help, + children, +}: PropsWithChildren<{ + width?: string | number; + help?: React.ReactNode; +}>) { + return ( + + {children} + + ); +} + export function SortableHeaderCell({ sort, children, query, - width, setQuery, + help, }: PropsWithChildren<{ sort: S; - width?: string | number; query: { sortBy: string; sortDir: string }; setQuery: { sortBy: (v: string) => unknown; sortDir: (v: string) => unknown }; + help?: React.ReactNode; }>) { const handleSortChange = (sortBy: S) => (e: SyntheticEvent) => { e.preventDefault(); @@ -90,18 +121,18 @@ export function SortableHeaderCell({ }; return ( - + - {children} + {children} - + ); } diff --git a/src/network/useContracts.ts b/src/network/useContracts.ts index c95de97..9517d21 100644 --- a/src/network/useContracts.ts +++ b/src/network/useContracts.ts @@ -7,6 +7,7 @@ export function useContracts(): { REWARD_TREASURY: `0x${string}`; REWARD_DISTRIBUTION: `0x${string}`; GATEWAY_REGISTRATION: `0x${string}`; + SOFT_CAP: `0x${string}`; SQD_TOKEN: string; } { const network = getSubsquidNetwork(); @@ -20,6 +21,7 @@ export function useContracts(): { REWARD_TREASURY: `0x785136e611E15D532C36502AaBdfE8E35008c7ca`, REWARD_DISTRIBUTION: `0x68f9fE3504652360afF430dF198E1Cb7B2dCfD57`, GATEWAY_REGISTRATION: `0xAB46F688AbA4FcD1920F21E9BD16B229316D8b0a`, + SOFT_CAP: `0x52f31c9c019f840A9C0e74F66ACc95455B254BeA`, SQD_TOKEN: 'tSQD', }; } @@ -31,6 +33,7 @@ export function useContracts(): { REWARD_TREASURY: `0x237abf43bc51fd5c50d0d598a1a4c26e56a8a2a0`, REWARD_DISTRIBUTION: `0x4de282bD18aE4987B3070F4D5eF8c80756362AEa`, GATEWAY_REGISTRATION: `0x8a90a1ce5fa8cf71de9e6f76b7d3c0b72feb8c4b`, + SOFT_CAP: `0xde29d5215c28036ce56091ea91038c94c84c87d0`, SQD_TOKEN: 'SQD', }; } diff --git a/src/pages/AssetsPage/Vestings.tsx b/src/pages/AssetsPage/Vestings.tsx index f4e9598..80a7407 100644 --- a/src/pages/AssetsPage/Vestings.tsx +++ b/src/pages/AssetsPage/Vestings.tsx @@ -31,8 +31,8 @@ export function MyVestings() { Vesting Balance + Deposited Releasable - Released @@ -40,13 +40,13 @@ export function MyVestings() { {assets.vestings.map((vesting, i) => { const d = data?.[i]; return ( - + {formatSqd(SQD_TOKEN, fromSqd(d?.balance))} + {formatSqd(SQD_TOKEN, d?.deposited)} {formatSqd(SQD_TOKEN, d?.releasable)} - {formatSqd(SQD_TOKEN, d?.released)} diff --git a/src/pages/DashboardPage/Workers.tsx b/src/pages/DashboardPage/Workers.tsx index c28b994..68f0c7a 100644 --- a/src/pages/DashboardPage/Workers.tsx +++ b/src/pages/DashboardPage/Workers.tsx @@ -96,7 +96,9 @@ export function Workers() { - Worker + + Worker + Status Version Delegator APR - {/**/} - {/* Delegation capacity*/} - {/**/} + + Delegation capacity + Registered - + {workers.map(worker => { return ( - + {/*{formatSqd(worker.totalDelegations.capacity, 0)}*/} + {percentFormatter(worker.utilizedPercent)} {dateFormat(worker.createdAt)} - + diff --git a/src/pages/DelegationsPage/DelegationsPage.tsx b/src/pages/DelegationsPage/DelegationsPage.tsx index c80fc05..0ed7f83 100644 --- a/src/pages/DelegationsPage/DelegationsPage.tsx +++ b/src/pages/DelegationsPage/DelegationsPage.tsx @@ -29,19 +29,22 @@ export function MyDelegations() { - Worker + + Worker + Status - Delegation - APR + Delegator APR + Delegation capacity + My Delegation Total reward - + {delegations.map(worker => { return ( - - + + - {formatSqd(SQD_TOKEN, worker.myDelegationsTotal)} {worker.stakerApr != null ? percentFormatter(worker.stakerApr) : '-'} + {percentFormatter(worker.utilizedPercent)} + {formatSqd(SQD_TOKEN, worker.myDelegationsTotal)} {formatSqd(SQD_TOKEN, worker.myDelegationsRewardsTotal)} - + diff --git a/src/pages/GatewaysPage/GatewaysPage.tsx b/src/pages/GatewaysPage/GatewaysPage.tsx index 7311137..95e40f0 100644 --- a/src/pages/GatewaysPage/GatewaysPage.tsx +++ b/src/pages/GatewaysPage/GatewaysPage.tsx @@ -103,7 +103,7 @@ export function MyGateways() { {data.map(gateway => { return ( - + diff --git a/src/pages/WorkersPage/WorkerDelegationCapacity.tsx b/src/pages/WorkersPage/WorkerDelegationCapacity.tsx index 5097c4a..d1a87e4 100644 --- a/src/pages/WorkersPage/WorkerDelegationCapacity.tsx +++ b/src/pages/WorkersPage/WorkerDelegationCapacity.tsx @@ -53,68 +53,68 @@ const DelegationCircularHolder = styled(Box, { display: 'flex', })); -export const WorkerDelegationCapacity = ({ - value: { capacity, utilizedPercent, limit, total }, -}: { - value: BlockchainApiWorker['totalDelegations']; -}) => { - const popupState = usePopupState({ variant: 'popover', popupId: 'delegation' }); - const { SQD_TOKEN } = useContracts(); +// export const WorkerDelegationCapacity = ({ +// value: { capacity, utilizedPercent, limit, total }, +// }: { +// value: BlockchainApiWorker['totalDelegations']; +// }) => { +// const popupState = usePopupState({ variant: 'popover', popupId: 'delegation' }); +// const { SQD_TOKEN } = useContracts(); - return ( - - - - - - - {utilizedPercent.equals(0) - ? '0' - : utilizedPercent.lessThan(1) - ? '<1' - : utilizedPercent.toFixed(0)} - % - - - - - - - Delegation capacity - {formatSqd(SQD_TOKEN, capacity)} - - - Delegated - {formatSqd(SQD_TOKEN, total)} - - - Delegation limit - {formatSqd(SQD_TOKEN, limit)} - - - - - - - ); -}; +// return ( +// +// +// +// +// +// +// {utilizedPercent.equals(0) +// ? '0' +// : utilizedPercent.lessThan(1) +// ? '<1' +// : utilizedPercent.toFixed(0)} +// % +// +// +// +// +// +// +// Delegation capacity +// {formatSqd(SQD_TOKEN, capacity)} +// +// +// Delegated +// {formatSqd(SQD_TOKEN, total)} +// +// +// Delegation limit +// {formatSqd(SQD_TOKEN, limit)} +// +// +// +// +// +// +// ); +// }; diff --git a/src/pages/WorkersPage/WorkerName.tsx b/src/pages/WorkersPage/WorkerName.tsx index 23f7a3d..19a7a86 100644 --- a/src/pages/WorkersPage/WorkerName.tsx +++ b/src/pages/WorkersPage/WorkerName.tsx @@ -21,9 +21,7 @@ export const WorkerName = ({ worker, to, }: { - worker: Pick & { - totalDelegations?: BlockchainApiWorker['totalDelegations']; - }; + worker: Pick; to?: string; }) => { return ( @@ -35,7 +33,9 @@ export const WorkerName = ({ /> {worker.name ? ( - {worker.name.length > 40 ? worker.name.slice(0, 37) + '...' : worker.name} + + {worker.name.length > 30 ? worker.name.slice(0, 27) + '...' : worker.name} + ) : null} @@ -48,9 +48,7 @@ export const WorkerName = ({ } /> - {/*{worker.totalDelegations ? (*/} - {/* */} - {/*) : null}*/} + {/* */} diff --git a/src/pages/WorkersPage/WorkerStatistics.tsx b/src/pages/WorkersPage/WorkerStatistics.tsx index 19ec508..cf8a20c 100644 --- a/src/pages/WorkersPage/WorkerStatistics.tsx +++ b/src/pages/WorkersPage/WorkerStatistics.tsx @@ -109,6 +109,10 @@ export const WorkerStatistics = ({ worker }: { worker: BlockchainApiFullWorker } Bond + + Bonded + {formatSqd(SQD_TOKEN, worker.bond, 8)} + Worker APR @@ -116,11 +120,7 @@ export const WorkerStatistics = ({ worker }: { worker: BlockchainApiFullWorker } - Bonded - {formatSqd(SQD_TOKEN, worker.bond, 8)} - - - Total rewards + Total reward {formatSqd(SQD_TOKEN, worker.totalReward, 8)} @@ -129,6 +129,18 @@ export const WorkerStatistics = ({ worker }: { worker: BlockchainApiFullWorker } Delegation + + Delegators + {worker.delegationCount} + + + Total delegation + {formatSqd(SQD_TOKEN, worker.totalDelegation, 8)} + + + Delegation capacity + {percentFormatter(worker.utilizedPercent)} + Delegator APR @@ -136,12 +148,10 @@ export const WorkerStatistics = ({ worker }: { worker: BlockchainApiFullWorker } - Delegators - {worker.delegationCount} - - - Total delegated - {formatSqd(SQD_TOKEN, worker.totalDelegation, 8)} + Total reward + + {formatSqd(SQD_TOKEN, worker.totalDelegationRewards, 8)} + diff --git a/src/pages/WorkersPage/WorkersPage.tsx b/src/pages/WorkersPage/WorkersPage.tsx index 0ddc9b1..1c12d25 100644 --- a/src/pages/WorkersPage/WorkersPage.tsx +++ b/src/pages/WorkersPage/WorkersPage.tsx @@ -44,7 +44,7 @@ export function MyWorkers() { Status Uptime, 24h Uptime, 90d - APR + Worker APR Total reward