Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 🎸 make venueId optional for createInstruction #290

Merged
merged 1 commit into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: [],
});
});
});
});
42 changes: 40 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,39 @@ export class SettlementsController {
const result = await this.settlementsService.executeInstruction(id, body);
return handleServiceResult(result);
}

@ApiTags('instructions')
@ApiOperation({
summary: 'Create a new Instruction',
})
@ApiOkResponse({
description: 'The ID of the newly created Instruction',
type: CreatedInstructionModel,
})
@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);
}
}
52 changes: 34 additions & 18 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,30 +210,44 @@ 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);
const expectedLegs = [
{
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',
},
];

expect(result).toEqual({
result: mockInstruction,
transactions: [mockTransaction],
});
expect(mockTransactionsService.submit).toHaveBeenCalledWith(
mockVenue.addInstruction,
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',
},
],
legs: expectedLegs,
venueId,
},
expect.objectContaining({ signer })
);

result = await service.createInstruction(undefined, body as CreateInstructionDto);
expect(result).toEqual({
result: mockInstruction,
transactions: [mockTransaction],
});
expect(mockTransactionsService.submit).toHaveBeenCalledWith(
mockPolymeshApi.settlements.addInstruction,
{
legs: expectedLegs,
},
expect.objectContaining({ signer })
);
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
Loading