Skip to content

Commit

Permalink
[Job Launcher] Display partially paid escrows (#1856)
Browse files Browse the repository at this point in the history
* Display partially paid escrows on Job Launcher

* Fix subgraph tests
  • Loading branch information
flopez7 authored Apr 12, 2024
1 parent 6e633f5 commit 0c413b4
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { JobStatus } from '../../types';
const RANGE_BUTTONS = [
{ label: 'Launched', value: JobStatus.LAUNCHED },
{ label: 'Pending', value: JobStatus.PENDING },
{ label: 'Partial', value: JobStatus.PARTIAL },
{ label: 'Completed', value: JobStatus.COMPLETED },
{ label: 'Canceled', value: JobStatus.CANCELED },
{ label: 'Failed', value: JobStatus.FAILED },
Expand Down
3 changes: 3 additions & 0 deletions packages/apps/job-launcher/client/src/layouts/AuthLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export default function AuthLayout() {
<ListItem>
<Link to="/jobs/pending">Pending</Link>
</ListItem>
<ListItem>
<Link to="/jobs/partial">Partial</Link>
</ListItem>
<ListItem>
<Link to="/jobs/completed">Completed</Link>
</ListItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { JobStatus } from '../../../types';

const JOB_NAV_ITEMS = [
{ status: JobStatus.LAUNCHED, label: 'launched' },
{ status: JobStatus.PARTIAL, label: 'partial' },
{ status: JobStatus.COMPLETED, label: 'completed' },
{ status: JobStatus.PENDING, label: 'pending' },
{ status: JobStatus.CANCELED, label: 'canceled' },
Expand Down
1 change: 1 addition & 0 deletions packages/apps/job-launcher/client/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export type JobRequest = {
export enum JobStatus {
LAUNCHED = 'LAUNCHED',
PENDING = 'PENDING',
PARTIAL = 'PARTIAL',
CANCELED = 'CANCELED',
FAILED = 'FAILED',
COMPLETED = 'COMPLETED',
Expand Down
2 changes: 2 additions & 0 deletions packages/apps/job-launcher/server/src/common/enums/job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum JobStatus {
CREATED = 'CREATED',
SET_UP = 'SET_UP',
LAUNCHED = 'LAUNCHED',
PARTIAL = 'PARTIAL',
COMPLETED = 'COMPLETED',
FAILED = 'FAILED',
TO_CANCEL = 'TO_CANCEL',
Expand All @@ -13,6 +14,7 @@ export enum JobStatus {
export enum JobStatusFilter {
PENDING = 'PENDING',
LAUNCHED = 'LAUNCHED',
PARTIAL = 'PARTIAL',
COMPLETED = 'COMPLETED',
FAILED = 'FAILED',
CANCELED = 'CANCELED',
Expand Down
9 changes: 3 additions & 6 deletions packages/apps/job-launcher/server/src/common/utils/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@ export function filterToEscrowStatus(
filterStatus: JobStatusFilter,
): EscrowStatus[] {
switch (filterStatus) {
case JobStatusFilter.PARTIAL:
return [EscrowStatus.Partial];
case JobStatusFilter.COMPLETED:
return [EscrowStatus.Complete];
case JobStatusFilter.CANCELED:
return [EscrowStatus.Cancelled];
default:
return [
EscrowStatus.Launched,
EscrowStatus.Pending,
EscrowStatus.Partial,
EscrowStatus.Paid,
];
return [EscrowStatus.Launched, EscrowStatus.Pending, EscrowStatus.Paid];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddPartialStatus1712826368303 implements MigrationInterface {
name = 'AddPartialStatus1712826368303';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TYPE "hmt"."jobs_status_enum"
RENAME TO "jobs_status_enum_old"
`);
await queryRunner.query(`
CREATE TYPE "hmt"."jobs_status_enum" AS ENUM(
'PENDING',
'PAID',
'CREATED',
'SET_UP',
'LAUNCHED',
'PARTIAL',
'COMPLETED',
'FAILED',
'TO_CANCEL',
'CANCELED'
)
`);
await queryRunner.query(`
ALTER TABLE "hmt"."jobs"
ALTER COLUMN "status" TYPE "hmt"."jobs_status_enum" USING "status"::"text"::"hmt"."jobs_status_enum"
`);
await queryRunner.query(`
DROP TYPE "hmt"."jobs_status_enum_old"
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TYPE "hmt"."jobs_status_enum_old" AS ENUM(
'PENDING',
'PAID',
'CREATED',
'SET_UP',
'LAUNCHED',
'COMPLETED',
'FAILED',
'TO_CANCEL',
'CANCELED'
)
`);
await queryRunner.query(`
ALTER TABLE "hmt"."jobs"
ALTER COLUMN "status" TYPE "hmt"."jobs_status_enum_old" USING "status"::"text"::"hmt"."jobs_status_enum_old"
`);
await queryRunner.query(`
DROP TYPE "hmt"."jobs_status_enum"
`);
await queryRunner.query(`
ALTER TYPE "hmt"."jobs_status_enum_old"
RENAME TO "jobs_status_enum"
`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2579,7 +2579,6 @@ describe('JobService', () => {
MOCK_ADDRESS,
MOCK_ADDRESS,
MOCK_ADDRESS,
MOCK_ADDRESS,
]);
});
it('should call the database with CANCELLED status', async () => {
Expand All @@ -2598,6 +2597,100 @@ describe('JobService', () => {
limit,
);
});

it('should call subgraph and database with COMPLETED status', async () => {
const jobEntityMock = [
{
status: JobStatus.LAUNCHED,
fundAmount: 100,
userId: 1,
id: 1,
escrowAddress: MOCK_ADDRESS,
chainId: ChainId.LOCALHOST,
},
];
const getEscrowsData = [
{
address: MOCK_ADDRESS,
status: EscrowStatus[EscrowStatus.Complete],
},
];
jobRepository.findByEscrowAddresses = jest
.fn()
.mockResolvedValue(jobEntityMock as any);
jobRepository.updateOne = jest
.fn()
.mockResolvedValue({ status: JobStatus.COMPLETED });
EscrowUtils.getEscrows = jest.fn().mockResolvedValue(getEscrowsData);

const results = await jobService.getJobsByStatus(
[ChainId.LOCALHOST],
userId,
JobStatusFilter.COMPLETED,
skip,
limit,
);

expect(results).toMatchObject([
{
status: JobStatus.COMPLETED,
fundAmount: 100,
jobId: 1,
escrowAddress: MOCK_ADDRESS,
network: NETWORKS[ChainId.LOCALHOST]?.title,
},
]);
expect(jobRepository.findByEscrowAddresses).toHaveBeenCalledWith(userId, [
MOCK_ADDRESS,
]);
});

it('should call subgraph and database with PARTIAL status', async () => {
const jobEntityMock = [
{
status: JobStatus.LAUNCHED,
fundAmount: 100,
userId: 1,
id: 1,
escrowAddress: MOCK_ADDRESS,
chainId: ChainId.LOCALHOST,
},
];
const getEscrowsData = [
{
address: MOCK_ADDRESS,
status: EscrowStatus[EscrowStatus.Partial],
},
];
jobRepository.findByEscrowAddresses = jest
.fn()
.mockResolvedValue(jobEntityMock as any);
jobRepository.updateOne = jest
.fn()
.mockResolvedValue({ status: JobStatus.PARTIAL });
EscrowUtils.getEscrows = jest.fn().mockResolvedValue(getEscrowsData);

const results = await jobService.getJobsByStatus(
[ChainId.LOCALHOST],
userId,
JobStatusFilter.PARTIAL,
skip,
limit,
);

expect(results).toMatchObject([
{
status: JobStatus.PARTIAL,
fundAmount: 100,
jobId: 1,
escrowAddress: MOCK_ADDRESS,
network: NETWORKS[ChainId.LOCALHOST]?.title,
},
]);
expect(jobRepository.findByEscrowAddresses).toHaveBeenCalledWith(userId, [
MOCK_ADDRESS,
]);
});
});

describe('escrowFailedWebhook', () => {
Expand Down
33 changes: 11 additions & 22 deletions packages/apps/job-launcher/server/src/modules/job/job.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -949,25 +949,6 @@ export class JobService {
await this.jobRepository.updateOne(jobEntity);
}

private getOracleAddresses(manifest: any) {
let exchangeOracle;
let recordingOracle;
const oracleType = this.getOracleType(manifest);
if (oracleType === OracleType.FORTUNE) {
exchangeOracle = this.web3ConfigService.fortuneExchangeOracleAddress;
recordingOracle = this.web3ConfigService.fortuneRecordingOracleAddress;
} else if (oracleType === OracleType.HCAPTCHA) {
exchangeOracle = this.web3ConfigService.hCaptchaOracleAddress;
recordingOracle = this.web3ConfigService.hCaptchaOracleAddress;
} else {
exchangeOracle = this.web3ConfigService.cvatExchangeOracleAddress;
recordingOracle = this.web3ConfigService.cvatRecordingOracleAddress;
}
const reputationOracle = this.web3ConfigService.reputationOracleAddress;

return { exchangeOracle, recordingOracle, reputationOracle };
}

public async uploadManifest(
requestType: JobRequestType,
chainId: ChainId,
Expand Down Expand Up @@ -1068,6 +1049,7 @@ export class JobService {
);
break;
case JobStatusFilter.LAUNCHED:
case JobStatusFilter.PARTIAL:
case JobStatusFilter.COMPLETED:
escrows = await this.findEscrowsByStatus(
networks,
Expand Down Expand Up @@ -1149,7 +1131,7 @@ export class JobService {
escrow.address.toLowerCase() === job.escrowAddress.toLowerCase(),
);
if (escrow) {
const newJob = await this.updateCompletedStatus(job, escrow);
const newJob = await this.updateJobStatus(job, escrow);
return newJob.status;
}
}
Expand Down Expand Up @@ -1334,7 +1316,7 @@ export class JobService {

escrow = await EscrowUtils.getEscrow(chainId, escrowAddress);
allocation = await stakingClient.getAllocation(escrowAddress);
jobEntity = await this.updateCompletedStatus(jobEntity, escrow);
jobEntity = await this.updateJobStatus(jobEntity, escrow);
}

let manifestData = await this.storageService.download(manifestUrl);
Expand Down Expand Up @@ -1497,7 +1479,7 @@ export class JobService {
return BigInt(feeValue ? feeValue : 1);
}

private async updateCompletedStatus(
private async updateJobStatus(
job: JobEntity,
escrow: EscrowData,
): Promise<JobEntity> {
Expand All @@ -1509,6 +1491,13 @@ export class JobService {
job.status = JobStatus.COMPLETED;
updatedJob = await this.jobRepository.updateOne(job);
}
if (
escrow.status === EscrowStatus[EscrowStatus.Partial] &&
job.status !== JobStatus.PARTIAL
) {
job.status = JobStatus.PARTIAL;
updatedJob = await this.jobRepository.updateOne(job);
}
return updatedJob;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/typescript/subgraph/src/mapping/Escrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export function handleBulkTransfer(event: BulkTransfer): void {
// Update escrow entity
const escrowEntity = Escrow.load(dataSource.address().toHex());
if (escrowEntity) {
escrowEntity.status = event.params._isPartial ? 'Partially Paid' : 'Paid';
escrowEntity.status = event.params._isPartial ? 'Partial' : 'Paid';

// Read data on-chain
const escrowContract = EscrowContract.bind(event.address);
Expand Down
7 changes: 1 addition & 6 deletions packages/sdk/typescript/subgraph/tests/escrow/escrow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,12 +611,7 @@ describe('Escrow', () => {
);

// Escrow
assert.fieldEquals(
'Escrow',
escrowAddress.toHex(),
'status',
'Partially Paid'
);
assert.fieldEquals('Escrow', escrowAddress.toHex(), 'status', 'Partial');

// Bulk 2
const bulk2 = createBulkTransferEvent(
Expand Down

0 comments on commit 0c413b4

Please sign in to comment.