diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts index a00472ea6c..7f7e79cb4e 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts @@ -54,7 +54,7 @@ describe('DefaultPayoutsCalculator', () => { .fn() .mockImplementation(async () => reservedFunds); - beforeAll(() => { + beforeEach(() => { mockedEscrowClient.build.mockResolvedValue({ getReservedFunds: mockedGetReservedFunds, } as unknown as EscrowClient); @@ -86,7 +86,50 @@ describe('DefaultPayoutsCalculator', () => { const expectedPayouts = acceptedResults.map((result) => ({ address: result.workerAddress, - amount: reservedFunds / BigInt(manifest.submissionsRequired), + amount: reservedFunds / BigInt(acceptedResults.length), + })); + + expect(normalizePayouts(payouts)).toEqual( + normalizePayouts(expectedPayouts), + ); + }); + + it('should split reserved funds by accepted results when fewer than required submissions are accepted', async () => { + const acceptedCount = faker.number.int({ min: 1, max: 10 }); + const rejectedCount = faker.number.int({ min: 1, max: 10 }); + const submissionsRequired = faker.number.int({ + min: acceptedCount + 1, + max: acceptedCount + 10, + }); + const payoutAmount = BigInt(faker.number.int({ min: 1000, max: 100000 })); + const reservedFunds = payoutAmount * BigInt(acceptedCount); + const acceptedResults = Array.from({ length: acceptedCount }, () => + generateFinalResult(VerificationResult.Accepted), + ); + const rejectedResults = Array.from({ length: rejectedCount }, () => + generateFinalResult(VerificationResult.Rejected), + ); + const manifest: BaseManifest = { + requestType: MarketingJobType.SOCIAL_MEDIA_PROMOTION, + submissionsRequired, + }; + + mockedGetReservedFunds.mockResolvedValueOnce(reservedFunds); + mockedStorageService.downloadJsonLikeData.mockResolvedValueOnce([ + ...acceptedResults, + ...rejectedResults, + ]); + + const payouts = await calculator.calculate({ + chainId: generateTestnetChainId(), + escrowAddress: faker.finance.ethereumAddress(), + finalResultsUrl: faker.internet.url(), + manifest, + }); + + const expectedPayouts = acceptedResults.map((result) => ({ + address: result.workerAddress, + amount: payoutAmount, })); expect(normalizePayouts(payouts)).toEqual( diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.ts index 5bb3c8e06c..7f545b65cc 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.ts @@ -1,12 +1,7 @@ import { EscrowClient } from '@human-protocol/sdk'; import { Injectable } from '@nestjs/common'; -import { - BaseFinalResult, - FortuneManifest, - MarketingManifest, - VerificationResult, -} from '@/common/types'; +import { BaseFinalResult, VerificationResult } from '@/common/types'; import { StorageService } from '@/modules/storage'; import { Web3Service } from '@/modules/web3'; @@ -16,8 +11,6 @@ import { EscrowPayoutsCalculator, } from './types'; -type DefaultPayoutsManifest = FortuneManifest | MarketingManifest; - @Injectable() export class DefaultPayoutsCalculator implements EscrowPayoutsCalculator { constructor( @@ -26,13 +19,10 @@ export class DefaultPayoutsCalculator implements EscrowPayoutsCalculator { ) {} async calculate({ - manifest, chainId, escrowAddress, finalResultsUrl, - }: CalculatePayoutsInput & { - manifest: DefaultPayoutsManifest; - }): Promise { + }: CalculatePayoutsInput): Promise { const signer = this.web3Service.getSigner(chainId); const escrowClient = await EscrowClient.build(signer); const finalResults = @@ -51,7 +41,7 @@ export class DefaultPayoutsCalculator implements EscrowPayoutsCalculator { } const reservedFunds = await escrowClient.getReservedFunds(escrowAddress); - const payoutAmount = reservedFunds / BigInt(manifest.submissionsRequired); + const payoutAmount = reservedFunds / BigInt(recipients.length); return recipients.map((recipient) => ({ address: recipient,