Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const OracleSchema = z.object({
address: z.string(),
chainId: z.number(),
role: z.string(),
name: z.string(),
url: z.string(),
jobTypes: z.array(z.string()),
registrationNeeded: z.boolean().optional().nullable(),
Expand All @@ -23,21 +24,6 @@ export type Oracle = OracleBase & {
name: string;
};

const OracleNameToUrls = {
CVAT: [
'https://stg-exchange-oracle.humanprotocol.org',
'https://exchange-oracle.humanprotocol.org',
],
Fortune: ['https://stg-fortune-exchange-oracle-server.humanprotocol.org'],
} as const;

const oracleUrlToNameMap = new Map<string, string>();
for (const [oracleName, oracleUrls] of Object.entries(OracleNameToUrls)) {
for (const oracleUrl of oracleUrls) {
oracleUrlToNameMap.set(oracleUrl, oracleName);
}
}

const isTestnet = env.VITE_NETWORK === 'testnet';

const H_CAPTCHA_ORACLE: Oracle = {
Expand Down Expand Up @@ -80,7 +66,7 @@ async function getOracles(selectedJobTypes: string[]) {
oracles = oracles.concat(
results.map((oracle: OracleBase) => ({
...oracle,
name: oracleUrlToNameMap.get(oracle.url) ?? '',
name: oracle.name ? oracle.name.split(' ')[0] : '',
}))
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class JwtUserData {
@AutoMap()
reputation_network: string;
@AutoMap()
qualifications?: string[];
qualifications: string[];
@AutoMap()
site_key: string;
@AutoMap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const jwtUserDataFixture: JwtUserData = {
wallet_address: POLYGON_WALLET_ADDR,
email: EMAIL,
kyc_status: 'approved',
qualifications: [],
site_key: H_CAPTCHA_SITE_KEY,
reputation_network: REPUTATION_NETWORK,
iat: IAT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ export class DiscoveredOracle implements IOperator {
@ApiPropertyOptional({ description: 'Website of the operator' })
website?: string;

@ApiPropertyOptional({ description: 'URL of the oracle operator' })
@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],
Expand All @@ -98,8 +98,8 @@ export class DiscoveredOracle implements IOperator {
})
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import {
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiBearerAuth,
ApiOkResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { OracleDiscoveryService } from './oracle-discovery.service';
import {
GetOraclesCommand,
Expand All @@ -17,6 +22,8 @@ import {
import { InjectMapper } from '@automapper/nestjs';
import { Mapper } from '@automapper/core';
import { EnvironmentConfigService } from '../../common/config/environment-config.service';
import { JwtPayload } from '../../common/config/params-decorators';
import { JwtUserData } from '../../common/utils/jwt-token.model';

@Controller()
export class OracleDiscoveryController {
Expand All @@ -25,7 +32,9 @@ export class OracleDiscoveryController {
private readonly environmentConfigService: EnvironmentConfigService,
@InjectMapper() private readonly mapper: Mapper,
) {}

@ApiTags('Oracle-Discovery')
@ApiBearerAuth()
@Get('/oracles')
@ApiOperation({ summary: 'Oracles discovery' })
@ApiOkResponse({
Expand All @@ -34,6 +43,7 @@ export class OracleDiscoveryController {
})
@UsePipes(new ValidationPipe())
public async getOracles(
@JwtPayload() jwtPayload: JwtUserData,
@Query() query: GetOraclesQuery,
): Promise<DiscoveredOracle[]> {
if (!this.environmentConfigService.jobsDiscoveryFlag) {
Expand All @@ -43,6 +53,22 @@ export class OracleDiscoveryController {
);
}
const command = this.mapper.map(query, GetOraclesQuery, GetOraclesCommand);
return await this.oracleDiscoveryService.getOracles(command);
const oracles = await this.oracleDiscoveryService.getOracles(command);

const isAudinoAvailableForUser =
jwtPayload.qualifications.includes('audino');

/**
* TODO: remove filtering logic when Audino available for everyone
*/
return oracles.filter((oracle) => {
const isAudinoOracle = oracle.jobTypes.includes('audio_transcription');

if (isAudinoOracle) {
return isAudinoAvailableForUser;
} else {
return true;
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export class OracleDiscoveryService {
new DiscoveredOracle({
id: exchangeOracle.id,
address: exchangeOracle.address,
name: exchangeOracle.name,
role: exchangeOracle.role,
url: exchangeOracle.url,
jobTypes: exchangeOracle.jobTypes,
Expand Down Expand Up @@ -128,7 +129,7 @@ export class OracleDiscoveryService {
operator: IOperator,
possibleJobTypes: string[],
): operator is DiscoveredOracle {
if (!operator.url) {
if (!operator.url || !operator.name || !operator.role) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ describe('OracleDiscoveryController', () => {
const dtoFixture = {
selected_job_types: ['job-type-1', 'job-type-2'],
} as GetOraclesQuery;
const result: DiscoveredOracle[] =
await controller.getOracles(dtoFixture);
const result: DiscoveredOracle[] = await controller.getOracles(
{ qualifications: [] } as any,
dtoFixture,
);
const expectedResponse = generateOracleDiscoveryResponseBody();
expect(serviceMock.getOracles).toHaveBeenCalled();
expect(result).toEqual(expectedResponse);
Expand All @@ -77,7 +79,9 @@ describe('OracleDiscoveryController', () => {

(configServiceMock as any).jobsDiscoveryFlag = false;

await expect(controller.getOracles(dtoFixture)).rejects.toThrow(
await expect(
controller.getOracles({ qualifications: [] } as any, dtoFixture),
).rejects.toThrow(
new HttpException(
'Oracles discovery is disabled',
HttpStatus.FORBIDDEN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const response1: DiscoveredOracle = {
address: '0xd06eac24a0c47c776Ce6826A93162c4AfC029047',
chainId: ChainId.POLYGON_AMOY,
role: 'role1',
name: 'oracle1',
url: 'common-url',
jobTypes: ['job-type-3'],
retriesCount: 0,
Expand All @@ -29,6 +30,7 @@ export const response2: DiscoveredOracle = {
address: '0xd10c3402155c058D78e4D5fB5f50E125F06eb39d',
chainId: ChainId.POLYGON_AMOY,
role: 'role2',
name: 'oracle2',
url: '',
jobTypes: ['job-type-1', 'job-type-3', 'job-type-4'],
retriesCount: 0,
Expand All @@ -49,6 +51,7 @@ export const response3: DiscoveredOracle = {
address: '0xd83422155c058D78e4D5fB5f50E125F06eb39d',
chainId: ChainId.POLYGON_AMOY,
role: 'role3',
name: 'oracle3',
url: 'common-url',
jobTypes: ['job-type-2'],
retriesCount: 0,
Expand All @@ -69,6 +72,7 @@ export const response4: DiscoveredOracle = {
address: '0xd83422155c058D78e4D5fB5f50E125F06eb39d',
chainId: ChainId.BSC_TESTNET,
role: 'role3',
name: 'oracle4',
url: 'common-url',
jobTypes: ['job-type-1', 'job-type-3', 'job-type-4'],
retriesCount: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const CreateJob = () => {
{/* {!IS_MAINNET && (
<MenuItem value={JobType.HCAPTCHA}>hCaptcha</MenuItem>
)} */}
{!IS_MAINNET && <MenuItem value={JobType.AUDINO}>Audino</MenuItem>}
<MenuItem value={JobType.AUDINO}>Audino</MenuItem>
</Select>
</FormControl>
<NetworkSelect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export type AudinoManifest = {
validation: {
min_quality: number;
};
job_bounty: string;
};

export type JobManifest = FortuneManifest | CvatManifest | AudinoManifest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class AbuseService {
data.slasher,
data.staker,
data.escrowAddress,
BigInt(ethers.parseUnits(data.amount.toString(), 'ether')),
BigInt(ethers.parseUnits(data.amount.toString(), 18)),
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { EscrowClient } from '@human-protocol/sdk';
import { EscrowClient, EscrowUtils } from '@human-protocol/sdk';
import { Injectable } from '@nestjs/common';
import { ethers } from 'ethers';
import type { OverrideProperties } from 'type-fest';

import { AUDINO_RESULTS_ANNOTATIONS_FILENAME } from '../../../common/constants';
import { AUDINO_VALIDATION_META_FILENAME } from '../../../common/constants';
import { AudinoAnnotationMeta, AudinoManifest } from '../../../common/types';

import { StorageService } from '../../storage';
Expand All @@ -28,7 +27,6 @@ export class AudinoPayoutsCalculator implements EscrowPayoutsCalculator {
) {}

async calculate({
manifest,
chainId,
escrowAddress,
}: CalculateAudinoPayoutsInput): Promise<CalculatedPayout[]> {
Expand All @@ -40,24 +38,23 @@ export class AudinoPayoutsCalculator implements EscrowPayoutsCalculator {

const annotations =
await this.storageService.downloadJsonLikeData<AudinoAnnotationMeta>(
`${intermediateResultsUrl}/${AUDINO_RESULTS_ANNOTATIONS_FILENAME}`,
`${intermediateResultsUrl}/${AUDINO_VALIDATION_META_FILENAME}`,
);

if (annotations.jobs.length === 0 || annotations.results.length === 0) {
throw new Error('Invalid annotation meta');
}

const jobBountyValue = ethers.parseUnits(manifest.job_bounty, 18);
const workersBounties = new Map<string, typeof jobBountyValue>();
const escrowData = await EscrowUtils.getEscrow(chainId, escrowAddress);
const jobBountyValue =
BigInt(escrowData.totalFundedAmount) / BigInt(annotations.jobs.length);

const workersBounties = new Map<string, bigint>();
for (const job of annotations.jobs) {
const jobFinalResult = annotations.results.find(
(result) => result.id === job.final_result_id,
);
if (
jobFinalResult
// && jobFinalResult.annotation_quality >= manifest.validation.min_quality
) {
if (jobFinalResult) {
const workerAddress = jobFinalResult.annotator_wallet_address;

const currentWorkerBounty = workersBounties.get(workerAddress) || 0n;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class CvatPayoutsCalculator implements EscrowPayoutsCalculator {
}

const jobBountyValue = ethers.parseUnits(manifest.job_bounty, 18);
const workersBounties = new Map<string, typeof jobBountyValue>();
const workersBounties = new Map<string, bigint>();

for (const job of annotations.jobs) {
const jobFinalResult = annotations.results.find(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class FortunePayoutsCalculator implements EscrowPayoutsCalculator {
.map((item) => item.workerAddress);

const payoutAmount =
BigInt(ethers.parseUnits(manifest.fundAmount.toString(), 'ether')) /
ethers.parseUnits(manifest.fundAmount.toString(), 18) /
BigInt(recipients.length);

return recipients.map((recipient) => ({
Expand Down