diff --git a/packages/apps/human-app/server/.env.example b/packages/apps/human-app/server/.env.example index 7b4e4a8684..bf68d5e568 100644 --- a/packages/apps/human-app/server/.env.example +++ b/packages/apps/human-app/server/.env.example @@ -1,8 +1,9 @@ HOST= # string, example: localhost PORT= # number, example: 5010 REPUTATION_ORACLE_URL= # string -REDIS_PORT= # string, example: localhost -REDIS_HOST= # number, example: 6379 +REPUTATION_ORACLE_ADDRESS= # string +REDIS_HOST= # string, example: localhost +REDIS_PORT= # number, example: 6379 CACHE_TTL_ORACLE_DISCOVERY= # number, example: 43200 CACHE_TTL_ORACLE_STATS= # number, example: 900 CACHE_TTL_USER_STATS= # number, example: 86400 diff --git a/packages/apps/human-app/server/README.md b/packages/apps/human-app/server/README.md index 4a793ce300..a90a442909 100644 --- a/packages/apps/human-app/server/README.md +++ b/packages/apps/human-app/server/README.md @@ -61,7 +61,7 @@ and transformation of data. NestJS provides many built-in pipes, so check the do ### Model -Interfaces are used to define the shape and responsibilities of the data: +Models are used to define the shape and responsibilities of the data: - **Dto (Data Transfer Object)**: Data sent from/to the frontend. - **Command**: Datatype used for data manipulation in business logic. diff --git a/packages/apps/human-app/server/docker-compose.yml b/packages/apps/human-app/server/docker-compose.yml index c5ce810ad3..6a98e9cb7d 100644 --- a/packages/apps/human-app/server/docker-compose.yml +++ b/packages/apps/human-app/server/docker-compose.yml @@ -16,9 +16,11 @@ services: HOST: ${HOST} PORT: ${PORT} REPUTATION_ORACLE_URL: ${REPUTATION_ORACLE_URL} + REPUTATION_ORACLE_ADDRESS: ${REPUTATION_ORACLE_ADDRESS} REDIS_PORT: ${REDIS_PORT} REDIS_HOST: redis CACHE_TTL_ORACLE_DISCOVERY: ${CACHE_TTL_ORACLE_DISCOVERY} + RPC_URL: ${RPC_URL} depends_on: - redis redis: @@ -27,6 +29,4 @@ services: ports: - '${REDIS_PORT}:6379' volumes: - - redis_data:/data -volumes: - redis_data: \ No newline at end of file + - redis_data:/data \ No newline at end of file diff --git a/packages/apps/human-app/server/package.json b/packages/apps/human-app/server/package.json index f43844836b..36537733eb 100644 --- a/packages/apps/human-app/server/package.json +++ b/packages/apps/human-app/server/package.json @@ -32,6 +32,8 @@ "@nestjs/platform-express": "^10.2.6", "@nestjs/swagger": "^7.1.13", "cache-manager": "^5.4.0", + "cache-manager-redis-store": "^3.0.1", + "ioredis": "^5.3.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "ethers": "^6.11.0", @@ -40,7 +42,6 @@ "rxjs": "^7.2.0" }, "devDependencies": { - "@nestjs/cache-manager": "^2.2.1", "@nestjs/cli": "^9.4.3", "@nestjs/schematics": "^9.2.0", "@nestjs/testing": "^9.4.3", @@ -50,11 +51,9 @@ "@types/supertest": "^2.0.15", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", - "cache-manager-redis-store": "^3.0.1", "eslint": "^8.55.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "ioredis": "^5.3.2", "jest": "29.5.0", "nock": "^13.5.1", "prettier": "^3.1.1", diff --git a/packages/apps/human-app/server/src/app.module.ts b/packages/apps/human-app/server/src/app.module.ts index a17022edc1..049037d469 100644 --- a/packages/apps/human-app/server/src/app.module.ts +++ b/packages/apps/human-app/server/src/app.module.ts @@ -22,12 +22,23 @@ import { StatisticsModule } from './modules/statistics/statistics.module'; import { StatisticsController } from './modules/statistics/statistics.controller'; import { ExchangeOracleModule } from './integrations/exchange-oracle/exchange-oracle.module'; import { KvStoreModule } from './integrations/kv-store/kv-store.module'; +import { EscrowUtilsModule } from './integrations/escrow/escrow-utils.module'; +import Joi from 'joi'; @Module({ imports: [ ConfigModule.forRoot({ envFilePath: '.env', isGlobal: true, + validationSchema: Joi.object({ + HOST: Joi.string().required(), + PORT: Joi.number().required(), + REPUTATION_ORACLE_URL: Joi.string().required(), + REPUTATION_ORACLE_ADDRESS: Joi.string().required(), + REDIS_PORT: Joi.number().required(), + REDIS_HOST: Joi.string().required(), + RPC_URL: Joi.string().required(), + }), }), AutomapperModule.forRoot({ strategyInitializer: classes(), @@ -44,6 +55,7 @@ import { KvStoreModule } from './integrations/kv-store/kv-store.module'; OracleDiscoveryModule, StatisticsModule, KvStoreModule, + EscrowUtilsModule, ], controllers: [ AppController, diff --git a/packages/apps/human-app/server/src/common/config/environment-config.service.ts b/packages/apps/human-app/server/src/common/config/environment-config.service.ts index 6f54e7051f..961eff1153 100644 --- a/packages/apps/human-app/server/src/common/config/environment-config.service.ts +++ b/packages/apps/human-app/server/src/common/config/environment-config.service.ts @@ -1,6 +1,5 @@ import { ConfigService } from '@nestjs/config'; import { Injectable } from '@nestjs/common'; -import { EnvironmentVariableMissingError } from '../interfaces/custom-exceptions.interface'; const DEFAULT_CACHE_TTL_ORACLE_STATS = 12 * 60 * 60; const DEFAULT_CACHE_TTL_USER_STATS = 15 * 60; const DEFAULT_CACHE_TTL_ORACLE_DISCOVERY = 24 * 60 * 60; @@ -10,21 +9,22 @@ const DEFAULT_CORS_ALLOWED_HEADERS = 'Content-Type, Accept'; export class EnvironmentConfigService { constructor(private configService: ConfigService) {} get host(): string { - return this.conditionallyReturnMandatoryEnvVariable('HOST'); + return this.configService.getOrThrow('HOST'); } get port(): number { - return this.conditionallyReturnMandatoryEnvVariable('PORT'); + return this.configService.getOrThrow('PORT'); } get reputationOracleUrl(): string { - return this.conditionallyReturnMandatoryEnvVariable( - 'REPUTATION_ORACLE_URL', - ); + return this.configService.getOrThrow('REPUTATION_ORACLE_URL'); + } + get reputationOracleAddress(): string { + return this.configService.getOrThrow('REPUTATION_ORACLE_ADDRESS'); } get cachePort(): number { - return this.conditionallyReturnMandatoryEnvVariable('REDIS_PORT'); + return this.configService.getOrThrow('REDIS_PORT'); } get cacheHost(): string { - return this.conditionallyReturnMandatoryEnvVariable('REDIS_HOST'); + return this.configService.getOrThrow('REDIS_HOST'); } get cacheTtlOracleStats(): number { return this.configService.get( @@ -47,7 +47,7 @@ export class EnvironmentConfigService { ); } get rpcUrl(): string { - return this.conditionallyReturnMandatoryEnvVariable('RPC_URL'); + return this.configService.getOrThrow('RPC_URL'); } get isCorsEnabled(): boolean { return this.configService.get('CORS_ENABLED', false); @@ -61,35 +61,7 @@ export class EnvironmentConfigService { get corsAllowedHeaders(): string { return this.configService.get( 'CORS_ALLOWED_HEADERS', - DEFAULT_CORS_ALLOWED_HEADERS + DEFAULT_CORS_ALLOWED_HEADERS, ); } - conditionallyReturnMandatoryEnvVariable(envName: string): T { - const value = this.configService.get(envName); - if (!value) { - throw new EnvironmentVariableMissingError(envName); - } - return value; - } - checkMandatoryConfig(): void { - const mandatoryVariables = [ - 'HOST', - 'PORT', - 'REPUTATION_ORACLE_URL', - 'REDIS_PORT', - 'REDIS_HOST', - 'RPC_URL', - ]; - const missingVariables: string[] = []; - - mandatoryVariables.forEach((variable) => { - if (!this.configService.get(variable)) { - missingVariables.push(variable); - } - }); - - if (missingVariables.length > 0) { - throw new EnvironmentVariableMissingError(missingVariables.join(', ')); - } - } } diff --git a/packages/apps/human-app/server/src/common/enums/global-common.interface.ts b/packages/apps/human-app/server/src/common/enums/global-common.ts similarity index 100% rename from packages/apps/human-app/server/src/common/enums/global-common.interface.ts rename to packages/apps/human-app/server/src/common/enums/global-common.ts diff --git a/packages/apps/human-app/server/src/common/interfaces/custom-exceptions.interface.ts b/packages/apps/human-app/server/src/common/interfaces/custom-exceptions.interface.ts deleted file mode 100644 index 909ab37778..0000000000 --- a/packages/apps/human-app/server/src/common/interfaces/custom-exceptions.interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -export class EnvironmentVariableMissingError extends Error { - constructor(variable: string) { - super(`Environment variable(s): {${variable}} not defined.`); - Object.setPrototypeOf(this, EnvironmentVariableMissingError.prototype); - } -} diff --git a/packages/apps/human-app/server/src/common/interfaces/pageable.interface.ts b/packages/apps/human-app/server/src/common/utils/pageable.model.ts similarity index 94% rename from packages/apps/human-app/server/src/common/interfaces/pageable.interface.ts rename to packages/apps/human-app/server/src/common/utils/pageable.model.ts index 237b4ed54b..1d9cb8dba9 100644 --- a/packages/apps/human-app/server/src/common/interfaces/pageable.interface.ts +++ b/packages/apps/human-app/server/src/common/utils/pageable.model.ts @@ -1,7 +1,7 @@ import { ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsEnum, IsNumber, IsOptional, Max, Min } from 'class-validator'; -import { SortOrder } from '../enums/global-common.interface'; +import { SortOrder } from '../enums/global-common'; import { AutoMap } from '@automapper/classes'; export abstract class PageableDto { diff --git a/packages/apps/human-app/server/src/integrations/escrow/escrow-utils-gateway.service.ts b/packages/apps/human-app/server/src/integrations/escrow/escrow-utils-gateway.service.ts new file mode 100644 index 0000000000..9c9e7eb183 --- /dev/null +++ b/packages/apps/human-app/server/src/integrations/escrow/escrow-utils-gateway.service.ts @@ -0,0 +1,16 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { ChainId, EscrowUtils } from '@human-protocol/sdk'; + +@Injectable() +export class EscrowUtilsGateway { + async getExchangeOracleAddressByEscrowAddress( + chainId: ChainId, + address: string, + ): Promise { + const escrowsData = await EscrowUtils.getEscrow(chainId, address); + if (!escrowsData.exchangeOracle) { + throw new NotFoundException('Exchange Oracle not found'); + } + return escrowsData.exchangeOracle; + } +} diff --git a/packages/apps/human-app/server/src/integrations/escrow/escrow-utils.module.ts b/packages/apps/human-app/server/src/integrations/escrow/escrow-utils.module.ts new file mode 100644 index 0000000000..a2f45c1332 --- /dev/null +++ b/packages/apps/human-app/server/src/integrations/escrow/escrow-utils.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { EscrowUtilsGateway } from './escrow-utils-gateway.service'; + +@Module({ + providers: [EscrowUtilsGateway], + exports: [EscrowUtilsGateway], +}) +export class EscrowUtilsModule {} diff --git a/packages/apps/human-app/server/src/integrations/escrow/spec/escrow-utils-gateway.spec.ts b/packages/apps/human-app/server/src/integrations/escrow/spec/escrow-utils-gateway.spec.ts new file mode 100644 index 0000000000..e8a521709e --- /dev/null +++ b/packages/apps/human-app/server/src/integrations/escrow/spec/escrow-utils-gateway.spec.ts @@ -0,0 +1,67 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { EscrowUtilsGateway } from '../escrow-utils-gateway.service'; +import { EscrowUtils, ChainId } from '@human-protocol/sdk'; +import { NotFoundException } from '@nestjs/common'; + +jest.mock('@human-protocol/sdk', () => { + return { + EscrowUtils: { + getEscrow: jest.fn().mockResolvedValue({ + exchangeOracle: '0x', + }), + }, + ChainId: { + POLYGON_AMOY: 1, + }, + }; +}); + +describe('EscrowUtilsGateway', () => { + let service: EscrowUtilsGateway; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [EscrowUtilsGateway], + }).compile(); + + service = module.get(EscrowUtilsGateway); + }); + + afterEach(async () => { + jest.restoreAllMocks(); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + describe('getExchangeOracleAddressByEscrowAddress', () => { + it('should fetch data from EscrowUtils', async () => { + const escrowAddress = 'escrowAddress'; + const expectedUrl = '0x'; + + const result = await service.getExchangeOracleAddressByEscrowAddress( + ChainId.POLYGON_AMOY, + escrowAddress, + ); + expect(EscrowUtils.getEscrow).toHaveBeenCalledWith( + ChainId.POLYGON_AMOY, + escrowAddress, + ); + expect(result).toBe(expectedUrl); + }); + + it('should throw error if Exchange Oracle not found', async () => { + const escrowAddress = 'escrowAddress'; + + (EscrowUtils.getEscrow as jest.Mock).mockResolvedValue({}); + + await expect( + service.getExchangeOracleAddressByEscrowAddress( + ChainId.POLYGON_AMOY, + escrowAddress, + ), + ).rejects.toThrow(new NotFoundException('Exchange Oracle not found')); + }); + }); +}); diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts index a76bd8c973..e407dd7030 100644 --- a/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts @@ -77,7 +77,6 @@ export class ExchangeOracleGateway { async fetchAssignedJobs( details: JobsFetchParamsDetails, ): Promise { - console.log("Details: ", details); const jobFetchParamsData = this.mapper.map( details.data, JobsFetchParams, diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts index a504abbbb7..61b11b1457 100644 --- a/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts @@ -3,7 +3,7 @@ import { HttpService } from '@nestjs/axios'; import { ExchangeOracleGateway } from '../exchange-oracle.gateway'; import { oracleStatsDetailsFixture, - statisticsExchangeOracleAddress, statisticsExchangeOracleUrl, + statisticsExchangeOracleUrl, userStatsDetailsFixture, } from '../../../modules/statistics/spec/statistics.fixtures'; import { AutomapperModule } from '@automapper/nestjs'; diff --git a/packages/apps/human-app/server/src/integrations/kv-store/kv-store-gateway.service.ts b/packages/apps/human-app/server/src/integrations/kv-store/kv-store-gateway.service.ts index 61b5ddd41b..a52fbc47fd 100644 --- a/packages/apps/human-app/server/src/integrations/kv-store/kv-store-gateway.service.ts +++ b/packages/apps/human-app/server/src/integrations/kv-store/kv-store-gateway.service.ts @@ -1,11 +1,11 @@ -import { Injectable, OnModuleInit } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { EnvironmentConfigService } from '../../common/config/environment-config.service'; import { ethers } from 'ethers'; -import { KVStoreClient } from '@human-protocol/sdk'; +import { KVStoreClient, KVStoreKeys } from '@human-protocol/sdk'; @Injectable() export class KvStoreGateway { - private URL_KEY = 'url'; + private URL_KEY = KVStoreKeys.url; private kvStoreClient: KVStoreClient; constructor(private environmentConfig: EnvironmentConfigService) {} async onModuleInit(): Promise { diff --git a/packages/apps/human-app/server/src/integrations/kv-store/spec/kv-store.gateway.spec.ts b/packages/apps/human-app/server/src/integrations/kv-store/spec/kv-store.gateway.spec.ts index b6b0159f3d..0405ddc762 100644 --- a/packages/apps/human-app/server/src/integrations/kv-store/spec/kv-store.gateway.spec.ts +++ b/packages/apps/human-app/server/src/integrations/kv-store/spec/kv-store.gateway.spec.ts @@ -1,18 +1,22 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { KVStoreClient } from '@human-protocol/sdk'; +import { KVStoreClient, KVStoreKeys } from '@human-protocol/sdk'; import { KvStoreGateway } from '../kv-store-gateway.service'; import { EnvironmentConfigService } from '../../../common/config/environment-config.service'; import { ethers } from 'ethers'; -jest.mock('@human-protocol/sdk', () => ({ - KVStoreClient: { - build: jest.fn().mockImplementation(() => - Promise.resolve({ - get: jest.fn().mockResolvedValue('https://example.com'), - }), - ), - }, -})); +jest.mock('@human-protocol/sdk', () => { + const actualSdk = jest.requireActual('@human-protocol/sdk'); + return { + ...actualSdk, + KVStoreClient: { + build: jest.fn().mockImplementation(() => + Promise.resolve({ + get: jest.fn().mockResolvedValue('https://example.com'), + }), + ), + }, + }; +}); describe('KvStoreGateway', () => { let service: KvStoreGateway; @@ -72,7 +76,7 @@ describe('KvStoreGateway', () => { expect(service['kvStoreClient'].get).toHaveBeenCalledWith( testAddress, - 'url', + KVStoreKeys.url, ); expect(result).toBe(expectedUrl); diff --git a/packages/apps/human-app/server/src/main.ts b/packages/apps/human-app/server/src/main.ts index c17ea6fe2d..9eda2e0b99 100644 --- a/packages/apps/human-app/server/src/main.ts +++ b/packages/apps/human-app/server/src/main.ts @@ -12,7 +12,6 @@ async function bootstrap() { const configService: ConfigService = app.get(ConfigService); const envConfigService = new EnvironmentConfigService(configService); - envConfigService.checkMandatoryConfig(); if (envConfigService.isCorsEnabled) { app.enableCors({ origin: envConfigService.corsEnabledOrigin, diff --git a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts index 158b834e8c..b5565b152f 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts @@ -2,7 +2,6 @@ import { Body, Controller, Get, - Headers, Post, Query, UsePipes, diff --git a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.module.ts b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.module.ts index f6bd83236f..3c1d6d22e5 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.module.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.module.ts @@ -3,9 +3,10 @@ import { JobAssignmentProfile } from './job-assignment.mapper'; import { Module } from '@nestjs/common'; import { ExchangeOracleModule } from '../../integrations/exchange-oracle/exchange-oracle.module'; import { KvStoreModule } from '../../integrations/kv-store/kv-store.module'; +import { EscrowUtilsModule } from '../../integrations/escrow/escrow-utils.module'; @Module({ - imports: [ExchangeOracleModule, KvStoreModule], + imports: [ExchangeOracleModule, KvStoreModule, EscrowUtilsModule], providers: [JobAssignmentService, JobAssignmentProfile], exports: [JobAssignmentService], }) diff --git a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.service.ts b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.service.ts index aef46ea412..e8a85502fd 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.service.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.service.ts @@ -11,19 +11,28 @@ import { ExchangeOracleGateway } from '../../integrations/exchange-oracle/exchan import { KvStoreGateway } from '../../integrations/kv-store/kv-store-gateway.service'; import { InjectMapper } from '@automapper/nestjs'; import { Mapper } from '@automapper/core'; +import { EscrowUtilsGateway } from '../../integrations/escrow/escrow-utils-gateway.service'; @Injectable() export class JobAssignmentService { constructor( private readonly kvStoreGateway: KvStoreGateway, private readonly exchangeOracleGateway: ExchangeOracleGateway, + private readonly escrowUtilsGateway: EscrowUtilsGateway, @InjectMapper() private readonly mapper: Mapper, ) {} async processJobAssignment( command: JobAssignmentCommand, ): Promise { + const exchangeOracleAddress = + await this.escrowUtilsGateway.getExchangeOracleAddressByEscrowAddress( + command.data.chainId, + command.data.escrowAddress, + ); const exchangeOracleUrl = - await this.kvStoreGateway.getExchangeOracleUrlByAddress(command.address); + await this.kvStoreGateway.getExchangeOracleUrlByAddress( + exchangeOracleAddress, + ); const details = this.mapper.map( command, JobAssignmentCommand, diff --git a/packages/apps/human-app/server/src/modules/job-assignment/model/job-assignment.model.ts b/packages/apps/human-app/server/src/modules/job-assignment/model/job-assignment.model.ts index 0050c6a3a1..3b97052f1e 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/model/job-assignment.model.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/model/job-assignment.model.ts @@ -5,18 +5,14 @@ import { PageableData, PageableDto, PageableParams, -} from '../../../common/interfaces/pageable.interface'; +} from '../../../common/utils/pageable.model'; import { AssignmentSortField, AssignmentStatus, -} from '../../../common/enums/global-common.interface'; +} from '../../../common/enums/global-common'; import { Type } from 'class-transformer'; export class JobAssignmentDto { - @AutoMap() - @IsString() - @ApiProperty() - address: string; @AutoMap() @IsString() @ApiProperty() @@ -39,8 +35,6 @@ export class JobAssignmentCommand { data: JobAssignmentParams; @AutoMap() token: string; - @AutoMap() - address: string; } export class JobAssignmentDetails { diff --git a/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.fixtures.ts b/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.fixtures.ts index 34ac24cd8c..4cc7266e08 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.fixtures.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.fixtures.ts @@ -17,7 +17,7 @@ import { AssignmentSortField, AssignmentStatus, SortOrder, -} from '../../../common/enums/global-common.interface'; +} from '../../../common/enums/global-common'; const EXCHANGE_ORACLE_URL = 'https://www.example.com/api'; const EXCHANGE_ORACLE_ADDRESS = '0x34df642'; const ESCROW_ADDRESS = 'test_address'; @@ -40,7 +40,6 @@ const TOKEN = 'test_user_token'; export const jobAssignmentToken = TOKEN; export const jobAssignmentOracleUrl = EXCHANGE_ORACLE_URL; export const jobAssignmentDtoFixture: JobAssignmentDto = { - address: EXCHANGE_ORACLE_ADDRESS, escrow_address: ESCROW_ADDRESS, chain_id: CHAIN_ID, }; @@ -52,7 +51,6 @@ const jobAssignmentParams: JobAssignmentParams = { export const jobAssignmentCommandFixture: JobAssignmentCommand = { data: jobAssignmentParams, token: TOKEN, - address: EXCHANGE_ORACLE_ADDRESS, }; export const jobAssignmentDetailsFixture: JobAssignmentDetails = { data: jobAssignmentParams, diff --git a/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.service.spec.ts b/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.service.spec.ts index 58ab5b660b..4cbc2987de 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.service.spec.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.service.spec.ts @@ -12,11 +12,13 @@ import { import { AutomapperModule } from '@automapper/nestjs'; import { classes } from '@automapper/classes'; import { JobAssignmentProfile } from '../job-assignment.mapper'; +import { EscrowUtilsGateway } from '../../../integrations/escrow/escrow-utils-gateway.service'; describe('JobAssignmentService', () => { let service: JobAssignmentService; let exchangeOracleGatewayMock: Partial; let kvStoreGatewayMock: Partial; + let escrowUtilsGatewayMock: Partial; beforeEach(async () => { exchangeOracleGatewayMock = { postNewJobAssignment: jest.fn(), @@ -25,6 +27,9 @@ describe('JobAssignmentService', () => { kvStoreGatewayMock = { getExchangeOracleUrlByAddress: jest.fn(), }; + escrowUtilsGatewayMock = { + getExchangeOracleAddressByEscrowAddress: jest.fn(), + }; const module: TestingModule = await Test.createTestingModule({ imports: [ @@ -37,6 +42,7 @@ describe('JobAssignmentService', () => { JobAssignmentProfile, { provide: ExchangeOracleGateway, useValue: exchangeOracleGatewayMock }, { provide: KvStoreGateway, useValue: kvStoreGatewayMock }, + { provide: EscrowUtilsGateway, useValue: escrowUtilsGatewayMock }, ], }).compile(); @@ -49,9 +55,12 @@ describe('JobAssignmentService', () => { describe('processJobAssignment', () => { it('should process job assignment correctly', async () => { + const escrowUtilExchangeOracleAddress = '0x'; const command = jobAssignmentCommandFixture; const details = jobAssignmentDetailsFixture; - + ( + escrowUtilsGatewayMock.getExchangeOracleAddressByEscrowAddress as jest.Mock + ).mockResolvedValue(escrowUtilExchangeOracleAddress); ( kvStoreGatewayMock.getExchangeOracleUrlByAddress as jest.Mock ).mockResolvedValue(jobAssignmentOracleUrl); @@ -63,9 +72,12 @@ describe('JobAssignmentService', () => { const result = await service.processJobAssignment(command); + expect( + escrowUtilsGatewayMock.getExchangeOracleAddressByEscrowAddress, + ).toHaveBeenCalledWith(command.data.chainId, command.data.escrowAddress); expect( kvStoreGatewayMock.getExchangeOracleUrlByAddress, - ).toHaveBeenCalledWith(command.address); + ).toHaveBeenCalledWith(escrowUtilExchangeOracleAddress); expect( exchangeOracleGatewayMock.postNewJobAssignment, ).toHaveBeenCalledWith(details); diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts index be34d87f45..5bb5c28d3c 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts @@ -6,12 +6,12 @@ import { JobDiscoveryFieldName, JobDiscoverySortField, JobStatus, -} from '../../../common/enums/global-common.interface'; +} from '../../../common/enums/global-common'; import { PageableData, PageableDto, PageableParams, -} from '../../../common/interfaces/pageable.interface'; +} from '../../../common/utils/pageable.model'; export class JobsDiscoveryParamsDto extends PageableDto { @AutoMap() diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts index f3ad330277..3d675cbc13 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts @@ -10,7 +10,7 @@ import { JobDiscoveryFieldName, JobDiscoverySortField, JobStatus, SortOrder, -} from '../../../common/enums/global-common.interface'; +} from '../../../common/enums/global-common'; const EXCHANGE_ORACLE_URL = 'https://www.test_url.org'; const ESCROW_ADDRESS = 'test_address'; const CHAIN_ID = 1; 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 d51d147517..9b6b6df4ad 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 @@ -1,29 +1,19 @@ import { IOperator } from '@human-protocol/sdk'; import { AutoMap } from '@automapper/classes'; -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsNumber, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsNumber } from 'class-validator'; import { Type } from 'class-transformer'; export class OracleDiscoveryDto { @AutoMap() @IsNumber() @Type(() => Number) - @IsOptional() - @ApiPropertyOptional({ example: 80002 }) + @ApiProperty({ example: 80002 }) chainId: number; - @AutoMap() - @ApiProperty({ example: '0x4708354213453af0cdC33eb75d94fBC00045841E' }) - address: string; - constructor(chainId: number, address: string) { - this.chainId = chainId; - this.address = address; - } } export class OracleDiscoveryCommand { @AutoMap() chainId: number; - @AutoMap() - address: string; } export class OracleDiscoveryResponse implements IOperator { diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.serivce.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.serivce.ts index db461253ad..853db99279 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.serivce.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.serivce.ts @@ -18,17 +18,17 @@ export class OracleDiscoveryService { async processOracleDiscovery( command: OracleDiscoveryCommand, ): Promise { - command.address = command.address.toLowerCase(); + const address = this.configService.reputationOracleAddress.toLowerCase(); let data: OracleDiscoveryResponse[] | undefined = - await this.cacheManager.get(command.address); + await this.cacheManager.get(command.chainId.toString()); if (!data) { data = await OperatorUtils.getReputationNetworkOperators( command.chainId, - command.address, + address, this.EXCHANGE_ORACLE, ); await this.cacheManager.set( - command.address, + command.chainId.toString(), data, this.configService.cacheTtlOracleDiscovery, ); diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts index 7a0af8919d..96dd715373 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts @@ -45,13 +45,11 @@ describe('OracleDiscoveryController', () => { it('oracle discovery should be called with input in OracleDiscoveryDto format and return OracleDiscoveryData', async () => { const dto: OracleDiscoveryDto = { chainId: 80001, - address: '0x4708354213453af0cdC33eb75d94fBC00045841E', }; const result: OracleDiscoveryResponse[] = await controller.getOracles(dto); const expectedCommand = { chainId: ChainId.POLYGON_MUMBAI, - address: dto.address, } as OracleDiscoveryCommand; expect(service.processOracleDiscovery).toHaveBeenCalledWith( expectedCommand, diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.service.spec.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.service.spec.ts index 46dcd711bd..c0b6c2c570 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.service.spec.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.service.spec.ts @@ -41,6 +41,13 @@ describe('OracleDiscoveryService', () => { set: jest.fn(), }, }, + { + provide: EnvironmentConfigService, + useValue: { + reputationOracleAddress: 'mockedaddress', + cacheTtlOracleDiscovery: 86400, + }, + }, ], }).compile(); configService = moduleRef.get( @@ -61,7 +68,6 @@ describe('OracleDiscoveryService', () => { { address: 'mockAddress2', role: 'validator' }, ]; const command: OracleDiscoveryCommand = { - address: 'mockAddress', chainId: 80001, }; jest.spyOn(cacheManager, 'get').mockResolvedValue(mockData); @@ -69,7 +75,6 @@ describe('OracleDiscoveryService', () => { const result = await oracleDiscoveryService.processOracleDiscovery(command); expect(result).toEqual(mockData); - expect(cacheManager.get).toHaveBeenCalledWith(command.address); expect(OperatorUtils.getReputationNetworkOperators).not.toHaveBeenCalled(); }); @@ -79,9 +84,9 @@ describe('OracleDiscoveryService', () => { { address: 'mockAddress2', role: 'validator' }, ]; const command: OracleDiscoveryCommand = { - address: 'mockAddress', chainId: 80001, }; + jest.spyOn(cacheManager, 'get').mockResolvedValue(undefined); jest .spyOn(OperatorUtils, 'getReputationNetworkOperators') @@ -90,15 +95,15 @@ describe('OracleDiscoveryService', () => { const result = await oracleDiscoveryService.processOracleDiscovery(command); expect(result).toEqual(mockData); - expect(cacheManager.get).toHaveBeenCalledWith(command.address); + expect(cacheManager.get).toHaveBeenCalledWith(command.chainId.toString()); expect(cacheManager.set).toHaveBeenCalledWith( - command.address, + command.chainId.toString(), mockData, configService.cacheTtlOracleDiscovery, ); expect(OperatorUtils.getReputationNetworkOperators).toHaveBeenCalledWith( command.chainId, - command.address, + 'mockedaddress', EXCHANGE_ORACLE, ); }); diff --git a/packages/apps/human-app/server/src/modules/statistics/spec/statistisc.controller.spec.ts b/packages/apps/human-app/server/src/modules/statistics/spec/statistics.controller.spec.ts similarity index 97% rename from packages/apps/human-app/server/src/modules/statistics/spec/statistisc.controller.spec.ts rename to packages/apps/human-app/server/src/modules/statistics/spec/statistics.controller.spec.ts index f06eb14e3e..b7d334c0bf 100644 --- a/packages/apps/human-app/server/src/modules/statistics/spec/statistisc.controller.spec.ts +++ b/packages/apps/human-app/server/src/modules/statistics/spec/statistics.controller.spec.ts @@ -5,7 +5,7 @@ import { statisticsServiceMock } from './statistics.service.mock'; import { oracleStatsCommandFixture, oracleStatsResponseFixture, - statisticsExchangeOracleAddress, statisticsExchangeOracleUrl, + statisticsExchangeOracleAddress, statisticsToken, userStatsCommandFixture, userStatsResponseFixture, diff --git a/packages/apps/human-app/server/src/modules/statistics/spec/statistics.fixtures.ts b/packages/apps/human-app/server/src/modules/statistics/spec/statistics.fixtures.ts index 00ed916d29..9198656ff4 100644 --- a/packages/apps/human-app/server/src/modules/statistics/spec/statistics.fixtures.ts +++ b/packages/apps/human-app/server/src/modules/statistics/spec/statistics.fixtures.ts @@ -1,9 +1,11 @@ import { - UserStatisticsCommand, UserStatisticsDetails, + UserStatisticsCommand, + UserStatisticsDetails, UserStatisticsResponse, } from '../model/user-statistics.model'; import { - OracleStatisticsCommand, OracleStatisticsDetails, + OracleStatisticsCommand, + OracleStatisticsDetails, OracleStatisticsResponse, } from '../model/oracle-statistics.model'; import { AxiosRequestConfig } from 'axios'; @@ -21,7 +23,7 @@ const ASSIGNMENTS_COMPLETED_ORACLE = 154363; const ASSIGNMENTS_REJECTED_ORACLE = 231; const ASSIGNMENTS_EXPIRED_ORACLE = 434; const EXCHANGE_ORACLE_ADDRESS = '0x32df932'; -const EXCHANGE_ORACLE_URL = 'https://test.oracle.com' +const EXCHANGE_ORACLE_URL = 'https://test.oracle.com'; const TOKEN = 'test-token'; export const statisticsToken = TOKEN; export const statisticsExchangeOracleAddress = EXCHANGE_ORACLE_ADDRESS; diff --git a/packages/apps/human-app/server/src/modules/statistics/spec/statistics.service.spec.ts b/packages/apps/human-app/server/src/modules/statistics/spec/statistics.service.spec.ts index 55aa73d20b..f2fca357ea 100644 --- a/packages/apps/human-app/server/src/modules/statistics/spec/statistics.service.spec.ts +++ b/packages/apps/human-app/server/src/modules/statistics/spec/statistics.service.spec.ts @@ -5,16 +5,19 @@ import { StatisticsService } from '../statistics.service'; import { ExchangeOracleGateway } from '../../../integrations/exchange-oracle/exchange-oracle.gateway'; import { EnvironmentConfigService } from '../../../common/config/environment-config.service'; import { Cache } from 'cache-manager'; -import { UserStatisticsCommand, UserStatisticsDetails } from '../model/user-statistics.model'; +import { + UserStatisticsCommand, + UserStatisticsDetails, +} from '../model/user-statistics.model'; import { KvStoreGateway } from '../../../integrations/kv-store/kv-store-gateway.service'; import { OracleStatisticsCommand, OracleStatisticsDetails, OracleStatisticsResponse, } from '../model/oracle-statistics.model'; -const EXCHANGE_ORACLE_URL = 'https://exchangeOracle.url' -const EXCHANGE_ORACLE_ADDRESS = '0x8f238b21aa2056' -const TOKEN = 'token1' +const EXCHANGE_ORACLE_URL = 'https://exchangeOracle.url'; +const EXCHANGE_ORACLE_ADDRESS = '0x8f238b21aa2056'; +const TOKEN = 'token1'; describe('StatisticsService', () => { let service: StatisticsService; let cacheManager: Cache & { get: jest.Mock; set: jest.Mock }; // Explicitly type as jest.Mock @@ -66,7 +69,9 @@ describe('StatisticsService', () => { const cachedData = { some: 'data' }; cacheManager.get.mockResolvedValue(cachedData); - const command: OracleStatisticsCommand = { address: EXCHANGE_ORACLE_ADDRESS }; + const command: OracleStatisticsCommand = { + address: EXCHANGE_ORACLE_ADDRESS, + }; const result: OracleStatisticsResponse = await service.getOracleStats(command); diff --git a/packages/apps/human-app/server/src/modules/statistics/statistics.controller.ts b/packages/apps/human-app/server/src/modules/statistics/statistics.controller.ts index 49de5e92a6..07268cd6cd 100644 --- a/packages/apps/human-app/server/src/modules/statistics/statistics.controller.ts +++ b/packages/apps/human-app/server/src/modules/statistics/statistics.controller.ts @@ -1,7 +1,6 @@ import { Controller, Get, - Headers, Query, UsePipes, ValidationPipe,