Skip to content

Commit b855445

Browse files
prashantasdevelopermonitz87VictorVicente
authored
v0.0.9 (#110)
* chore: πŸ€– Bump SDK version to 15.0.0-alpha.1 * chore: πŸ€– Bump SDK version to 15.0.0-alpha.4 * chore: πŸ€– Bump SDK version to 15.0.0-alpha.6 * chore: πŸ€– Bump nestjs packages to latest version * fix: πŸ› Update max validation check in `paginated-params.dto.ts` * chore: πŸ€– Remove `forbidNonWhitelisted` from Validation options * chore: πŸ€– Bump SDK version to 15.0.0-alpha.10 BREAKING CHANGE: 🧨 `ticker-reservations/:ticker` now doesn't throw errors if ticker is not present or Asset is already created. To check ticker availability, we can now use `details.status` * chore: πŸ€– Fix SDK version in yarn.lock * feat: 🎸 Add an endpoint to get Asset's operation history * feat: rename write endpoints to be more RPC-like BREAKING CHANGES: - `POST accounts/transfers` -> `POST accounts/transfer` - `POST assets/:ticker/set-documents` -> `POST assets/:ticker/documents/set` - `POST assets/create-asset` -> `POST assets/create` - `POST assets/:ticker/checkpoints/schedules` -> `POST assets/:ticker/checkpoints/schedules/create` - `DELETE assets/:ticker/checkpoints/schedules/:id` -> `POST assets/:ticker/checkpoints/schedules/:id/delete` - `PUT assets/:ticker/compliance-requirements` -> `POST assets/:ticker/compliance-requirements/set` - `PATCH assets/:ticker/corporate-actions/default-config` -> `POST assets/:ticker/corporate-actions/default-config/modify` - `POST assets/:ticker/corporate-actions/dividend-distributions` -> `POST assets/:ticker/corporate-actions/dividend-distributions/create` - `DELETE assets/:ticker/corporate-actions/:id` -> `POST assets/:ticker/corporate-actions/:id/delete` - `POST assets/:ticker/corporate-actions/:id/payments` -> `POST assets/:ticker/corporate-actions/dividend-distributions/:id/payments/pay` - `PUT assets/:ticker/corporate-actions/:id/documents` -> `POST assets/:ticker/corporate-actions/:id/documents/link` - `PUT assets/:ticker/corporate-actions/:id/checkpoint` -> `POST assets/:ticker/corporate-actions/dividend-distributions/:id/modify-checkpoint` - `POST identities/secondary-accounts` -> `POST identities/secondary-accounts/add` - `POST identities/:did/portfolios/asset-movements` -> `POST identities/:did/portfolios/move-assets` - `POST portfolios` -> `POST portfolios/create` - `DELETE identities/:did/portfolios/:id` -> `POST identities/:did/portfolios/:id/delete` - `POST venues/:id/instructions` ->`POST venues/:id/instructions/create` - `POST venues` -> `POST venues/create` - `PATCH venues/:id` -> `POST venues/:id/modify` * fix: πŸ› rename missing endpoint * docs: ✏️ Update summary * feat: 🎸 rename add secondary key endpoint BREAKING CHANGE: 🧨 rename `POST identities/secondary-accounts/add` to `POST identities/secondary-accounts/invite` * chore: πŸ€– Address review comments Co-authored-by: JeremΓ­as DΓ­az <[email protected]> Co-authored-by: Victor Vicente <[email protected]>
1 parent 2df7216 commit b855445

32 files changed

+1056
-693
lines changed

β€Žpackage.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"license": "UNLICENSED",
88
"scripts": {
99
"prepare": "husky install",
10-
"postinstall": "rimraf node_modules/@polymathnetwork/polymesh-sdk/node_modules/@polkadot/{util-crypto,wasm-crypto}",
1110
"prebuild": "rimraf dist",
11+
"postinstall": "rimraf node_modules/@polymathnetwork/polymesh-sdk/node_modules/@polkadot/{util-crypto,wasm-crypto,util}",
1212
"build": "nest build",
1313
"commit": "npx git-cz",
1414
"format": "prettier-eslint --write \"src/**/*.ts\" \"test/**/*.ts\"",
@@ -24,34 +24,34 @@
2424
"test:e2e": "jest --config ./test/jest-e2e.json"
2525
},
2626
"dependencies": {
27-
"@nestjs/axios": "^0.0.7",
28-
"@nestjs/common": "^8.4.4",
29-
"@nestjs/config": "^2.0.0",
30-
"@nestjs/core": "^8.4.4",
31-
"@nestjs/platform-express": "^8.4.4",
32-
"@nestjs/schedule": "^1.1.0",
27+
"@nestjs/axios": "^0.0.8",
28+
"@nestjs/common": "^8.4.6",
29+
"@nestjs/config": "^2.1.0",
30+
"@nestjs/core": "^8.4.6",
31+
"@nestjs/platform-express": "^8.4.6",
32+
"@nestjs/schedule": "^2.0.1",
3333
"@nestjs/swagger": "^5.2.1",
34-
"@polymathnetwork/hashicorp-vault-signing-manager": "^1.1.0",
35-
"@polymathnetwork/local-signing-manager": "^1.0.5",
36-
"@polymathnetwork/polymesh-sdk": "14.0.0-alpha.14",
37-
"@polymathnetwork/signing-manager-types": "^1.0.3",
38-
"class-transformer": "0.4.0",
39-
"class-validator": "0.13.1",
34+
"@polymathnetwork/hashicorp-vault-signing-manager": "1.3.0",
35+
"@polymathnetwork/local-signing-manager": "1.2.0",
36+
"@polymathnetwork/polymesh-sdk": "15.0.0-alpha.10",
37+
"@polymathnetwork/signing-manager-types": "2.0.0",
38+
"class-transformer": "0.5.1",
39+
"class-validator": "^0.13.2",
4040
"joi": "17.4.0",
4141
"json-stable-stringify": "^1.0.1",
4242
"lodash": "4.17.21",
4343
"reflect-metadata": "0.1.13",
4444
"rimraf": "3.0.2",
4545
"rxjs": "^7.5.5",
46-
"swagger-ui-express": "4.1.6"
46+
"swagger-ui-express": "4.4.0"
4747
},
4848
"devDependencies": {
4949
"@babel/plugin-transform-modules-commonjs": "7.15.0",
5050
"@commitlint/cli": "12.1.4",
5151
"@commitlint/config-conventional": "12.1.4",
52-
"@nestjs/cli": "8.2.5",
53-
"@nestjs/schematics": "^8.0.10",
54-
"@nestjs/testing": "^8.4.4",
52+
"@nestjs/cli": "^8.2.6",
53+
"@nestjs/schematics": "^8.0.11",
54+
"@nestjs/testing": "^8.4.6",
5555
"@types/axios": "^0.14.0",
5656
"@types/cron": "^1.7.3",
5757
"@types/express": "4.17.11",

β€Žsrc/accounts/accounts.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class AccountsController {
6262
'<li>Insufficient free balance</li>' +
6363
'</ul>',
6464
})
65-
@Post('transfers')
65+
@Post('transfer')
6666
async transferPolyx(@Body() params: TransferPolyxDto): Promise<TransactionQueueModel> {
6767
const { transactions } = await this.accountsService.transferPolyx(params);
6868
return new TransactionQueueModel({ transactions });

β€Žsrc/accounts/accounts.util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function createPermissionsModel(permissions: Permissions): PermissionsMod
1414
let assetPermissions: AssetPermissionsModel | null;
1515
if (assets) {
1616
const { type, values } = assets;
17-
assetPermissions = new AssetPermissionsModel({ type, values: values.map(v => v.toJson()) });
17+
assetPermissions = new AssetPermissionsModel({ type, values: values.map(v => v.toHuman()) });
1818
} else {
1919
assetPermissions = null;
2020
}

β€Žsrc/assets/assets.controller.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,36 @@ describe('AssetsController', () => {
338338
});
339339
});
340340
});
341+
342+
describe('getOperationHistory', () => {
343+
it('should call the service and return the results', async () => {
344+
const mockAgent = {
345+
did: 'Ox6'.padEnd(66, '0'),
346+
};
347+
const mockHistory = [
348+
{
349+
blockNumber: new BigNumber(123),
350+
blockHash: 'blockHash',
351+
blockDate: new Date('07/11/2022'),
352+
eventIndex: new BigNumber(1),
353+
},
354+
];
355+
const mockAgentOperations = [
356+
{
357+
identity: mockAgent,
358+
history: mockHistory,
359+
},
360+
];
361+
mockAssetsService.getOperationHistory.mockResolvedValue(mockAgentOperations);
362+
363+
const result = await controller.getOperationHistory({ ticker: 'TICKER' });
364+
365+
expect(result).toEqual([
366+
{
367+
did: mockAgent.did,
368+
history: mockHistory,
369+
},
370+
]);
371+
});
372+
});
341373
});

β€Žsrc/assets/assets.controller.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { IssueDto } from '~/assets/dto/issue.dto';
2020
import { RedeemTokensDto } from '~/assets/dto/redeem-tokens.dto';
2121
import { SetAssetDocumentsDto } from '~/assets/dto/set-asset-documents.dto';
2222
import { TickerParamsDto } from '~/assets/dto/ticker-params.dto';
23+
import { AgentOperationModel } from '~/assets/models/agent-operation.model';
2324
import { AssetDetailsModel } from '~/assets/models/asset-details.model';
2425
import { AssetDocumentModel } from '~/assets/models/asset-document.model';
2526
import { IdentityBalanceModel } from '~/assets/models/identity-balance.model';
@@ -191,7 +192,7 @@ export class AssetsController {
191192
@ApiBadRequestResponse({
192193
description: 'The supplied Document list is equal to the current one',
193194
})
194-
@Post(':ticker/set-documents')
195+
@Post(':ticker/documents/set')
195196
public async setDocuments(
196197
@Param() { ticker }: TickerParamsDto,
197198
@Body() setAssetDocumentsDto: SetAssetDocumentsDto
@@ -267,7 +268,7 @@ export class AssetsController {
267268
@ApiGoneResponse({
268269
description: 'The ticker has already been used to create an asset',
269270
})
270-
@Post('create-asset')
271+
@Post('create')
271272
public async createAsset(@Body() params: CreateAssetDto): Promise<TransactionQueueModel> {
272273
const { transactions } = await this.assetsService.createAsset(params);
273274
return new TransactionQueueModel({ transactions });
@@ -414,4 +415,29 @@ export class AssetsController {
414415
const { transactions } = await this.assetsService.controllerTransfer(ticker, params);
415416
return new TransactionQueueModel({ transactions });
416417
}
418+
419+
@ApiOperation({
420+
summary: "Fetch an Asset's operation history",
421+
description:
422+
"This endpoint provides a list of events triggered by transactions performed by various agent Identities, related to the Asset's configuration",
423+
})
424+
@ApiParam({
425+
name: 'ticker',
426+
description: 'The ticker of the Asset whose operation history is to be fetched',
427+
type: 'string',
428+
example: 'TICKER',
429+
})
430+
@ApiOkResponse({
431+
description: 'List of operations grouped by the agent Identity who performed them',
432+
isArray: true,
433+
type: AgentOperationModel,
434+
})
435+
@Get(':ticker/operations')
436+
public async getOperationHistory(
437+
@Param() { ticker }: TickerParamsDto
438+
): Promise<AgentOperationModel[]> {
439+
const agentOperations = await this.assetsService.getOperationHistory(ticker);
440+
441+
return agentOperations.map(agentOperation => new AgentOperationModel(agentOperation));
442+
}
417443
}

β€Žsrc/assets/assets.service.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,4 +633,35 @@ describe('AssetsService', () => {
633633
findSpy.mockRestore();
634634
});
635635
});
636+
637+
describe('getOperationHistory', () => {
638+
it("should return the Asset's operation history", async () => {
639+
const mockAsset = new MockAsset();
640+
641+
const findOneSpy = jest.spyOn(service, 'findOne');
642+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
643+
findOneSpy.mockResolvedValue(mockAsset as any);
644+
645+
const mockOperations = [
646+
{
647+
identity: {
648+
did: 'Ox6'.padEnd(66, '0'),
649+
},
650+
history: [
651+
{
652+
blockNumber: new BigNumber(123),
653+
blockHash: 'blockHash',
654+
blockDate: new Date('07/11/2022'),
655+
eventIndex: new BigNumber(1),
656+
},
657+
],
658+
},
659+
];
660+
mockAsset.getOperationHistory.mockResolvedValue(mockOperations);
661+
662+
const result = await service.getOperationHistory('TICKER');
663+
expect(result).toEqual(mockOperations);
664+
findOneSpy.mockRestore();
665+
});
666+
});
636667
});

β€Žsrc/assets/assets.service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
AssetDocument,
66
AuthorizationRequest,
77
ErrorCode,
8+
HistoricAgentOperation,
89
IdentityBalance,
910
ResultSet,
1011
} from '@polymathnetwork/polymesh-sdk/types';
@@ -153,4 +154,9 @@ export class AssetsService {
153154
{ signingAccount: address }
154155
);
155156
}
157+
158+
public async getOperationHistory(ticker: string): Promise<HistoricAgentOperation[]> {
159+
const asset = await this.findOne(ticker);
160+
return asset.getOperationHistory();
161+
}
156162
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* istanbul ignore file */
2+
3+
import { ApiProperty } from '@nestjs/swagger';
4+
import { HistoricAgentOperation } from '@polymathnetwork/polymesh-sdk/types';
5+
import { Type } from 'class-transformer';
6+
7+
import { EventIdentifierModel } from '~/common/models/event-identifier.model';
8+
9+
export class AgentOperationModel {
10+
@ApiProperty({
11+
description: 'DID of the Agent that performed the operations',
12+
example: '0x0600000000000000000000000000000000000000000000000000000000000000',
13+
})
14+
readonly did: string;
15+
16+
@ApiProperty({
17+
description: 'List of Asset Operation Events that were triggered by the Agent Identity',
18+
type: EventIdentifierModel,
19+
isArray: true,
20+
})
21+
@Type(() => EventIdentifierModel)
22+
readonly history: EventIdentifierModel[];
23+
24+
constructor(data: HistoricAgentOperation) {
25+
const {
26+
identity: { did },
27+
history,
28+
} = data;
29+
Object.assign(this, {
30+
did,
31+
history: history.map(eventIdentifier => new EventIdentifierModel(eventIdentifier)),
32+
});
33+
}
34+
}

β€Žsrc/checkpoints/checkpoints.controller.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Body, Controller, Delete, Get, Param, Post, Query } from '@nestjs/common';
1+
import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common';
22
import {
33
ApiBadRequestResponse,
44
ApiCreatedResponse,
@@ -256,7 +256,7 @@ export class CheckpointsController {
256256
description: 'Details of the newly created Checkpoint Schedule',
257257
type: CreatedCheckpointScheduleModel,
258258
})
259-
@Post('schedules')
259+
@Post('schedules/create')
260260
public async createSchedule(
261261
@Param() { ticker }: TickerParamsDto,
262262
@Body() createCheckpointScheduleDto: CreateCheckpointScheduleDto
@@ -400,7 +400,7 @@ export class CheckpointsController {
400400
@ApiNotFoundResponse({
401401
description: "Schedule doesn't exist. It may have expired, been removed, or never been created",
402402
})
403-
@Delete('schedules/:id')
403+
@Post('schedules/:id/delete')
404404
public async deleteSchedule(
405405
@Param() { ticker, id }: DeleteCheckpointScheduleParamsDto,
406406
@Query() { signer }: SignerDto

β€Žsrc/common/decorators/transformation.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function ToBigNumber() {
2020
* Entity -> POJO
2121
*/
2222
export function FromEntity() {
23-
return applyDecorators(Transform(({ value }: { value: Entity<unknown> }) => value?.toJson()));
23+
return applyDecorators(Transform(({ value }: { value: Entity<unknown> }) => value?.toHuman()));
2424
}
2525

2626
/**
@@ -31,7 +31,7 @@ export function FromMaybeEntityArray() {
3131
Transform(({ value }: { value: unknown[] }) =>
3232
value.map(val => {
3333
if (isEntity(val)) {
34-
return val.toJson();
34+
return val.toHuman();
3535
}
3636

3737
return val;
@@ -44,16 +44,16 @@ export function FromMaybeEntityArray() {
4444
* or serialize the value if it is an SDK Entity in
4545
*/
4646
export function FromEntityObject() {
47-
return applyDecorators(Transform(({ value }: { value: unknown }) => toJsonObject(value)));
47+
return applyDecorators(Transform(({ value }: { value: unknown }) => toHumanObject(value)));
4848
}
4949

50-
function toJsonObject(obj: unknown): unknown {
50+
function toHumanObject(obj: unknown): unknown {
5151
if (isEntity(obj)) {
52-
return obj.toJson();
52+
return obj.toHuman();
5353
}
5454

5555
if (Array.isArray(obj)) {
56-
return obj.map(toJsonObject);
56+
return obj.map(toHumanObject);
5757
}
5858

5959
if (obj instanceof BigNumber && !obj.isNaN()) {
@@ -62,7 +62,7 @@ function toJsonObject(obj: unknown): unknown {
6262

6363
if (obj && typeof obj === 'object') {
6464
// eslint-disable-next-line @typescript-eslint/no-explicit-any
65-
return mapValues(obj as any, val => toJsonObject(val));
65+
return mapValues(obj as any, val => toHumanObject(val));
6666
}
6767
return obj;
6868
}

β€Žsrc/common/dto/paginated-params.dto.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
/* istanbul ignore file */
22

33
import { BigNumber } from '@polymathnetwork/polymesh-sdk';
4-
import { IsOptional, Max, ValidateIf } from 'class-validator';
4+
import { IsOptional, ValidateIf } from 'class-validator';
55

66
import { ToBigNumber } from '~/common/decorators/transformation';
77
import { IsBigNumber } from '~/common/decorators/validation';
88

99
export class PaginatedParamsDto {
1010
@ValidateIf(({ start }: PaginatedParamsDto) => !!start)
11-
@IsBigNumber()
11+
@IsBigNumber({
12+
max: 30,
13+
})
1214
@ToBigNumber()
13-
@Max(30)
1415
readonly size: BigNumber = new BigNumber(10);
1516

1617
@IsOptional()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* istanbul ignore file */
2+
3+
import { ApiProperty } from '@nestjs/swagger';
4+
import { BigNumber } from '@polymathnetwork/polymesh-sdk';
5+
6+
import { FromBigNumber } from '~/common/decorators/transformation';
7+
8+
export class EventIdentifierModel {
9+
@ApiProperty({
10+
description: 'Number of the block where the event resides',
11+
type: 'string',
12+
example: '1000000',
13+
})
14+
@FromBigNumber()
15+
readonly blockNumber: BigNumber;
16+
17+
@ApiProperty({
18+
description: 'Hash of the block where the event resides',
19+
type: 'string',
20+
example: '0x9d05973b0bacdbf26b705358fbcb7085354b1b7836ee1cc54e824810479dccf6',
21+
})
22+
readonly blockHash: string;
23+
24+
@ApiProperty({
25+
description: 'Date when the block was finalized',
26+
type: 'string',
27+
example: new Date('10/14/1987').toISOString(),
28+
})
29+
readonly blockDate: Date;
30+
31+
@ApiProperty({
32+
description: 'Index of the event in the block',
33+
type: 'string',
34+
example: '1',
35+
})
36+
@FromBigNumber()
37+
readonly eventIndex: BigNumber;
38+
39+
constructor(model: EventIdentifierModel) {
40+
Object.assign(this, model);
41+
}
42+
}

0 commit comments

Comments
Β (0)