From 4a662ec25d37be7e86f14f10cac938cf62e0a24c Mon Sep 17 00:00:00 2001 From: Toms Date: Thu, 21 Nov 2024 16:29:51 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20get=20all=20eligible=20d?= =?UTF-8?q?ividend=20distributions=20for=20did?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../corporate-actions.controller.spec.ts | 1 + src/identities/identities.controller.spec.ts | 21 ++++++++++++ src/identities/identities.controller.ts | 33 +++++++++++++++++++ src/identities/identities.service.spec.ts | 20 ++++++++++- src/identities/identities.service.ts | 7 ++++ src/test-utils/mocks.ts | 1 + src/test-utils/service-mocks.ts | 1 + 7 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/corporate-actions/corporate-actions.controller.spec.ts b/src/corporate-actions/corporate-actions.controller.spec.ts index d6c9214e..66f413ab 100644 --- a/src/corporate-actions/corporate-actions.controller.spec.ts +++ b/src/corporate-actions/corporate-actions.controller.spec.ts @@ -31,6 +31,7 @@ describe('CorporateActionsController', () => { linkDocuments: jest.fn(), reclaimRemainingFunds: jest.fn(), modifyCheckpoint: jest.fn(), + findUnclaimedDistributionsByAsset: jest.fn(), }; beforeEach(async () => { diff --git a/src/identities/identities.controller.spec.ts b/src/identities/identities.controller.spec.ts index bf23fe07..04fde060 100644 --- a/src/identities/identities.controller.spec.ts +++ b/src/identities/identities.controller.spec.ts @@ -21,6 +21,8 @@ import { PendingAuthorizationsModel } from '~/authorizations/models/pending-auth import { ClaimsService } from '~/claims/claims.service'; import { PaginatedResultsModel } from '~/common/models/paginated-results.model'; import { ResultsModel } from '~/common/models/results.model'; +import { createDividendDistributionDetailsModel } from '~/corporate-actions/corporate-actions.util'; +import { MockDistributionWithDetails } from '~/corporate-actions/mocks/distribution-with-details.mock'; import { RegisterIdentityDto } from '~/identities/dto/register-identity.dto'; import { IdentitiesController } from '~/identities/identities.controller'; import { IdentitiesService } from '~/identities/identities.service'; @@ -754,4 +756,23 @@ describe('IdentitiesController', () => { }); }); }); + + describe('getUnclaimedDividendDistributions', () => { + it('should return unclaimed Dividend Distributions associated with Identity', async () => { + const mockDistributions = [new MockDistributionWithDetails()]; + + mockIdentitiesService.getPendingDistributions.mockResolvedValue(mockDistributions); + + const result = await controller.getPendingDistributions({ did }); + + expect(result).toEqual( + new ResultsModel({ + results: mockDistributions.map(distributionWithDetails => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + createDividendDistributionDetailsModel(distributionWithDetails as any) + ), + }) + ); + }); + }); }); diff --git a/src/identities/identities.controller.ts b/src/identities/identities.controller.ts index e72b8006..265c4be1 100644 --- a/src/identities/identities.controller.ts +++ b/src/identities/identities.controller.ts @@ -48,6 +48,8 @@ import { DidDto, IncludeExpiredFilterDto } from '~/common/dto/params.dto'; import { PaginatedResultsModel } from '~/common/models/paginated-results.model'; import { ResultsModel } from '~/common/models/results.model'; import { handleServiceResult, TransactionResponseModel } from '~/common/utils'; +import { createDividendDistributionDetailsModel } from '~/corporate-actions/corporate-actions.util'; +import { DividendDistributionDetailsModel } from '~/corporate-actions/models/dividend-distribution-details.model'; import { DeveloperTestingService } from '~/developer-testing/developer-testing.service'; import { CreateMockIdentityDto } from '~/developer-testing/dto/create-mock-identity.dto'; import { AddSecondaryAccountParamsDto } from '~/identities/dto/add-secondary-account-params.dto'; @@ -754,4 +756,35 @@ export class IdentitiesController { next, }); } + + @ApiTags('dividend-distributions') + @ApiOperation({ + summary: 'Fetch eligible Dividend Distributions', + description: + 'This endpoint will provide the list of Dividend Distributions that are eligible to be claimed by the current Identity', + }) + @ApiParam({ + name: 'did', + description: 'The DID of the Identity for which fetch pending Dividend Distributions for', + type: 'string', + required: true, + example: '0x0600000000000000000000000000000000000000000000000000000000000000', + }) + @ApiArrayResponse(DividendDistributionDetailsModel, { + description: + 'List of Dividend Distributions that are eligible to be claimed by the specified Identity', + paginated: false, + }) + @Get(':did/pending-distributions') + public async getPendingDistributions( + @Param() { did }: DidDto + ): Promise> { + const results = await this.identitiesService.getPendingDistributions(did); + + return new ResultsModel({ + results: results.map(distributionWithDetails => + createDividendDistributionDetailsModel(distributionWithDetails) + ), + }); + } } diff --git a/src/identities/identities.service.spec.ts b/src/identities/identities.service.spec.ts index b64efd8f..38dfbca1 100644 --- a/src/identities/identities.service.spec.ts +++ b/src/identities/identities.service.spec.ts @@ -6,6 +6,7 @@ import { BigNumber } from '@polymeshassociation/polymesh-sdk'; import { TxTags } from '@polymeshassociation/polymesh-sdk/types'; import { AccountsService } from '~/accounts/accounts.service'; +import { MockDistributionWithDetails } from '~/corporate-actions/mocks/distribution-with-details.mock'; import { RegisterIdentityDto } from '~/identities/dto/register-identity.dto'; import { IdentitiesService } from '~/identities/identities.service'; import { mockPolymeshLoggerProvider } from '~/logger/mock-polymesh-logger'; @@ -27,7 +28,7 @@ import { } from '~/test-utils/service-mocks'; import * as transactionsUtilModule from '~/transactions/transactions.util'; -const { signer } = testValues; +const { signer, did } = testValues; jest.mock('@polymeshassociation/polymesh-sdk/utils', () => ({ ...jest.requireActual('@polymeshassociation/polymesh-sdk/utils'), @@ -290,4 +291,21 @@ describe('IdentitiesService', () => { expect(result).toEqual(mockAssets); }); }); + + describe('getPendingDistributions', () => { + it('should return the Dividend Distributions associated with an Asset that have not been claimed', async () => { + const mockDistributions = [new MockDistributionWithDetails()]; + + const mockIdentity = new MockIdentity(); + + const findOneSpy = jest.spyOn(service, 'findOne'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + findOneSpy.mockResolvedValue(mockIdentity as any); + mockIdentity.getPendingDistributions.mockResolvedValue(mockDistributions); + + const result = await service.getPendingDistributions(did); + + expect(result).toEqual(mockDistributions); + }); + }); }); diff --git a/src/identities/identities.service.ts b/src/identities/identities.service.ts index a047fa9a..79b31287 100644 --- a/src/identities/identities.service.ts +++ b/src/identities/identities.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { BigNumber } from '@polymeshassociation/polymesh-sdk'; import { AuthorizationRequest, + DistributionWithDetails, FungibleAsset, Identity, NftCollection, @@ -152,4 +153,10 @@ export class IdentitiesService { return identity.isAssetPreApproved(asset); } + + public async getPendingDistributions(did: string): Promise { + const identity = await this.findOne(did); + + return identity.getPendingDistributions(); + } } diff --git a/src/test-utils/mocks.ts b/src/test-utils/mocks.ts index 9b086408..760f6766 100644 --- a/src/test-utils/mocks.ts +++ b/src/test-utils/mocks.ts @@ -320,6 +320,7 @@ export class MockIdentity { public getHeldAssets = jest.fn(); public preApprovedAssets = jest.fn(); public isAssetPreApproved = jest.fn(); + public getPendingDistributions = jest.fn(); } export class MockPortfolio { diff --git a/src/test-utils/service-mocks.ts b/src/test-utils/service-mocks.ts index 46811eb2..8facf777 100644 --- a/src/test-utils/service-mocks.ts +++ b/src/test-utils/service-mocks.ts @@ -152,6 +152,7 @@ export class MockIdentitiesService { attestPrimaryKeyRotation = jest.fn(); isAssetPreApproved = jest.fn(); getPreApprovedAssets = jest.fn(); + getPendingDistributions = jest.fn(); } export class MockSettlementsService {