Skip to content

Commit

Permalink
fix: properly calculate worker unlock date
Browse files Browse the repository at this point in the history
  • Loading branch information
belopash committed Oct 23, 2024
1 parent b4690e0 commit 57378a6
Show file tree
Hide file tree
Showing 14 changed files with 338 additions and 79 deletions.
94 changes: 94 additions & 0 deletions src/api/contracts/subsquid.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ import {
createUseWatchContractEvent,
} from 'wagmi/codegen'

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ArbMulticall
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

export const arbMulticallAbi = [
{
type: 'function',
inputs: [],
name: 'getCurrentBlockTimestamp',
outputs: [{ name: 'timestamp', internalType: 'uint256', type: 'uint256' }],
stateMutability: 'view',
},
{
type: 'function',
inputs: [],
name: 'getL1BlockNumber',
outputs: [
{ name: 'l1BlockNumber', internalType: 'uint256', type: 'uint256' },
],
stateMutability: 'view',
},
] as const

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GatewayRegistry
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -569,12 +592,65 @@ export const workerRegistryAbi = [
outputs: [],
stateMutability: 'nonpayable',
},
{
type: 'function',
inputs: [],
name: 'lockPeriod',
outputs: [{ name: '', internalType: 'uint128', type: 'uint128' }],
stateMutability: 'view',
},
{
type: 'function',
inputs: [{ name: 'workerId', internalType: 'uint256', type: 'uint256' }],
name: 'getWorker',
outputs: [
{
name: '',
internalType: 'struct WorkerRegistration.Worker',
type: 'tuple',
components: [
{ name: 'creator', internalType: 'address', type: 'address' },
{ name: 'peerId', internalType: 'bytes', type: 'bytes' },
{ name: 'bond', internalType: 'uint256', type: 'uint256' },
{ name: 'registeredAt', internalType: 'uint128', type: 'uint128' },
{ name: 'deregisteredAt', internalType: 'uint128', type: 'uint128' },
{ name: 'metadata', internalType: 'string', type: 'string' },
],
},
],
stateMutability: 'view',
},
] as const

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// React
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link arbMulticallAbi}__
*/
export const useReadArbMulticall = /*#__PURE__*/ createUseReadContract({
abi: arbMulticallAbi,
})

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link arbMulticallAbi}__ and `functionName` set to `"getCurrentBlockTimestamp"`
*/
export const useReadArbMulticallGetCurrentBlockTimestamp =
/*#__PURE__*/ createUseReadContract({
abi: arbMulticallAbi,
functionName: 'getCurrentBlockTimestamp',
})

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link arbMulticallAbi}__ and `functionName` set to `"getL1BlockNumber"`
*/
export const useReadArbMulticallGetL1BlockNumber =
/*#__PURE__*/ createUseReadContract({
abi: arbMulticallAbi,
functionName: 'getL1BlockNumber',
})

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link gatewayRegistryAbi}__
*/
Expand Down Expand Up @@ -1278,6 +1354,24 @@ export const useReadWorkerRegistryBondAmount =
functionName: 'bondAmount',
})

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link workerRegistryAbi}__ and `functionName` set to `"lockPeriod"`
*/
export const useReadWorkerRegistryLockPeriod =
/*#__PURE__*/ createUseReadContract({
abi: workerRegistryAbi,
functionName: 'lockPeriod',
})

/**
* Wraps __{@link useReadContract}__ with `abi` set to __{@link workerRegistryAbi}__ and `functionName` set to `"getWorker"`
*/
export const useReadWorkerRegistryGetWorker =
/*#__PURE__*/ createUseReadContract({
abi: workerRegistryAbi,
functionName: 'getWorker',
})

/**
* Wraps __{@link useWriteContract}__ with `abi` set to __{@link workerRegistryAbi}__
*/
Expand Down
95 changes: 95 additions & 0 deletions src/api/subsquid-network-squid/useFixWorkers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useMemo } from 'react';

import { getBlockTime } from '@lib/network';
import { useBlock, useReadContracts } from 'wagmi';

import { Worker, WorkerStatus } from '@api/subsquid-network-squid';
import { useContracts } from '@network/useContracts';

import {
useReadRouterWorkerRegistration,
useReadWorkerRegistryLockPeriod,
workerRegistryAbi,
} from '../contracts/subsquid.generated';

export function useFixWorkers<T extends Pick<Worker, 'id' | 'status'>>({
workers,
}: {
workers?: T[];
}) {
const { ROUTER, CHAIN_ID_L1 } = useContracts();

const { data: registryAddress, isLoading: isRegistryAddressLoading } =
useReadRouterWorkerRegistration({
address: ROUTER,
query: { enabled: !!ROUTER },
});

const { data: lockPeriod, isLoading: isLockPeriodLoading } = useReadWorkerRegistryLockPeriod({
address: registryAddress || '0x',
});

const { data: lastL1Block, isLoading: isLastL1BlockLoading } = useBlock({
chainId: CHAIN_ID_L1,
includeTransactions: false,
});

const { data: workersInfo, isLoading: isWorkersInfoLoading } = useReadContracts({
contracts: workers?.map(worker => {
return {
abi: workerRegistryAbi,
address: registryAddress || '0x',
functionName: 'getWorker',
args: [BigInt(worker.id)],
} as const;
}),
allowFailure: false,
query: {
enabled: !!workers && !!registryAddress,
},
});

const data = useMemo(() => {
if (!workersInfo || !lastL1Block) return workers;

return workers?.map((worker, i) => {
const workerInfo = workersInfo?.[i];

const registeredAt = workerInfo.registeredAt;
const deregisteredAt = workerInfo.deregisteredAt + (lockPeriod ?? 0n);
const timestamp = Number(lastL1Block.timestamp) * 1000;

const { status, statusChangeAt } =
lastL1Block.number < registeredAt
? {
status: WorkerStatus.Registering,
statusChangeAt: new Date(
timestamp + getBlockTime(registeredAt - lastL1Block.number),
).toString(),
}
: lastL1Block.number < deregisteredAt
? {
status: WorkerStatus.Deregistering,
statusChangeAt: new Date(
timestamp + getBlockTime(deregisteredAt - lastL1Block.number),
).toString(),
}
: { status: worker.status };

return {
...worker,
status,
statusChangeAt,
};
});
}, [workers, workersInfo, lastL1Block, lockPeriod]);

return {
isLoading:
isRegistryAddressLoading ||
isLockPeriodLoading ||
isLastL1BlockLoading ||
isWorkersInfoLoading,
data,
};
}
35 changes: 23 additions & 12 deletions src/api/subsquid-network-squid/workers-graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
Worker,
} from './graphql';
import { useNetworkSettings } from './settings-graphql';
import { useFixWorkers } from './useFixWorkers';

// inherit API interface for internal class
// export interface BlockchainApiWorker extends Omit<WorkerFragmentFragment, 'createdAt'> {
Expand Down Expand Up @@ -246,7 +247,7 @@ export function useMyWorkers({ sortBy, sortDir }: { sortBy: WorkerSortBy; sortDi
const { isPending: isSettingsLoading } = useNetworkSettings();

const enabled = !!address;
const { data, isLoading } = useMyWorkersQuery(
const { data: workers, isLoading } = useMyWorkersQuery(
datasource,
{
address: address || '',
Expand All @@ -264,13 +265,15 @@ export function useMyWorkers({ sortBy, sortDir }: { sortBy: WorkerSortBy; sortDi
},
);

const workers = useMemo(() => {
return sortWorkers(data || [], sortBy, sortDir);
}, [data, sortBy, sortDir]);
const { data: fixedWorkers, isLoading: isFixedWorkersLoading } = useFixWorkers({ workers });

const data = useMemo(() => {
return sortWorkers(fixedWorkers || [], sortBy, sortDir);
}, [fixedWorkers, sortBy, sortDir]);

return {
data: workers,
isLoading: enabled ? isSettingsLoading || isLoading : false,
data,
isLoading: isSettingsLoading || isLoading || isFixedWorkersLoading,
};
}

Expand All @@ -280,7 +283,7 @@ export function useWorkerByPeerId(peerId?: string) {
const { isPending: isSettingsLoading } = useNetworkSettings();
const { address } = useAccount();

const { data, isPending } = useWorkerByPeerIdQuery(
const { data: worker, isLoading } = useWorkerByPeerIdQuery(
datasource,
{ peerId: peerId || '', address },
{
Expand All @@ -300,9 +303,13 @@ export function useWorkerByPeerId(peerId?: string) {
},
);

const { data: fixedWorker, isLoading: isFixedWorkerLoading } = useFixWorkers({
workers: worker ? [worker] : undefined,
});

return {
data,
isPending: enabled ? isSettingsLoading || isPending : false,
data: fixedWorker?.[0],
isLoading: isSettingsLoading || isLoading || isFixedWorkerLoading,
};
}

Expand Down Expand Up @@ -374,6 +381,10 @@ export function useMyDelegations({ sortBy, sortDir }: { sortBy: WorkerSortBy; so
{ address: address || '0x' },
);

const { data: fixedDelegations, isLoading: isFixedDelegationsLoading } = useFixWorkers({
workers: delegationsQuery?.workers,
});

const data = useMemo(() => {
type W = SimplifyDeep<
Pick<
Expand All @@ -395,7 +406,7 @@ export function useMyDelegations({ sortBy, sortDir }: { sortBy: WorkerSortBy; so
}
>;

const workers = delegationsQuery?.workers.map(w => {
const workers = fixedDelegations?.map(w => {
const worker: W = {
id: w.id,
name: w.name,
Expand Down Expand Up @@ -436,10 +447,10 @@ export function useMyDelegations({ sortBy, sortDir }: { sortBy: WorkerSortBy; so
});

return sortWorkers(workers || [], sortBy, sortDir);
}, [delegationsQuery?.workers, sortBy, sortDir]);
}, [fixedDelegations, sortBy, sortDir]);

return {
isLoading: isSettingsLoading || isDelegationsQueryLoading,
isLoading: isSettingsLoading || isDelegationsQueryLoading || isFixedDelegationsLoading,
data,
};
}
Expand Down
25 changes: 20 additions & 5 deletions src/i18n/dateFormat.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { format, isValid } from 'date-fns';

export function dateFormat(
value: Date | string | number | bigint | undefined,
value: Date | string | number | undefined,
tpl: 'dateTime' | 'date' | string = 'date',
) {
if (!value) return null;
Expand All @@ -14,12 +14,27 @@ export function dateFormat(

if (value.valueOf() == 0) return null;

if (typeof value === 'bigint') {
value = Number(value);
}

const date = new Date(value);
if (!isValid(date)) return null;

return format(new Date(value), tpl);
}

export function relativeDateFormat(
from: Date | string | number | undefined,
to: Date | string | number | undefined,
) {
const fromMs = typeof from === 'number' ? from : new Date(from || 0).getTime();
const toMs = typeof to === 'number' ? to : new Date(to || 0).getTime();
const diff = Math.max(toMs - fromMs, 0) / 1000;

const days = Math.floor(diff / 86400);
const hours = Math.floor((diff % 86400) / 3600);
const minutes = Math.floor((diff % 3600) / 60);
const seconds = Math.floor(diff % 60);

if (days > 0) return `${days}d ${hours}h`;
if (hours > 0) return `${hours}h ${minutes}m`;
if (minutes > 0) return `${minutes}m ${seconds}s`;
return `${seconds}s`;
}
4 changes: 4 additions & 0 deletions src/lib/network/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ export function peerIdToHex(peerId: string) {
export function unwrapMulticallResult<T>(result?: MulticallResponse<T>): T | undefined {
return result?.status === 'success' ? (result.result as T) : undefined;
}

export function getBlockTime(blocksCount: number | bigint) {
return Number(blocksCount) * 12_000;
}
9 changes: 6 additions & 3 deletions src/network/useContracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export function useContracts(): {
GATEWAY_REGISTRATION: `0x${string}`;
SOFT_CAP: `0x${string}`;
SQD_TOKEN: string;
l1ChainId: number;
CHAIN_ID_L1: number;
MULTICALL: `0x${string}`;
} {
const network = getSubsquidNetwork();

Expand All @@ -28,7 +29,8 @@ export function useContracts(): {
SOFT_CAP: `0x52f31c9c019f840A9C0e74F66ACc95455B254BeA`,
SQD_TOKEN: 'tSQD',
ROUTER: '0xD2093610c5d27c201CD47bCF1Df4071610114b64',
l1ChainId: sepolia.id,
CHAIN_ID_L1: sepolia.id,
MULTICALL: '0x7eCfBaa8742fDf5756DAC92fbc8b90a19b8815bF',
};
}
case NetworkName.Mainnet: {
Expand All @@ -42,7 +44,8 @@ export function useContracts(): {
SOFT_CAP: `0x0eb27b1cbba04698dd7ce0f2364584d33a616545`,
SQD_TOKEN: 'SQD',
ROUTER: '0x67F56D27dab93eEb07f6372274aCa277F49dA941',
l1ChainId: mainnet.id,
CHAIN_ID_L1: mainnet.id,
MULTICALL: '0x7eCfBaa8742fDf5756DAC92fbc8b90a19b8815bF',
};
}
}
Expand Down
Loading

0 comments on commit 57378a6

Please sign in to comment.