Skip to content

Commit

Permalink
feat: 🎸 make venueId optional for createInstruction
Browse files Browse the repository at this point in the history
  • Loading branch information
sansan committed Oct 10, 2024
1 parent a1fdeaa commit 396713d
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 9 deletions.
24 changes: 24 additions & 0 deletions src/settlements/settlements.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import {
Nft,
TransferError,
} from '@polymeshassociation/polymesh-sdk/types';
import { when } from 'jest-when';

import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
import { LegType } from '~/common/types';
import { createPortfolioIdentifierModel } from '~/portfolios/portfolios.util';
import { CreateInstructionDto } from '~/settlements/dto/create-instruction.dto';
import { SettlementsController } from '~/settlements/settlements.controller';
import { SettlementsService } from '~/settlements/settlements.service';
import { processedTxResult, testValues } from '~/test-utils/consts';
Expand Down Expand Up @@ -322,4 +324,26 @@ describe('SettlementsController', () => {
expect(result).toEqual(processedTxResult);
});
});

describe('addInstruction', () => {
it('should create an instruction and return the data returned by the service', async () => {
const mockInstruction = new MockInstruction();

when(mockInstruction.getLegs).calledWith().mockResolvedValue({ data: [] });

const mockData = {
...txResult,
result: mockInstruction,
};
mockSettlementsService.createInstruction.mockResolvedValue(mockData);

const result = await controller.addInstruction({} as CreateInstructionDto);

expect(result).toEqual({
...processedTxResult,
instruction: mockInstruction, // in jest the @FromEntity decorator is not applied
legs: [],
});
});
});
});
49 changes: 47 additions & 2 deletions src/settlements/settlements.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ApiQuery,
ApiTags,
} from '@nestjs/swagger';
import { Instruction } from '@polymeshassociation/polymesh-sdk/types';

import { ApiArrayResponse } from '~/common/decorators/swagger';
import { IdParamsDto } from '~/common/dto/id-params.dto';
Expand All @@ -15,19 +16,21 @@ 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, TransactionResponseModel } from '~/common/utils';
import { handleServiceResult, TransactionResolver, TransactionResponseModel } from '~/common/utils';
import { PortfolioDto } from '~/portfolios/dto/portfolio.dto';
import { AffirmAsMediatorDto } from '~/settlements/dto/affirm-as-mediator.dto';
import { AffirmInstructionDto } from '~/settlements/dto/affirm-instruction.dto';
import { CreateInstructionDto } from '~/settlements/dto/create-instruction.dto';
import { ExecuteInstructionDto } from '~/settlements/dto/execute-instruction.dto';
import { LegIdParamsDto } from '~/settlements/dto/leg-id-params.dto';
import { LegValidationParamsDto } from '~/settlements/dto/leg-validation-params.dto';
import { CreatedInstructionModel } from '~/settlements/models/created-instruction.model';
import { InstructionModel } from '~/settlements/models/instruction.model';
import { InstructionAffirmationModel } from '~/settlements/models/instruction-affirmation.model';
import { OffChainAffirmationModel } from '~/settlements/models/off-chain-affirmation.model';
import { TransferBreakdownModel } from '~/settlements/models/transfer-breakdown.model';
import { SettlementsService } from '~/settlements/settlements.service';
import { createInstructionModel } from '~/settlements/settlements.util';
import { createInstructionModel, legsToLegModel } from '~/settlements/settlements.util';

@ApiTags('settlements')
@Controller()
Expand Down Expand Up @@ -384,4 +387,46 @@ export class SettlementsController {
const result = await this.settlementsService.executeInstruction(id, body);
return handleServiceResult(result);
}

@ApiTags('instructions')
@ApiOperation({
summary: 'Execute an existing Instruction',
description: 'This endpoint will execute a pending Instruction of type `SettleManual`',
})
@ApiParam({
name: 'id',
description: 'The ID of the Instruction to be executed',
type: 'string',
example: '123',
})
@ApiOkResponse({
description: 'Details of the transaction',
type: TransactionQueueModel,
})
@Post('instructions/create')
public async addInstruction(
@Body() createInstructionDto: CreateInstructionDto
): Promise<TransactionResponseModel> {
const serviceResult = await this.settlementsService.createInstruction(
undefined,
createInstructionDto
);

const resolver: TransactionResolver<Instruction> = async ({
result: instruction,
transactions,
details,
}) => {
const { data: legs } = await instruction.getLegs();

return new CreatedInstructionModel({
instruction,
details,
transactions,
legs: legsToLegModel(legs),
});
};

return handleServiceResult(serviceResult, resolver);
}
}
36 changes: 32 additions & 4 deletions src/settlements/settlements.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { POLYMESH_API } from '~/polymesh/polymesh.consts';
import { PolymeshModule } from '~/polymesh/polymesh.module';
import { PolymeshService } from '~/polymesh/polymesh.service';
import { PortfolioDto } from '~/portfolios/dto/portfolio.dto';
import { CreateInstructionDto } from '~/settlements/dto/create-instruction.dto';
import { LegDto } from '~/settlements/dto/leg.dto';
import { OffChainAffirmationReceiptDto } from '~/settlements/dto/offchain-affirmation-receipt.dto';
import { OffChainLegDto } from '~/settlements/dto/offchain-leg.dto';
Expand Down Expand Up @@ -165,7 +166,7 @@ describe('SettlementsService', () => {
describe('createInstruction', () => {
it('should run an addInstruction procedure and return the queue data', async () => {
const mockVenue = new MockVenue();

const venueId = new BigNumber(123);
const transaction = {
blockHash: '0x1',
txHash: '0x2',
Expand All @@ -182,6 +183,7 @@ describe('SettlementsService', () => {
const findVenueSpy = jest.spyOn(service, 'findVenue');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
findVenueSpy.mockResolvedValue(mockVenue as any);
mockPolymeshApi.settlements.addInstruction.mockResolvedValue(mockTransaction);

const onChainLeg = {
type: LegType.onChain,
Expand All @@ -208,15 +210,41 @@ describe('SettlementsService', () => {
...params,
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await service.createInstruction(new BigNumber(123), body as any);
let result = await service.createInstruction(venueId, body as CreateInstructionDto);

expect(result).toEqual({
result: mockInstruction,
transactions: [mockTransaction],
});
expect(mockTransactionsService.submit).toHaveBeenCalledWith(
mockPolymeshApi.settlements.addInstruction,
{
legs: [
{
from: 'fromDid',
to: { identity: 'toDid', id: new BigNumber(1) },
amount: new BigNumber(100),
asset: 'FAKE_TICKER',
},
{
from: '0x01',
to: '0x02',
offChainAmount: new BigNumber(100),
asset: 'OFF_CHAIN_TICKER',
},
],
venueId,
},
expect.objectContaining({ signer })
);

result = await service.createInstruction(undefined, body as CreateInstructionDto);
expect(result).toEqual({
result: mockInstruction,
transactions: [mockTransaction],
});
expect(mockTransactionsService.submit).toHaveBeenCalledWith(
mockVenue.addInstruction,
mockPolymeshApi.settlements.addInstruction,
{
legs: [
{
Expand Down
16 changes: 13 additions & 3 deletions src/settlements/settlements.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,28 @@ export class SettlementsService {
}

public async createInstruction(
venueId: BigNumber,
venueId: BigNumber | undefined,
createInstructionDto: CreateInstructionDto
): ServiceReturn<Instruction> {
const { options, args } = extractTxOptions(createInstructionDto);
const venue = await this.findVenue(venueId);

const {
polymeshService: {
polymeshApi: { settlements },
},
} = this;

if (venueId) {
await this.findVenue(venueId); // Check if venue exists
}

const params = {
...args,
legs: args.legs.map(leg => leg.toLeg()),
venueId,
};

return this.transactionsService.submit(venue.addInstruction, params, options);
return this.transactionsService.submit(settlements.addInstruction, params, options);
}

public async findVenuesByOwner(did: string): Promise<Venue[]> {
Expand Down
1 change: 1 addition & 0 deletions src/test-utils/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export class MockPolymesh {
getInstruction: jest.fn(),
getVenue: jest.fn(),
createVenue: jest.fn(),
addInstruction: jest.fn(),
};

public claims = {
Expand Down

0 comments on commit 396713d

Please sign in to comment.