Skip to content

Commit

Permalink
feat: 🎸 add endpoint to get paymentHistory for a distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
sansan committed Nov 21, 2024
1 parent 4a662ec commit 375297a
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 2 deletions.
40 changes: 39 additions & 1 deletion src/corporate-actions/corporate-actions.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createMock } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';
import { DistributionPayment, ResultSet } from '@polymeshassociation/polymesh-sdk/types';

import { AssetDocumentDto } from '~/assets/dto/asset-document.dto';
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
import { ResultsModel } from '~/common/models/results.model';
import { CorporateActionsController } from '~/corporate-actions/corporate-actions.controller';
import { CorporateActionsService } from '~/corporate-actions/corporate-actions.service';
Expand All @@ -12,9 +15,10 @@ import {
import { MockCorporateActionDefaultConfig } from '~/corporate-actions/mocks/corporate-action-default-config.mock';
import { MockDistributionWithDetails } from '~/corporate-actions/mocks/distribution-with-details.mock';
import { MockDistribution } from '~/corporate-actions/mocks/dividend-distribution.mock';
import { DistributionPaymentModel } from '~/corporate-actions/models/distribution-payment.model';
import { processedTxResult, testValues } from '~/test-utils/consts';

const { did, signer, txResult, assetId } = testValues;
const { did, signer, txResult, assetId, blockHash, blockNumber } = testValues;

describe('CorporateActionsController', () => {
let controller: CorporateActionsController;
Expand All @@ -32,6 +36,7 @@ describe('CorporateActionsController', () => {
reclaimRemainingFunds: jest.fn(),
modifyCheckpoint: jest.fn(),
findUnclaimedDistributionsByAsset: jest.fn(),
getPaymentHistory: jest.fn(),
};

beforeEach(async () => {
Expand Down Expand Up @@ -278,4 +283,37 @@ describe('CorporateActionsController', () => {
);
});
});

describe('getPaymentHistory', () => {
it('should return a paginated list of payments for a specific Dividend Distribution', async () => {
const mockDistributionPayment = createMock<DistributionPayment>({
target: { did },
amount: new BigNumber(100),
date: new Date(),
blockHash,
blockNumber,
withheldTax: new BigNumber(10),
});
const { target, ...rest } = mockDistributionPayment;

const mockPaginatedResult = createMock<ResultSet<DistributionPayment>>({
data: [mockDistributionPayment],
next: new BigNumber(2),
});

mockCorporateActionsService.getPaymentHistory.mockResolvedValue(mockPaginatedResult);

const result = await controller.getPaymentHistory(
{ asset: assetId, id: new BigNumber(1) },
{ size: new BigNumber(10), start: new BigNumber(0) }
);

expect(result).toEqual(
new PaginatedResultsModel({
results: [new DistributionPaymentModel({ ...rest, did: target.did })],
next: new BigNumber(2),
})
);
});
});
});
51 changes: 51 additions & 0 deletions src/corporate-actions/corporate-actions.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import {
ApiTags,
ApiUnprocessableEntityResponse,
} from '@nestjs/swagger';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';
import { DividendDistribution } from '@polymeshassociation/polymesh-sdk/types';

import { AssetParamsDto } from '~/assets/dto/asset-params.dto';
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/';
import { IsAsset } from '~/common/decorators/validation';
import { IdParamsDto } from '~/common/dto/id-params.dto';
import { PaginatedParamsDto } from '~/common/dto/paginated-params.dto';
import { TransactionBaseDto } from '~/common/dto/transaction-base-dto';
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
import { ResultsModel } from '~/common/models/results.model';
import { TransactionQueueModel } from '~/common/models/transaction-queue.model';
import { handleServiceResult, TransactionResolver, TransactionResponseModel } from '~/common/utils';
Expand All @@ -31,6 +34,7 @@ import { PayDividendsDto } from '~/corporate-actions/dto/pay-dividends.dto';
import { CorporateActionDefaultConfigModel } from '~/corporate-actions/models/corporate-action-default-config.model';
import { CorporateActionTargetsModel } from '~/corporate-actions/models/corporate-action-targets.model';
import { CreatedDividendDistributionModel } from '~/corporate-actions/models/created-dividend-distribution.model';
import { DistributionPaymentModel } from '~/corporate-actions/models/distribution-payment.model';
import { DividendDistributionModel } from '~/corporate-actions/models/dividend-distribution.model';
import { DividendDistributionDetailsModel } from '~/corporate-actions/models/dividend-distribution-details.model';
import { TaxWithholdingModel } from '~/corporate-actions/models/tax-withholding.model';
Expand Down Expand Up @@ -484,4 +488,51 @@ export class CorporateActionsController {
);
return handleServiceResult(result);
}

@ApiTags('dividend-distributions')
@ApiOperation({
summary: 'Get Payment History of a Dividend Distribution',
description: 'This endpoint retrieves the Payment History of a Dividend Distribution',
})
@ApiParam({
name: 'asset',
description:
'The Asset (Ticker/Asset ID) whose Dividend Distribution Payment History is to be retrieved',
type: 'string',
example: '3616b82e-8e10-80ae-dc95-2ea28b9db8b3',
})
@ApiParam({
name: 'id',
description:
'The Corporate Action number for the the Dividend Distribution (Dividend Distribution ID)',
type: 'string',
example: '123',
})
@ApiNotFoundResponse({
description:
'<ul>' + '<li>Asset does not exist</li>' + '<li>Distribution does not exist</li>' + '</ul>',
})
@ApiArrayResponse(DistributionPaymentModel, {
description: 'List of payments made for the Distribution',
paginated: true,
})
@Get('dividend-distributions/:id/payment-history')
public async getPaymentHistory(
@Param() { id, asset }: DividendDistributionParamsDto,
@Query() { size, start }: PaginatedParamsDto
): Promise<PaginatedResultsModel<DistributionPaymentModel>> {
const result = await this.corporateActionsService.getPaymentHistory(
asset,
id,
size,
new BigNumber(start || 0)
);

return new PaginatedResultsModel({
results: result.data.map(
({ target: { did }, ...rest }) => new DistributionPaymentModel({ did, ...rest })
),
next: result.next,
});
}
}
39 changes: 38 additions & 1 deletion src/corporate-actions/corporate-actions.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
/* eslint-disable import/first */
const mockIsPolymeshTransaction = jest.fn();

import { createMock } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';
import { CaCheckpointType, TxTags } from '@polymeshassociation/polymesh-sdk/types';
import {
CaCheckpointType,
DistributionPayment,
DistributionWithDetails,
DividendDistribution,
TxTags,
} from '@polymeshassociation/polymesh-sdk/types';

import { AssetsService } from '~/assets/assets.service';
import { AssetDocumentDto } from '~/assets/dto/asset-document.dto';
Expand Down Expand Up @@ -402,4 +409,34 @@ describe('CorporateActionsService', () => {
});
});
});

describe('getPaymentHistory', () => {
it('should return the payment history for a specific Dividend Distribution', async () => {
const mockPaginatedResult = {
data: [createMock<DistributionPayment>()],
next: new BigNumber(2),
count: new BigNumber(2),
};

const mockDistribution = createMock<DividendDistribution>({
getPaymentHistory: jest.fn().mockResolvedValue(mockPaginatedResult),
});

const mockDistributionWithDetails = createMock<DistributionWithDetails>({
distribution: mockDistribution,
});

const findDistributionSpy = jest.spyOn(service, 'findDistribution');
findDistributionSpy.mockResolvedValue(mockDistributionWithDetails);

const result = await service.getPaymentHistory(
assetId,
new BigNumber(1),
new BigNumber(10),
new BigNumber(0)
);

expect(result).toEqual(mockPaginatedResult);
});
});
});
13 changes: 13 additions & 0 deletions src/corporate-actions/corporate-actions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { Injectable } from '@nestjs/common';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';
import {
CorporateActionDefaultConfig,
DistributionPayment,
DistributionWithDetails,
DividendDistribution,
ResultSet,
} from '@polymeshassociation/polymesh-sdk/types';

import { AssetsService } from '~/assets/assets.service';
Expand Down Expand Up @@ -152,4 +154,15 @@ export class CorporateActionsService {

return this.transactionService.submit(distribution.modifyCheckpoint, args, options);
}

public async getPaymentHistory(
asset: string,
id: BigNumber,
size: BigNumber,
start?: BigNumber
): Promise<ResultSet<DistributionPayment>> {
const { distribution } = await this.findDistribution(asset, id);

return distribution.getPaymentHistory({ size, start });
}
}
57 changes: 57 additions & 0 deletions src/corporate-actions/models/distribution-payment.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* istanbul ignore file */

import { ApiProperty } from '@nestjs/swagger';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';

import { FromBigNumber } from '~/common/decorators';

export class DistributionPaymentModel {
@ApiProperty({
description: 'Block number when the payment was made',
type: 'string',
example: '1234567',
})
@FromBigNumber()
blockNumber: BigNumber;

@ApiProperty({
description: 'Hash of the block when the payment was made',
type: 'string',
example: '0xec1d41dd553ce03c3e462aab8bcfba0e1726e6bf310db6e06a933bf0430419c0',
})
blockHash: string;

@ApiProperty({
description: 'Date when the payment was made',
example: new Date('10/14/1987').toISOString(),
type: 'string',
})
date: Date;

@ApiProperty({
description: 'The DID of the payment recipient',
type: 'string',
example: '0x0600000000000000000000000000000000000000000000000000000000000000',
})
did: string;

@ApiProperty({
description: 'Amount of the payment',
type: 'string',
example: '1000000',
})
@FromBigNumber()
amount: BigNumber;

@ApiProperty({
description: 'Percentage (0-100) of tax withholding for the target identity',
type: 'string',
example: '15',
})
@FromBigNumber()
withheldTax: BigNumber;

constructor(model: DistributionPaymentModel) {
Object.assign(this, model);
}
}
6 changes: 6 additions & 0 deletions src/test-utils/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const did = '0x01'.padEnd(66, '0');
const dryRun = false;
const ticker = 'TICKER';
const assetId = '3616b82e-8e10-80ae-dc95-2ea28b9db8b3';
const blockNumber = new BigNumber(1);
const blockHash = '0xec1d41dd553ce03c3e462aab8bcfba0e1726e6bf310db6e06a933bf0430419c0';
const date = new Date('2001-01-01');

const user = new UserModel({
id: '-1',
Expand Down Expand Up @@ -110,6 +113,9 @@ export const testValues = {
dryRun,
ticker,
assetId,
blockNumber,
blockHash,
date,
};

export const extrinsic = {
Expand Down

0 comments on commit 375297a

Please sign in to comment.