From 996517b5cdfaa1bb136abcffcd5fb0030e5986be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Tue, 14 Oct 2025 17:40:37 +0200 Subject: [PATCH 01/11] Refactor escrow, transaction and worker methods to fix mismatch with Subgraph --- .../human-protocol-sdk/src/escrow.ts | 86 ++++++-- .../human-protocol-sdk/src/graphql/types.ts | 34 ++- .../human-protocol-sdk/src/interfaces.ts | 23 +- .../human-protocol-sdk/src/transaction.ts | 58 ++++- .../human-protocol-sdk/src/worker.ts | 21 +- .../human-protocol-sdk/test/escrow.test.ts | 168 +++++++++++++-- .../test/transaction.test.ts | 204 ++++++++++++++++-- .../human-protocol-sdk/test/worker.test.ts | 30 ++- 8 files changed, 534 insertions(+), 90 deletions(-) diff --git a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts index 0a68944b2e..9ce9137052 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts @@ -1785,23 +1785,29 @@ export class EscrowUtils { * interface IEscrow { * id: string; * address: string; - * amountPaid: string; - * balance: string; - * count: string; - * jobRequesterId: string; + * amountPaid: bigint; + * balance: bigint; + * count: bigint; * factoryAddress: string; * finalResultsUrl?: string; + * finalResultsHash?: string; * intermediateResultsUrl?: string; + * intermediateResultsHash?: string; * launcher: string; + * jobRequesterId?: string; * manifestHash?: string; * manifest?: string; * recordingOracle?: string; * reputationOracle?: string; * exchangeOracle?: string; - * status: EscrowStatus; + * recordingOracleFee?: bigint; + * reputationOracleFee?: bigint; + * exchangeOracleFee?: bigint; + * status: string; * token: string; - * totalFundedAmount: string; - * createdAt: string; + * totalFundedAmount: bigint; + * createdAt: bigint; + * chainId: number; * }; * ``` * @@ -1873,13 +1879,30 @@ export class EscrowUtils { skip: skip, } ); - escrows.map((escrow) => (escrow.chainId = networkData.chainId)); + const mapped: IEscrow[] = (escrows || []).map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + chainId: networkData.chainId, + })); if (!escrows) { return []; } - return escrows; + return mapped; } /** @@ -1906,23 +1929,29 @@ export class EscrowUtils { * interface IEscrow { * id: string; * address: string; - * amountPaid: string; - * balance: string; - * count: string; - * jobRequesterId: string; + * amountPaid: bigint; + * balance: bigint; + * count: bigint; * factoryAddress: string; * finalResultsUrl?: string; + * finalResultsHash?: string; * intermediateResultsUrl?: string; + * intermediateResultsHash?: string; * launcher: string; + * jobRequesterId?: string; * manifestHash?: string; * manifest?: string; * recordingOracle?: string; * reputationOracle?: string; * exchangeOracle?: string; - * status: EscrowStatus; + * recordingOracleFee?: bigint; + * reputationOracleFee?: bigint; + * exchangeOracleFee?: bigint; + * status: string; * token: string; - * totalFundedAmount: string; - * createdAt: string; + * totalFundedAmount: bigint; + * createdAt: bigint; + * chainId: number; * }; * ``` * @@ -1953,14 +1982,31 @@ export class EscrowUtils { throw ErrorInvalidAddress; } - const { escrow } = await gqlFetch<{ escrow: EscrowData }>( + const { escrow } = await gqlFetch<{ escrow: EscrowData | null }>( getSubgraphUrl(networkData), GET_ESCROW_BY_ADDRESS_QUERY(), { escrowAddress: escrowAddress.toLowerCase() } ); - escrow.chainId = networkData.chainId; - - return escrow || null; + if (!escrow) return null; + + return { + ...escrow, + amountPaid: BigInt(escrow.amountPaid || 0), + balance: BigInt(escrow.balance || 0), + count: BigInt(escrow.count || 0), + recordingOracleFee: escrow.recordingOracleFee + ? BigInt(escrow.recordingOracleFee) + : undefined, + reputationOracleFee: escrow.reputationOracleFee + ? BigInt(escrow.reputationOracleFee) + : undefined, + exchangeOracleFee: escrow.exchangeOracleFee + ? BigInt(escrow.exchangeOracleFee) + : undefined, + totalFundedAmount: BigInt(escrow.totalFundedAmount || 0), + createdAt: BigInt(escrow.createdAt || 0), + chainId: networkData.chainId, + }; } /** diff --git a/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts b/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts index 72d018be28..2875426d10 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts @@ -12,6 +12,7 @@ export type EscrowData = { intermediateResultsUrl?: string; intermediateResultsHash?: string; launcher: string; + jobRequesterId?: string; manifestHash?: string; manifestUrl?: string; recordingOracle?: string; @@ -24,7 +25,38 @@ export type EscrowData = { token: string; totalFundedAmount: string; createdAt: string; - chainId: number; +}; + +export type WorkerData = { + id: string; + address: string; + totalHMTAmountReceived: string; + payoutCount: number; +}; + +export type InternalTransactionData = { + from: string; + to: string; + value: string; + method: string; + receiver?: string; + escrow?: string; + token?: string; + id?: string; +}; + +export type TransactionData = { + block: string; + txHash: string; + from: string; + to: string; + timestamp: string; + value: string; + method: string; + receiver?: string; + escrow?: string; + token?: string; + internalTransactions: InternalTransactionData[]; }; export type HMTStatisticsData = { diff --git a/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts b/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts index bc585f0f94..6e9d90fc93 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts @@ -77,27 +77,28 @@ export interface IReputationNetworkSubgraph export interface IEscrow { id: string; address: string; - amountPaid: string; - balance: string; - count: string; + amountPaid: bigint; + balance: bigint; + count: bigint; factoryAddress: string; finalResultsUrl?: string; finalResultsHash?: string; intermediateResultsUrl?: string; intermediateResultsHash?: string; launcher: string; + jobRequesterId?: string; manifestHash?: string; manifest?: string; recordingOracle?: string; reputationOracle?: string; exchangeOracle?: string; - recordingOracleFee?: string; - reputationOracleFee?: string; - exchangeOracleFee?: string; + recordingOracleFee?: bigint; + reputationOracleFee?: bigint; + exchangeOracleFee?: bigint; status: string; token: string; - totalFundedAmount: string; - createdAt: string; + totalFundedAmount: bigint; + createdAt: bigint; chainId: number; } @@ -156,7 +157,7 @@ export interface IKVStore { export interface InternalTransaction { from: string; to: string; - value: string; + value: bigint; method: string; receiver?: string; escrow?: string; @@ -169,7 +170,7 @@ export interface ITransaction { from: string; to: string; timestamp: bigint; - value: string; + value: bigint; method: string; receiver?: string; escrow?: string; @@ -214,7 +215,7 @@ export interface IStatusEventFilter extends IPagination { export interface IWorker { id: string; address: string; - totalHMTAmountReceived: number; + totalHMTAmountReceived: bigint; payoutCount: number; } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts b/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts index 26f5cce107..8896a07718 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts @@ -14,6 +14,7 @@ import { } from './graphql/queries/transaction'; import { ITransaction, ITransactionsFilter } from './interfaces'; import { getSubgraphUrl, getUnixTimestamp } from './utils'; +import { TransactionData } from './graphql'; export class TransactionUtils { /** @@ -26,7 +27,7 @@ export class TransactionUtils { * from: string; * to: string; * timestamp: bigint; - * value: string; + * value: bigint; * method: string; * receiver?: string; * escrow?: string; @@ -35,6 +36,18 @@ export class TransactionUtils { * }; * ``` * + * ```ts + * type InternalTransaction = { + * from: string; + * to: string; + * value: bigint; + * method: string; + * receiver?: string; + * escrow?: string; + * token?: string; + * }; + * ``` + * * @param {ChainId} chainId The chain ID. * @param {string} hash The transaction hash. * @returns {Promise} - Returns the transaction details or null if not found. @@ -61,12 +74,23 @@ export class TransactionUtils { } const { transaction } = await gqlFetch<{ - transaction: ITransaction; + transaction: TransactionData | null; }>(getSubgraphUrl(networkData), GET_TRANSACTION_QUERY, { hash: hash.toLowerCase(), }); + if (!transaction) return null; - return transaction || null; + return { + ...transaction, + block: BigInt(transaction.block), + timestamp: BigInt(transaction.timestamp), + value: BigInt(transaction.value || 0), + internalTransactions: + transaction.internalTransactions?.map((itx) => ({ + ...itx, + value: BigInt(itx.value || 0), + })) || [], + }; } /** @@ -92,6 +116,18 @@ export class TransactionUtils { * skip?: number; // (Optional) Number of transactions to skip. Default is 0. * orderDirection?: OrderDirection; // (Optional) Order of the results. Default is DESC. * } + * + * + * ```ts + * type InternalTransaction = { + * from: string; + * to: string; + * value: bigint; + * method: string; + * receiver?: string; + * escrow?: string; + * token?: string; + * }; * ``` * * ```ts @@ -101,7 +137,7 @@ export class TransactionUtils { * from: string; * to: string; * timestamp: bigint; - * value: string; + * value: bigint; * method: string; * receiver?: string; * escrow?: string; @@ -150,7 +186,7 @@ export class TransactionUtils { } const { transactions } = await gqlFetch<{ - transactions: ITransaction[]; + transactions: TransactionData[]; }>(getSubgraphUrl(networkData), GET_TRANSACTIONS_QUERY(filter), { fromAddress: filter?.fromAddress, toAddress: filter?.toAddress, @@ -172,6 +208,16 @@ export class TransactionUtils { return []; } - return transactions; + return transactions.map((transaction) => ({ + ...transaction, + block: BigInt(transaction.block), + timestamp: BigInt(transaction.timestamp), + value: BigInt(transaction.value || 0), + internalTransactions: + transaction.internalTransactions?.map((itx) => ({ + ...itx, + value: BigInt(itx.value || 0), + })) || [], + })); } } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/worker.ts b/packages/sdk/typescript/human-protocol-sdk/src/worker.ts index f3d75bac3b..a609955353 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/worker.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/worker.ts @@ -1,11 +1,12 @@ +import { ethers } from 'ethers'; import gqlFetch from 'graphql-request'; import { NETWORKS } from './constants'; import { ChainId, OrderDirection } from './enums'; import { ErrorInvalidAddress, ErrorUnsupportedChainID } from './error'; +import { WorkerData } from './graphql'; import { GET_WORKER_QUERY, GET_WORKERS_QUERY } from './graphql/queries/worker'; import { IWorker, IWorkersFilter } from './interfaces'; import { getSubgraphUrl } from './utils'; -import { ethers } from 'ethers'; export class WorkerUtils { /** @@ -37,12 +38,17 @@ export class WorkerUtils { } const { worker } = await gqlFetch<{ - worker: IWorker; + worker: WorkerData | null; }>(getSubgraphUrl(networkData), GET_WORKER_QUERY, { address: address.toLowerCase(), }); - return worker || null; + if (!worker) return null; + + return { + ...worker, + totalHMTAmountReceived: BigInt(worker.totalHMTAmountReceived || 0), + }; } /** @@ -65,7 +71,7 @@ export class WorkerUtils { * type IWorker = { * id: string; * address: string; - * totalHMTAmountReceived: string; + * totalHMTAmountReceived: bigint; * payoutCount: number; * }; * ``` @@ -102,7 +108,7 @@ export class WorkerUtils { } const { workers } = await gqlFetch<{ - workers: IWorker[]; + workers: WorkerData[]; }>(getSubgraphUrl(networkData), GET_WORKERS_QUERY(filter), { address: filter?.address?.toLowerCase(), first: first, @@ -115,6 +121,9 @@ export class WorkerUtils { return []; } - return workers; + return workers.map((w) => ({ + ...w, + totalHMTAmountReceived: BigInt(w.totalHMTAmountReceived || 0), + })); } } diff --git a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts index 22790818ec..3292f2cc15 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts @@ -44,6 +44,7 @@ import { } from '../src/error'; import { EscrowClient, EscrowUtils } from '../src/escrow'; import { + EscrowData, GET_ESCROWS_QUERY, GET_ESCROW_BY_ADDRESS_QUERY, GET_PAYOUTS_QUERY, @@ -58,6 +59,7 @@ import { FAKE_URL, VALID_URL, } from './utils/constants'; +import { IEscrow } from '../src/interfaces'; describe('EscrowClient', () => { let escrowClient: any, @@ -2808,19 +2810,19 @@ describe('EscrowUtils', () => { }); test('should successfully getEscrows', async () => { - const escrows = [ + const escrows: EscrowData[] = [ { id: '1', address: '0x0', amountPaid: '3', balance: '0', count: '1', - jobRequesterId: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Completed', token: '0x0', totalFundedAmount: '3', + createdAt: '1', }, { id: '2', @@ -2828,12 +2830,12 @@ describe('EscrowUtils', () => { amountPaid: '0', balance: '3', count: '2', - jobRequesterId: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Pending', token: '0x0', totalFundedAmount: '3', + createdAt: '1', }, ]; const gqlFetchSpy = vi @@ -2845,7 +2847,25 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getEscrows(filter); - expect(result).toEqual(escrows); + const expected = escrows.map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + chainId: ChainId.POLYGON_AMOY, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_ESCROWS_QUERY(filter), @@ -2866,14 +2886,14 @@ describe('EscrowUtils', () => { }); test('should successfully getEscrows for the filter with status array', async () => { - const escrows = [ + const escrows: EscrowData[] = [ { id: '1', address: '0x0', amountPaid: '3', balance: '0', count: '1', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Pending', @@ -2886,7 +2906,7 @@ describe('EscrowUtils', () => { amountPaid: '3', balance: '0', count: '1', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Complete', @@ -2903,19 +2923,37 @@ describe('EscrowUtils', () => { status: [EscrowStatus.Pending, EscrowStatus.Complete], }); - expect(result).toEqual(escrows); + const expected = escrows.map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + chainId: ChainId.POLYGON_AMOY, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalled(); }); test('should successfully getEscrows for the filter', async () => { - const escrows = [ + const escrows: EscrowData[] = [ { id: '1', address: '0x0', amountPaid: '3', balance: '0', count: '1', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Completed', @@ -2932,12 +2970,30 @@ describe('EscrowUtils', () => { launcher: ethers.ZeroAddress, }); - expect(result).toEqual(escrows); + const expected = escrows.map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + chainId: ChainId.POLYGON_AMOY, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalled(); }); test('should successfully getEscrows created by a specific job requester', async () => { - const escrows = [ + const escrows: EscrowData[] = [ { id: '1', address: '0x0', @@ -2945,6 +3001,7 @@ describe('EscrowUtils', () => { balance: '0', count: '1', jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Completed', @@ -2961,19 +3018,37 @@ describe('EscrowUtils', () => { jobRequesterId: '1', }); - expect(result).toEqual(escrows); + const expected = escrows.map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + chainId: ChainId.POLYGON_AMOY, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalled(); }); test('should successfully getEscrows with pagination', async () => { - const escrows = [ + const escrows: EscrowData[] = [ { id: '1', address: '0x0', amountPaid: '3', balance: '0', count: '1', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Completed', @@ -2986,7 +3061,7 @@ describe('EscrowUtils', () => { amountPaid: '0', balance: '3', count: '2', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Pending', @@ -3005,7 +3080,25 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getEscrows(filter); - expect(result).toEqual(escrows); + const expected = escrows.map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + chainId: ChainId.POLYGON_AMOY, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_ESCROWS_QUERY(filter), @@ -3026,14 +3119,14 @@ describe('EscrowUtils', () => { }); test('should successfully getEscrows with pagination over limits', async () => { - const escrows = [ + const escrows: EscrowData[] = [ { id: '1', address: '0x0', amountPaid: '3', balance: '0', count: '1', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Completed', @@ -3056,7 +3149,7 @@ describe('EscrowUtils', () => { amountPaid: '0', balance: '3', count: '2', - jobRequesterId: '1', + createdAt: '1', factoryAddress: '0x0', launcher: '0x0', status: 'Pending', @@ -3085,7 +3178,26 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getEscrows(filter); - expect(result).toEqual(escrows); + + const expected = escrows.map((e) => ({ + ...e, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: BigInt(e.createdAt || 0), + recordingOracleFee: e.recordingOracleFee + ? BigInt(e.recordingOracleFee) + : undefined, + reputationOracleFee: e.reputationOracleFee + ? BigInt(e.reputationOracleFee) + : undefined, + exchangeOracleFee: e.exchangeOracleFee + ? BigInt(e.exchangeOracleFee) + : undefined, + chainId: ChainId.POLYGON_AMOY, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_ESCROWS_QUERY(filter), @@ -3155,7 +3267,19 @@ describe('EscrowUtils', () => { const result = await EscrowUtils.getEscrow(chainId, ethers.ZeroAddress); - expect(result).toEqual({ ...escrow, chainId }); + const expected: IEscrow = { + ...escrow, + amountPaid: 3n, + balance: 0n, + count: 1n, + totalFundedAmount: 3n, + recordingOracleFee: 1n, + reputationOracleFee: 1n, + exchangeOracleFee: 1n, + createdAt: 0n, + chainId, + }; + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( NETWORKS[ChainId.LOCALHOST]?.subgraphUrl, GET_ESCROW_BY_ADDRESS_QUERY(), diff --git a/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts index 31b015d41c..c94132cc4f 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts @@ -15,6 +15,7 @@ import { ErrorCannotUseDateAndBlockSimultaneously, ErrorInvalidHashProvided, } from '../src/error'; +import { TransactionData } from '../src/graphql'; import { GET_TRANSACTION_QUERY } from '../src/graphql/queries/transaction'; import { ITransaction, ITransactionsFilter } from '../src/interfaces'; import { TransactionUtils } from '../src/transaction'; @@ -24,12 +25,12 @@ describe('TransactionUtils', () => { const txHash = '0x62dD51230A30401C455c8398d06F85e4EaB6309f'; const invalidHash = 'InvalidHash'; - const mockTransaction: ITransaction = { - block: 12345n, + const mockTransaction = { + block: '12345', txHash: txHash, from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', - timestamp: 1625247600n, + timestamp: '1625247600', value: '1000000000000000000', method: 'transfer', internalTransactions: [ @@ -59,7 +60,24 @@ describe('TransactionUtils', () => { hash: txHash.toLowerCase(), } ); - expect(result).toEqual(mockTransaction); + const expected: ITransaction = { + block: 12345n, + txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual(expected); }); test('should throw an error for an invalid transaction hash', async () => { @@ -81,12 +99,12 @@ describe('TransactionUtils', () => { }); describe('getTransactions', () => { - const mockTransaction: ITransaction = { - block: 12345n, + const mockTransaction: TransactionData = { + block: '12345', txHash: '0x62dD51230A30401C455c8398d06F85e4EaB6309f', from: '0x1234567890123456789012345678901234567890', to: '0x0987654321098765432109876543210987654321', - timestamp: 1625247600n, + timestamp: '1625247600', value: '1000000000000000000', method: 'transfer', internalTransactions: [ @@ -129,7 +147,25 @@ describe('TransactionUtils', () => { skip: 0, } ); - expect(result).toEqual([mockTransaction, mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected, expected]); + // type assertions (bigint fields) }); test('should return an array of transactions with date filter', async () => { @@ -164,7 +200,24 @@ describe('TransactionUtils', () => { skip: 0, } ); - expect(result).toEqual([mockTransaction, mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected, expected]); }); test('should return an array of transactions with address filter', async () => { @@ -198,7 +251,24 @@ describe('TransactionUtils', () => { skip: 0, } ); - expect(result).toEqual([mockTransaction, mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected, expected]); }); test('should return an array of transactions filtered by method', async () => { @@ -232,7 +302,24 @@ describe('TransactionUtils', () => { skip: 0, } ); - expect(result).toEqual([mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected]); }); test('should return an array of transactions filtered by escrow', async () => { @@ -266,7 +353,24 @@ describe('TransactionUtils', () => { skip: 0, } ); - expect(result).toEqual([mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected]); }); test('should return an array of transactions filtered by token', async () => { @@ -300,7 +404,24 @@ describe('TransactionUtils', () => { skip: 0, } ); - expect(result).toEqual([mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected]); }); test('should throw an error if both date and block filters are used', async () => { @@ -362,7 +483,24 @@ describe('TransactionUtils', () => { skip: 10, } ); - expect(result).toEqual([mockTransaction, mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected, expected]); }); test('should return an array of transactions with pagination over limits', async () => { @@ -395,7 +533,24 @@ describe('TransactionUtils', () => { skip: 10, } ); - expect(result).toEqual([mockTransaction, mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected, expected]); }); test('should return an array of transactions with pagination and filters', async () => { @@ -431,7 +586,24 @@ describe('TransactionUtils', () => { skip: 5, } ); - expect(result).toEqual([mockTransaction, mockTransaction]); + const expected: ITransaction = { + block: 12345n, + txHash: mockTransaction.txHash, + from: mockTransaction.from, + to: mockTransaction.to, + timestamp: 1625247600n, + value: 1000000000000000000n, + method: 'transfer', + internalTransactions: [ + { + from: mockTransaction.internalTransactions[0].from, + to: mockTransaction.internalTransactions[0].to, + value: 1000000000000000000n, + method: 'transfer', + }, + ], + }; + expect(result).toEqual([expected, expected]); }); }); }); diff --git a/packages/sdk/typescript/human-protocol-sdk/test/worker.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/worker.test.ts index f9a2b7d04e..e306650345 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/worker.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/worker.test.ts @@ -9,6 +9,7 @@ import { } from '../src/graphql/queries/worker'; import { IWorker, IWorkersFilter } from '../src/interfaces'; import { WorkerUtils } from '../src/worker'; +import { WorkerData } from '../src/graphql'; vi.mock('graphql-request', () => { return { @@ -19,10 +20,10 @@ vi.mock('graphql-request', () => { describe('WorkerUtils', () => { describe('getWorker', () => { const workerAddress = '0x1234567890abcdef1234567890abcdef12345678'; - const mockWorker: IWorker = { + const mockWorker: WorkerData = { id: workerAddress, address: workerAddress, - totalHMTAmountReceived: 1000, + totalHMTAmountReceived: '1000', payoutCount: 10, }; @@ -43,7 +44,11 @@ describe('WorkerUtils', () => { address: workerAddress.toLowerCase(), } ); - expect(result).toEqual(mockWorker); + const expected: IWorker = { + ...mockWorker, + totalHMTAmountReceived: BigInt(mockWorker.totalHMTAmountReceived || 0), + }; + expect(result).toEqual(expected); }); test('should return null if worker is not found', async () => { @@ -85,17 +90,17 @@ describe('WorkerUtils', () => { }); describe('getWorkers', () => { - const mockWorkers: IWorker[] = [ + const mockWorkers: WorkerData[] = [ { id: '0x1234567890abcdef1234567890abcdef12345678', address: '0x1234567890abcdef1234567890abcdef12345678', - totalHMTAmountReceived: 1000, + totalHMTAmountReceived: '1000', payoutCount: 10, }, { id: '0xabcdefabcdefabcdefabcdefabcdefabcdef', address: '0xabcdefabcdefabcdefabcdefabcdefabcdef', - totalHMTAmountReceived: 2000, + totalHMTAmountReceived: '2000', payoutCount: 20, }, ]; @@ -126,7 +131,11 @@ describe('WorkerUtils', () => { orderDirection: 'asc', } ); - expect(result).toEqual(mockWorkers); + const expected: IWorker[] = mockWorkers.map((mockWorker) => ({ + ...mockWorker, + totalHMTAmountReceived: BigInt(mockWorker.totalHMTAmountReceived || 0), + })); + expect(result).toEqual(expected); }); test('should return an empty list if no workers are found', async () => { @@ -194,7 +203,12 @@ describe('WorkerUtils', () => { orderDirection: 'desc', } ); - expect(result).toEqual(mockWorkers); + + const expected: IWorker[] = mockWorkers.map((mockWorker) => ({ + ...mockWorker, + totalHMTAmountReceived: BigInt(mockWorker.totalHMTAmountReceived || 0), + })); + expect(result).toEqual(expected); }); }); }); From a7cbbc744d2c1192e39a003cd1a9e005f2a705fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Wed, 15 Oct 2025 10:36:07 +0200 Subject: [PATCH 02/11] Refactor staking and transaction utilities to use integers for amounts and timestamps in Python SDK and solve some issues with default values --- .../human_protocol_sdk/escrow/escrow_utils.py | 22 +++---- .../operator/operator_utils.py | 42 +++++++------- .../staking/staking_utils.py | 36 ++++++------ .../transaction/transaction_utils.py | 20 +++---- .../staking/test_staking_utils.py | 57 ++++++++++++++++++- .../transaction/test_transaction_utils.py | 18 +++--- 6 files changed, 126 insertions(+), 69 deletions(-) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py index 18dc28bb98..34234db211 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py @@ -292,15 +292,17 @@ def get_escrows( chain_id=chain_id, id=escrow.get("id", ""), address=escrow.get("address", ""), - amount_paid=int(escrow.get("amountPaid", 0)), - balance=int(escrow.get("balance", 0)), - count=int(escrow.get("count", 0)), + amount_paid=int(escrow.get("amountPaid") or 0), + balance=int(escrow.get("balance") or 0), + count=int(escrow.get("count") or 0), factory_address=escrow.get("factoryAddress", ""), launcher=escrow.get("launcher", ""), status=escrow.get("status", ""), token=escrow.get("token", ""), - total_funded_amount=int(escrow.get("totalFundedAmount", 0)), - created_at=datetime.fromtimestamp(int(escrow.get("createdAt", 0))), + total_funded_amount=int(escrow.get("totalFundedAmount") or 0), + created_at=datetime.fromtimestamp( + int(escrow.get("createdAt") or 0) + ), final_results_url=escrow.get("finalResultsUrl", None), final_results_hash=escrow.get("finalResultsHash", None), intermediate_results_url=escrow.get("intermediateResultsUrl", None), @@ -393,15 +395,15 @@ def get_escrow( chain_id=chain_id, id=escrow.get("id", ""), address=escrow.get("address", ""), - amount_paid=int(escrow.get("amountPaid", 0)), - balance=int(escrow.get("balance", 0)), - count=int(escrow.get("count", 0)), + amount_paid=int(escrow.get("amountPaid") or 0), + balance=int(escrow.get("balance") or 0), + count=int(escrow.get("count") or 0), factory_address=escrow.get("factoryAddress", ""), launcher=escrow.get("launcher", ""), status=escrow.get("status", ""), token=escrow.get("token", ""), - total_funded_amount=int(escrow.get("totalFundedAmount", 0)), - created_at=datetime.fromtimestamp(int(escrow.get("createdAt", 0))), + total_funded_amount=int(escrow.get("totalFundedAmount") or 0), + created_at=datetime.fromtimestamp(int(escrow.get("createdAt") or 0)), final_results_url=escrow.get("finalResultsUrl", None), final_results_hash=escrow.get("finalResultsHash", None), intermediate_results_url=escrow.get("intermediateResultsUrl", None), diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py index 55a3752caf..9aeb7ce7b0 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py @@ -240,18 +240,18 @@ def get_operators(filter: OperatorFilter) -> List[OperatorData]: network["address"] for network in operator["reputationNetworks"] ] - staker = operator.get("staker", {}) + staker = operator.get("staker") or {} operators.append( OperatorData( chain_id=filter.chain_id, id=operator.get("id", ""), address=operator.get("address", ""), - staked_amount=int(staker.get("stakedAmount", 0)), - locked_amount=int(staker.get("lockedAmount", 0)), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp", 0)), - withdrawn_amount=int(staker.get("withdrawnAmount", 0)), - slashed_amount=int(staker.get("slashedAmount", 0)), - amount_jobs_processed=int(operator.get("amountJobsProcessed", 0)), + staked_amount=int(staker.get("stakedAmount") or 0), + locked_amount=int(staker.get("lockedAmount") or 0), + locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), + withdrawn_amount=int(staker.get("withdrawnAmount") or 0), + slashed_amount=int(staker.get("slashedAmount") or 0), + amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), role=operator.get("role", None), fee=int(operator.get("fee")) if operator.get("fee", None) else None, public_key=operator.get("publicKey", None), @@ -338,17 +338,17 @@ def get_operator( network["address"] for network in operator["reputationNetworks"] ] - staker = operator.get("staker", {}) + staker = operator.get("staker") or {} return OperatorData( chain_id=chain_id, id=operator.get("id", ""), address=operator.get("address", ""), - staked_amount=int(staker.get("stakedAmount", 0)), - locked_amount=int(staker.get("lockedAmount", 0)), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp", 0)), - withdrawn_amount=int(staker.get("withdrawnAmount", 0)), - slashed_amount=int(staker.get("slashedAmount", 0)), - amount_jobs_processed=int(operator.get("amountJobsProcessed", 0)), + staked_amount=int(staker.get("stakedAmount") or 0), + locked_amount=int(staker.get("lockedAmount") or 0), + locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), + withdrawn_amount=int(staker.get("withdrawnAmount") or 0), + slashed_amount=int(staker.get("slashedAmount") or 0), + amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), role=operator.get("role", None), fee=int(operator.get("fee")) if operator.get("fee", None) else None, public_key=operator.get("publicKey", None), @@ -429,13 +429,13 @@ def get_reputation_network_operators( id=operator.get("id", ""), address=operator.get("address", ""), staked_amount=int( - (staker := operator.get("staker") or {}).get("stakedAmount", 0) + (staker := operator.get("staker") or {}).get("stakedAmount") or 0 ), - locked_amount=int(staker.get("lockedAmount", 0)), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp", 0)), - withdrawn_amount=int(staker.get("withdrawnAmount", 0)), - slashed_amount=int(staker.get("slashedAmount", 0)), - amount_jobs_processed=int(operator.get("amountJobsProcessed", 0)), + locked_amount=int(staker.get("lockedAmount") or 0), + locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), + withdrawn_amount=int(staker.get("withdrawnAmount") or 0), + slashed_amount=int(staker.get("slashedAmount") or 0), + amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), role=operator.get("role", None), fee=int(operator.get("fee")) if operator.get("fee", None) else None, public_key=operator.get("publicKey", None), @@ -516,7 +516,7 @@ def get_rewards_info(chain_id: ChainId, slasher: str) -> List[RewardData]: return [ RewardData( escrow_address=reward_added_event.get("escrowAddress", ""), - amount=int(reward_added_event.get("amount", 0)), + amount=int(reward_added_event.get("amount") or 0), ) for reward_added_event in reward_added_events ] diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py index 9579bad428..681163e2ff 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py @@ -39,12 +39,12 @@ def __init__( self, id: str, address: str, - staked_amount: str, - locked_amount: str, - withdrawn_amount: str, - slashed_amount: str, - locked_until_timestamp: str, - last_deposit_timestamp: str, + staked_amount: int, + locked_amount: int, + withdrawn_amount: int, + slashed_amount: int, + locked_until_timestamp: int, + last_deposit_timestamp: int, ): self.id = id self.address = address @@ -84,12 +84,12 @@ def get_staker(chain_id: ChainId, address: str) -> Optional[StakerData]: return StakerData( id=staker.get("id", ""), address=staker.get("address", ""), - staked_amount=staker.get("stakedAmount", ""), - locked_amount=staker.get("lockedAmount", ""), - withdrawn_amount=staker.get("withdrawnAmount", ""), - slashed_amount=staker.get("slashedAmount", ""), - locked_until_timestamp=staker.get("lockedUntilTimestamp", ""), - last_deposit_timestamp=staker.get("lastDepositTimestamp", ""), + staked_amount=int(staker.get("stakedAmount") or 0), + locked_amount=int(staker.get("lockedAmount") or 0), + withdrawn_amount=int(staker.get("withdrawnAmount") or 0), + slashed_amount=int(staker.get("slashedAmount") or 0), + locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), + last_deposit_timestamp=int(staker.get("lastDepositTimestamp") or 0), ) @staticmethod @@ -129,12 +129,12 @@ def get_stakers(filter: StakersFilter) -> List[StakerData]: StakerData( id=staker.get("id", ""), address=staker.get("address", ""), - staked_amount=staker.get("stakedAmount", ""), - locked_amount=staker.get("lockedAmount", ""), - withdrawn_amount=staker.get("withdrawnAmount", ""), - slashed_amount=staker.get("slashedAmount", ""), - locked_until_timestamp=staker.get("lockedUntilTimestamp", ""), - last_deposit_timestamp=staker.get("lastDepositTimestamp", ""), + staked_amount=int(staker.get("stakedAmount") or 0), + locked_amount=int(staker.get("lockedAmount") or 0), + withdrawn_amount=int(staker.get("withdrawnAmount") or 0), + slashed_amount=int(staker.get("slashedAmount") or 0), + locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), + last_deposit_timestamp=int(staker.get("lastDepositTimestamp") or 0), ) for staker in stakers_raw ] diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py index 54b561fc3c..6bfbe3b65a 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py @@ -38,7 +38,7 @@ def __init__( self, from_address: str, to_address: str, - value: str, + value: int, method: str, receiver: str, escrow: str, @@ -62,7 +62,7 @@ def __init__( from_address: str, to_address: str, timestamp: int, - value: str, + value: int, method: str, receiver: str, escrow: str, @@ -141,12 +141,12 @@ def get_transaction(chain_id: ChainId, hash: str) -> Optional[TransactionData]: return TransactionData( chain_id=chain_id, - block=transaction.get("block", 0), + block=int(transaction.get("block", 0) or 0), tx_hash=transaction.get("txHash", ""), from_address=transaction.get("from", ""), to_address=transaction.get("to", ""), - timestamp=transaction.get("timestamp", 0), - value=transaction.get("value", ""), + timestamp=int(transaction.get("timestamp") or 0), + value=int(transaction.get("value") or 0), method=transaction.get("method", ""), receiver=transaction.get("receiver", ""), escrow=transaction.get("escrow", ""), @@ -155,7 +155,7 @@ def get_transaction(chain_id: ChainId, hash: str) -> Optional[TransactionData]: InternalTransaction( from_address=internal_tx.get("from", ""), to_address=internal_tx.get("to", ""), - value=internal_tx.get("value", ""), + value=int(internal_tx.get("value") or 0), method=internal_tx.get("method", ""), receiver=internal_tx.get("receiver", ""), escrow=internal_tx.get("escrow", ""), @@ -239,12 +239,12 @@ def get_transactions(filter: TransactionFilter) -> List[TransactionData]: [ TransactionData( chain_id=filter.chain_id, - block=transaction.get("block", 0), + block=int(transaction.get("block", 0) or 0), tx_hash=transaction.get("txHash", ""), from_address=transaction.get("from", ""), to_address=transaction.get("to", ""), - timestamp=transaction.get("timestamp", 0), - value=transaction.get("value", ""), + timestamp=int(transaction.get("timestamp") or 0), + value=int(transaction.get("value") or 0), method=transaction.get("method", ""), receiver=transaction.get("receiver", ""), escrow=transaction.get("escrow", ""), @@ -253,7 +253,7 @@ def get_transactions(filter: TransactionFilter) -> List[TransactionData]: InternalTransaction( from_address=internal_tx.get("from", ""), to_address=internal_tx.get("to", ""), - value=internal_tx.get("value", ""), + value=int(internal_tx.get("value") or 0), method=internal_tx.get("method", ""), receiver=internal_tx.get("receiver", ""), escrow=internal_tx.get("escrow", ""), diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py index 6547858b5e..eb0b07e800 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py @@ -73,7 +73,50 @@ def test_get_stakers(self): self.assertEqual(len(stakers), 2) self.assertIsInstance(stakers[0], StakerData) self.assertEqual(stakers[0].id, "1") + self.assertEqual(stakers[0].address, mock_staker_1["address"]) + self.assertEqual( + stakers[0].staked_amount, int(mock_staker_1["stakedAmount"]) + ) + self.assertEqual( + stakers[0].locked_amount, int(mock_staker_1["lockedAmount"]) + ) + self.assertEqual( + stakers[0].withdrawn_amount, int(mock_staker_1["withdrawnAmount"]) + ) + self.assertEqual( + stakers[0].slashed_amount, int(mock_staker_1["slashedAmount"]) + ) + self.assertEqual( + stakers[0].locked_until_timestamp, + int(mock_staker_1["lockedUntilTimestamp"]), + ) + self.assertEqual( + stakers[0].last_deposit_timestamp, + int(mock_staker_1["lastDepositTimestamp"]), + ) + self.assertIsInstance(stakers[1], StakerData) self.assertEqual(stakers[1].id, "2") + self.assertEqual(stakers[1].address, mock_staker_2["address"]) + self.assertEqual( + stakers[1].staked_amount, int(mock_staker_2["stakedAmount"]) + ) + self.assertEqual( + stakers[1].locked_amount, int(mock_staker_2["lockedAmount"]) + ) + self.assertEqual( + stakers[1].withdrawn_amount, int(mock_staker_2["withdrawnAmount"]) + ) + self.assertEqual( + stakers[1].slashed_amount, int(mock_staker_2["slashedAmount"]) + ) + self.assertEqual( + stakers[1].locked_until_timestamp, + int(mock_staker_2["lockedUntilTimestamp"]), + ) + self.assertEqual( + stakers[1].last_deposit_timestamp, + int(mock_staker_2["lastDepositTimestamp"]), + ) def test_get_stakers_empty_response(self): with patch( @@ -120,7 +163,19 @@ def test_get_staker(self): ) self.assertIsInstance(staker, StakerData) self.assertEqual(staker.id, "1") - self.assertEqual(staker.address, "0x123") + self.assertEqual(staker.address, mock_staker["address"]) + self.assertEqual(staker.staked_amount, int(mock_staker["stakedAmount"])) + self.assertEqual(staker.locked_amount, int(mock_staker["lockedAmount"])) + self.assertEqual( + staker.withdrawn_amount, int(mock_staker["withdrawnAmount"]) + ) + self.assertEqual(staker.slashed_amount, int(mock_staker["slashedAmount"])) + self.assertEqual( + staker.locked_until_timestamp, int(mock_staker["lockedUntilTimestamp"]) + ) + self.assertEqual( + staker.last_deposit_timestamp, int(mock_staker["lastDepositTimestamp"]) + ) def test_get_staker_empty_data(self): with patch( diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py index 77c812c759..02ed2b8cbd 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py @@ -19,11 +19,11 @@ def test_get_transactions(self): "human_protocol_sdk.transaction.transaction_utils.get_data_from_subgraph" ) as mock_function: mock_transaction_1 = { - "block": 123, + "block": "123", "txHash": "0x1234567890123456789012345678901234567890123456789012345678901234", "from": "0x1234567890123456789012345678901234567890", "to": "0x9876543210987654321098765432109876543210", - "timestamp": 1622700000, + "timestamp": "1622700000", "value": "1000000000000000000", "method": "transfer", "internalTransactions": [ @@ -36,11 +36,11 @@ def test_get_transactions(self): ], } mock_transaction_2 = { - "block": 456, + "block": "456", "txHash": "0x9876543210987654321098765432109876543210987654321098765432109876", "from": "0x9876543210987654321098765432109876543210", "to": "0x1234567890123456789012345678901234567890", - "timestamp": 1622800000, + "timestamp": "1622800000", "value": "2000000000000000000", "method": "transfer", "internalTransactions": [ @@ -151,11 +151,11 @@ def test_get_transaction(self): "human_protocol_sdk.transaction.transaction_utils.get_data_from_subgraph" ) as mock_function: mock_transaction = { - "block": 123, + "block": "123", "txHash": "0x1234567890123456789012345678901234567890123456789012345678901234", "from": "0x1234567890123456789012345678901234567890", "to": "0x9876543210987654321098765432109876543210", - "timestamp": 1622700000, + "timestamp": "1622700000", "value": "1000000000000000000", "method": "transfer", "internalTransactions": [ @@ -184,12 +184,12 @@ def test_get_transaction(self): ) self.assertIsNotNone(transaction) self.assertEqual(transaction.chain_id, ChainId.POLYGON_AMOY) - self.assertEqual(transaction.block, mock_transaction["block"]) + self.assertEqual(transaction.block, int(mock_transaction["block"])) self.assertEqual(transaction.tx_hash, mock_transaction["txHash"]) self.assertEqual(transaction.from_address, mock_transaction["from"]) self.assertEqual(transaction.to_address, mock_transaction["to"]) - self.assertEqual(transaction.timestamp, mock_transaction["timestamp"]) - self.assertEqual(transaction.value, mock_transaction["value"]) + self.assertEqual(transaction.timestamp, int(mock_transaction["timestamp"])) + self.assertEqual(transaction.value, int(mock_transaction["value"])) self.assertEqual(transaction.method, mock_transaction["method"]) def test_get_transaction_empty_data(self): From 9cc37683ff2e7f4ca9bf1599e3e92bc8c414b5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Wed, 15 Oct 2025 13:30:44 +0200 Subject: [PATCH 03/11] Refactor escrow, staking, and transaction utilities to handle missing values --- .../human_protocol_sdk/escrow/escrow_utils.py | 36 ++++----- .../operator/operator_utils.py | 78 ++++++++++--------- .../staking/staking_utils.py | 8 +- .../transaction/transaction_utils.py | 56 ++++++------- .../human_protocol_sdk/worker/worker_utils.py | 18 +++-- 5 files changed, 101 insertions(+), 95 deletions(-) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py index 34234db211..43c6a64246 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py @@ -290,15 +290,15 @@ def get_escrows( [ EscrowData( chain_id=chain_id, - id=escrow.get("id", ""), - address=escrow.get("address", ""), + id=escrow.get("id") or "", + address=escrow.get("address") or "", amount_paid=int(escrow.get("amountPaid") or 0), balance=int(escrow.get("balance") or 0), count=int(escrow.get("count") or 0), - factory_address=escrow.get("factoryAddress", ""), - launcher=escrow.get("launcher", ""), - status=escrow.get("status", ""), - token=escrow.get("token", ""), + factory_address=escrow.get("factoryAddress") or "", + launcher=escrow.get("launcher") or "", + status=escrow.get("status") or "", + token=escrow.get("token") or "", total_funded_amount=int(escrow.get("totalFundedAmount") or 0), created_at=datetime.fromtimestamp( int(escrow.get("createdAt") or 0) @@ -316,17 +316,17 @@ def get_escrows( exchange_oracle=escrow.get("exchangeOracle", None), recording_oracle_fee=( int(escrow.get("recordingOracleFee")) - if escrow.get("recordingOracleFee", None) not in (None, "") + if escrow.get("recordingOracleFee", None) not in (None) or "" else None ), reputation_oracle_fee=( int(escrow.get("reputationOracleFee")) - if escrow.get("reputationOracleFee", None) not in (None, "") + if escrow.get("reputationOracleFee", None) not in (None) or "" else None ), exchange_oracle_fee=( int(escrow.get("exchangeOracleFee")) - if escrow.get("exchangeOracleFee", None) not in (None, "") + if escrow.get("exchangeOracleFee", None) not in (None) or "" else None ), ) @@ -393,15 +393,15 @@ def get_escrow( return EscrowData( chain_id=chain_id, - id=escrow.get("id", ""), - address=escrow.get("address", ""), + id=escrow.get("id") or "", + address=escrow.get("address") or "", amount_paid=int(escrow.get("amountPaid") or 0), balance=int(escrow.get("balance") or 0), count=int(escrow.get("count") or 0), - factory_address=escrow.get("factoryAddress", ""), - launcher=escrow.get("launcher", ""), - status=escrow.get("status", ""), - token=escrow.get("token", ""), + factory_address=escrow.get("factoryAddress") or "", + launcher=escrow.get("launcher") or "", + status=escrow.get("status") or "", + token=escrow.get("token") or "", total_funded_amount=int(escrow.get("totalFundedAmount") or 0), created_at=datetime.fromtimestamp(int(escrow.get("createdAt") or 0)), final_results_url=escrow.get("finalResultsUrl", None), @@ -415,17 +415,17 @@ def get_escrow( exchange_oracle=escrow.get("exchangeOracle", None), recording_oracle_fee=( int(escrow.get("recordingOracleFee")) - if escrow.get("recordingOracleFee", None) not in (None, "") + if escrow.get("recordingOracleFee", None) not in (None) or "" else None ), reputation_oracle_fee=( int(escrow.get("reputationOracleFee")) - if escrow.get("reputationOracleFee", None) not in (None, "") + if escrow.get("reputationOracleFee", None) not in (None) or "" else None ), exchange_oracle_fee=( int(escrow.get("exchangeOracleFee")) - if escrow.get("exchangeOracleFee", None) not in (None, "") + if escrow.get("exchangeOracleFee", None) not in (None) or "" else None ), ) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py index 9aeb7ce7b0..4ce112b5e9 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py @@ -244,20 +244,24 @@ def get_operators(filter: OperatorFilter) -> List[OperatorData]: operators.append( OperatorData( chain_id=filter.chain_id, - id=operator.get("id", ""), - address=operator.get("address", ""), + id=operator.get("id") or "", + address=operator.get("address") or "", staked_amount=int(staker.get("stakedAmount") or 0), locked_amount=int(staker.get("lockedAmount") or 0), locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), withdrawn_amount=int(staker.get("withdrawnAmount") or 0), slashed_amount=int(staker.get("slashedAmount") or 0), amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), - role=operator.get("role", None), - fee=int(operator.get("fee")) if operator.get("fee", None) else None, - public_key=operator.get("publicKey", None), - webhook_url=operator.get("webhookUrl", None), - website=operator.get("website", None), - url=operator.get("url", None), + role=operator.get("role") or None, + fee=( + int(operator.get("fee")) + if operator.get("fee") or None + else None + ), + public_key=operator.get("publicKey") or None, + webhook_url=operator.get("webhookUrl") or None, + website=operator.get("website") or None, + url=operator.get("url") or None, job_types=( operator.get("jobTypes").split(",") if isinstance(operator.get("jobTypes"), str) @@ -267,13 +271,13 @@ def get_operators(filter: OperatorFilter) -> List[OperatorData]: else [] ) ), - registration_needed=operator.get("registrationNeeded", None), + registration_needed=operator.get("registrationNeeded") or None, registration_instructions=operator.get( - "registrationInstructions", None + "registrationInstructions" or None ), reputation_networks=reputation_networks, - name=operator.get("name", None), - category=operator.get("category", None), + name=operator.get("name") or None, + category=operator.get("category") or None, ) ) @@ -341,20 +345,20 @@ def get_operator( staker = operator.get("staker") or {} return OperatorData( chain_id=chain_id, - id=operator.get("id", ""), - address=operator.get("address", ""), + id=operator.get("id") or "", + address=operator.get("address") or "", staked_amount=int(staker.get("stakedAmount") or 0), locked_amount=int(staker.get("lockedAmount") or 0), locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), withdrawn_amount=int(staker.get("withdrawnAmount") or 0), slashed_amount=int(staker.get("slashedAmount") or 0), amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), - role=operator.get("role", None), - fee=int(operator.get("fee")) if operator.get("fee", None) else None, - public_key=operator.get("publicKey", None), - webhook_url=operator.get("webhookUrl", None), - website=operator.get("website", None), - url=operator.get("url", None), + role=operator.get("role") or None, + fee=int(operator.get("fee")) if operator.get("fee") or None else None, + public_key=operator.get("publicKey") or None, + webhook_url=operator.get("webhookUrl") or None, + website=operator.get("website") or None, + url=operator.get("url") or None, job_types=( operator.get("jobTypes").split(",") if isinstance(operator.get("jobTypes"), str) @@ -364,11 +368,11 @@ def get_operator( else [] ) ), - registration_needed=operator.get("registrationNeeded", None), - registration_instructions=operator.get("registrationInstructions", None), + registration_needed=operator.get("registrationNeeded") or None, + registration_instructions=operator.get("registrationInstructions") or None, reputation_networks=reputation_networks, - name=operator.get("name", None), - category=operator.get("category", None), + name=operator.get("name") or None, + category=operator.get("category") or None, ) @staticmethod @@ -426,8 +430,8 @@ def get_reputation_network_operators( return [ OperatorData( chain_id=chain_id, - id=operator.get("id", ""), - address=operator.get("address", ""), + id=operator.get("id") or "", + address=operator.get("address") or "", staked_amount=int( (staker := operator.get("staker") or {}).get("stakedAmount") or 0 ), @@ -436,12 +440,12 @@ def get_reputation_network_operators( withdrawn_amount=int(staker.get("withdrawnAmount") or 0), slashed_amount=int(staker.get("slashedAmount") or 0), amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), - role=operator.get("role", None), - fee=int(operator.get("fee")) if operator.get("fee", None) else None, - public_key=operator.get("publicKey", None), - webhook_url=operator.get("webhookUrl", None), - website=operator.get("website", None), - url=operator.get("url", None), + role=operator.get("role") or None, + fee=int(operator.get("fee")) if operator.get("fee") or None else None, + public_key=operator.get("publicKey") or None, + webhook_url=operator.get("webhookUrl") or None, + website=operator.get("website") or None, + url=operator.get("url") or None, job_types=( operator.get("jobTypes").split(",") if isinstance(operator.get("jobTypes"), str) @@ -451,9 +455,9 @@ def get_reputation_network_operators( else [] ) ), - registration_needed=operator.get("registrationNeeded", None), + registration_needed=operator.get("registrationNeeded") or None, registration_instructions=operator.get( - "registrationInstructions", None + "registrationInstructions" or None ), reputation_networks=( [network["address"] for network in operator["reputationNetworks"]] @@ -461,8 +465,8 @@ def get_reputation_network_operators( and isinstance(operator.get("reputationNetworks"), list) else [] ), - name=operator.get("name", None), - category=operator.get("category", None), + name=operator.get("name") or None, + category=operator.get("category") or None, ) for operator in operators ] @@ -515,7 +519,7 @@ def get_rewards_info(chain_id: ChainId, slasher: str) -> List[RewardData]: return [ RewardData( - escrow_address=reward_added_event.get("escrowAddress", ""), + escrow_address=reward_added_event.get("escrowAddress") or "", amount=int(reward_added_event.get("amount") or 0), ) for reward_added_event in reward_added_events diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py index 681163e2ff..6e13809043 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py @@ -82,8 +82,8 @@ def get_staker(chain_id: ChainId, address: str) -> Optional[StakerData]: staker = data["data"]["staker"] return StakerData( - id=staker.get("id", ""), - address=staker.get("address", ""), + id=staker.get("id") or "", + address=staker.get("address") or "", staked_amount=int(staker.get("stakedAmount") or 0), locked_amount=int(staker.get("lockedAmount") or 0), withdrawn_amount=int(staker.get("withdrawnAmount") or 0), @@ -127,8 +127,8 @@ def get_stakers(filter: StakersFilter) -> List[StakerData]: stakers_raw = data["data"]["stakers"] return [ StakerData( - id=staker.get("id", ""), - address=staker.get("address", ""), + id=staker.get("id") or "", + address=staker.get("address") or "", staked_amount=int(staker.get("stakedAmount") or 0), locked_amount=int(staker.get("lockedAmount") or 0), withdrawn_amount=int(staker.get("withdrawnAmount") or 0), diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py index 6bfbe3b65a..214f7108e2 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py @@ -141,25 +141,25 @@ def get_transaction(chain_id: ChainId, hash: str) -> Optional[TransactionData]: return TransactionData( chain_id=chain_id, - block=int(transaction.get("block", 0) or 0), - tx_hash=transaction.get("txHash", ""), - from_address=transaction.get("from", ""), - to_address=transaction.get("to", ""), + block=int(transaction.get("block") or 0), + tx_hash=transaction.get("txHash") or "", + from_address=transaction.get("from") or "", + to_address=transaction.get("to") or "", timestamp=int(transaction.get("timestamp") or 0), value=int(transaction.get("value") or 0), - method=transaction.get("method", ""), - receiver=transaction.get("receiver", ""), - escrow=transaction.get("escrow", ""), - token=transaction.get("token", ""), + method=transaction.get("method") or "", + receiver=transaction.get("receiver") or "", + escrow=transaction.get("escrow") or "", + token=transaction.get("token") or "", internal_transactions=[ InternalTransaction( - from_address=internal_tx.get("from", ""), - to_address=internal_tx.get("to", ""), + from_address=internal_tx.get("from") or "", + to_address=internal_tx.get("to") or "", value=int(internal_tx.get("value") or 0), - method=internal_tx.get("method", ""), - receiver=internal_tx.get("receiver", ""), - escrow=internal_tx.get("escrow", ""), - token=internal_tx.get("token", ""), + method=internal_tx.get("method") or "", + receiver=internal_tx.get("receiver") or "", + escrow=internal_tx.get("escrow") or "", + token=internal_tx.get("token") or "", ) for internal_tx in transaction.get("internalTransactions", []) ], @@ -239,25 +239,25 @@ def get_transactions(filter: TransactionFilter) -> List[TransactionData]: [ TransactionData( chain_id=filter.chain_id, - block=int(transaction.get("block", 0) or 0), - tx_hash=transaction.get("txHash", ""), - from_address=transaction.get("from", ""), - to_address=transaction.get("to", ""), + block=int(transaction.get("block") or 0), + tx_hash=transaction.get("txHash") or "", + from_address=transaction.get("from") or "", + to_address=transaction.get("to") or "", timestamp=int(transaction.get("timestamp") or 0), value=int(transaction.get("value") or 0), - method=transaction.get("method", ""), - receiver=transaction.get("receiver", ""), - escrow=transaction.get("escrow", ""), - token=transaction.get("token", ""), + method=transaction.get("method") or "", + receiver=transaction.get("receiver") or "", + escrow=transaction.get("escrow") or "", + token=transaction.get("token") or "", internal_transactions=[ InternalTransaction( - from_address=internal_tx.get("from", ""), - to_address=internal_tx.get("to", ""), + from_address=internal_tx.get("from") or "", + to_address=internal_tx.get("to") or "", value=int(internal_tx.get("value") or 0), - method=internal_tx.get("method", ""), - receiver=internal_tx.get("receiver", ""), - escrow=internal_tx.get("escrow", ""), - token=internal_tx.get("token", ""), + method=internal_tx.get("method") or "", + receiver=internal_tx.get("receiver") or "", + escrow=internal_tx.get("escrow") or "", + token=internal_tx.get("token") or "", ) for internal_tx in transaction.get("internalTransactions", []) ], diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py index 2364d8537e..7f15bba249 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py @@ -87,10 +87,12 @@ def get_workers(filter: WorkerFilter) -> List[WorkerData]: for worker in workers_raw: workers.append( WorkerData( - id=worker.get("id", ""), - address=worker.get("address", ""), - total_amount_received=int(worker.get("totalHMTAmountReceived", 0)), - payout_count=int(worker.get("payoutCount", 0)), + id=worker.get("id") or "", + address=worker.get("address") or "", + total_amount_received=int( + worker.get("totalHMTAmountReceived") or 0 + ), + payout_count=int(worker.get("payoutCount") or 0), ) ) @@ -133,8 +135,8 @@ def get_worker(chain_id: ChainId, worker_address: str) -> Optional[WorkerData]: worker = worker_data["data"]["worker"] return WorkerData( - id=worker.get("id", ""), - address=worker.get("address", ""), - total_amount_received=int(worker.get("totalHMTAmountReceived", 0)), - payout_count=int(worker.get("payoutCount", 0)), + id=worker.get("id") or "", + address=worker.get("address") or "", + total_amount_received=int(worker.get("totalHMTAmountReceived") or 0), + payout_count=int(worker.get("payoutCount") or 0), ) From b2ca94738e5d19eca94646ec8243030a7ce6be33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Thu, 16 Oct 2025 18:08:02 +0200 Subject: [PATCH 04/11] - Updated EscrowData, WorkerData, InternalTransactionData, TransactionData, DailyEscrowData, and other related types to use string instead of bigint or number for monetary values and timestamps. - Changed optional fields to nullable types (e.g., `string | null`) for better handling of absent data. - Introduced new interfaces for StakerData and operator subgraph structures. - Adjusted mapping functions in operator, staking, transaction, and worker utilities to accommodate the new types. - Updated tests to reflect changes in data structures and ensure compatibility with the new type definitions. --- .../human-protocol-sdk/example/staking.ts | 4 +- .../human-protocol-sdk/src/escrow.ts | 138 ++++++------ .../human-protocol-sdk/src/graphql/types.ts | 133 ++++++++---- .../human-protocol-sdk/src/interfaces.ts | 79 +++---- .../human-protocol-sdk/src/operator.ts | 12 +- .../human-protocol-sdk/src/staking.ts | 21 +- .../human-protocol-sdk/src/transaction.ts | 62 +++--- .../human-protocol-sdk/src/worker.ts | 19 +- .../human-protocol-sdk/test/escrow.test.ts | 203 ++++++++++++++---- .../human-protocol-sdk/test/operator.test.ts | 25 +-- .../human-protocol-sdk/test/staking.test.ts | 66 ++++-- .../test/transaction.test.ts | 93 +++++++- 12 files changed, 550 insertions(+), 305 deletions(-) diff --git a/packages/sdk/typescript/human-protocol-sdk/example/staking.ts b/packages/sdk/typescript/human-protocol-sdk/example/staking.ts index f4ca4617cc..8c4f66a6a4 100644 --- a/packages/sdk/typescript/human-protocol-sdk/example/staking.ts +++ b/packages/sdk/typescript/human-protocol-sdk/example/staking.ts @@ -5,7 +5,7 @@ import { ethers } from 'ethers'; const runStakingExamples = async () => { const stakers = await StakingUtils.getStakers({ - chainId: ChainId.LOCALHOST, + chainId: ChainId.POLYGON_AMOY, maxLockedAmount: ethers.parseEther('5').toString(), orderBy: 'lastDepositTimestamp', orderDirection: OrderDirection.ASC, @@ -16,7 +16,7 @@ const runStakingExamples = async () => { try { const staker = await StakingUtils.getStaker( - ChainId.LOCALHOST, + ChainId.POLYGON_AMOY, stakers[0].address ); console.log('Staker info:', staker); diff --git a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts index 9ce9137052..c26a6a123b 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts @@ -60,12 +60,12 @@ import { IStatusEventFilter, } from './interfaces'; import { + CancellationRefund, EscrowStatus, EscrowWithdraw, NetworkData, - TransactionLikeWithNonce, Payout, - CancellationRefund, + TransactionLikeWithNonce, } from './types'; import { getSubgraphUrl, @@ -535,7 +535,7 @@ export class EscrowClient extends BaseEthersClient { const escrowContract = this.getEscrowContract(escrowAddress); const hasFundsToReserveParam = typeof a === 'bigint'; - const fundsToReserve = hasFundsToReserveParam ? (a as bigint) : undefined; + const fundsToReserve = hasFundsToReserveParam ? (a as bigint) : null; const txOptions = (hasFundsToReserveParam ? b : a) || {}; // When fundsToReserve is provided and is 0, allow empty URL. // In this situation not solutions might have been provided so the escrow can be straight cancelled. @@ -557,7 +557,7 @@ export class EscrowClient extends BaseEthersClient { } try { - if (fundsToReserve !== undefined) { + if (fundsToReserve !== null) { await ( await escrowContract['storeResults(string,string,uint256)']( url, @@ -1789,24 +1789,24 @@ export class EscrowUtils { * balance: bigint; * count: bigint; * factoryAddress: string; - * finalResultsUrl?: string; - * finalResultsHash?: string; - * intermediateResultsUrl?: string; - * intermediateResultsHash?: string; + * finalResultsUrl: string | null; + * finalResultsHash: string | null; + * intermediateResultsUrl: string | null; + * intermediateResultsHash: string | null; * launcher: string; - * jobRequesterId?: string; - * manifestHash?: string; - * manifest?: string; - * recordingOracle?: string; - * reputationOracle?: string; - * exchangeOracle?: string; - * recordingOracleFee?: bigint; - * reputationOracleFee?: bigint; - * exchangeOracleFee?: bigint; + * jobRequesterId: string | null; + * manifestHash: string | null; + * manifest: string | null; + * recordingOracle: string | null; + * reputationOracle: string | null; + * exchangeOracle: string | null; + * recordingOracleFee: number | null; + * reputationOracleFee: number | null; + * exchangeOracleFee: number | null; * status: string; * token: string; * totalFundedAmount: bigint; - * createdAt: bigint; + * createdAt: number; * chainId: number; * }; * ``` @@ -1879,24 +1879,9 @@ export class EscrowUtils { skip: skip, } ); - const mapped: IEscrow[] = (escrows || []).map((e) => ({ - ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) - : undefined, - reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) - : undefined, - exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) - : undefined, - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), - chainId: networkData.chainId, - })); + const mapped: IEscrow[] = (escrows || []).map((e) => + mapEscrow(e, networkData.chainId) + ); if (!escrows) { return []; @@ -1933,24 +1918,24 @@ export class EscrowUtils { * balance: bigint; * count: bigint; * factoryAddress: string; - * finalResultsUrl?: string; - * finalResultsHash?: string; - * intermediateResultsUrl?: string; - * intermediateResultsHash?: string; + * finalResultsUrl: string | null; + * finalResultsHash: string | null; + * intermediateResultsUrl: string | null; + * intermediateResultsHash: string | null; * launcher: string; - * jobRequesterId?: string; - * manifestHash?: string; - * manifest?: string; - * recordingOracle?: string; - * reputationOracle?: string; - * exchangeOracle?: string; - * recordingOracleFee?: bigint; - * reputationOracleFee?: bigint; - * exchangeOracleFee?: bigint; + * jobRequesterId: string | null; + * manifestHash: string | null; + * manifest: string | null; + * recordingOracle: string | null; + * reputationOracle: string | null; + * exchangeOracle: string | null; + * recordingOracleFee: number | null; + * reputationOracleFee: number | null; + * exchangeOracleFee: number | null; * status: string; * token: string; * totalFundedAmount: bigint; - * createdAt: bigint; + * createdAt: number; * chainId: number; * }; * ``` @@ -1989,24 +1974,7 @@ export class EscrowUtils { ); if (!escrow) return null; - return { - ...escrow, - amountPaid: BigInt(escrow.amountPaid || 0), - balance: BigInt(escrow.balance || 0), - count: BigInt(escrow.count || 0), - recordingOracleFee: escrow.recordingOracleFee - ? BigInt(escrow.recordingOracleFee) - : undefined, - reputationOracleFee: escrow.reputationOracleFee - ? BigInt(escrow.reputationOracleFee) - : undefined, - exchangeOracleFee: escrow.exchangeOracleFee - ? BigInt(escrow.exchangeOracleFee) - : undefined, - totalFundedAmount: BigInt(escrow.totalFundedAmount || 0), - createdAt: BigInt(escrow.createdAt || 0), - chainId: networkData.chainId, - }; + return mapEscrow(escrow, networkData.chainId); } /** @@ -2344,3 +2312,37 @@ export class EscrowUtils { return cancellationRefundEvents?.[0] || null; } } + +function mapEscrow(e: EscrowData, chainId: ChainId | number): IEscrow { + return { + id: e.id, + address: e.address, + amountPaid: BigInt(e.amountPaid || 0), + balance: BigInt(e.balance || 0), + count: BigInt(e.count || 0), + factoryAddress: e.factoryAddress, + finalResultsUrl: e.finalResultsUrl, + finalResultsHash: e.finalResultsHash, + intermediateResultsUrl: e.intermediateResultsUrl, + intermediateResultsHash: e.intermediateResultsHash, + launcher: e.launcher, + jobRequesterId: e.jobRequesterId, + manifestHash: e.manifestHash, + manifest: e.manifest, + recordingOracle: e.recordingOracle, + reputationOracle: e.reputationOracle, + exchangeOracle: e.exchangeOracle, + recordingOracleFee: e.recordingOracleFee + ? Number(e.recordingOracleFee) + : null, + reputationOracleFee: e.reputationOracleFee + ? Number(e.reputationOracleFee) + : null, + exchangeOracleFee: e.exchangeOracleFee ? Number(e.exchangeOracleFee) : null, + status: e.status, + token: e.token, + totalFundedAmount: BigInt(e.totalFundedAmount || 0), + createdAt: Number(e.createdAt || 0) * 1000, + chainId: Number(chainId), + }; +} diff --git a/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts b/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts index 2875426d10..93b1f92c6a 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts @@ -1,3 +1,4 @@ +import { IReputationNetwork } from '../interfaces'; import { ChainId } from '../enums'; export type EscrowData = { @@ -7,20 +8,20 @@ export type EscrowData = { balance: string; count: string; factoryAddress: string; - finalResultsUrl?: string; - finalResultsHash?: string; - intermediateResultsUrl?: string; - intermediateResultsHash?: string; + finalResultsUrl: string | null; + finalResultsHash: string | null; + intermediateResultsUrl: string | null; + intermediateResultsHash: string | null; launcher: string; - jobRequesterId?: string; - manifestHash?: string; - manifestUrl?: string; - recordingOracle?: string; - reputationOracle?: string; - exchangeOracle?: string; - recordingOracleFee?: string; - reputationOracleFee?: string; - exchangeOracleFee?: string; + jobRequesterId: string | null; + manifestHash: string | null; + manifest: string | null; + recordingOracle: string | null; + reputationOracle: string | null; + exchangeOracle: string | null; + recordingOracleFee: string | null; + reputationOracleFee: string | null; + exchangeOracleFee: string | null; status: string; token: string; totalFundedAmount: string; @@ -31,7 +32,7 @@ export type WorkerData = { id: string; address: string; totalHMTAmountReceived: string; - payoutCount: number; + payoutCount: string; }; export type InternalTransactionData = { @@ -39,10 +40,10 @@ export type InternalTransactionData = { to: string; value: string; method: string; - receiver?: string; - escrow?: string; - token?: string; - id?: string; + receiver: string | null; + escrow: string | null; + token: string | null; + id: string | null; }; export type TransactionData = { @@ -53,9 +54,9 @@ export type TransactionData = { timestamp: string; value: string; method: string; - receiver?: string; - escrow?: string; - token?: string; + receiver: string | null; + escrow: string | null; + token: string | null; internalTransactions: InternalTransactionData[]; }; @@ -111,21 +112,21 @@ export type RewardAddedEventData = { export type DailyEscrowData = { timestamp: Date; - escrowsTotal: number; - escrowsPending: number; - escrowsSolved: number; - escrowsPaid: number; - escrowsCancelled: number; + escrowsTotal: string; + escrowsPending: string; + escrowsSolved: string; + escrowsPaid: string; + escrowsCancelled: string; }; export type EscrowStatistics = { - totalEscrows: number; + totalEscrows: string; dailyEscrowsData: DailyEscrowData[]; }; export type DailyWorkerData = { timestamp: Date; - activeWorkers: number; + activeWorkers: string; }; export type WorkerStatistics = { @@ -134,9 +135,9 @@ export type WorkerStatistics = { export type DailyPaymentData = { timestamp: Date; - totalAmountPaid: bigint; - totalCount: number; - averageAmountPerWorker: bigint; + totalAmountPaid: string; + totalCount: string; + averageAmountPerWorker: string; }; export type PaymentStatistics = { @@ -150,34 +151,34 @@ export type HMTHolderData = { export type HMTHolder = { address: string; - balance: bigint; + balance: string; }; export type DailyHMTData = { timestamp: Date; - totalTransactionAmount: bigint; - totalTransactionCount: number; - dailyUniqueSenders: number; - dailyUniqueReceivers: number; + totalTransactionAmount: string; + totalTransactionCount: string; + dailyUniqueSenders: string; + dailyUniqueReceivers: string; }; export type HMTStatistics = { - totalTransferAmount: bigint; - totalTransferCount: number; - totalHolders: number; + totalTransferAmount: string; + totalTransferCount: string; + totalHolders: string; }; export type IMDataEntity = { - served: number; - solved: number; + served: string; + solved: string; }; export type IMData = Record; export type DailyTaskData = { timestamp: Date; - tasksTotal: number; - tasksSolved: number; + tasksTotal: string; + tasksSolved: string; }; export type TaskStatistics = { @@ -185,7 +186,7 @@ export type TaskStatistics = { }; export type StatusEvent = { - timestamp: number; + timestamp: string; escrowAddress: string; status: string; chainId: ChainId; @@ -197,5 +198,47 @@ export type KVStoreData = { key: string; value: string; timestamp: Date; - block: number; + block: string; +}; + +export type StakerData = { + id: string; + address: string; + stakedAmount: string; + lockedAmount: string; + withdrawnAmount: string; + slashedAmount: string; + lockedUntilTimestamp: string; + lastDepositTimestamp: string; }; + +export interface IOperatorSubgraph { + id: string; + address: string; + amountJobsProcessed: string; + role?: string; + fee?: string; + publicKey?: string; + webhookUrl?: string; + website?: string; + url?: string; + registrationNeeded?: boolean; + registrationInstructions?: string; + name?: string; + category?: string; + jobTypes?: string | string[]; + reputationNetworks?: { address: string }[]; + staker?: { + stakedAmount: string; + lockedAmount: string; + lockedUntilTimestamp: string; + withdrawnAmount: string; + slashedAmount: string; + lastDepositTimestamp: string; + }; +} + +export interface IReputationNetworkSubgraph + extends Omit { + operators: IOperatorSubgraph[]; +} diff --git a/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts b/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts index 6e9d90fc93..af653ec88c 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts @@ -12,7 +12,7 @@ export interface IOperator { address: string; stakedAmount: bigint; lockedAmount: bigint; - lockedUntilTimestamp: bigint; + lockedUntilTimestamp: number; withdrawnAmount: bigint; slashedAmount: bigint; amountJobsProcessed: bigint; @@ -30,32 +30,6 @@ export interface IOperator { category?: string; } -export interface IOperatorSubgraph { - id: string; - address: string; - amountJobsProcessed: bigint; - role?: string; - fee?: bigint; - publicKey?: string; - webhookUrl?: string; - website?: string; - url?: string; - registrationNeeded?: boolean; - registrationInstructions?: string; - name?: string; - category?: string; - jobTypes?: string | string[]; - reputationNetworks?: { address: string }[]; - staker?: { - stakedAmount: bigint; - lockedAmount: bigint; - lockedUntilTimestamp: bigint; - withdrawnAmount: bigint; - slashedAmount: bigint; - lastDepositTimestamp: bigint; - }; -} - export interface IOperatorsFilter extends IPagination { chainId: ChainId; roles?: string[]; @@ -69,11 +43,6 @@ export interface IReputationNetwork { operators: IOperator[]; } -export interface IReputationNetworkSubgraph - extends Omit { - operators: IOperatorSubgraph[]; -} - export interface IEscrow { id: string; address: string; @@ -81,24 +50,24 @@ export interface IEscrow { balance: bigint; count: bigint; factoryAddress: string; - finalResultsUrl?: string; - finalResultsHash?: string; - intermediateResultsUrl?: string; - intermediateResultsHash?: string; + finalResultsUrl: string | null; + finalResultsHash: string | null; + intermediateResultsUrl: string | null; + intermediateResultsHash: string | null; launcher: string; - jobRequesterId?: string; - manifestHash?: string; - manifest?: string; - recordingOracle?: string; - reputationOracle?: string; - exchangeOracle?: string; - recordingOracleFee?: bigint; - reputationOracleFee?: bigint; - exchangeOracleFee?: bigint; + jobRequesterId: string | null; + manifestHash: string | null; + manifest: string | null; + recordingOracle: string | null; + reputationOracle: string | null; + exchangeOracle: string | null; + recordingOracleFee: number | null; + reputationOracleFee: number | null; + exchangeOracleFee: number | null; status: string; token: string; totalFundedAmount: bigint; - createdAt: bigint; + createdAt: number; chainId: number; } @@ -159,9 +128,9 @@ export interface InternalTransaction { to: string; value: bigint; method: string; - receiver?: string; - escrow?: string; - token?: string; + receiver: string | null; + escrow: string | null; + token: string | null; } export interface ITransaction { @@ -169,12 +138,12 @@ export interface ITransaction { txHash: string; from: string; to: string; - timestamp: bigint; + timestamp: number; value: bigint; method: string; - receiver?: string; - escrow?: string; - token?: string; + receiver: string | null; + escrow: string | null; + token: string | null; internalTransactions: InternalTransaction[]; } @@ -229,10 +198,10 @@ export interface IStaker { address: string; stakedAmount: bigint; lockedAmount: bigint; - lockedUntil: bigint; withdrawableAmount: bigint; slashedAmount: bigint; - lastDepositTimestamp: bigint; + lockedUntil: number; + lastDepositTimestamp: number; } export interface IStakersFilter extends IPagination { diff --git a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts b/packages/sdk/typescript/human-protocol-sdk/src/operator.ts index 0f4ed7be6c..91bc4ea94b 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/operator.ts @@ -1,14 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import gqlFetch from 'graphql-request'; +import { IOperator, IOperatorsFilter, IReward } from './interfaces'; +import { GET_REWARD_ADDED_EVENTS_QUERY } from './graphql/queries/reward'; import { - IOperator, IOperatorSubgraph, - IOperatorsFilter, IReputationNetworkSubgraph, - IReward, -} from './interfaces'; -import { GET_REWARD_ADDED_EVENTS_QUERY } from './graphql/queries/reward'; -import { RewardAddedEventData } from './graphql'; + RewardAddedEventData, +} from './graphql'; import { GET_LEADER_QUERY, GET_LEADERS_QUERY, @@ -238,7 +236,7 @@ function mapOperator(operator: IOperatorSubgraph, chainId: ChainId): IOperator { address: operator.address, stakedAmount: BigInt(staker?.stakedAmount || 0), lockedAmount: BigInt(staker?.lockedAmount || 0), - lockedUntilTimestamp: BigInt(staker?.lockedUntilTimestamp || 0), + lockedUntilTimestamp: Number(staker?.lockedUntilTimestamp || 0) * 1000, withdrawnAmount: BigInt(staker?.withdrawnAmount || 0), slashedAmount: BigInt(staker?.slashedAmount || 0), amountJobsProcessed: BigInt(operator.amountJobsProcessed || 0), diff --git a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts index 5dc51374d0..29dd0b9dc4 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts @@ -24,6 +24,7 @@ import { ErrorUnsupportedChainID, } from './error'; import { IStaker, IStakersFilter, StakerInfo } from './interfaces'; +import { StakerData } from './graphql'; import { NetworkData } from './types'; import { getSubgraphUrl, throwError } from './utils'; import { @@ -509,7 +510,7 @@ export class StakingUtils { throw ErrorUnsupportedChainID; } - const { staker } = await gqlFetch<{ staker: IStaker }>( + const { staker } = await gqlFetch<{ staker: StakerData }>( getSubgraphUrl(networkData), GET_STAKER_BY_ADDRESS_QUERY, { id: stakerAddress.toLowerCase() } @@ -519,7 +520,7 @@ export class StakingUtils { throw ErrorStakerNotFound; } - return staker; + return mapStaker(staker); } /** @@ -539,7 +540,7 @@ export class StakingUtils { throw ErrorUnsupportedChainID; } - const { stakers } = await gqlFetch<{ stakers: IStaker[] }>( + const { stakers } = await gqlFetch<{ stakers: StakerData[] }>( getSubgraphUrl(networkData), GET_STAKERS_QUERY(filter), { @@ -577,6 +578,18 @@ export class StakingUtils { return []; } - return stakers; + return stakers.map((s) => mapStaker(s)); } } + +function mapStaker(s: StakerData): IStaker { + return { + address: s.address, + stakedAmount: BigInt(s.stakedAmount || 0), + lockedAmount: BigInt(s.lockedAmount || 0), + withdrawableAmount: BigInt(s.withdrawnAmount || 0), + slashedAmount: BigInt(s.slashedAmount || 0), + lockedUntil: Number(s.lockedUntilTimestamp || 0) * 1000, + lastDepositTimestamp: Number(s.lastDepositTimestamp || 0) * 1000, + }; +} diff --git a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts b/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts index 8896a07718..c4076092b8 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts @@ -8,13 +8,17 @@ import { ErrorInvalidHashProvided, ErrorUnsupportedChainID, } from './error'; +import { TransactionData } from './graphql'; import { - GET_TRANSACTIONS_QUERY, GET_TRANSACTION_QUERY, + GET_TRANSACTIONS_QUERY, } from './graphql/queries/transaction'; -import { ITransaction, ITransactionsFilter } from './interfaces'; +import { + InternalTransaction, + ITransaction, + ITransactionsFilter, +} from './interfaces'; import { getSubgraphUrl, getUnixTimestamp } from './utils'; -import { TransactionData } from './graphql'; export class TransactionUtils { /** @@ -80,17 +84,7 @@ export class TransactionUtils { }); if (!transaction) return null; - return { - ...transaction, - block: BigInt(transaction.block), - timestamp: BigInt(transaction.timestamp), - value: BigInt(transaction.value || 0), - internalTransactions: - transaction.internalTransactions?.map((itx) => ({ - ...itx, - value: BigInt(itx.value || 0), - })) || [], - }; + return mapTransaction(transaction); } /** @@ -208,16 +202,34 @@ export class TransactionUtils { return []; } - return transactions.map((transaction) => ({ - ...transaction, - block: BigInt(transaction.block), - timestamp: BigInt(transaction.timestamp), - value: BigInt(transaction.value || 0), - internalTransactions: - transaction.internalTransactions?.map((itx) => ({ - ...itx, - value: BigInt(itx.value || 0), - })) || [], - })); + return transactions.map((transaction) => mapTransaction(transaction)); } } + +function mapTransaction(t: TransactionData): ITransaction { + const internalTransactions: InternalTransaction[] = ( + t.internalTransactions || [] + ).map((itx) => ({ + from: itx.from, + to: itx.to, + value: BigInt(itx.value || 0), + method: itx.method, + receiver: itx.receiver, + escrow: itx.escrow, + token: itx.token, + })); + + return { + block: BigInt(t.block), + txHash: t.txHash, + from: t.from, + to: t.to, + timestamp: Number(t.timestamp || 0) * 1000, + value: BigInt(t.value || 0), + method: t.method, + receiver: t.receiver, + escrow: t.escrow, + token: t.token, + internalTransactions, + }; +} diff --git a/packages/sdk/typescript/human-protocol-sdk/src/worker.ts b/packages/sdk/typescript/human-protocol-sdk/src/worker.ts index a609955353..60fa11ed5f 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/worker.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/worker.ts @@ -45,10 +45,7 @@ export class WorkerUtils { if (!worker) return null; - return { - ...worker, - totalHMTAmountReceived: BigInt(worker.totalHMTAmountReceived || 0), - }; + return mapWorker(worker); } /** @@ -121,9 +118,15 @@ export class WorkerUtils { return []; } - return workers.map((w) => ({ - ...w, - totalHMTAmountReceived: BigInt(w.totalHMTAmountReceived || 0), - })); + return workers.map((w) => mapWorker(w)); } } + +function mapWorker(w: WorkerData): IWorker { + return { + id: w.id, + address: w.address, + totalHMTAmountReceived: BigInt(w.totalHMTAmountReceived || 0), + payoutCount: Number(w.payoutCount || 0), + }; +} diff --git a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts index 3292f2cc15..615f259eaf 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts @@ -59,7 +59,7 @@ import { FAKE_URL, VALID_URL, } from './utils/constants'; -import { IEscrow } from '../src/interfaces'; +import { IEscrow, IEscrowsFilter } from '../src/interfaces'; describe('EscrowClient', () => { let escrowClient: any, @@ -2823,6 +2823,19 @@ describe('EscrowUtils', () => { token: '0x0', totalFundedAmount: '3', createdAt: '1', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, { id: '2', @@ -2836,6 +2849,19 @@ describe('EscrowUtils', () => { token: '0x0', totalFundedAmount: '3', createdAt: '1', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, ]; const gqlFetchSpy = vi @@ -2853,16 +2879,16 @@ describe('EscrowUtils', () => { balance: BigInt(e.balance || 0), count: BigInt(e.count || 0), totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), + createdAt: Number(e.createdAt || 0) * 1000, recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) - : undefined, + ? Number(e.recordingOracleFee) + : null, reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) - : undefined, + ? Number(e.reputationOracleFee) + : null, exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) - : undefined, + ? Number(e.exchangeOracleFee) + : null, chainId: ChainId.POLYGON_AMOY, })); expect(result).toEqual(expected); @@ -2899,6 +2925,19 @@ describe('EscrowUtils', () => { status: 'Pending', token: '0x0', totalFundedAmount: '3', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, { id: '2', @@ -2912,6 +2951,19 @@ describe('EscrowUtils', () => { status: 'Complete', token: '0x0', totalFundedAmount: '3', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, ]; const gqlFetchSpy = vi @@ -2929,16 +2981,16 @@ describe('EscrowUtils', () => { balance: BigInt(e.balance || 0), count: BigInt(e.count || 0), totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), + createdAt: Number(e.createdAt || 0) * 1000, recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) - : undefined, + ? Number(e.recordingOracleFee) + : null, reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) - : undefined, + ? Number(e.reputationOracleFee) + : null, exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) - : undefined, + ? Number(e.exchangeOracleFee) + : null, chainId: ChainId.POLYGON_AMOY, })); expect(result).toEqual(expected); @@ -2959,6 +3011,19 @@ describe('EscrowUtils', () => { status: 'Completed', token: '0x0', totalFundedAmount: '3', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, ]; const gqlFetchSpy = vi @@ -2976,16 +3041,16 @@ describe('EscrowUtils', () => { balance: BigInt(e.balance || 0), count: BigInt(e.count || 0), totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), + createdAt: Number(e.createdAt || 0) * 1000, recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) - : undefined, + ? Number(e.recordingOracleFee) + : null, reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) - : undefined, + ? Number(e.reputationOracleFee) + : null, exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) - : undefined, + ? Number(e.exchangeOracleFee) + : null, chainId: ChainId.POLYGON_AMOY, })); expect(result).toEqual(expected); @@ -3007,6 +3072,18 @@ describe('EscrowUtils', () => { status: 'Completed', token: '0x0', totalFundedAmount: '3', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, }, ]; const gqlFetchSpy = vi @@ -3024,16 +3101,16 @@ describe('EscrowUtils', () => { balance: BigInt(e.balance || 0), count: BigInt(e.count || 0), totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), + createdAt: Number(e.createdAt || 0) * 1000, recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) - : undefined, + ? Number(e.recordingOracleFee) + : null, reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) - : undefined, + ? Number(e.reputationOracleFee) + : null, exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) - : undefined, + ? Number(e.exchangeOracleFee) + : null, chainId: ChainId.POLYGON_AMOY, })); expect(result).toEqual(expected); @@ -3054,6 +3131,19 @@ describe('EscrowUtils', () => { status: 'Completed', token: '0x0', totalFundedAmount: '3', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, { id: '2', @@ -3067,6 +3157,19 @@ describe('EscrowUtils', () => { status: 'Pending', token: '0x0', totalFundedAmount: '3', + finalResultsHash: null, + finalResultsUrl: null, + intermediateResultsHash: null, + intermediateResultsUrl: null, + manifestHash: null, + manifest: null, + recordingOracle: null, + recordingOracleFee: null, + reputationOracle: null, + reputationOracleFee: null, + exchangeOracle: null, + exchangeOracleFee: null, + jobRequesterId: null, }, ]; const gqlFetchSpy = vi @@ -3086,16 +3189,16 @@ describe('EscrowUtils', () => { balance: BigInt(e.balance || 0), count: BigInt(e.count || 0), totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), + createdAt: Number(e.createdAt || 0) * 1000, recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) - : undefined, + ? Number(e.recordingOracleFee) + : null, reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) - : undefined, + ? Number(e.reputationOracleFee) + : null, exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) - : undefined, + ? Number(e.exchangeOracleFee) + : null, chainId: ChainId.POLYGON_AMOY, })); expect(result).toEqual(expected); @@ -3142,6 +3245,9 @@ describe('EscrowUtils', () => { exchangeOracleFee: '1', recordingOracleFee: '1', reputationOracleFee: '1', + jobRequesterId: '1', + manifest: null, + manifestHash: null, }, { id: '2', @@ -3165,6 +3271,9 @@ describe('EscrowUtils', () => { exchangeOracleFee: '1', recordingOracleFee: '1', reputationOracleFee: '1', + jobRequesterId: '1', + manifest: null, + manifestHash: null, }, ]; const gqlFetchSpy = vi @@ -3185,15 +3294,15 @@ describe('EscrowUtils', () => { balance: BigInt(e.balance || 0), count: BigInt(e.count || 0), totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: BigInt(e.createdAt || 0), + createdAt: Number(e.createdAt || 0) * 1000, recordingOracleFee: e.recordingOracleFee - ? BigInt(e.recordingOracleFee) + ? Number(e.recordingOracleFee) : undefined, reputationOracleFee: e.reputationOracleFee - ? BigInt(e.reputationOracleFee) + ? Number(e.reputationOracleFee) : undefined, exchangeOracleFee: e.exchangeOracleFee - ? BigInt(e.exchangeOracleFee) + ? Number(e.exchangeOracleFee) : undefined, chainId: ChainId.POLYGON_AMOY, })); @@ -3260,6 +3369,9 @@ describe('EscrowUtils', () => { exchangeOracleFee: '1', recordingOracleFee: '1', reputationOracleFee: '1', + jobRequesterId: null, + manifest: null, + manifestHash: null, }; const gqlFetchSpy = vi .spyOn(gqlFetch, 'default') @@ -3273,11 +3385,14 @@ describe('EscrowUtils', () => { balance: 0n, count: 1n, totalFundedAmount: 3n, - recordingOracleFee: 1n, - reputationOracleFee: 1n, - exchangeOracleFee: 1n, - createdAt: 0n, + recordingOracleFee: 1, + reputationOracleFee: 1, + exchangeOracleFee: 1, + createdAt: 0, chainId, + jobRequesterId: null, + manifest: null, + manifestHash: null, }; expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( diff --git a/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts index 16119abd3c..68e28e6eea 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts @@ -20,14 +20,9 @@ import { GET_LEADERS_QUERY, GET_REPUTATION_NETWORK_QUERY, } from '../src/graphql/queries/operator'; -import { - IOperator, - IOperatorsFilter, - IOperatorSubgraph, - IReputationNetworkSubgraph, - IReward, -} from '../src/interfaces'; +import { IOperator, IOperatorsFilter, IReward } from '../src/interfaces'; import { OperatorUtils } from '../src/operator'; +import { IOperatorSubgraph, IReputationNetworkSubgraph } from '../src/graphql'; vi.mock('graphql-request', () => { return { @@ -42,7 +37,7 @@ describe('OperatorUtils', () => { const mockOperatorSubgraph: IOperatorSubgraph = { id: stakerAddress, address: stakerAddress, - amountJobsProcessed: ethers.parseEther('25'), + amountJobsProcessed: ethers.parseEther('25').toString(), jobTypes: ['type1', 'type2'], registrationNeeded: true, registrationInstructions: 'www.google.com', @@ -53,12 +48,12 @@ describe('OperatorUtils', () => { }, ], staker: { - stakedAmount: ethers.parseEther('100'), - lockedAmount: ethers.parseEther('25'), - lockedUntilTimestamp: ethers.toBigInt(0), - withdrawnAmount: ethers.parseEther('25'), - slashedAmount: ethers.parseEther('25'), - lastDepositTimestamp: ethers.toBigInt(0), + stakedAmount: ethers.parseEther('100').toString(), + lockedAmount: ethers.parseEther('25').toString(), + lockedUntilTimestamp: '0', + withdrawnAmount: ethers.parseEther('25').toString(), + slashedAmount: ethers.parseEther('25').toString(), + lastDepositTimestamp: '0', }, }; const operator: IOperator = { @@ -73,7 +68,7 @@ describe('OperatorUtils', () => { chainId: ChainId.LOCALHOST, stakedAmount: ethers.parseEther('100'), lockedAmount: ethers.parseEther('25'), - lockedUntilTimestamp: ethers.toBigInt(0), + lockedUntilTimestamp: 0, withdrawnAmount: ethers.parseEther('25'), slashedAmount: ethers.parseEther('25'), }; diff --git a/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts index b0eaa4448f..a3e85fa70e 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts @@ -22,6 +22,7 @@ import { } from './utils/constants'; import { IStaker, IStakersFilter } from '../src/interfaces'; import { StakingUtils } from '../src/staking'; +import { StakerData } from '../src/graphql'; vi.mock('graphql-request', () => { return { @@ -564,14 +565,15 @@ describe('StakingUtils', () => { const invalidAddress = 'InvalidAddress'; describe('getStaker', () => { - const mockStaker: IStaker = { + const mockStaker: StakerData = { + id: '0x0987654321098765432109876543210987654320', address: stakerAddress, - stakedAmount: 1000n, - lockedAmount: 100n, - lockedUntil: 1234567890n, - withdrawableAmount: 900n, - slashedAmount: 0n, - lastDepositTimestamp: 1234567890n, + stakedAmount: '1000', + lockedAmount: '100', + lockedUntilTimestamp: '1234567890', + withdrawnAmount: '900', + slashedAmount: '0', + lastDepositTimestamp: '1234567890', }; test('should return staker information', async () => { @@ -589,7 +591,16 @@ describe('StakingUtils', () => { expect.anything(), { id: stakerAddress.toLowerCase() } ); - expect(result).toEqual(mockStaker); + const expectedStaker: IStaker = { + address: mockStaker.address, + stakedAmount: BigInt(mockStaker.stakedAmount), + lockedAmount: BigInt(mockStaker.lockedAmount), + withdrawableAmount: BigInt(mockStaker.withdrawnAmount), + slashedAmount: BigInt(mockStaker.slashedAmount), + lockedUntil: Number(mockStaker.lockedUntilTimestamp) * 1000, + lastDepositTimestamp: Number(mockStaker.lastDepositTimestamp) * 1000, + }; + expect(result).toEqual(expectedStaker); }); test('should throw an error for an invalid staker address', async () => { @@ -621,24 +632,26 @@ describe('StakingUtils', () => { }); describe('getStakers', () => { - const mockStakers: IStaker[] = [ + const mockStakers: StakerData[] = [ { + id: '0x0987654321098765432109876543210987654320', address: stakerAddress, - stakedAmount: 1000n, - lockedAmount: 100n, - lockedUntil: 1234567890n, - withdrawableAmount: 900n, - slashedAmount: 0n, - lastDepositTimestamp: 1234567890n, + stakedAmount: '1000', + lockedAmount: '100', + lockedUntilTimestamp: '1234567890', + withdrawnAmount: '900', + slashedAmount: '0', + lastDepositTimestamp: '1234567890', }, { + id: '0x0987654321098765432109876543210987654321', address: '0x0987654321098765432109876543210987654321', - stakedAmount: 2000n, - lockedAmount: 200n, - lockedUntil: 1234567891n, - withdrawableAmount: 1800n, - slashedAmount: 0n, - lastDepositTimestamp: 1234567890n, + stakedAmount: '2000', + lockedAmount: '200', + lockedUntilTimestamp: '1234567891', + withdrawnAmount: '1800', + slashedAmount: '0', + lastDepositTimestamp: '1234567890', }, ]; @@ -672,7 +685,16 @@ describe('StakingUtils', () => { skip: 0, }) ); - expect(result).toEqual(mockStakers); + const expectedStakers = mockStakers.map((s) => ({ + address: s.address, + stakedAmount: BigInt(s.stakedAmount), + lockedAmount: BigInt(s.lockedAmount), + withdrawableAmount: BigInt(s.withdrawnAmount), + slashedAmount: BigInt(s.slashedAmount), + lockedUntil: Number(s.lockedUntilTimestamp) * 1000, + lastDepositTimestamp: Number(s.lastDepositTimestamp) * 1000, + })); + expect(result).toEqual(expectedStakers); }); test('should return an empty array if no stakers found', async () => { diff --git a/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts index c94132cc4f..3cbea573dc 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/transaction.test.ts @@ -33,12 +33,18 @@ describe('TransactionUtils', () => { timestamp: '1625247600', value: '1000000000000000000', method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: '0x1234567890123456789012345678901234567890', to: '0x1234567890123456789012345678901234567891', value: '1000000000000000000', method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -65,15 +71,21 @@ describe('TransactionUtils', () => { txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -107,12 +119,19 @@ describe('TransactionUtils', () => { timestamp: '1625247600', value: '1000000000000000000', method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: '0x1234567890123456789012345678901234567890', to: '0x1234567890123456789012345678901234567891', value: '1000000000000000000', method: 'transfer', + receiver: null, + escrow: null, + token: null, + id: null, }, ], }; @@ -152,15 +171,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -205,15 +230,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -256,15 +287,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -307,15 +344,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -358,15 +401,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -409,15 +458,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -488,15 +543,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -538,15 +599,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; @@ -591,15 +658,21 @@ describe('TransactionUtils', () => { txHash: mockTransaction.txHash, from: mockTransaction.from, to: mockTransaction.to, - timestamp: 1625247600n, + timestamp: 1625247600000, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, internalTransactions: [ { from: mockTransaction.internalTransactions[0].from, to: mockTransaction.internalTransactions[0].to, value: 1000000000000000000n, method: 'transfer', + receiver: null, + escrow: null, + token: null, }, ], }; From bbacf06d5bf977c098585ced37c8ada8808a1c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Thu, 16 Oct 2025 18:12:14 +0200 Subject: [PATCH 05/11] Refactor EscrowUtils for improved readability --- .../human_protocol_sdk/escrow/escrow_utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py index 43c6a64246..3e0f4bdfce 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py @@ -316,17 +316,17 @@ def get_escrows( exchange_oracle=escrow.get("exchangeOracle", None), recording_oracle_fee=( int(escrow.get("recordingOracleFee")) - if escrow.get("recordingOracleFee", None) not in (None) or "" + if escrow.get("recordingOracleFee") else None ), reputation_oracle_fee=( int(escrow.get("reputationOracleFee")) - if escrow.get("reputationOracleFee", None) not in (None) or "" + if escrow.get("reputationOracleFee") else None ), exchange_oracle_fee=( int(escrow.get("exchangeOracleFee")) - if escrow.get("exchangeOracleFee", None) not in (None) or "" + if escrow.get("exchangeOracleFee") else None ), ) @@ -415,17 +415,17 @@ def get_escrow( exchange_oracle=escrow.get("exchangeOracle", None), recording_oracle_fee=( int(escrow.get("recordingOracleFee")) - if escrow.get("recordingOracleFee", None) not in (None) or "" + if escrow.get("recordingOracleFee") else None ), reputation_oracle_fee=( int(escrow.get("reputationOracleFee")) - if escrow.get("reputationOracleFee", None) not in (None) or "" + if escrow.get("reputationOracleFee") else None ), exchange_oracle_fee=( int(escrow.get("exchangeOracleFee")) - if escrow.get("exchangeOracleFee", None) not in (None) or "" + if escrow.get("exchangeOracleFee") else None ), ) From 8547da7117a66384e9d4d2bcb2ed9be241fb29bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Fri, 17 Oct 2025 17:16:17 +0200 Subject: [PATCH 06/11] Refactor GraphQL types and interfaces for improved nullability and consistency - Removed unused types and consolidated daily statistics types. - Updated operator-related fields to allow null values for better handling of optional data. - Introduced new types for payout and cancellation refund data. - Adjusted mapping functions to accommodate changes in data types and nullability. - Enhanced test cases to reflect the updated types and ensure correctness. --- .../human_protocol_sdk/escrow/escrow_utils.py | 109 ++++---- .../operator/operator_utils.py | 240 +++++++++++------- .../staking/staking_utils.py | 4 +- .../transaction/transaction_utils.py | 82 +++--- .../human_protocol_sdk/worker/worker_utils.py | 18 +- .../escrow/test_escrow_utils.py | 20 +- .../operator/test_operator_utils.py | 36 +-- .../staking/test_staking_utils.py | 14 +- .../transaction/test_transaction_utils.py | 4 +- .../human-protocol-sdk/src/escrow.ts | 108 +++++--- .../human-protocol-sdk/src/graphql/types.ts | 118 +++------ .../human-protocol-sdk/src/interfaces.ts | 122 +++++++-- .../human-protocol-sdk/src/operator.ts | 20 +- .../human-protocol-sdk/src/staking.ts | 12 +- .../human-protocol-sdk/src/statistics.ts | 120 +++++---- .../human-protocol-sdk/src/transaction.ts | 6 +- .../human-protocol-sdk/src/types.ts | 79 ------ .../human-protocol-sdk/test/escrow.test.ts | 133 +++++++--- .../human-protocol-sdk/test/operator.test.ts | 14 + .../test/statistics.test.ts | 8 +- 20 files changed, 694 insertions(+), 573 deletions(-) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py index 3e0f4bdfce..fa1135452d 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py @@ -57,10 +57,11 @@ def __init__( count: int, factory_address: str, launcher: str, + job_requester_id: Optional[str], status: str, token: str, total_funded_amount: int, - created_at: datetime, + created_at: int, final_results_url: Optional[str] = None, final_results_hash: Optional[str] = None, intermediate_results_url: Optional[str] = None, @@ -85,10 +86,11 @@ def __init__( :param count: Count :param factory_address: Factory address :param launcher: Launcher + :param job_requester_id: Job requester identifier :param status: Status :param token: Token :param total_funded_amount: Total funded amount - :param created_at: Creation date + :param created_at: Creation timestamp in milliseconds :param final_results_url: URL for final results. :param final_results_hash: Hash for final results. :param intermediate_results_url: URL for intermediate results. @@ -114,6 +116,7 @@ def __init__( self.intermediate_results_url = intermediate_results_url self.intermediate_results_hash = intermediate_results_hash self.launcher = launcher + self.job_requester_id = job_requester_id self.manifest_hash = manifest_hash self.manifest = manifest self.recording_oracle = recording_oracle @@ -125,7 +128,7 @@ def __init__( self.status = status self.token = token self.total_funded_amount = total_funded_amount - self.created_at = created_at + self.created_at = created_at * 1000 self.chain_id = chain_id @@ -133,7 +136,7 @@ class StatusEvent: """ Initializes a StatusEvent instance. - :param timestamp: The timestamp of the event. + :param timestamp: The timestamp of the event in milliseconds. :param status: The status of the escrow. :param chain_id: The chain identifier where the event occurred. :param escrow_address: The address of the escrow. @@ -142,7 +145,7 @@ class StatusEvent: def __init__( self, timestamp: int, status: str, chain_id: ChainId, escrow_address: str ): - self.timestamp = timestamp + self.timestamp = timestamp * 1000 self.status = status self.chain_id = chain_id self.escrow_address = escrow_address @@ -157,7 +160,7 @@ class Payout: :param escrow_address: The address of the escrow that executed the payout. :param recipient: The address of the recipient. :param amount: The amount of the payout. - :param created_at: The time of creation of the payout. + :param created_at: The time of creation of the payout in milliseconds. """ def __init__( @@ -167,7 +170,7 @@ def __init__( self.escrow_address = escrow_address self.recipient = recipient self.amount = amount - self.created_at = created_at + self.created_at = created_at * 1000 class CancellationRefund: @@ -179,7 +182,7 @@ class CancellationRefund: :param receiver: The address of the recipient receiving the refund. :param amount: The amount being refunded. :param block: The block number in which the refund was processed. - :param timestamp: The timestamp of the refund event. + :param timestamp: The timestamp of the refund event in milliseconds. :param tx_hash: The transaction hash of the refund event. """ @@ -198,7 +201,7 @@ def __init__( self.receiver = receiver self.amount = amount self.block = block - self.timestamp = timestamp + self.timestamp = timestamp * 1000 self.tx_hash = tx_hash @@ -290,30 +293,27 @@ def get_escrows( [ EscrowData( chain_id=chain_id, - id=escrow.get("id") or "", - address=escrow.get("address") or "", - amount_paid=int(escrow.get("amountPaid") or 0), - balance=int(escrow.get("balance") or 0), - count=int(escrow.get("count") or 0), - factory_address=escrow.get("factoryAddress") or "", - launcher=escrow.get("launcher") or "", - status=escrow.get("status") or "", - token=escrow.get("token") or "", - total_funded_amount=int(escrow.get("totalFundedAmount") or 0), - created_at=datetime.fromtimestamp( - int(escrow.get("createdAt") or 0) - ), - final_results_url=escrow.get("finalResultsUrl", None), - final_results_hash=escrow.get("finalResultsHash", None), - intermediate_results_url=escrow.get("intermediateResultsUrl", None), - intermediate_results_hash=escrow.get( - "intermediateResultsHash", None - ), - manifest_hash=escrow.get("manifestHash", None), - manifest=escrow.get("manifest", None), - recording_oracle=escrow.get("recordingOracle", None), - reputation_oracle=escrow.get("reputationOracle", None), - exchange_oracle=escrow.get("exchangeOracle", None), + id=escrow.get("id"), + address=escrow.get("address"), + amount_paid=int(escrow.get("amountPaid")), + balance=int(escrow.get("balance")), + count=int(escrow.get("count")), + factory_address=escrow.get("factoryAddress"), + launcher=escrow.get("launcher"), + job_requester_id=escrow.get("jobRequesterId"), + status=escrow.get("status"), + token=escrow.get("token"), + total_funded_amount=int(escrow.get("totalFundedAmount")), + created_at=int(escrow.get("createdAt")), + final_results_url=escrow.get("finalResultsUrl"), + final_results_hash=escrow.get("finalResultsHash"), + intermediate_results_url=escrow.get("intermediateResultsUrl"), + intermediate_results_hash=escrow.get("intermediateResultsHash"), + manifest_hash=escrow.get("manifestHash"), + manifest=escrow.get("manifest"), + recording_oracle=escrow.get("recordingOracle"), + reputation_oracle=escrow.get("reputationOracle"), + exchange_oracle=escrow.get("exchangeOracle"), recording_oracle_fee=( int(escrow.get("recordingOracleFee")) if escrow.get("recordingOracleFee") @@ -393,26 +393,27 @@ def get_escrow( return EscrowData( chain_id=chain_id, - id=escrow.get("id") or "", - address=escrow.get("address") or "", - amount_paid=int(escrow.get("amountPaid") or 0), - balance=int(escrow.get("balance") or 0), - count=int(escrow.get("count") or 0), - factory_address=escrow.get("factoryAddress") or "", - launcher=escrow.get("launcher") or "", - status=escrow.get("status") or "", - token=escrow.get("token") or "", - total_funded_amount=int(escrow.get("totalFundedAmount") or 0), - created_at=datetime.fromtimestamp(int(escrow.get("createdAt") or 0)), - final_results_url=escrow.get("finalResultsUrl", None), - final_results_hash=escrow.get("finalResultsHash", None), - intermediate_results_url=escrow.get("intermediateResultsUrl", None), - intermediate_results_hash=escrow.get("intermediateResultsHash", None), - manifest_hash=escrow.get("manifestHash", None), - manifest=escrow.get("manifest", None), - recording_oracle=escrow.get("recordingOracle", None), - reputation_oracle=escrow.get("reputationOracle", None), - exchange_oracle=escrow.get("exchangeOracle", None), + id=escrow.get("id"), + address=escrow.get("address"), + amount_paid=int(escrow.get("amountPaid")), + balance=int(escrow.get("balance")), + count=int(escrow.get("count")), + factory_address=escrow.get("factoryAddress"), + launcher=escrow.get("launcher"), + job_requester_id=escrow.get("jobRequesterId"), + status=escrow.get("status"), + token=escrow.get("token"), + total_funded_amount=int(escrow.get("totalFundedAmount")), + created_at=int(escrow.get("createdAt")), + final_results_url=escrow.get("finalResultsUrl"), + final_results_hash=escrow.get("finalResultsHash"), + intermediate_results_url=escrow.get("intermediateResultsUrl"), + intermediate_results_hash=escrow.get("intermediateResultsHash"), + manifest_hash=escrow.get("manifestHash"), + manifest=escrow.get("manifest"), + recording_oracle=escrow.get("recordingOracle"), + reputation_oracle=escrow.get("reputationOracle"), + exchange_oracle=escrow.get("exchangeOracle"), recording_oracle_fee=( int(escrow.get("recordingOracleFee")) if escrow.get("recordingOracleFee") @@ -478,7 +479,7 @@ def get_status_events(filter: StatusEventFilter) -> List[StatusEvent]: events_with_chain_id = [ StatusEvent( - timestamp=event["timestamp"], + timestamp=int(event["timestamp"]), escrow_address=event["escrowAddress"], status=event["status"], chain_id=filter.chain_id, diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py index 4ce112b5e9..9e3e23a58e 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py @@ -89,12 +89,13 @@ def __init__( chain_id: ChainId, id: str, address: str, - staked_amount: int, - locked_amount: int, - locked_until_timestamp: int, - withdrawn_amount: int, - slashed_amount: int, amount_jobs_processed: int, + reputation_networks: List[str], + staked_amount: Optional[int] = None, + locked_amount: Optional[int] = None, + locked_until_timestamp: Optional[int] = None, + withdrawn_amount: Optional[int] = None, + slashed_amount: Optional[int] = None, role: Optional[str] = None, fee: Optional[int] = None, public_key: Optional[str] = None, @@ -104,7 +105,6 @@ def __init__( job_types: Optional[List[str]] = None, registration_needed: Optional[bool] = None, registration_instructions: Optional[str] = None, - reputation_networks: Optional[List[str]] = None, name: Optional[str] = None, category: Optional[str] = None, ): @@ -139,7 +139,9 @@ def __init__( self.address = address self.staked_amount = staked_amount self.locked_amount = locked_amount - self.locked_until_timestamp = locked_until_timestamp + self.locked_until_timestamp = ( + locked_until_timestamp * 1000 if locked_until_timestamp else None + ) self.withdrawn_amount = withdrawn_amount self.slashed_amount = slashed_amount self.amount_jobs_processed = amount_jobs_processed @@ -244,24 +246,45 @@ def get_operators(filter: OperatorFilter) -> List[OperatorData]: operators.append( OperatorData( chain_id=filter.chain_id, - id=operator.get("id") or "", - address=operator.get("address") or "", - staked_amount=int(staker.get("stakedAmount") or 0), - locked_amount=int(staker.get("lockedAmount") or 0), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), - withdrawn_amount=int(staker.get("withdrawnAmount") or 0), - slashed_amount=int(staker.get("slashedAmount") or 0), + id=operator.get("id"), + address=operator.get("address"), + staked_amount=( + int(staker.get("stakedAmount")) + if staker.get("stakedAmount") is not None + else None + ), + locked_amount=( + int(staker.get("lockedAmount")) + if staker.get("lockedAmount") is not None + else None + ), + locked_until_timestamp=( + int(staker.get("lockedUntilTimestamp")) + if staker.get("lockedUntilTimestamp") is not None + else None + ), + withdrawn_amount=( + int(staker.get("withdrawnAmount")) + if staker.get("withdrawnAmount") is not None + else None + ), + slashed_amount=( + int(staker.get("slashedAmount")) + if staker.get("slashedAmount") is not None + else None + ), amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), - role=operator.get("role") or None, + role=operator.get("role"), + # Preserve 0 fee; only None if absent fee=( int(operator.get("fee")) - if operator.get("fee") or None + if operator.get("fee") is not None else None ), - public_key=operator.get("publicKey") or None, - webhook_url=operator.get("webhookUrl") or None, - website=operator.get("website") or None, - url=operator.get("url") or None, + public_key=operator.get("publicKey"), + webhook_url=operator.get("webhookUrl"), + website=operator.get("website"), + url=operator.get("url"), job_types=( operator.get("jobTypes").split(",") if isinstance(operator.get("jobTypes"), str) @@ -271,13 +294,11 @@ def get_operators(filter: OperatorFilter) -> List[OperatorData]: else [] ) ), - registration_needed=operator.get("registrationNeeded") or None, - registration_instructions=operator.get( - "registrationInstructions" or None - ), + registration_needed=operator.get("registrationNeeded"), + registration_instructions=operator.get("registrationInstructions"), reputation_networks=reputation_networks, - name=operator.get("name") or None, - category=operator.get("category") or None, + name=operator.get("name"), + category=operator.get("category"), ) ) @@ -345,20 +366,40 @@ def get_operator( staker = operator.get("staker") or {} return OperatorData( chain_id=chain_id, - id=operator.get("id") or "", - address=operator.get("address") or "", - staked_amount=int(staker.get("stakedAmount") or 0), - locked_amount=int(staker.get("lockedAmount") or 0), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), - withdrawn_amount=int(staker.get("withdrawnAmount") or 0), - slashed_amount=int(staker.get("slashedAmount") or 0), + id=operator.get("id"), + address=operator.get("address"), + staked_amount=( + int(staker.get("stakedAmount")) + if staker.get("stakedAmount") is not None + else None + ), + locked_amount=( + int(staker.get("lockedAmount")) + if staker.get("lockedAmount") is not None + else None + ), + locked_until_timestamp=( + int(staker.get("lockedUntilTimestamp")) + if staker.get("lockedUntilTimestamp") is not None + else None + ), + withdrawn_amount=( + int(staker.get("withdrawnAmount")) + if staker.get("withdrawnAmount") is not None + else None + ), + slashed_amount=( + int(staker.get("slashedAmount")) + if staker.get("slashedAmount") is not None + else None + ), amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), - role=operator.get("role") or None, - fee=int(operator.get("fee")) if operator.get("fee") or None else None, - public_key=operator.get("publicKey") or None, - webhook_url=operator.get("webhookUrl") or None, - website=operator.get("website") or None, - url=operator.get("url") or None, + role=operator.get("role"), + fee=(int(operator.get("fee")) if operator.get("fee") is not None else None), + public_key=operator.get("publicKey"), + webhook_url=operator.get("webhookUrl"), + website=operator.get("website"), + url=operator.get("url"), job_types=( operator.get("jobTypes").split(",") if isinstance(operator.get("jobTypes"), str) @@ -368,11 +409,11 @@ def get_operator( else [] ) ), - registration_needed=operator.get("registrationNeeded") or None, - registration_instructions=operator.get("registrationInstructions") or None, + registration_needed=operator.get("registrationNeeded"), + registration_instructions=operator.get("registrationInstructions"), reputation_networks=reputation_networks, - name=operator.get("name") or None, - category=operator.get("category") or None, + name=operator.get("name"), + category=operator.get("category"), ) @staticmethod @@ -427,49 +468,76 @@ def get_reputation_network_operators( return [] operators = reputation_network_data["data"]["reputationNetwork"]["operators"] - return [ - OperatorData( - chain_id=chain_id, - id=operator.get("id") or "", - address=operator.get("address") or "", - staked_amount=int( - (staker := operator.get("staker") or {}).get("stakedAmount") or 0 - ), - locked_amount=int(staker.get("lockedAmount") or 0), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), - withdrawn_amount=int(staker.get("withdrawnAmount") or 0), - slashed_amount=int(staker.get("slashedAmount") or 0), - amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), - role=operator.get("role") or None, - fee=int(operator.get("fee")) if operator.get("fee") or None else None, - public_key=operator.get("publicKey") or None, - webhook_url=operator.get("webhookUrl") or None, - website=operator.get("website") or None, - url=operator.get("url") or None, - job_types=( - operator.get("jobTypes").split(",") - if isinstance(operator.get("jobTypes"), str) - else ( - operator.get("jobTypes", []) - if isinstance(operator.get("jobTypes"), list) + result: List[OperatorData] = [] + for operator in operators: + staker = operator.get("staker") or {} + result.append( + OperatorData( + chain_id=chain_id, + id=operator.get("id"), + address=operator.get("address"), + staked_amount=( + int(staker.get("stakedAmount")) + if staker.get("stakedAmount") is not None + else None + ), + locked_amount=( + int(staker.get("lockedAmount")) + if staker.get("lockedAmount") is not None + else None + ), + locked_until_timestamp=( + int(staker.get("lockedUntilTimestamp")) + if staker.get("lockedUntilTimestamp") is not None + else None + ), + withdrawn_amount=( + int(staker.get("withdrawnAmount")) + if staker.get("withdrawnAmount") is not None + else None + ), + slashed_amount=( + int(staker.get("slashedAmount")) + if staker.get("slashedAmount") is not None + else None + ), + amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), + role=operator.get("role"), + fee=( + int(operator.get("fee")) + if operator.get("fee") is not None + else None + ), + public_key=operator.get("publicKey"), + webhook_url=operator.get("webhookUrl"), + website=operator.get("website"), + url=operator.get("url"), + job_types=( + operator.get("jobTypes").split(",") + if isinstance(operator.get("jobTypes"), str) + else ( + operator.get("jobTypes", []) + if isinstance(operator.get("jobTypes"), list) + else [] + ) + ), + registration_needed=operator.get("registrationNeeded"), + registration_instructions=operator.get("registrationInstructions"), + reputation_networks=( + [ + network["address"] + for network in operator.get("reputationNetworks", []) + ] + if operator.get("reputationNetworks") + and isinstance(operator.get("reputationNetworks"), list) else [] - ) - ), - registration_needed=operator.get("registrationNeeded") or None, - registration_instructions=operator.get( - "registrationInstructions" or None - ), - reputation_networks=( - [network["address"] for network in operator["reputationNetworks"]] - if operator.get("reputationNetworks") - and isinstance(operator.get("reputationNetworks"), list) - else [] - ), - name=operator.get("name") or None, - category=operator.get("category") or None, + ), + name=operator.get("name"), + category=operator.get("category"), + ) ) - for operator in operators - ] + + return result @staticmethod def get_rewards_info(chain_id: ChainId, slasher: str) -> List[RewardData]: @@ -519,8 +587,8 @@ def get_rewards_info(chain_id: ChainId, slasher: str) -> List[RewardData]: return [ RewardData( - escrow_address=reward_added_event.get("escrowAddress") or "", - amount=int(reward_added_event.get("amount") or 0), + escrow_address=reward_added_event.get("escrowAddress"), + amount=int(reward_added_event.get("amount")), ) for reward_added_event in reward_added_events ] diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py index 6e13809043..75df379140 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py @@ -52,8 +52,8 @@ def __init__( self.locked_amount = locked_amount self.withdrawn_amount = withdrawn_amount self.slashed_amount = slashed_amount - self.locked_until_timestamp = locked_until_timestamp - self.last_deposit_timestamp = last_deposit_timestamp + self.locked_until_timestamp = locked_until_timestamp * 1000 + self.last_deposit_timestamp = last_deposit_timestamp * 1000 class StakingUtilsError(Exception): diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py index 214f7108e2..1b88aa89da 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/transaction/transaction_utils.py @@ -40,9 +40,9 @@ def __init__( to_address: str, value: int, method: str, - receiver: str, - escrow: str, - token: str, + receiver: Optional[str], + escrow: Optional[str], + token: Optional[str], ): self.from_address = from_address self.to_address = to_address @@ -64,9 +64,9 @@ def __init__( timestamp: int, value: int, method: str, - receiver: str, - escrow: str, - token: str, + receiver: Optional[str], + escrow: Optional[str], + token: Optional[str], internal_transactions: List[InternalTransaction], ): self.chain_id = chain_id @@ -74,7 +74,7 @@ def __init__( self.tx_hash = tx_hash self.from_address = from_address self.to_address = to_address - self.timestamp = timestamp + self.timestamp = timestamp * 1000 self.value = value self.method = method self.receiver = receiver @@ -141,25 +141,25 @@ def get_transaction(chain_id: ChainId, hash: str) -> Optional[TransactionData]: return TransactionData( chain_id=chain_id, - block=int(transaction.get("block") or 0), - tx_hash=transaction.get("txHash") or "", - from_address=transaction.get("from") or "", - to_address=transaction.get("to") or "", - timestamp=int(transaction.get("timestamp") or 0), - value=int(transaction.get("value") or 0), - method=transaction.get("method") or "", - receiver=transaction.get("receiver") or "", - escrow=transaction.get("escrow") or "", - token=transaction.get("token") or "", + block=int(transaction.get("block")), + tx_hash=transaction.get("txHash"), + from_address=transaction.get("from"), + to_address=transaction.get("to"), + timestamp=int(transaction.get("timestamp")), + value=int(transaction.get("value")), + method=transaction.get("method"), + receiver=transaction.get("receiver"), + escrow=transaction.get("escrow"), + token=transaction.get("token"), internal_transactions=[ InternalTransaction( - from_address=internal_tx.get("from") or "", - to_address=internal_tx.get("to") or "", - value=int(internal_tx.get("value") or 0), - method=internal_tx.get("method") or "", - receiver=internal_tx.get("receiver") or "", - escrow=internal_tx.get("escrow") or "", - token=internal_tx.get("token") or "", + from_address=internal_tx.get("from"), + to_address=internal_tx.get("to"), + value=int(internal_tx.get("value")), + method=internal_tx.get("method"), + receiver=internal_tx.get("receiver"), + escrow=internal_tx.get("escrow"), + token=internal_tx.get("token"), ) for internal_tx in transaction.get("internalTransactions", []) ], @@ -239,25 +239,25 @@ def get_transactions(filter: TransactionFilter) -> List[TransactionData]: [ TransactionData( chain_id=filter.chain_id, - block=int(transaction.get("block") or 0), - tx_hash=transaction.get("txHash") or "", - from_address=transaction.get("from") or "", - to_address=transaction.get("to") or "", - timestamp=int(transaction.get("timestamp") or 0), - value=int(transaction.get("value") or 0), - method=transaction.get("method") or "", - receiver=transaction.get("receiver") or "", - escrow=transaction.get("escrow") or "", - token=transaction.get("token") or "", + block=int(transaction.get("block")), + tx_hash=transaction.get("txHash"), + from_address=transaction.get("from"), + to_address=transaction.get("to"), + timestamp=int(transaction.get("timestamp")), + value=int(transaction.get("value")), + method=transaction.get("method"), + receiver=transaction.get("receiver"), + escrow=transaction.get("escrow"), + token=transaction.get("token"), internal_transactions=[ InternalTransaction( - from_address=internal_tx.get("from") or "", - to_address=internal_tx.get("to") or "", - value=int(internal_tx.get("value") or 0), - method=internal_tx.get("method") or "", - receiver=internal_tx.get("receiver") or "", - escrow=internal_tx.get("escrow") or "", - token=internal_tx.get("token") or "", + from_address=internal_tx.get("from"), + to_address=internal_tx.get("to"), + value=int(internal_tx.get("value")), + method=internal_tx.get("method"), + receiver=internal_tx.get("receiver"), + escrow=internal_tx.get("escrow"), + token=internal_tx.get("token"), ) for internal_tx in transaction.get("internalTransactions", []) ], diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py index 7f15bba249..3e0c766505 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py @@ -87,12 +87,10 @@ def get_workers(filter: WorkerFilter) -> List[WorkerData]: for worker in workers_raw: workers.append( WorkerData( - id=worker.get("id") or "", - address=worker.get("address") or "", - total_amount_received=int( - worker.get("totalHMTAmountReceived") or 0 - ), - payout_count=int(worker.get("payoutCount") or 0), + id=worker.get("id"), + address=worker.get("address"), + total_amount_received=int(worker.get("totalHMTAmountReceived")), + payout_count=int(worker.get("payoutCount")), ) ) @@ -135,8 +133,8 @@ def get_worker(chain_id: ChainId, worker_address: str) -> Optional[WorkerData]: worker = worker_data["data"]["worker"] return WorkerData( - id=worker.get("id") or "", - address=worker.get("address") or "", - total_amount_received=int(worker.get("totalHMTAmountReceived") or 0), - payout_count=int(worker.get("payoutCount") or 0), + id=worker.get("id"), + address=worker.get("address"), + total_amount_received=int(worker.get("totalHMTAmountReceived")), + payout_count=int(worker.get("payoutCount")), ) diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/escrow/test_escrow_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/escrow/test_escrow_utils.py index 3f22ee0e4e..88b52db16e 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/escrow/test_escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/escrow/test_escrow_utils.py @@ -131,7 +131,7 @@ def side_effect(subgraph_url, query, params): filtered[0].total_funded_amount, int(mock_escrow["totalFundedAmount"]) ) self.assertEqual( - int(filtered[0].created_at.timestamp()), int(mock_escrow["createdAt"]) + int(filtered[0].created_at), int(mock_escrow["createdAt"]) * 1000 ) filter = EscrowFilter(chain_id=ChainId.POLYGON_AMOY) @@ -181,6 +181,7 @@ def test_get_escrows_with_status_array(self): "status": "Pending", "token": "0x1234567890123456789012345678901234567891", "totalFundedAmount": "1000000000000000000", + "createdAt": "1672531200000", } mock_escrow_2 = { "id": "0x1234567890123456789012345678901234567891", @@ -200,6 +201,7 @@ def test_get_escrows_with_status_array(self): "status": "Complete", "token": "0x1234567890123456789012345678901234567891", "totalFundedAmount": "1000000000000000000", + "createdAt": "1672531200000", } def side_effect(subgraph_url, query, params): @@ -318,7 +320,7 @@ def test_get_escrow(self): escrow.total_funded_amount, int(mock_escrow["totalFundedAmount"]) ) self.assertEqual( - int(escrow.created_at.timestamp()), int(mock_escrow["createdAt"]) + int(escrow.created_at), int(mock_escrow["createdAt"]) * 1000 ) def test_get_escrow_empty_data(self): @@ -385,7 +387,7 @@ def test_get_status_events(self): result = EscrowUtils.get_status_events(filter) self.assertEqual(len(result), 1) - self.assertEqual(result[0].timestamp, 1620000000) + self.assertEqual(result[0].timestamp, 1620000000000) self.assertEqual(result[0].escrow_address, "0x123") self.assertEqual(result[0].status, "Pending") self.assertEqual(result[0].chain_id, ChainId.POLYGON_AMOY) @@ -418,7 +420,7 @@ def test_get_status_events_with_date_range(self): result = EscrowUtils.get_status_events(filter) self.assertEqual(len(result), 1) - self.assertEqual(result[0].timestamp, 1620000000) + self.assertEqual(result[0].timestamp, 1620000000000) self.assertEqual(result[0].escrow_address, "0x123") self.assertEqual(result[0].status, "Pending") self.assertEqual(result[0].chain_id, ChainId.POLYGON_AMOY) @@ -460,7 +462,7 @@ def test_get_status_events_with_launcher(self): result = EscrowUtils.get_status_events(filter) self.assertEqual(len(result), 1) - self.assertEqual(result[0].timestamp, 1620000000) + self.assertEqual(result[0].timestamp, 1620000000000) self.assertEqual(result[0].escrow_address, "0x123") self.assertEqual(result[0].status, "Pending") self.assertEqual(result[0].chain_id, ChainId.POLYGON_AMOY) @@ -513,7 +515,7 @@ def test_get_payouts(self): result[0].recipient, "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef" ) self.assertEqual(result[0].amount, 1000000000000000000) - self.assertEqual(result[0].created_at, 1672531200) + self.assertEqual(result[0].created_at, 1672531200000) def test_get_payouts_with_filters(self): with patch( @@ -551,7 +553,7 @@ def test_get_payouts_with_filters(self): result[0].recipient, "0x1234567890123456789012345678901234567892" ) self.assertEqual(result[0].amount, 1000000000000000000) - self.assertEqual(result[0].created_at, 1672531200) + self.assertEqual(result[0].created_at, 1672531200000) def test_get_payouts_no_data(self): with patch( @@ -638,7 +640,7 @@ def side_effect(subgraph_url, query, params): self.assertEqual(refunds[0].receiver, mock_refund["receiver"]) self.assertEqual(refunds[0].amount, int(mock_refund["amount"])) self.assertEqual(refunds[0].block, int(mock_refund["block"])) - self.assertEqual(refunds[0].timestamp, int(mock_refund["timestamp"])) + self.assertEqual(refunds[0].timestamp, int(mock_refund["timestamp"]) * 1000) self.assertEqual(refunds[0].tx_hash, mock_refund["txHash"]) def test_get_cancellation_refunds_invalid_escrow_address(self): @@ -713,7 +715,7 @@ def test_get_cancellation_refund(self): self.assertEqual(refund.receiver, mock_refund["receiver"]) self.assertEqual(refund.amount, int(mock_refund["amount"])) self.assertEqual(refund.block, int(mock_refund["block"])) - self.assertEqual(refund.timestamp, int(mock_refund["timestamp"])) + self.assertEqual(refund.timestamp, int(mock_refund["timestamp"]) * 1000) self.assertEqual(refund.tx_hash, mock_refund["txHash"]) def test_get_cancellation_refund_no_data(self): diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py index 4c42033a97..c616126b36 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py @@ -45,8 +45,8 @@ def test_get_operators(self): "lockedAmount": "25", "withdrawnAmount": "25", "slashedAmount": "25", - "lockedUntilTimestamp": "0", - "lastDepositTimestamp": "0", + "lockedUntilTimestamp": "123456789", + "lastDepositTimestamp": "123456789", }, } ], @@ -74,7 +74,7 @@ def test_get_operators(self): self.assertEqual(operators[0].address, DEFAULT_GAS_PAYER) self.assertEqual(operators[0].staked_amount, 100) self.assertEqual(operators[0].locked_amount, 25) - self.assertEqual(operators[0].locked_until_timestamp, 0) + self.assertEqual(operators[0].locked_until_timestamp, 123456789000) self.assertEqual(operators[0].withdrawn_amount, 25) self.assertEqual(operators[0].slashed_amount, 25) self.assertEqual(operators[0].amount_jobs_processed, 25) @@ -121,8 +121,8 @@ def test_get_operators_when_job_types_is_none(self): "lockedAmount": "25", "withdrawnAmount": "25", "slashedAmount": "25", - "lockedUntilTimestamp": "0", - "lastDepositTimestamp": "0", + "lockedUntilTimestamp": "123456789", + "lastDepositTimestamp": "123456789", }, } ], @@ -150,7 +150,7 @@ def test_get_operators_when_job_types_is_none(self): self.assertEqual(operators[0].address, DEFAULT_GAS_PAYER) self.assertEqual(operators[0].staked_amount, 100) self.assertEqual(operators[0].locked_amount, 25) - self.assertEqual(operators[0].locked_until_timestamp, 0) + self.assertEqual(operators[0].locked_until_timestamp, 123456789000) self.assertEqual(operators[0].withdrawn_amount, 25) self.assertEqual(operators[0].slashed_amount, 25) self.assertEqual(operators[0].amount_jobs_processed, 25) @@ -197,8 +197,8 @@ def test_get_operators_when_job_types_is_array(self): "lockedAmount": "25", "withdrawnAmount": "25", "slashedAmount": "25", - "lockedUntilTimestamp": "0", - "lastDepositTimestamp": "0", + "lockedUntilTimestamp": "123456789", + "lastDepositTimestamp": "123456789", }, } ], @@ -226,7 +226,7 @@ def test_get_operators_when_job_types_is_array(self): self.assertEqual(operators[0].address, DEFAULT_GAS_PAYER) self.assertEqual(operators[0].staked_amount, 100) self.assertEqual(operators[0].locked_amount, 25) - self.assertEqual(operators[0].locked_until_timestamp, 0) + self.assertEqual(operators[0].locked_until_timestamp, 123456789000) self.assertEqual(operators[0].withdrawn_amount, 25) self.assertEqual(operators[0].slashed_amount, 25) self.assertEqual(operators[0].amount_jobs_processed, 25) @@ -307,8 +307,8 @@ def test_get_operator(self): "lockedAmount": "25", "withdrawnAmount": "25", "slashedAmount": "25", - "lockedUntilTimestamp": "0", - "lastDepositTimestamp": "0", + "lockedUntilTimestamp": "123456789", + "lastDepositTimestamp": "123456789", }, } } @@ -328,7 +328,7 @@ def test_get_operator(self): self.assertEqual(operator.address, staker_address) self.assertEqual(operator.staked_amount, 100) self.assertEqual(operator.locked_amount, 25) - self.assertEqual(operator.locked_until_timestamp, 0) + self.assertEqual(operator.locked_until_timestamp, 123456789000) self.assertEqual(operator.withdrawn_amount, 25) self.assertEqual(operator.slashed_amount, 25) self.assertEqual(operator.amount_jobs_processed, 25) @@ -375,8 +375,8 @@ def test_get_operator_when_job_types_is_none(self): "lockedAmount": "25", "withdrawnAmount": "25", "slashedAmount": "25", - "lockedUntilTimestamp": "0", - "lastDepositTimestamp": "0", + "lockedUntilTimestamp": "123456789", + "lastDepositTimestamp": "123456789", }, } } @@ -396,7 +396,7 @@ def test_get_operator_when_job_types_is_none(self): self.assertEqual(operator.address, staker_address) self.assertEqual(operator.staked_amount, 100) self.assertEqual(operator.locked_amount, 25) - self.assertEqual(operator.locked_until_timestamp, 0) + self.assertEqual(operator.locked_until_timestamp, 123456789000) self.assertEqual(operator.withdrawn_amount, 25) self.assertEqual(operator.slashed_amount, 25) self.assertEqual(operator.amount_jobs_processed, 25) @@ -443,8 +443,8 @@ def test_get_operator_when_job_types_is_array(self): "lockedAmount": "25", "withdrawnAmount": "25", "slashedAmount": "25", - "lockedUntilTimestamp": "0", - "lastDepositTimestamp": "0", + "lockedUntilTimestamp": "123456789", + "lastDepositTimestamp": "123456789", }, } } @@ -464,7 +464,7 @@ def test_get_operator_when_job_types_is_array(self): self.assertEqual(operator.address, staker_address) self.assertEqual(operator.staked_amount, 100) self.assertEqual(operator.locked_amount, 25) - self.assertEqual(operator.locked_until_timestamp, 0) + self.assertEqual(operator.locked_until_timestamp, 123456789000) self.assertEqual(operator.withdrawn_amount, 25) self.assertEqual(operator.slashed_amount, 25) self.assertEqual(operator.amount_jobs_processed, 25) diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py index eb0b07e800..0f9183eb8b 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/staking/test_staking_utils.py @@ -88,11 +88,11 @@ def test_get_stakers(self): ) self.assertEqual( stakers[0].locked_until_timestamp, - int(mock_staker_1["lockedUntilTimestamp"]), + int(mock_staker_1["lockedUntilTimestamp"]) * 1000, ) self.assertEqual( stakers[0].last_deposit_timestamp, - int(mock_staker_1["lastDepositTimestamp"]), + int(mock_staker_1["lastDepositTimestamp"]) * 1000, ) self.assertIsInstance(stakers[1], StakerData) self.assertEqual(stakers[1].id, "2") @@ -111,11 +111,11 @@ def test_get_stakers(self): ) self.assertEqual( stakers[1].locked_until_timestamp, - int(mock_staker_2["lockedUntilTimestamp"]), + int(mock_staker_2["lockedUntilTimestamp"]) * 1000, ) self.assertEqual( stakers[1].last_deposit_timestamp, - int(mock_staker_2["lastDepositTimestamp"]), + int(mock_staker_2["lastDepositTimestamp"]) * 1000, ) def test_get_stakers_empty_response(self): @@ -171,10 +171,12 @@ def test_get_staker(self): ) self.assertEqual(staker.slashed_amount, int(mock_staker["slashedAmount"])) self.assertEqual( - staker.locked_until_timestamp, int(mock_staker["lockedUntilTimestamp"]) + staker.locked_until_timestamp, + int(mock_staker["lockedUntilTimestamp"]) * 1000, ) self.assertEqual( - staker.last_deposit_timestamp, int(mock_staker["lastDepositTimestamp"]) + staker.last_deposit_timestamp, + int(mock_staker["lastDepositTimestamp"]) * 1000, ) def test_get_staker_empty_data(self): diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py index 02ed2b8cbd..aee4e3914f 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/transaction/test_transaction_utils.py @@ -188,7 +188,9 @@ def test_get_transaction(self): self.assertEqual(transaction.tx_hash, mock_transaction["txHash"]) self.assertEqual(transaction.from_address, mock_transaction["from"]) self.assertEqual(transaction.to_address, mock_transaction["to"]) - self.assertEqual(transaction.timestamp, int(mock_transaction["timestamp"])) + self.assertEqual( + transaction.timestamp, int(mock_transaction["timestamp"]) * 1000 + ) self.assertEqual(transaction.value, int(mock_transaction["value"])) self.assertEqual(transaction.method, mock_transaction["method"]) diff --git a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts index c26a6a123b..b56037ff0e 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts @@ -43,6 +43,7 @@ import { WarnVersionMismatch, } from './error'; import { + CancellationRefundData, EscrowData, GET_CANCELLATION_REFUNDS_QUERY, GET_CANCELLATION_REFUND_BY_ADDRESS_QUERY, @@ -50,6 +51,7 @@ import { GET_ESCROW_BY_ADDRESS_QUERY, GET_PAYOUTS_QUERY, GET_STATUS_UPDATES_QUERY, + PayoutData, StatusEvent, } from './graphql'; import { @@ -58,15 +60,12 @@ import { IEscrowsFilter, IPayoutFilter, IStatusEventFilter, + IStatusEvent, + ICancellationRefund, + IPayout, + IEscrowWithdraw, } from './interfaces'; -import { - CancellationRefund, - EscrowStatus, - EscrowWithdraw, - NetworkData, - Payout, - TransactionLikeWithNonce, -} from './types'; +import { EscrowStatus, NetworkData, TransactionLikeWithNonce } from './types'; import { getSubgraphUrl, getUnixTimestamp, @@ -901,7 +900,7 @@ export class EscrowClient extends BaseEthersClient { * @param {string} escrowAddress Address of the escrow to withdraw. * @param {string} tokenAddress Address of the token to withdraw. * @param {Overrides} [txOptions] - Additional transaction parameters (optional, defaults to an empty object). - * @returns {EscrowWithdraw} Returns the escrow withdrawal data including transaction hash and withdrawal amount. Throws error if any. + * @returns {IEscrowWithdraw} Returns the escrow withdrawal data including transaction hash and withdrawal amount. Throws error if any. * * * **Code example** @@ -930,7 +929,7 @@ export class EscrowClient extends BaseEthersClient { escrowAddress: string, tokenAddress: string, txOptions: Overrides = {} - ): Promise { + ): Promise { if (!ethers.isAddress(escrowAddress)) { throw ErrorInvalidEscrowAddressProvided; } @@ -969,7 +968,7 @@ export class EscrowClient extends BaseEthersClient { const from = parsedLog?.args[0]; if (parsedLog?.name === 'Transfer' && from === escrowAddress) { - amountTransferred = parsedLog?.args[2]; + amountTransferred = BigInt(parsedLog?.args[2]); break; } } @@ -979,13 +978,11 @@ export class EscrowClient extends BaseEthersClient { throw ErrorTransferEventNotFoundInTransactionLogs; } - const escrowWithdrawData: EscrowWithdraw = { + return { txHash: transactionReceipt?.hash || '', tokenAddress, withdrawnAmount: amountTransferred, }; - - return escrowWithdrawData; } catch (e) { return throwError(e); } @@ -2035,7 +2032,7 @@ export class EscrowUtils { */ public static async getStatusEvents( filter: IStatusEventFilter - ): Promise { + ): Promise { const { chainId, statuses, @@ -2088,14 +2085,12 @@ export class EscrowUtils { return []; } - const statusEvents = data['escrowStatusEvents'] as StatusEvent[]; - - const eventsWithChainId = statusEvents.map((event) => ({ - ...event, + return data['escrowStatusEvents'].map((event) => ({ + timestamp: Number(event.timestamp) * 1000, + escrowAddress: event.escrowAddress, + status: EscrowStatus[event.status as keyof typeof EscrowStatus], chainId, })); - - return eventsWithChainId; } /** @@ -2107,7 +2102,7 @@ export class EscrowUtils { * Fetch payouts from the subgraph. * * @param {IPayoutFilter} filter Filter parameters. - * @returns {Promise} List of payouts matching the filters. + * @returns {Promise} List of payouts matching the filters. * * **Code example** * @@ -2124,7 +2119,7 @@ export class EscrowUtils { * console.log(payouts); * ``` */ - public static async getPayouts(filter: IPayoutFilter): Promise { + public static async getPayouts(filter: IPayoutFilter): Promise { const networkData = NETWORKS[filter.chainId]; if (!networkData) { throw ErrorUnsupportedChainID; @@ -2141,7 +2136,7 @@ export class EscrowUtils { const skip = filter.skip || 0; const orderDirection = filter.orderDirection || OrderDirection.DESC; - const { payouts } = await gqlFetch<{ payouts: Payout[] }>( + const { payouts } = await gqlFetch<{ payouts: PayoutData[] }>( getSubgraphUrl(networkData), GET_PAYOUTS_QUERY(filter), { @@ -2154,8 +2149,17 @@ export class EscrowUtils { orderDirection, } ); + if (!payouts) { + return []; + } - return payouts || []; + return payouts.map((payout) => ({ + id: payout.id, + escrowAddress: payout.escrowAddress, + recipient: payout.recipient, + amount: BigInt(payout.amount), + createdAt: Number(payout.createdAt) * 1000, + })); } /** @@ -2179,7 +2183,7 @@ export class EscrowUtils { * ``` * * ```ts - * type CancellationRefund = { + * interface ICancellationRefund { * id: string; * escrowAddress: string; * receiver: string; @@ -2192,7 +2196,7 @@ export class EscrowUtils { * * * @param {Object} filter Filter parameters. - * @returns {Promise} List of cancellation refunds matching the filters. + * @returns {Promise} List of cancellation refunds matching the filters. * * **Code example** * @@ -2215,7 +2219,7 @@ export class EscrowUtils { first?: number; skip?: number; orderDirection?: OrderDirection; - }): Promise { + }): Promise { const networkData = NETWORKS[filter.chainId]; if (!networkData) throw ErrorUnsupportedChainID; if (filter.escrowAddress && !ethers.isAddress(filter.escrowAddress)) { @@ -2231,7 +2235,7 @@ export class EscrowUtils { const orderDirection = filter.orderDirection || OrderDirection.DESC; const { cancellationRefundEvents } = await gqlFetch<{ - cancellationRefundEvents: CancellationRefund[]; + cancellationRefundEvents: CancellationRefundData[]; }>(getSubgraphUrl(networkData), GET_CANCELLATION_REFUNDS_QUERY(filter), { escrowAddress: filter.escrowAddress?.toLowerCase(), receiver: filter.receiver?.toLowerCase(), @@ -2242,7 +2246,19 @@ export class EscrowUtils { orderDirection, }); - return cancellationRefundEvents || []; + if (!cancellationRefundEvents || cancellationRefundEvents.length === 0) { + return []; + } + + return cancellationRefundEvents.map((event) => ({ + id: event.id, + escrowAddress: event.escrowAddress, + receiver: event.receiver, + amount: BigInt(event.amount), + block: Number(event.block), + timestamp: Number(event.timestamp) * 1000, + txHash: event.txHash, + })); } /** @@ -2266,7 +2282,7 @@ export class EscrowUtils { * ``` * * ```ts - * type CancellationRefund = { + * interface ICancellationRefund { * id: string; * escrowAddress: string; * receiver: string; @@ -2280,7 +2296,7 @@ export class EscrowUtils { * * @param {ChainId} chainId Network in which the escrow has been deployed * @param {string} escrowAddress Address of the escrow - * @returns {Promise} Cancellation refund data + * @returns {Promise} Cancellation refund data * * **Code example** * @@ -2293,7 +2309,7 @@ export class EscrowUtils { public static async getCancellationRefund( chainId: ChainId, escrowAddress: string - ): Promise { + ): Promise { const networkData = NETWORKS[chainId]; if (!networkData) throw ErrorUnsupportedChainID; @@ -2302,14 +2318,26 @@ export class EscrowUtils { } const { cancellationRefundEvents } = await gqlFetch<{ - cancellationRefundEvents: any; + cancellationRefundEvents: CancellationRefundData[]; }>( getSubgraphUrl(networkData), GET_CANCELLATION_REFUND_BY_ADDRESS_QUERY(), { escrowAddress: escrowAddress.toLowerCase() } ); - return cancellationRefundEvents?.[0] || null; + if (!cancellationRefundEvents || cancellationRefundEvents.length === 0) { + return null; + } + + return { + id: cancellationRefundEvents[0].id, + escrowAddress: cancellationRefundEvents[0].escrowAddress, + receiver: cancellationRefundEvents[0].receiver, + amount: BigInt(cancellationRefundEvents[0].amount), + block: Number(cancellationRefundEvents[0].block), + timestamp: Number(cancellationRefundEvents[0].timestamp) * 1000, + txHash: cancellationRefundEvents[0].txHash, + }; } } @@ -2317,9 +2345,9 @@ function mapEscrow(e: EscrowData, chainId: ChainId | number): IEscrow { return { id: e.id, address: e.address, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), factoryAddress: e.factoryAddress, finalResultsUrl: e.finalResultsUrl, finalResultsHash: e.finalResultsHash, @@ -2341,8 +2369,8 @@ function mapEscrow(e: EscrowData, chainId: ChainId | number): IEscrow { exchangeOracleFee: e.exchangeOracleFee ? Number(e.exchangeOracleFee) : null, status: e.status, token: e.token, - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, chainId: Number(chainId), }; } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts b/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts index 93b1f92c6a..79023a88e4 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/graphql/types.ts @@ -1,5 +1,4 @@ import { IReputationNetwork } from '../interfaces'; -import { ChainId } from '../enums'; export type EscrowData = { id: string; @@ -110,86 +109,15 @@ export type RewardAddedEventData = { amount: string; }; -export type DailyEscrowData = { - timestamp: Date; - escrowsTotal: string; - escrowsPending: string; - escrowsSolved: string; - escrowsPaid: string; - escrowsCancelled: string; -}; - -export type EscrowStatistics = { - totalEscrows: string; - dailyEscrowsData: DailyEscrowData[]; -}; - -export type DailyWorkerData = { - timestamp: Date; - activeWorkers: string; -}; - -export type WorkerStatistics = { - dailyWorkersData: DailyWorkerData[]; -}; - -export type DailyPaymentData = { - timestamp: Date; - totalAmountPaid: string; - totalCount: string; - averageAmountPerWorker: string; -}; - -export type PaymentStatistics = { - dailyPaymentsData: DailyPaymentData[]; -}; - export type HMTHolderData = { address: string; balance: string; }; -export type HMTHolder = { - address: string; - balance: string; -}; - -export type DailyHMTData = { - timestamp: Date; - totalTransactionAmount: string; - totalTransactionCount: string; - dailyUniqueSenders: string; - dailyUniqueReceivers: string; -}; - -export type HMTStatistics = { - totalTransferAmount: string; - totalTransferCount: string; - totalHolders: string; -}; - -export type IMDataEntity = { - served: string; - solved: string; -}; - -export type IMData = Record; - -export type DailyTaskData = { - timestamp: Date; - tasksTotal: string; - tasksSolved: string; -}; - -export type TaskStatistics = { - dailyTasksData: DailyTaskData[]; -}; - export type StatusEvent = { timestamp: string; escrowAddress: string; status: string; - chainId: ChainId; }; export type KVStoreData = { @@ -216,29 +144,47 @@ export interface IOperatorSubgraph { id: string; address: string; amountJobsProcessed: string; - role?: string; - fee?: string; - publicKey?: string; - webhookUrl?: string; - website?: string; - url?: string; - registrationNeeded?: boolean; - registrationInstructions?: string; - name?: string; - category?: string; - jobTypes?: string | string[]; - reputationNetworks?: { address: string }[]; - staker?: { + role: string | null; + fee: string | null; + publicKey: string | null; + webhookUrl: string | null; + website: string | null; + url: string | null; + registrationNeeded: boolean | null; + registrationInstructions: string | null; + name: string | null; + category: string | null; + jobTypes: string | string[] | null; + reputationNetworks: { address: string }[]; + staker: { stakedAmount: string; lockedAmount: string; lockedUntilTimestamp: string; withdrawnAmount: string; slashedAmount: string; lastDepositTimestamp: string; - }; + } | null; } export interface IReputationNetworkSubgraph extends Omit { operators: IOperatorSubgraph[]; } + +export type PayoutData = { + id: string; + escrowAddress: string; + recipient: string; + amount: string; + createdAt: string; +}; + +export type CancellationRefundData = { + id: string; + escrowAddress: string; + receiver: string; + amount: string; + block: string; + timestamp: string; + txHash: string; +}; diff --git a/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts b/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts index af653ec88c..c47656c690 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/interfaces.ts @@ -10,24 +10,24 @@ export interface IOperator { id: string; chainId: ChainId; address: string; - stakedAmount: bigint; - lockedAmount: bigint; - lockedUntilTimestamp: number; - withdrawnAmount: bigint; - slashedAmount: bigint; - amountJobsProcessed: bigint; - role?: string; - fee?: bigint; - publicKey?: string; - webhookUrl?: string; - website?: string; - url?: string; - jobTypes?: string[]; - registrationNeeded?: boolean; - registrationInstructions?: string; - reputationNetworks?: string[]; - name?: string; - category?: string; + stakedAmount: bigint | null; + lockedAmount: bigint | null; + lockedUntilTimestamp: number | null; + withdrawnAmount: bigint | null; + slashedAmount: bigint | null; + amountJobsProcessed: bigint | null; + role: string | null; + fee: bigint | null; + publicKey: string | null; + webhookUrl: string | null; + website: string | null; + url: string | null; + jobTypes: string[] | null; + registrationNeeded: boolean | null; + registrationInstructions: string | null; + reputationNetworks: string[]; + name: string | null; + category: string | null; } export interface IOperatorsFilter extends IPagination { @@ -48,7 +48,7 @@ export interface IEscrow { address: string; amountPaid: bigint; balance: bigint; - count: bigint; + count: number; factoryAddress: string; finalResultsUrl: string | null; finalResultsHash: string | null; @@ -228,3 +228,87 @@ export interface ICancellationRefundFilter extends IPagination { from?: Date; to?: Date; } + +export interface IDailyEscrow { + timestamp: number; + escrowsTotal: number; + escrowsPending: number; + escrowsSolved: number; + escrowsPaid: number; + escrowsCancelled: number; +} + +export interface IEscrowStatistics { + totalEscrows: number; + dailyEscrowsData: IDailyEscrow[]; +} + +export interface IDailyWorker { + timestamp: number; + activeWorkers: number; +} + +export interface IWorkerStatistics { + dailyWorkersData: IDailyWorker[]; +} + +export interface IDailyPayment { + timestamp: number; + totalAmountPaid: bigint; + totalCount: number; + averageAmountPerWorker: bigint; +} + +export interface IPaymentStatistics { + dailyPaymentsData: IDailyPayment[]; +} + +export interface IHMTStatistics { + totalTransferAmount: bigint; + totalTransferCount: number; + totalHolders: number; +} + +export interface IHMTHolder { + address: string; + balance: bigint; +} + +export interface IDailyHMT { + timestamp: number; + totalTransactionAmount: bigint; + totalTransactionCount: number; + dailyUniqueSenders: number; + dailyUniqueReceivers: number; +} + +export interface IStatusEvent { + timestamp: number; + escrowAddress: string; + status: EscrowStatus; + chainId: ChainId; +} + +export interface ICancellationRefund { + id: string; + escrowAddress: string; + receiver: string; + amount: bigint; + block: number; + timestamp: number; + txHash: string; +} + +export interface IPayout { + id: string; + escrowAddress: string; + recipient: string; + amount: bigint; + createdAt: number; +} + +export interface IEscrowWithdraw { + txHash: string; + tokenAddress: string; + withdrawnAmount: bigint; +} diff --git a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts b/packages/sdk/typescript/human-protocol-sdk/src/operator.ts index 91bc4ea94b..cbca6e866a 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/operator.ts @@ -234,14 +234,20 @@ function mapOperator(operator: IOperatorSubgraph, chainId: ChainId): IOperator { id: operator.id, chainId, address: operator.address, - stakedAmount: BigInt(staker?.stakedAmount || 0), - lockedAmount: BigInt(staker?.lockedAmount || 0), - lockedUntilTimestamp: Number(staker?.lockedUntilTimestamp || 0) * 1000, - withdrawnAmount: BigInt(staker?.withdrawnAmount || 0), - slashedAmount: BigInt(staker?.slashedAmount || 0), - amountJobsProcessed: BigInt(operator.amountJobsProcessed || 0), + stakedAmount: staker?.stakedAmount ? BigInt(staker?.stakedAmount) : null, + lockedAmount: staker?.lockedAmount ? BigInt(staker?.lockedAmount) : null, + lockedUntilTimestamp: staker?.lockedUntilTimestamp + ? Number(staker.lockedUntilTimestamp) * 1000 + : null, + withdrawnAmount: staker?.withdrawnAmount + ? BigInt(staker?.withdrawnAmount) + : null, + slashedAmount: staker?.slashedAmount ? BigInt(staker?.slashedAmount) : null, + amountJobsProcessed: operator.amountJobsProcessed + ? BigInt(operator.amountJobsProcessed) + : null, role: operator.role, - fee: operator.fee ? BigInt(operator.fee) : undefined, + fee: operator.fee ? BigInt(operator.fee) : null, publicKey: operator.publicKey, webhookUrl: operator.webhookUrl, website: operator.website, diff --git a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts index 29dd0b9dc4..1fab0ed1fd 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts @@ -585,11 +585,11 @@ export class StakingUtils { function mapStaker(s: StakerData): IStaker { return { address: s.address, - stakedAmount: BigInt(s.stakedAmount || 0), - lockedAmount: BigInt(s.lockedAmount || 0), - withdrawableAmount: BigInt(s.withdrawnAmount || 0), - slashedAmount: BigInt(s.slashedAmount || 0), - lockedUntil: Number(s.lockedUntilTimestamp || 0) * 1000, - lastDepositTimestamp: Number(s.lastDepositTimestamp || 0) * 1000, + stakedAmount: BigInt(s.stakedAmount), + lockedAmount: BigInt(s.lockedAmount), + withdrawableAmount: BigInt(s.withdrawnAmount), + slashedAmount: BigInt(s.slashedAmount), + lockedUntil: Number(s.lockedUntilTimestamp) * 1000, + lastDepositTimestamp: Number(s.lastDepositTimestamp) * 1000, }; } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts index b88b228836..715c094621 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts @@ -1,27 +1,29 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { ethers } from 'ethers'; import gqlFetch from 'graphql-request'; +import { OrderDirection } from './enums'; import { + EscrowStatisticsData, + EventDayData, GET_ESCROW_STATISTICS_QUERY, GET_EVENT_DAY_DATA_QUERY, - GET_HOLDERS_QUERY, GET_HMTOKEN_STATISTICS_QUERY, - EscrowStatistics, - EscrowStatisticsData, - EventDayData, - HMTStatistics, - HMTStatisticsData, - PaymentStatistics, - WorkerStatistics, + GET_HOLDERS_QUERY, HMTHolderData, - HMTHolder, - DailyHMTData, + HMTStatisticsData, } from './graphql'; -import { IHMTHoldersParams, IStatisticsFilter } from './interfaces'; +import { + IDailyHMT, + IEscrowStatistics, + IHMTHolder, + IHMTHoldersParams, + IHMTStatistics, + IPaymentStatistics, + IStatisticsFilter, + IWorkerStatistics, +} from './interfaces'; import { NetworkData } from './types'; import { getSubgraphUrl, getUnixTimestamp, throwError } from './utils'; -import { OrderDirection } from './enums'; /** * ## Introduction @@ -85,8 +87,8 @@ export class StatisticsClient { * ``` * * ```ts - * type DailyEscrowsData = { - * timestamp: Date; + * interface IDailyEscrow { + * timestamp: number; * escrowsTotal: number; * escrowsPending: number; * escrowsSolved: number; @@ -94,14 +96,14 @@ export class StatisticsClient { * escrowsCancelled: number; * }; * - * type EscrowStatistics = { + * interface IEscrowStatistics { * totalEscrows: number; - * dailyEscrowsData: DailyEscrowsData[]; + * dailyEscrowsData: IDailyEscrow[]; * }; * ``` * * @param {IStatisticsFilter} filter Statistics params with duration data - * @returns {Promise} Escrow statistics data. + * @returns {Promise} Escrow statistics data. * * **Code example** * @@ -119,7 +121,7 @@ export class StatisticsClient { */ async getEscrowStatistics( filter: IStatisticsFilter = {} - ): Promise { + ): Promise { try { const first = filter.first !== undefined ? Math.min(filter.first, 1000) : 10; @@ -145,7 +147,7 @@ export class StatisticsClient { ? +escrowStatistics.totalEscrowCount : 0, dailyEscrowsData: eventDayDatas.map((eventDayData) => ({ - timestamp: new Date(+eventDayData.timestamp * 1000), + timestamp: +eventDayData.timestamp * 1000, escrowsTotal: +eventDayData.dailyEscrowCount, escrowsPending: +eventDayData.dailyPendingStatusEventCount, escrowsSolved: +eventDayData.dailyCompletedStatusEventCount, @@ -174,18 +176,18 @@ export class StatisticsClient { * ``` * * ```ts - * type DailyWorkerData = { - * timestamp: Date; + * interface IDailyWorker { + * timestamp: number; * activeWorkers: number; * }; * - * type WorkerStatistics = { - * dailyWorkersData: DailyWorkerData[]; + * interface IWorkerStatistics { + * dailyWorkersData: IDailyWorker[]; * }; * ``` * * @param {IStatisticsFilter} filter Statistics params with duration data - * @returns {Promise} Worker statistics data. + * @returns {Promise} Worker statistics data. * * **Code example** * @@ -203,7 +205,7 @@ export class StatisticsClient { */ async getWorkerStatistics( filter: IStatisticsFilter = {} - ): Promise { + ): Promise { try { const first = filter.first !== undefined ? Math.min(filter.first, 1000) : 10; @@ -222,7 +224,7 @@ export class StatisticsClient { return { dailyWorkersData: eventDayDatas.map((eventDayData) => ({ - timestamp: new Date(+eventDayData.timestamp * 1000), + timestamp: +eventDayData.timestamp * 1000, activeWorkers: +eventDayData.dailyWorkerCount, })), }; @@ -247,20 +249,20 @@ export class StatisticsClient { * ``` * * ```ts - * type DailyPaymentData = { - * timestamp: Date; - * totalAmountPaid: BigNumber; + * interface IDailyPayment { + * timestamp: number; + * totalAmountPaid: bigint; * totalCount: number; - * averageAmountPerWorker: BigNumber; + * averageAmountPerWorker: bigint; * }; * - * type PaymentStatistics = { - * dailyPaymentsData: DailyPaymentData[]; + * interface IPaymentStatistics { + * dailyPaymentsData: IDailyPayment[]; * }; * ``` * * @param {IStatisticsFilter} filter Statistics params with duration data - * @returns {Promise} Payment statistics data. + * @returns {Promise} Payment statistics data. * * **Code example** * @@ -299,7 +301,7 @@ export class StatisticsClient { */ async getPaymentStatistics( filter: IStatisticsFilter = {} - ): Promise { + ): Promise { try { const first = filter.first !== undefined ? Math.min(filter.first, 1000) : 10; @@ -318,14 +320,14 @@ export class StatisticsClient { return { dailyPaymentsData: eventDayDatas.map((eventDayData) => ({ - timestamp: new Date(+eventDayData.timestamp * 1000), - totalAmountPaid: ethers.toBigInt(eventDayData.dailyHMTPayoutAmount), + timestamp: +eventDayData.timestamp * 1000, + totalAmountPaid: BigInt(eventDayData.dailyHMTPayoutAmount), totalCount: +eventDayData.dailyPayoutCount, averageAmountPerWorker: eventDayData.dailyWorkerCount === '0' - ? ethers.toBigInt(0) - : ethers.toBigInt(eventDayData.dailyHMTPayoutAmount) / - ethers.toBigInt(eventDayData.dailyWorkerCount), + ? BigInt(0) + : BigInt(eventDayData.dailyHMTPayoutAmount) / + BigInt(eventDayData.dailyWorkerCount), })), }; } catch (e: any) { @@ -337,14 +339,14 @@ export class StatisticsClient { * This function returns the statistical data of HMToken. * * ```ts - * type HMTStatistics = { - * totalTransferAmount: BigNumber; - * totalTransferCount: BigNumber; + * interface IHMTStatistics { + * totalTransferAmount: bigint; + * totalTransferCount: number; * totalHolders: number; * }; * ``` * - * @returns {Promise} HMToken statistics data. + * @returns {Promise} HMToken statistics data. * * **Code example** * @@ -361,17 +363,15 @@ export class StatisticsClient { * }); * ``` */ - async getHMTStatistics(): Promise { + async getHMTStatistics(): Promise { try { const { hmtokenStatistics } = await gqlFetch<{ hmtokenStatistics: HMTStatisticsData; }>(this.subgraphUrl, GET_HMTOKEN_STATISTICS_QUERY); return { - totalTransferAmount: ethers.toBigInt( - hmtokenStatistics.totalValueTransfered - ), - totalTransferCount: Number(hmtokenStatistics.totalTransferEventCount), + totalTransferAmount: BigInt(hmtokenStatistics.totalValueTransfered), + totalTransferCount: +hmtokenStatistics.totalTransferEventCount, totalHolders: +hmtokenStatistics.holders, }; } catch (e: any) { @@ -385,7 +385,7 @@ export class StatisticsClient { * **Input parameters** * * @param {IHMTHoldersParams} params HMT Holders params with filters and ordering - * @returns {Promise} List of HMToken holders. + * @returns {Promise} List of HMToken holders. * * **Code example** * @@ -404,7 +404,7 @@ export class StatisticsClient { * }))); * ``` */ - async getHMTHolders(params: IHMTHoldersParams = {}): Promise { + async getHMTHolders(params: IHMTHoldersParams = {}): Promise { try { const { address, orderDirection } = params; const query = GET_HOLDERS_QUERY(address); @@ -421,7 +421,7 @@ export class StatisticsClient { return holders.map((holder) => ({ address: holder.address, - balance: ethers.toBigInt(holder.balance), + balance: BigInt(holder.balance), })); } catch (e: any) { return throwError(e); @@ -444,8 +444,8 @@ export class StatisticsClient { * ``` * * ```ts - * type DailyHMTData = { - * timestamp: Date; + * interface IDailyHMT { + * timestamp: number; * totalTransactionAmount: bigint; * totalTransactionCount: number; * dailyUniqueSenders: number; @@ -454,7 +454,7 @@ export class StatisticsClient { * ``` * * @param {IStatisticsFilter} filter Statistics params with duration data - * @returns {Promise} Daily HMToken statistics data. + * @returns {Promise} Daily HMToken statistics data. * * **Code example** * @@ -475,9 +475,7 @@ export class StatisticsClient { * console.log('HMT statistics from 5/8 - 6/8:', hmtStatisticsRange); * ``` */ - async getHMTDailyData( - filter: IStatisticsFilter = {} - ): Promise { + async getHMTDailyData(filter: IStatisticsFilter = {}): Promise { try { const first = filter.first !== undefined ? Math.min(filter.first, 1000) : 10; @@ -495,10 +493,8 @@ export class StatisticsClient { }); return eventDayDatas.map((eventDayData) => ({ - timestamp: new Date(+eventDayData.timestamp * 1000), - totalTransactionAmount: ethers.toBigInt( - eventDayData.dailyHMTTransferAmount - ), + timestamp: +eventDayData.timestamp * 1000, + totalTransactionAmount: BigInt(eventDayData.dailyHMTTransferAmount), totalTransactionCount: +eventDayData.dailyHMTTransferCount, dailyUniqueSenders: +eventDayData.dailyUniqueSenders, dailyUniqueReceivers: +eventDayData.dailyUniqueReceivers, diff --git a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts b/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts index c4076092b8..fc8cd3e987 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts @@ -212,7 +212,7 @@ function mapTransaction(t: TransactionData): ITransaction { ).map((itx) => ({ from: itx.from, to: itx.to, - value: BigInt(itx.value || 0), + value: BigInt(itx.value), method: itx.method, receiver: itx.receiver, escrow: itx.escrow, @@ -224,8 +224,8 @@ function mapTransaction(t: TransactionData): ITransaction { txHash: t.txHash, from: t.from, to: t.to, - timestamp: Number(t.timestamp || 0) * 1000, - value: BigInt(t.value || 0), + timestamp: Number(t.timestamp) * 1000, + value: BigInt(t.value), method: t.method, receiver: t.receiver, escrow: t.escrow, diff --git a/packages/sdk/typescript/human-protocol-sdk/src/types.ts b/packages/sdk/typescript/human-protocol-sdk/src/types.ts index 0b3b6f9811..14497c4bc5 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/types.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/types.ts @@ -143,83 +143,4 @@ export type NetworkData = { oldFactoryAddress: string; }; -/** - * Represents the response data for an escrow withdrawal. - */ -export type EscrowWithdraw = { - /** - * The hash of the transaction associated with the escrow withdrawal. - */ - txHash: string; - /** - * The address of the token used for the withdrawal. - */ - tokenAddress: string; - /** - * The amount withdrawn from the escrow. - */ - withdrawnAmount: bigint; -}; - -/** - * Represents a payout from an escrow. - */ -export type Payout = { - /** - * Unique identifier of the payout. - */ - id: string; - /** - * The address of the escrow associated with the payout. - */ - escrowAddress: string; - /** - * The address of the recipient who received the payout. - */ - recipient: string; - /** - * The amount paid to the recipient. - */ - amount: bigint; - /** - * The timestamp when the payout was created (in UNIX format). - */ - createdAt: number; -}; - -/** - * Represents a cancellation refund event. - */ -export type CancellationRefund = { - /** - * Unique identifier of the cancellation refund event. - */ - id: string; - /** - * The address of the escrow associated with the cancellation refund. - */ - escrowAddress: string; - /** - * The address of the receiver who received the refund. - */ - receiver: string; - /** - * The amount refunded to the receiver. - */ - amount: bigint; - /** - * The block number in which the cancellation refund event occurred. - */ - - block: number; - /** - * The timestamp when the cancellation refund event occurred (in UNIX format). - */ - timestamp: number; - /** - * The transaction hash of the cancellation refund event. - */ - txHash: string; -}; - export type TransactionLikeWithNonce = TransactionLike & { nonce: number }; diff --git a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts index 615f259eaf..d97f270ff7 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts @@ -59,7 +59,7 @@ import { FAKE_URL, VALID_URL, } from './utils/constants'; -import { IEscrow, IEscrowsFilter } from '../src/interfaces'; +import { IEscrow, IPayout } from '../src/interfaces'; describe('EscrowClient', () => { let escrowClient: any, @@ -2875,11 +2875,11 @@ describe('EscrowUtils', () => { const result = await EscrowUtils.getEscrows(filter); const expected = escrows.map((e) => ({ ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, recordingOracleFee: e.recordingOracleFee ? Number(e.recordingOracleFee) : null, @@ -2977,11 +2977,11 @@ describe('EscrowUtils', () => { const expected = escrows.map((e) => ({ ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, recordingOracleFee: e.recordingOracleFee ? Number(e.recordingOracleFee) : null, @@ -3037,11 +3037,11 @@ describe('EscrowUtils', () => { const expected = escrows.map((e) => ({ ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, recordingOracleFee: e.recordingOracleFee ? Number(e.recordingOracleFee) : null, @@ -3097,11 +3097,11 @@ describe('EscrowUtils', () => { const expected = escrows.map((e) => ({ ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, recordingOracleFee: e.recordingOracleFee ? Number(e.recordingOracleFee) : null, @@ -3185,11 +3185,11 @@ describe('EscrowUtils', () => { const result = await EscrowUtils.getEscrows(filter); const expected = escrows.map((e) => ({ ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, recordingOracleFee: e.recordingOracleFee ? Number(e.recordingOracleFee) : null, @@ -3290,11 +3290,11 @@ describe('EscrowUtils', () => { const expected = escrows.map((e) => ({ ...e, - amountPaid: BigInt(e.amountPaid || 0), - balance: BigInt(e.balance || 0), - count: BigInt(e.count || 0), - totalFundedAmount: BigInt(e.totalFundedAmount || 0), - createdAt: Number(e.createdAt || 0) * 1000, + amountPaid: BigInt(e.amountPaid), + balance: BigInt(e.balance), + count: Number(e.count), + totalFundedAmount: BigInt(e.totalFundedAmount), + createdAt: Number(e.createdAt) * 1000, recordingOracleFee: e.recordingOracleFee ? Number(e.recordingOracleFee) : undefined, @@ -3372,6 +3372,7 @@ describe('EscrowUtils', () => { jobRequesterId: null, manifest: null, manifestHash: null, + createdAt: '0', }; const gqlFetchSpy = vi .spyOn(gqlFetch, 'default') @@ -3383,7 +3384,7 @@ describe('EscrowUtils', () => { ...escrow, amountPaid: 3n, balance: 0n, - count: 1n, + count: 1, totalFundedAmount: 3n, recordingOracleFee: 1, reputationOracleFee: 1, @@ -3446,7 +3447,12 @@ describe('EscrowUtils', () => { const result = await EscrowUtils.getStatusEvents({ chainId: ChainId.LOCALHOST, }); - expect(result).toEqual(pendingEvents); + const expectedResults = pendingEvents.map((event) => ({ + ...event, + status: EscrowStatus.Pending, + timestamp: +event.timestamp * 1000, + })); + expect(result).toEqual(expectedResults); expect(gqlFetchSpy).toHaveBeenCalled(); }); @@ -3479,7 +3485,12 @@ describe('EscrowUtils', () => { to: toDate, }); - expect(result).toEqual(pendingEvents); + const expectedResults = pendingEvents.map((event) => ({ + ...event, + status: EscrowStatus.Pending, + timestamp: +event.timestamp * 1000, + })); + expect(result).toEqual(expectedResults); expect(gqlFetchSpy).toHaveBeenCalled(); }); @@ -3513,7 +3524,12 @@ describe('EscrowUtils', () => { to: toDate, }); - expect(result).toEqual(partialEvents); + const expectedResults = partialEvents.map((event) => ({ + ...event, + status: EscrowStatus.Partial, + timestamp: +event.timestamp * 1000, + })); + expect(result).toEqual(expectedResults); expect(gqlFetchSpy).toHaveBeenCalled(); }); @@ -3546,7 +3562,12 @@ describe('EscrowUtils', () => { to: toDate, }); - expect(result).toEqual(pendingEvents); + const expectedResults = pendingEvents.map((event) => ({ + ...event, + status: EscrowStatus.Pending, + timestamp: +event.timestamp * 1000, + })); + expect(result).toEqual(expectedResults); expect(gqlFetchSpy).toHaveBeenCalled(); }); }); @@ -3611,7 +3632,15 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getPayouts(filter); - expect(result).toEqual(payouts); + + const expected: IPayout[] = payouts.map((payout) => ({ + id: payout.id, + escrowAddress: payout.escrowAddress, + recipient: payout.recipient, + amount: BigInt(payout.amount), + createdAt: Number(payout.createdAt) * 1000, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_PAYOUTS_QUERY(filter), @@ -3651,7 +3680,15 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getPayouts(filter); - expect(result).toEqual(payouts); + + const expected: IPayout[] = payouts.map((payout) => ({ + id: payout.id, + escrowAddress: payout.escrowAddress, + recipient: payout.recipient, + amount: BigInt(payout.amount), + createdAt: Number(payout.createdAt) * 1000, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_PAYOUTS_QUERY(filter), @@ -3696,7 +3733,15 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getPayouts(filter); - expect(result).toEqual(payouts); + + const expected: IPayout[] = payouts.map((payout) => ({ + id: payout.id, + escrowAddress: payout.escrowAddress, + recipient: payout.recipient, + amount: BigInt(payout.amount), + createdAt: Number(payout.createdAt) * 1000, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_PAYOUTS_QUERY(filter), @@ -3741,7 +3786,15 @@ describe('EscrowUtils', () => { }; const result = await EscrowUtils.getPayouts(filter); - expect(result).toEqual(payouts); + + const expected: IPayout[] = payouts.map((payout) => ({ + id: payout.id, + escrowAddress: payout.escrowAddress, + recipient: payout.recipient, + amount: BigInt(payout.amount), + createdAt: Number(payout.createdAt) * 1000, + })); + expect(result).toEqual(expected); expect(gqlFetchSpy).toHaveBeenCalledWith( 'https://api.studio.thegraph.com/query/74256/amoy/version/latest', GET_PAYOUTS_QUERY(filter), diff --git a/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts index 68e28e6eea..690c700b55 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/operator.test.ts @@ -55,6 +55,13 @@ describe('OperatorUtils', () => { slashedAmount: ethers.parseEther('25').toString(), lastDepositTimestamp: '0', }, + category: null, + fee: null, + name: null, + publicKey: null, + role: null, + url: null, + webhookUrl: null, }; const operator: IOperator = { id: stakerAddress, @@ -71,6 +78,13 @@ describe('OperatorUtils', () => { lockedUntilTimestamp: 0, withdrawnAmount: ethers.parseEther('25'), slashedAmount: ethers.parseEther('25'), + role: null, + fee: null, + publicKey: null, + webhookUrl: null, + url: null, + name: null, + category: null, }; describe('getOperator', () => { diff --git a/packages/sdk/typescript/human-protocol-sdk/test/statistics.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/statistics.test.ts index 2201383242..8d6a741df2 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/statistics.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/statistics.test.ts @@ -80,7 +80,7 @@ describe('StatisticsClient', () => { totalEscrows: 1, dailyEscrowsData: [ { - timestamp: new Date(1000), + timestamp: 1000, escrowsTotal: 1, escrowsPending: 1, escrowsSolved: 1, @@ -141,7 +141,7 @@ describe('StatisticsClient', () => { expect(result).toEqual({ dailyWorkersData: [ { - timestamp: new Date(1000), + timestamp: 1000, activeWorkers: 4, }, ], @@ -200,7 +200,7 @@ describe('StatisticsClient', () => { expect(result).toEqual({ dailyPaymentsData: [ { - timestamp: new Date(1000), + timestamp: 1000, totalAmountPaid: ethers.toBigInt(100), totalCount: 4, averageAmountPerWorker: ethers.toBigInt(25), @@ -453,7 +453,7 @@ describe('StatisticsClient', () => { expect(result).toEqual([ { - timestamp: new Date(1000), + timestamp: 1000, totalTransactionAmount: ethers.toBigInt(100), totalTransactionCount: 4, dailyUniqueSenders: 100, From ce94c9c58f97647ab5564b05a0794edd9dee5d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Mon, 20 Oct 2025 11:41:07 +0200 Subject: [PATCH 07/11] Update all SDK dependencies to use new types --- .../server/src/modules/stats/stats.service.ts | 9 +- .../modules/webhook/webhook.service.spec.ts | 18 +++ .../src/modules/webhook/webhook.service.ts | 6 +- .../model/oracle-discovery.model.ts | 111 +++++++++++------- .../oracle-discovery.controller.ts | 20 ++-- .../oracle-discovery.service.ts | 6 + .../modules/cron-job/cron-job.service.spec.ts | 6 +- .../src/modules/cron-job/cron-job.service.ts | 6 +- .../src/modules/job/job.service.spec.ts | 15 +-- .../routing-protocol.service.spec.ts | 50 +++++--- .../server/src/modules/web3/web3.dto.ts | 6 +- 11 files changed, 159 insertions(+), 94 deletions(-) diff --git a/packages/apps/dashboard/server/src/modules/stats/stats.service.ts b/packages/apps/dashboard/server/src/modules/stats/stats.service.ts index 10440c770f..b878ca1375 100644 --- a/packages/apps/dashboard/server/src/modules/stats/stats.service.ts +++ b/packages/apps/dashboard/server/src/modules/stats/stats.service.ts @@ -1,5 +1,4 @@ -import { NETWORKS, StatisticsClient } from '@human-protocol/sdk'; -import { DailyHMTData } from '@human-protocol/sdk/dist/graphql'; +import { IDailyHMT, NETWORKS, StatisticsClient } from '@human-protocol/sdk'; import { HttpService } from '@nestjs/axios'; import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager'; import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; @@ -265,7 +264,7 @@ export class StatsService implements OnModuleInit { } private async isHmtDailyStatsFetched(): Promise { - const data = await this.cacheManager.get( + const data = await this.cacheManager.get( `${HMT_PREFIX}${HMT_STATS_START_DATE}`, ); return !!data; @@ -298,7 +297,7 @@ export class StatsService implements OnModuleInit { operatingNetworks.map(async (network) => { const statisticsClient = new StatisticsClient(NETWORKS[network]); let skip = 0; - let fetchedRecords: DailyHMTData[] = []; + let fetchedRecords: IDailyHMT[] = []; do { fetchedRecords = await statisticsClient.getHMTDailyData({ @@ -310,7 +309,7 @@ export class StatsService implements OnModuleInit { for (const record of fetchedRecords) { const dailyCacheKey = `${HMT_PREFIX}${ - record.timestamp.toISOString().split('T')[0] + new Date(record.timestamp).toISOString().split('T')[0] }`; // Sum daily values diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts index 36ff3634d6..4bc06a1b4b 100644 --- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts +++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts @@ -323,6 +323,24 @@ describe('WebhookService', () => { ), ).rejects.toThrow(new NotFoundError('Oracle not found')); }); + + it('should throw NotFoundError if webhook url is not found', async () => { + (EscrowClient.build as any).mockImplementation(() => ({ + getJobLauncherAddress: jest.fn().mockResolvedValue(MOCK_ADDRESS), + })); + + (OperatorUtils.getOperator as any).mockResolvedValue({ + webhookUrl: null, + }); + + await expect( + (webhookService as any).getOracleWebhookUrl( + JOB_LAUNCHER_WEBHOOK_URL, + ChainId.LOCALHOST, + EventType.ESCROW_FAILED, + ), + ).rejects.toThrow(new NotFoundError('Oracle webhook URL not found')); + }); }); describe('handleWebhookError', () => { diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts index 09193ecc22..f19145aaf1 100644 --- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts +++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts @@ -184,8 +184,10 @@ export class WebhookService { if (!oracle) { throw new NotFoundError('Oracle not found'); } - const oracleWebhookUrl = oracle.webhookUrl; + if (!oracle.webhookUrl) { + throw new NotFoundError('Oracle webhook URL not found'); + } - return oracleWebhookUrl; + return oracle.webhookUrl; } } diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts index 2ceadc2123..c3a3dae974 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts @@ -8,24 +8,24 @@ type DiscoveredOracleCreateProps = { id: string; address: string; chainId: ChainId; - stakedAmount: bigint; - lockedAmount: bigint; - lockedUntilTimestamp: bigint; - withdrawnAmount: bigint; - slashedAmount: bigint; - amountJobsProcessed: bigint; - role?: string; - fee?: bigint; - publicKey?: string; - webhookUrl?: string; - website?: string; - url: string; - jobTypes: string[]; - registrationNeeded?: boolean; - registrationInstructions?: string; - reputationNetworks?: string[]; - name?: string; - category?: string; + stakedAmount: bigint | null; + lockedAmount: bigint | null; + lockedUntilTimestamp: number | null; + withdrawnAmount: bigint | null; + slashedAmount: bigint | null; + amountJobsProcessed: bigint | null; + role: string | null; + fee: bigint | null; + publicKey: string | null; + webhookUrl: string | null; + website: string | null; + url: string | null; + jobTypes: string[] | null; + registrationNeeded: boolean | null; + registrationInstructions: string | null; + reputationNetworks: string[]; + name: string | null; + category: string | null; }; export class DiscoveredOracle { @@ -38,23 +38,31 @@ export class DiscoveredOracle { @ApiProperty({ description: 'Chain ID where the oracle is registered' }) chainId: ChainId; - @ApiProperty({ description: 'Amount staked by the operator' }) - stakedAmount: string; + @ApiPropertyOptional({ description: 'Amount staked by the operator' }) + stakedAmount?: string; - @ApiProperty({ description: 'Amount currently locked by the operator' }) - lockedAmount: string; + @ApiPropertyOptional({ + description: 'Amount currently locked by the operator', + }) + lockedAmount?: string; - @ApiProperty({ description: 'Timestamp until funds are locked' }) - lockedUntilTimestamp: string; + @ApiPropertyOptional({ description: 'Timestamp until funds are locked' }) + lockedUntilTimestamp?: string; - @ApiProperty({ description: 'Total amount withdrawn by the operator' }) - withdrawnAmount: string; + @ApiPropertyOptional({ + description: 'Total amount withdrawn by the operator', + }) + withdrawnAmount?: string; - @ApiProperty({ description: 'Total amount slashed from the operator' }) - slashedAmount: string; + @ApiPropertyOptional({ + description: 'Total amount slashed from the operator', + }) + slashedAmount?: string; - @ApiProperty({ description: 'Number of jobs processed by the operator' }) - amountJobsProcessed: string; + @ApiPropertyOptional({ + description: 'Number of jobs processed by the operator', + }) + amountJobsProcessed?: string; @ApiPropertyOptional({ description: 'Fee charged by the operator' }) fee?: bigint; @@ -68,11 +76,11 @@ export class DiscoveredOracle { @ApiPropertyOptional({ description: 'Website of the operator' }) website?: string; - @ApiProperty({ description: 'URL of the oracle operator' }) - url: string; + @ApiPropertyOptional({ description: 'URL of the oracle operator' }) + url?: string; - @ApiProperty({ description: 'Role of the oracle operator' }) - role: string; + @ApiPropertyOptional({ description: 'Role of the oracle operator' }) + role?: string; @ApiPropertyOptional({ type: [String], @@ -81,7 +89,7 @@ export class DiscoveredOracle { jobTypes: string[]; @ApiPropertyOptional({ description: 'Indicates if registration is needed' }) - registrationNeeded: boolean; + registrationNeeded?: boolean; @ApiPropertyOptional({ description: 'Instructions for registration, if needed', @@ -94,8 +102,8 @@ export class DiscoveredOracle { }) reputationNetworks?: string[]; - @ApiProperty({ description: 'Name of the operator' }) - name: string; + @ApiPropertyOptional({ description: 'Name of the operator' }) + name?: string; @ApiPropertyOptional({ description: 'Category of the operator' }) category?: string; @@ -107,14 +115,27 @@ export class DiscoveredOracle { executionsToSkip = 0; constructor(props: DiscoveredOracleCreateProps) { - Object.assign(this, props); - this.registrationNeeded = props.registrationNeeded || false; - this.stakedAmount = this.stakedAmount.toString(); - this.lockedAmount = this.lockedAmount.toString(); - this.withdrawnAmount = this.withdrawnAmount.toString(); - this.slashedAmount = this.slashedAmount.toString(); - this.amountJobsProcessed = this.amountJobsProcessed.toString(); - this.lockedUntilTimestamp = this.lockedUntilTimestamp.toString(); + this.id = props.id; + this.address = props.address; + this.chainId = props.chainId; + this.registrationNeeded = props.registrationNeeded ?? undefined; + this.role = props.role ?? undefined; + this.url = props.url ?? undefined; + this.name = props.name ?? undefined; + this.fee = props.fee ?? undefined; + this.publicKey = props.publicKey ?? undefined; + this.webhookUrl = props.webhookUrl ?? undefined; + this.website = props.website ?? undefined; + this.category = props.category ?? undefined; + this.registrationInstructions = props.registrationInstructions ?? undefined; + this.jobTypes = props.jobTypes ?? []; + this.reputationNetworks = props.reputationNetworks ?? undefined; + this.stakedAmount = props.stakedAmount?.toString(); + this.lockedAmount = props.lockedAmount?.toString(); + this.withdrawnAmount = props.withdrawnAmount?.toString(); + this.slashedAmount = props.slashedAmount?.toString(); + this.amountJobsProcessed = props.amountJobsProcessed?.toString(); + this.lockedUntilTimestamp = props.lockedUntilTimestamp?.toString(); } } diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts index 6308b142bd..64a8b169c3 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts @@ -55,18 +55,24 @@ export class OracleDiscoveryController { id: 'thisrty-oracle', address: process.env.THIRSTYFI_ORACLE_ADDRESS ?? '', chainId: ChainId.POLYGON, - stakedAmount: '0' as any, - lockedAmount: '0' as any, - lockedUntilTimestamp: '0' as any, - withdrawnAmount: '0' as any, - slashedAmount: '0' as any, - amountJobsProcessed: '0' as any, + stakedAmount: 0n, + lockedAmount: 0n, + lockedUntilTimestamp: 0, + withdrawnAmount: 0n, + slashedAmount: 0n, + amountJobsProcessed: 0n, role: 'exchange_oracle', url: ' ', jobTypes: ['thirstyfi'], name: 'ThirstyFi', registrationNeeded: false, - // registrationInstructions: 'https://www.thisrty.com/', + registrationInstructions: null, + publicKey: null, + webhookUrl: null, + website: null, + fee: null, + reputationNetworks: [], + category: null, }); oracles.push(thisrtyOracle); diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts index 1c04b9dae1..5850cab5e6 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts @@ -106,6 +106,12 @@ export class OracleDiscoveryService { slashedAmount: exchangeOracle.slashedAmount, amountJobsProcessed: exchangeOracle.amountJobsProcessed, lockedUntilTimestamp: exchangeOracle.lockedUntilTimestamp, + fee: exchangeOracle.fee, + publicKey: exchangeOracle.publicKey, + webhookUrl: exchangeOracle.webhookUrl, + website: exchangeOracle.website, + reputationNetworks: exchangeOracle.reputationNetworks, + category: exchangeOracle.category, }), ); } diff --git a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts index bfb4aca116..e7121a703a 100644 --- a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts @@ -8,10 +8,10 @@ import { EscrowClient, EscrowStatus, EscrowUtils, + IStatusEvent, KVStoreUtils, NETWORKS, } from '@human-protocol/sdk'; -import { StatusEvent } from '@human-protocol/sdk/dist/graphql'; import { HttpService } from '@nestjs/axios'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; @@ -1107,7 +1107,7 @@ describe('CronJobService', () => { describe('syncJobStatuses Cron Job', () => { let cronJobEntityMock: Partial; let jobEntityMock: Partial; - let escrowEventMock: Partial; + let escrowEventMock: Partial; beforeEach(() => { cronJobEntityMock = { @@ -1125,7 +1125,7 @@ describe('CronJobService', () => { escrowEventMock = { chainId: ChainId.LOCALHOST, escrowAddress: MOCK_ADDRESS, - status: EscrowStatus[EscrowStatus.Partial], + status: EscrowStatus.Partial, }; jest.spyOn(repository, 'findOneByType').mockResolvedValue(null); diff --git a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts index 6dec225751..33e2552034 100644 --- a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts +++ b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts @@ -515,19 +515,19 @@ export class CronJobService { } if (!job || job.status === JobStatus.CANCELED) continue; - if (event.status === EscrowStatus[EscrowStatus.Cancelled]) { + if (event.status === EscrowStatus.Cancelled) { await this.jobService.cancelJob(job); continue; } let newStatus: JobStatus | null = null; if ( - event.status === EscrowStatus[EscrowStatus.Partial] && + event.status === EscrowStatus.Partial && job.status !== JobStatus.PARTIAL ) { newStatus = JobStatus.PARTIAL; } else if ( - event.status === EscrowStatus[EscrowStatus.Complete] && + event.status === EscrowStatus.Complete && job.status !== JobStatus.COMPLETED ) { newStatus = JobStatus.COMPLETED; diff --git a/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts b/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts index 5d350aa9ba..f829d0021d 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts @@ -1745,16 +1745,17 @@ describe('JobService', () => { describe('cancelJob', () => { it('should create a refund payment and set status to CANCELED', async () => { const jobEntity = createJobEntity(); - const refundAmount = faker.number.float({ min: 1, max: 10 }); + const tokenDecimals = (TOKEN_ADDRESSES[jobEntity.chainId as ChainId] ?? + {})[jobEntity.token as EscrowFundToken]?.decimals; + const refundAmount = faker.number.float({ + min: 1, + max: 10, + fractionDigits: tokenDecimals, + }); mockPaymentService.getJobPayments.mockResolvedValueOnce([]); mockedEscrowUtils.getCancellationRefund.mockResolvedValueOnce({ - amount: ethers.parseUnits( - refundAmount.toString(), - (TOKEN_ADDRESSES[jobEntity.chainId as ChainId] ?? {})[ - jobEntity.token as EscrowFundToken - ]?.decimals, - ), + amount: ethers.parseUnits(refundAmount.toString(), tokenDecimals), escrowAddress: jobEntity.escrowAddress!, } as any); mockPaymentService.createRefundPayment.mockResolvedValueOnce(undefined); diff --git a/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.spec.ts b/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.spec.ts index 9893a6d342..01d3e64cbd 100644 --- a/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.spec.ts @@ -147,8 +147,8 @@ describe('RoutingProtocolService', () => { it('should select the first available oracle of specified type', async () => { const availableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, - { role: Role.ExchangeOracle, address: '0xExchangeOracle2' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle2', url: null }, ]; const result = routingProtocolService.selectOracleFromAvailable( @@ -163,8 +163,8 @@ describe('RoutingProtocolService', () => { it('should shuffle oracles and return the first oracle from the shuffled list', () => { const availableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, - { role: Role.ExchangeOracle, address: '0xExchangeOracle2' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle2', url: null }, ]; jest @@ -183,8 +183,8 @@ describe('RoutingProtocolService', () => { it('should update oracle order and select from the newly shuffled list if jobType changes', () => { const availableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, - { role: Role.ExchangeOracle, address: '0xExchangeOracle2' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle2', url: null }, ]; routingProtocolService.oracleOrder = { @@ -218,7 +218,7 @@ describe('RoutingProtocolService', () => { it('should not shuffle if the oracle hash has not changed for the same jobType', () => { const availableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, ]; const latestOraclesHash = 'hash123'; @@ -257,8 +257,8 @@ describe('RoutingProtocolService', () => { it('should update the oracle order and hash if the list of available oracles changes', () => { const availableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, - { role: Role.ExchangeOracle, address: '0xExchangeOracle2' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle2', url: null }, ]; const previousHash = 'oldHash'; @@ -294,10 +294,18 @@ describe('RoutingProtocolService', () => { it('should select the oracle from available ones and rotate index', async () => { const availableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, - { role: Role.ExchangeOracle, address: '0xExchangeOracle2' }, - { role: Role.RecordingOracle, address: '0xRecordingOracle1' }, - { role: Role.RecordingOracle, address: '0xRecordingOracle2' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle2', url: null }, + { + role: Role.RecordingOracle, + address: '0xRecordingOracle1', + url: null, + }, + { + role: Role.RecordingOracle, + address: '0xRecordingOracle2', + url: null, + }, ]; const result1 = routingProtocolService.selectOracleFromAvailable( @@ -342,8 +350,12 @@ describe('RoutingProtocolService', () => { describe('selectOracles', () => { it('should select reputation oracle and find available oracles', async () => { const mockAvailableOracles = [ - { role: Role.ExchangeOracle, address: '0xExchangeOracle1' }, - { role: Role.RecordingOracle, address: '0xRecordingOracle1' }, + { role: Role.ExchangeOracle, address: '0xExchangeOracle1', url: null }, + { + role: Role.RecordingOracle, + address: '0xRecordingOracle1', + url: null, + }, ]; web3Service.findAvailableOracles = jest @@ -386,8 +398,8 @@ describe('RoutingProtocolService', () => { ) .mockReturnValue(`${reputationOracle},otherOracle`); jest.spyOn(web3Service, 'findAvailableOracles').mockResolvedValue([ - { address: exchangeOracle, role: Role.ExchangeOracle }, - { address: recordingOracle, role: Role.RecordingOracle }, + { address: exchangeOracle, role: Role.ExchangeOracle, url: null }, + { address: recordingOracle, role: Role.RecordingOracle, url: null }, ]); await expect( @@ -438,7 +450,7 @@ describe('RoutingProtocolService', () => { jest .spyOn(web3Service, 'findAvailableOracles') .mockResolvedValue([ - { address: 'anotherOracle', role: Role.ExchangeOracle }, + { address: 'anotherOracle', role: Role.ExchangeOracle, url: null }, ]); await expect( @@ -467,7 +479,7 @@ describe('RoutingProtocolService', () => { jest .spyOn(web3Service, 'findAvailableOracles') .mockResolvedValue([ - { address: 'anotherOracle', role: Role.RecordingOracle }, + { address: 'anotherOracle', role: Role.RecordingOracle, url: null }, ]); await expect( diff --git a/packages/apps/job-launcher/server/src/modules/web3/web3.dto.ts b/packages/apps/job-launcher/server/src/modules/web3/web3.dto.ts index 4766e6641c..ea3b2dc6ce 100644 --- a/packages/apps/job-launcher/server/src/modules/web3/web3.dto.ts +++ b/packages/apps/job-launcher/server/src/modules/web3/web3.dto.ts @@ -4,9 +4,9 @@ import { IsString } from 'class-validator'; export class OracleDataDto implements Partial { address: string; - role?: string; - url?: string; - jobTypes?: string[]; + role: string | null; + url: string | null; + jobTypes?: string[] | null; } export class AvailableOraclesDto { From b62347f81eab97a23db3750e0b9d0ba1b7e464b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Tue, 21 Oct 2025 19:10:43 +0200 Subject: [PATCH 08/11] Refactor data types in EscrowData, OperatorData, and StakerData to use string instead of int and parse values inside constructor; improve nullability handling in various models. --- .../model/oracle-discovery.model.ts | 24 +- .../oracle-discovery.service.ts | 4 +- .../human_protocol_sdk/escrow/escrow_utils.py | 94 +++----- .../operator/operator_utils.py | 226 +++++------------- .../staking/staking_utils.py | 48 ++-- .../human_protocol_sdk/worker/worker_utils.py | 16 +- .../operator/test_operator_utils.py | 3 + .../human-protocol-sdk/src/escrow.ts | 10 +- 8 files changed, 150 insertions(+), 275 deletions(-) diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts index c3a3dae974..5d5ad71871 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts @@ -14,17 +14,17 @@ type DiscoveredOracleCreateProps = { withdrawnAmount: bigint | null; slashedAmount: bigint | null; amountJobsProcessed: bigint | null; - role: string | null; + role: string; fee: bigint | null; publicKey: string | null; webhookUrl: string | null; website: string | null; - url: string | null; + url: string; jobTypes: string[] | null; registrationNeeded: boolean | null; registrationInstructions: string | null; reputationNetworks: string[]; - name: string | null; + name: string; category: string | null; }; @@ -76,11 +76,11 @@ export class DiscoveredOracle { @ApiPropertyOptional({ description: 'Website of the operator' }) website?: string; - @ApiPropertyOptional({ description: 'URL of the oracle operator' }) - url?: string; + @ApiProperty({ description: 'URL of the oracle operator' }) + url: string; - @ApiPropertyOptional({ description: 'Role of the oracle operator' }) - role?: string; + @ApiProperty({ description: 'Role of the oracle operator' }) + role: string; @ApiPropertyOptional({ type: [String], @@ -102,8 +102,8 @@ export class DiscoveredOracle { }) reputationNetworks?: string[]; - @ApiPropertyOptional({ description: 'Name of the operator' }) - name?: string; + @ApiProperty({ description: 'Name of the operator' }) + name: string; @ApiPropertyOptional({ description: 'Category of the operator' }) category?: string; @@ -119,9 +119,9 @@ export class DiscoveredOracle { this.address = props.address; this.chainId = props.chainId; this.registrationNeeded = props.registrationNeeded ?? undefined; - this.role = props.role ?? undefined; - this.url = props.url ?? undefined; - this.name = props.name ?? undefined; + this.role = props.role; + this.url = props.url; + this.name = props.name; this.fee = props.fee ?? undefined; this.publicKey = props.publicKey ?? undefined; this.webhookUrl = props.webhookUrl ?? undefined; diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts index 5850cab5e6..c7e93ee143 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.service.ts @@ -93,8 +93,8 @@ export class OracleDiscoveryService { new DiscoveredOracle({ id: exchangeOracle.id, address: exchangeOracle.address, - name: exchangeOracle.name, - role: exchangeOracle.role, + name: exchangeOracle.name as string, + role: exchangeOracle.role as string, url: exchangeOracle.url as string, jobTypes: exchangeOracle.jobTypes as string[], registrationNeeded: exchangeOracle.registrationNeeded, diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py index fa1135452d..f2888d87dc 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py @@ -52,16 +52,16 @@ def __init__( chain_id: ChainId, id: str, address: str, - amount_paid: int, - balance: int, - count: int, + amount_paid: str, + balance: str, + count: str, factory_address: str, launcher: str, job_requester_id: Optional[str], status: str, token: str, - total_funded_amount: int, - created_at: int, + total_funded_amount: str, + created_at: str, final_results_url: Optional[str] = None, final_results_hash: Optional[str] = None, intermediate_results_url: Optional[str] = None, @@ -71,9 +71,9 @@ def __init__( recording_oracle: Optional[str] = None, reputation_oracle: Optional[str] = None, exchange_oracle: Optional[str] = None, - recording_oracle_fee: Optional[int] = None, - reputation_oracle_fee: Optional[int] = None, - exchange_oracle_fee: Optional[int] = None, + recording_oracle_fee: Optional[str] = None, + reputation_oracle_fee: Optional[str] = None, + exchange_oracle_fee: Optional[str] = None, ): """ Initializes an EscrowData instance. @@ -107,9 +107,9 @@ def __init__( self.id = id self.address = address - self.amount_paid = amount_paid - self.balance = balance - self.count = count + self.amount_paid = int(amount_paid) + self.balance = int(balance) + self.count = int(count) self.factory_address = factory_address self.final_results_url = final_results_url self.final_results_hash = final_results_hash @@ -122,13 +122,19 @@ def __init__( self.recording_oracle = recording_oracle self.reputation_oracle = reputation_oracle self.exchange_oracle = exchange_oracle - self.recording_oracle_fee = recording_oracle_fee - self.reputation_oracle_fee = reputation_oracle_fee - self.exchange_oracle_fee = exchange_oracle_fee + self.recording_oracle_fee = ( + int(recording_oracle_fee) if recording_oracle_fee is not None else None + ) + self.reputation_oracle_fee = ( + int(reputation_oracle_fee) if reputation_oracle_fee is not None else None + ) + self.exchange_oracle_fee = ( + int(exchange_oracle_fee) if exchange_oracle_fee is not None else None + ) self.status = status self.token = token - self.total_funded_amount = total_funded_amount - self.created_at = created_at * 1000 + self.total_funded_amount = int(total_funded_amount) + self.created_at = int(created_at) * 1000 self.chain_id = chain_id @@ -295,16 +301,16 @@ def get_escrows( chain_id=chain_id, id=escrow.get("id"), address=escrow.get("address"), - amount_paid=int(escrow.get("amountPaid")), - balance=int(escrow.get("balance")), - count=int(escrow.get("count")), + amount_paid=escrow.get("amountPaid"), + balance=escrow.get("balance"), + count=escrow.get("count"), factory_address=escrow.get("factoryAddress"), launcher=escrow.get("launcher"), job_requester_id=escrow.get("jobRequesterId"), status=escrow.get("status"), token=escrow.get("token"), - total_funded_amount=int(escrow.get("totalFundedAmount")), - created_at=int(escrow.get("createdAt")), + total_funded_amount=escrow.get("totalFundedAmount"), + created_at=escrow.get("createdAt"), final_results_url=escrow.get("finalResultsUrl"), final_results_hash=escrow.get("finalResultsHash"), intermediate_results_url=escrow.get("intermediateResultsUrl"), @@ -314,21 +320,9 @@ def get_escrows( recording_oracle=escrow.get("recordingOracle"), reputation_oracle=escrow.get("reputationOracle"), exchange_oracle=escrow.get("exchangeOracle"), - recording_oracle_fee=( - int(escrow.get("recordingOracleFee")) - if escrow.get("recordingOracleFee") - else None - ), - reputation_oracle_fee=( - int(escrow.get("reputationOracleFee")) - if escrow.get("reputationOracleFee") - else None - ), - exchange_oracle_fee=( - int(escrow.get("exchangeOracleFee")) - if escrow.get("exchangeOracleFee") - else None - ), + recording_oracle_fee=escrow.get("recordingOracleFee"), + reputation_oracle_fee=escrow.get("reputationOracleFee"), + exchange_oracle_fee=escrow.get("exchangeOracleFee"), ) for escrow in escrows_raw ] @@ -395,16 +389,16 @@ def get_escrow( chain_id=chain_id, id=escrow.get("id"), address=escrow.get("address"), - amount_paid=int(escrow.get("amountPaid")), - balance=int(escrow.get("balance")), - count=int(escrow.get("count")), + amount_paid=escrow.get("amountPaid"), + balance=escrow.get("balance"), + count=escrow.get("count"), factory_address=escrow.get("factoryAddress"), launcher=escrow.get("launcher"), job_requester_id=escrow.get("jobRequesterId"), status=escrow.get("status"), token=escrow.get("token"), - total_funded_amount=int(escrow.get("totalFundedAmount")), - created_at=int(escrow.get("createdAt")), + total_funded_amount=escrow.get("totalFundedAmount"), + created_at=escrow.get("createdAt"), final_results_url=escrow.get("finalResultsUrl"), final_results_hash=escrow.get("finalResultsHash"), intermediate_results_url=escrow.get("intermediateResultsUrl"), @@ -414,21 +408,9 @@ def get_escrow( recording_oracle=escrow.get("recordingOracle"), reputation_oracle=escrow.get("reputationOracle"), exchange_oracle=escrow.get("exchangeOracle"), - recording_oracle_fee=( - int(escrow.get("recordingOracleFee")) - if escrow.get("recordingOracleFee") - else None - ), - reputation_oracle_fee=( - int(escrow.get("reputationOracleFee")) - if escrow.get("reputationOracleFee") - else None - ), - exchange_oracle_fee=( - int(escrow.get("exchangeOracleFee")) - if escrow.get("exchangeOracleFee") - else None - ), + recording_oracle_fee=escrow.get("recordingOracleFee"), + reputation_oracle_fee=escrow.get("reputationOracleFee"), + exchange_oracle_fee=escrow.get("exchangeOracleFee"), ) @staticmethod diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py index 9e3e23a58e..9bed4d8fc6 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/operator/operator_utils.py @@ -21,7 +21,7 @@ import logging import os -from typing import List, Optional +from typing import List, Optional, Union from human_protocol_sdk.constants import NETWORKS, ChainId, OrderDirection from human_protocol_sdk.gql.reward import get_reward_added_events_query @@ -89,20 +89,20 @@ def __init__( chain_id: ChainId, id: str, address: str, - amount_jobs_processed: int, - reputation_networks: List[str], - staked_amount: Optional[int] = None, - locked_amount: Optional[int] = None, - locked_until_timestamp: Optional[int] = None, - withdrawn_amount: Optional[int] = None, - slashed_amount: Optional[int] = None, + amount_jobs_processed: str, + reputation_networks: Union[List[str], str], + staked_amount: Optional[str] = None, + locked_amount: Optional[str] = None, + locked_until_timestamp: Optional[str] = None, + withdrawn_amount: Optional[str] = None, + slashed_amount: Optional[str] = None, role: Optional[str] = None, - fee: Optional[int] = None, + fee: Optional[str] = None, public_key: Optional[str] = None, webhook_url: Optional[str] = None, website: Optional[str] = None, url: Optional[str] = None, - job_types: Optional[List[str]] = None, + job_types: Optional[Union[List[str], str]] = None, registration_needed: Optional[bool] = None, registration_instructions: Optional[str] = None, name: Optional[str] = None, @@ -137,26 +137,42 @@ def __init__( self.chain_id = chain_id self.id = id self.address = address - self.staked_amount = staked_amount - self.locked_amount = locked_amount + self.staked_amount = int(staked_amount) if staked_amount is not None else None + self.locked_amount = int(locked_amount) if locked_amount is not None else None self.locked_until_timestamp = ( - locked_until_timestamp * 1000 if locked_until_timestamp else None + int(locked_until_timestamp) * 1000 + if locked_until_timestamp is not None + else None ) - self.withdrawn_amount = withdrawn_amount - self.slashed_amount = slashed_amount - self.amount_jobs_processed = amount_jobs_processed + self.withdrawn_amount = ( + int(withdrawn_amount) if withdrawn_amount is not None else None + ) + self.slashed_amount = ( + int(slashed_amount) if slashed_amount is not None else None + ) + self.amount_jobs_processed = int(amount_jobs_processed) self.role = role - self.fee = fee + self.fee = int(fee) if fee is not None else None self.public_key = public_key self.webhook_url = webhook_url self.website = website self.url = url - self.job_types = job_types self.registration_needed = registration_needed self.registration_instructions = registration_instructions - self.reputation_networks = reputation_networks + vals = reputation_networks if isinstance(reputation_networks, list) else [] + self.reputation_networks = [ + (rn if isinstance(rn, str) else rn.get("address")) + for rn in vals + if (isinstance(rn, str) and rn) + or (isinstance(rn, dict) and rn.get("address")) + ] self.name = name self.category = category + self.job_types = ( + job_types.split(",") + if isinstance(job_types, str) + else (job_types if isinstance(job_types, list) else []) + ) class RewardData: @@ -234,69 +250,28 @@ def get_operators(filter: OperatorFilter) -> List[OperatorData]: operators_raw = operators_data["data"]["operators"] for operator in operators_raw: - reputation_networks = [] - if operator.get("reputationNetworks") and isinstance( - operator.get("reputationNetworks"), list - ): - reputation_networks = [ - network["address"] for network in operator["reputationNetworks"] - ] - staker = operator.get("staker") or {} operators.append( OperatorData( chain_id=filter.chain_id, id=operator.get("id"), address=operator.get("address"), - staked_amount=( - int(staker.get("stakedAmount")) - if staker.get("stakedAmount") is not None - else None - ), - locked_amount=( - int(staker.get("lockedAmount")) - if staker.get("lockedAmount") is not None - else None - ), - locked_until_timestamp=( - int(staker.get("lockedUntilTimestamp")) - if staker.get("lockedUntilTimestamp") is not None - else None - ), - withdrawn_amount=( - int(staker.get("withdrawnAmount")) - if staker.get("withdrawnAmount") is not None - else None - ), - slashed_amount=( - int(staker.get("slashedAmount")) - if staker.get("slashedAmount") is not None - else None - ), - amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), + staked_amount=staker.get("stakedAmount"), + locked_amount=staker.get("lockedAmount"), + locked_until_timestamp=staker.get("lockedUntilTimestamp"), + withdrawn_amount=staker.get("withdrawnAmount"), + slashed_amount=staker.get("slashedAmount"), + amount_jobs_processed=operator.get("amountJobsProcessed"), role=operator.get("role"), - # Preserve 0 fee; only None if absent - fee=( - int(operator.get("fee")) - if operator.get("fee") is not None - else None - ), + fee=operator.get("fee"), public_key=operator.get("publicKey"), webhook_url=operator.get("webhookUrl"), website=operator.get("website"), url=operator.get("url"), - job_types=( - operator.get("jobTypes").split(",") - if isinstance(operator.get("jobTypes"), str) - else ( - operator.get("jobTypes", []) - if isinstance(operator.get("jobTypes"), list) - else [] - ) - ), + job_types=operator.get("jobTypes"), registration_needed=operator.get("registrationNeeded"), registration_instructions=operator.get("registrationInstructions"), - reputation_networks=reputation_networks, + reputation_networks=operator.get("reputationNetworks"), name=operator.get("name"), category=operator.get("category"), ) @@ -354,64 +329,27 @@ def get_operator( return None operator = operator_data["data"]["operator"] - reputation_networks = [] - - if operator.get("reputationNetworks") and isinstance( - operator.get("reputationNetworks"), list - ): - reputation_networks = [ - network["address"] for network in operator["reputationNetworks"] - ] - staker = operator.get("staker") or {} return OperatorData( chain_id=chain_id, id=operator.get("id"), address=operator.get("address"), - staked_amount=( - int(staker.get("stakedAmount")) - if staker.get("stakedAmount") is not None - else None - ), - locked_amount=( - int(staker.get("lockedAmount")) - if staker.get("lockedAmount") is not None - else None - ), - locked_until_timestamp=( - int(staker.get("lockedUntilTimestamp")) - if staker.get("lockedUntilTimestamp") is not None - else None - ), - withdrawn_amount=( - int(staker.get("withdrawnAmount")) - if staker.get("withdrawnAmount") is not None - else None - ), - slashed_amount=( - int(staker.get("slashedAmount")) - if staker.get("slashedAmount") is not None - else None - ), - amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), + staked_amount=staker.get("stakedAmount"), + locked_amount=staker.get("lockedAmount"), + locked_until_timestamp=staker.get("lockedUntilTimestamp"), + withdrawn_amount=staker.get("withdrawnAmount"), + slashed_amount=staker.get("slashedAmount"), + amount_jobs_processed=operator.get("amountJobsProcessed"), role=operator.get("role"), - fee=(int(operator.get("fee")) if operator.get("fee") is not None else None), + fee=operator.get("fee"), public_key=operator.get("publicKey"), webhook_url=operator.get("webhookUrl"), website=operator.get("website"), url=operator.get("url"), - job_types=( - operator.get("jobTypes").split(",") - if isinstance(operator.get("jobTypes"), str) - else ( - operator.get("jobTypes", []) - if isinstance(operator.get("jobTypes"), list) - else [] - ) - ), + job_types=operator.get("jobTypes"), registration_needed=operator.get("registrationNeeded"), registration_instructions=operator.get("registrationInstructions"), - reputation_networks=reputation_networks, + reputation_networks=operator.get("reputationNetworks"), name=operator.get("name"), category=operator.get("category"), ) @@ -476,62 +414,22 @@ def get_reputation_network_operators( chain_id=chain_id, id=operator.get("id"), address=operator.get("address"), - staked_amount=( - int(staker.get("stakedAmount")) - if staker.get("stakedAmount") is not None - else None - ), - locked_amount=( - int(staker.get("lockedAmount")) - if staker.get("lockedAmount") is not None - else None - ), - locked_until_timestamp=( - int(staker.get("lockedUntilTimestamp")) - if staker.get("lockedUntilTimestamp") is not None - else None - ), - withdrawn_amount=( - int(staker.get("withdrawnAmount")) - if staker.get("withdrawnAmount") is not None - else None - ), - slashed_amount=( - int(staker.get("slashedAmount")) - if staker.get("slashedAmount") is not None - else None - ), - amount_jobs_processed=int(operator.get("amountJobsProcessed") or 0), + staked_amount=staker.get("stakedAmount"), + locked_amount=staker.get("lockedAmount"), + locked_until_timestamp=staker.get("lockedUntilTimestamp"), + withdrawn_amount=staker.get("withdrawnAmount"), + slashed_amount=staker.get("slashedAmount"), + amount_jobs_processed=operator.get("amountJobsProcessed"), role=operator.get("role"), - fee=( - int(operator.get("fee")) - if operator.get("fee") is not None - else None - ), + fee=operator.get("fee"), public_key=operator.get("publicKey"), webhook_url=operator.get("webhookUrl"), website=operator.get("website"), url=operator.get("url"), - job_types=( - operator.get("jobTypes").split(",") - if isinstance(operator.get("jobTypes"), str) - else ( - operator.get("jobTypes", []) - if isinstance(operator.get("jobTypes"), list) - else [] - ) - ), + job_types=operator.get("jobTypes"), registration_needed=operator.get("registrationNeeded"), registration_instructions=operator.get("registrationInstructions"), - reputation_networks=( - [ - network["address"] - for network in operator.get("reputationNetworks", []) - ] - if operator.get("reputationNetworks") - and isinstance(operator.get("reputationNetworks"), list) - else [] - ), + reputation_networks=operator.get("reputationNetworks"), name=operator.get("name"), category=operator.get("category"), ) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py index 75df379140..3729fc0e7d 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py @@ -39,21 +39,21 @@ def __init__( self, id: str, address: str, - staked_amount: int, - locked_amount: int, - withdrawn_amount: int, - slashed_amount: int, - locked_until_timestamp: int, - last_deposit_timestamp: int, + staked_amount: str, + locked_amount: str, + withdrawn_amount: str, + slashed_amount: str, + locked_until_timestamp: str, + last_deposit_timestamp: str, ): self.id = id self.address = address - self.staked_amount = staked_amount - self.locked_amount = locked_amount - self.withdrawn_amount = withdrawn_amount - self.slashed_amount = slashed_amount - self.locked_until_timestamp = locked_until_timestamp * 1000 - self.last_deposit_timestamp = last_deposit_timestamp * 1000 + self.staked_amount = int(staked_amount) + self.locked_amount = int(locked_amount) + self.withdrawn_amount = int(withdrawn_amount) + self.slashed_amount = int(slashed_amount) + self.locked_until_timestamp = int(locked_until_timestamp) * 1000 + self.last_deposit_timestamp = int(last_deposit_timestamp) * 1000 class StakingUtilsError(Exception): @@ -84,12 +84,12 @@ def get_staker(chain_id: ChainId, address: str) -> Optional[StakerData]: return StakerData( id=staker.get("id") or "", address=staker.get("address") or "", - staked_amount=int(staker.get("stakedAmount") or 0), - locked_amount=int(staker.get("lockedAmount") or 0), - withdrawn_amount=int(staker.get("withdrawnAmount") or 0), - slashed_amount=int(staker.get("slashedAmount") or 0), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), - last_deposit_timestamp=int(staker.get("lastDepositTimestamp") or 0), + staked_amount=staker.get("stakedAmount"), + locked_amount=staker.get("lockedAmount"), + withdrawn_amount=staker.get("withdrawnAmount"), + slashed_amount=staker.get("slashedAmount"), + locked_until_timestamp=staker.get("lockedUntilTimestamp"), + last_deposit_timestamp=staker.get("lastDepositTimestamp"), ) @staticmethod @@ -129,12 +129,12 @@ def get_stakers(filter: StakersFilter) -> List[StakerData]: StakerData( id=staker.get("id") or "", address=staker.get("address") or "", - staked_amount=int(staker.get("stakedAmount") or 0), - locked_amount=int(staker.get("lockedAmount") or 0), - withdrawn_amount=int(staker.get("withdrawnAmount") or 0), - slashed_amount=int(staker.get("slashedAmount") or 0), - locked_until_timestamp=int(staker.get("lockedUntilTimestamp") or 0), - last_deposit_timestamp=int(staker.get("lastDepositTimestamp") or 0), + staked_amount=staker.get("stakedAmount"), + locked_amount=staker.get("lockedAmount"), + withdrawn_amount=staker.get("withdrawnAmount"), + slashed_amount=staker.get("slashedAmount"), + locked_until_timestamp=staker.get("lockedUntilTimestamp"), + last_deposit_timestamp=staker.get("lastDepositTimestamp"), ) for staker in stakers_raw ] diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py index 3e0c766505..c363898ce6 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/worker/worker_utils.py @@ -23,8 +23,8 @@ def __init__( self, id: str, address: str, - total_amount_received: int, - payout_count: int, + total_amount_received: str, + payout_count: str, ): """ Initializes a WorkerData instance. @@ -37,8 +37,8 @@ def __init__( self.id = id self.address = address - self.total_amount_received = total_amount_received - self.payout_count = payout_count + self.total_amount_received = int(total_amount_received) + self.payout_count = int(payout_count) class WorkerUtils: @@ -89,8 +89,8 @@ def get_workers(filter: WorkerFilter) -> List[WorkerData]: WorkerData( id=worker.get("id"), address=worker.get("address"), - total_amount_received=int(worker.get("totalHMTAmountReceived")), - payout_count=int(worker.get("payoutCount")), + total_amount_received=worker.get("totalHMTAmountReceived"), + payout_count=worker.get("payoutCount"), ) ) @@ -135,6 +135,6 @@ def get_worker(chain_id: ChainId, worker_address: str) -> Optional[WorkerData]: return WorkerData( id=worker.get("id"), address=worker.get("address"), - total_amount_received=int(worker.get("totalHMTAmountReceived")), - payout_count=int(worker.get("payoutCount")), + total_amount_received=worker.get("totalHMTAmountReceived"), + payout_count=worker.get("payoutCount"), ) diff --git a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py index c616126b36..b77c23db86 100644 --- a/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py +++ b/packages/sdk/python/human-protocol-sdk/test/human_protocol_sdk/operator/test_operator_utils.py @@ -525,6 +525,7 @@ def test_get_reputation_network_operators(self): "jobTypes": job_types, "registrationNeeded": True, "registrationInstructions": url, + "amountJobsProcessed": "25", } ], } @@ -576,6 +577,7 @@ def test_get_reputation_network_operators_when_job_types_is_none(self): "jobTypes": job_types, "registrationNeeded": True, "registrationInstructions": url, + "amountJobsProcessed": "25", } ], } @@ -627,6 +629,7 @@ def test_get_reputation_network_operators_when_job_types_is_array(self): "jobTypes": job_types, "registrationNeeded": True, "registrationInstructions": url, + "amountJobsProcessed": "25", } ], } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts index b56037ff0e..d40c1f0cfe 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts @@ -1876,15 +1876,7 @@ export class EscrowUtils { skip: skip, } ); - const mapped: IEscrow[] = (escrows || []).map((e) => - mapEscrow(e, networkData.chainId) - ); - - if (!escrows) { - return []; - } - - return mapped; + return (escrows || []).map((e) => mapEscrow(e, networkData.chainId)); } /** From e0e7cad68ff24ab836c3c5fcef5b4c182fb587d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Tue, 21 Oct 2025 19:18:08 +0200 Subject: [PATCH 09/11] Created changeset --- .changeset/rich-kids-rush.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/rich-kids-rush.md diff --git a/.changeset/rich-kids-rush.md b/.changeset/rich-kids-rush.md new file mode 100644 index 0000000000..b24d8b8d45 --- /dev/null +++ b/.changeset/rich-kids-rush.md @@ -0,0 +1,9 @@ +--- +"@human-protocol/sdk": major +--- + +### Changed + +- Created proper Subgraph types and cast values to the interfaces we have for SDK +- Refactor EscrowUtils, TransactionUtils, OperatorUtils and WorkerUtils methods to fix mismatch types with Subgraph +- Created some mappings to remove duplicated code From e9f95a010cd74a2e0c2ae6089c2124011042786b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Wed, 22 Oct 2025 12:00:11 +0200 Subject: [PATCH 10/11] Refactor Payout and CancellationRefund classes to use string for amount, block, and timestamp and convert to int in constructor. --- .../human_protocol_sdk/escrow/escrow_utils.py | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py index f2888d87dc..3d1512a04a 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_utils.py @@ -170,13 +170,13 @@ class Payout: """ def __init__( - self, id: str, escrow_address: str, recipient: str, amount: int, created_at: int + self, id: str, escrow_address: str, recipient: str, amount: str, created_at: str ): self.id = id self.escrow_address = escrow_address self.recipient = recipient - self.amount = amount - self.created_at = created_at * 1000 + self.amount = int(amount) + self.created_at = int(created_at) * 1000 class CancellationRefund: @@ -197,17 +197,17 @@ def __init__( id: str, escrow_address: str, receiver: str, - amount: int, - block: int, - timestamp: int, + amount: str, + block: str, + timestamp: str, tx_hash: str, ): self.id = id self.escrow_address = escrow_address self.receiver = receiver - self.amount = amount - self.block = block - self.timestamp = timestamp * 1000 + self.amount = int(amount) + self.block = int(block) + self.timestamp = int(timestamp) * 1000 self.tx_hash = tx_hash @@ -525,8 +525,8 @@ def get_payouts(filter: PayoutFilter) -> List[Payout]: id=payout["id"], escrow_address=payout["escrowAddress"], recipient=payout["recipient"], - amount=int(payout["amount"]), - created_at=int(payout["createdAt"]), + amount=payout["amount"], + created_at=payout["createdAt"], ) for payout in payouts_raw ] @@ -589,9 +589,9 @@ def get_cancellation_refunds( id=refund["id"], escrow_address=refund["escrowAddress"], receiver=refund["receiver"], - amount=int(refund["amount"]), - block=int(refund["block"]), - timestamp=int(refund["timestamp"]), + amount=refund["amount"], + block=refund["block"], + timestamp=refund["timestamp"], tx_hash=refund["txHash"], ) for refund in refunds_raw @@ -658,8 +658,8 @@ def get_cancellation_refund( id=refund["id"], escrow_address=refund["escrowAddress"], receiver=refund["receiver"], - amount=int(refund["amount"]), - block=int(refund["block"]), - timestamp=int(refund["timestamp"]), + amount=refund["amount"], + block=refund["block"], + timestamp=refund["timestamp"], tx_hash=refund["txHash"], ) From ef3021515bee287581b328e767858c7f004a64c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Wed, 22 Oct 2025 12:12:17 +0200 Subject: [PATCH 11/11] Refactor StakingUtils to remove default empty string for id and address in StakerData initialization --- .../human_protocol_sdk/staking/staking_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py index 3729fc0e7d..2da710d030 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_utils.py @@ -82,8 +82,8 @@ def get_staker(chain_id: ChainId, address: str) -> Optional[StakerData]: staker = data["data"]["staker"] return StakerData( - id=staker.get("id") or "", - address=staker.get("address") or "", + id=staker.get("id"), + address=staker.get("address"), staked_amount=staker.get("stakedAmount"), locked_amount=staker.get("lockedAmount"), withdrawn_amount=staker.get("withdrawnAmount"),