Skip to content

Commit

Permalink
Merge pull request #176 from PolymeshAssociation/alpha
Browse files Browse the repository at this point in the history
Release latest changes
  • Loading branch information
VictorVicente authored Feb 8, 2023
2 parents 755c99c + 041fed1 commit 8f14d88
Show file tree
Hide file tree
Showing 55 changed files with 2,691 additions and 255 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

A REST API wrapper for the Polymesh blockchain.

This version is compatible with chain versions 5.0.x
This version is compatible with chain versions 5.1.x

## Setup

Expand Down Expand Up @@ -61,16 +61,25 @@ $ yarn test:cov
```bash
PORT=## port in which the server will listen. Defaults to 3000 ##
POLYMESH_NODE_URL=## websocket URL for a Polymesh node ##
POLYMESH_MIDDLEWARE_URL=## URL for an instance of the Polymesh GraphQL Middleware service ##
POLYMESH_MIDDLEWARE_V2_URL=## URL for an instance of the Polymesh GraphQL Middleware Native SubQuery service ##
POLYMESH_MIDDLEWARE_URL=## URL for an instance of the Polymesh GraphQL Middleware service @deprecated in favour of POLYMESH_MIDDLEWARE_V2_URL##
POLYMESH_MIDDLEWARE_API_KEY=## API key for the Middleware GraphQL service ##
LOCAL_SIGNERS=## list of comma separated IDs to refer to the corresponding mnemonic ##
LOCAL_MNEMONICS=## list of comma separated mnemonics for the signer service (each mnemonic corresponds to a signer in LOCAL_SIGNERS) ##

# Below are optional params that enable some features. The above should be good to get started with

DEVELOPER_SUDO_MNEMONIC=## a mnemonic that has `sudo` privileges for a chain. Defaults to `//Alice` ##
DEVELOPER_UTILS=## set to `true` to enable developer testing endpoints ##

# Vault Signer:
VAULT_URL=## The URL of a Vault transit engine##
VAULT_TOKEN=## The access token for authorization with the Vault instance ##

# Fireblocks Signer:
FIREBLOCKS_URL=## The fireblocks URL ##
FIREBLOCKS_API_KEY=## The API Key to use ##
FIREBLOCKS_SECRET_PATH=## Path to secret file to sign requests with ##
# Webhooks:
SUBSCRIPTIONS_TTL=## Amount of milliseconds before a subscription is considered expired ##
SUBSCRIPTIONS_MAX_HANDSHAKE_TRIES=## Amount of attempts to activate a subscription via handshake before it is considered rejected ##
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"scripts": {
"nest": "nest",
"prepare": "husky install",
"dedupe": "npx yarn-deduplicate yarn.lock",
"prebuild": "rimraf dist",
"postinstall": "rimraf node_modules/@polymeshassociation/polymesh-sdk/node_modules/@polkadot/{util-crypto,wasm-crypto,util,wasm-bridge} && rimraf node_modules/@polymeshassociation/{hashicorp-vault-signing-manager,fireblocks-signing-manager}/node_modules/@polkadot/{util,util-crypto,wasm-bridge}",
"build": "nest build",
Expand Down Expand Up @@ -43,11 +44,11 @@
"@nestjs/schedule": "^2.1.0",
"@nestjs/swagger": "^6.1.3",
"@nestjs/typeorm": "^9.0.1",
"@polymeshassociation/fireblocks-signing-manager": "1.0.0",
"@polymeshassociation/hashicorp-vault-signing-manager": "1.1.1",
"@polymeshassociation/local-signing-manager": "1.2.0",
"@polymeshassociation/polymesh-sdk": "19.0.0-beta.3",
"@polymeshassociation/signing-manager-types": "1.0.0",
"@polymeshassociation/fireblocks-signing-manager": "^1.0.3",
"@polymeshassociation/hashicorp-vault-signing-manager": "^1.1.6",
"@polymeshassociation/local-signing-manager": "^1.3.0",
"@polymeshassociation/polymesh-sdk": "19.0.0-beta.5",
"@polymeshassociation/signing-manager-types": "^1.2.1",
"class-transformer": "0.5.1",
"class-validator": "^0.13.2",
"joi": "17.4.0",
Expand Down
1 change: 1 addition & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { UsersModule } from '~/users/users.module';
LOCAL_MNEMONICS: Joi.string().allow(''),
VAULT_TOKEN: Joi.string().allow(''),
VAULT_URL: Joi.string().allow(''),
DEVELOPER_SUDO_MNEMONIC: Joi.string().default('//Alice'),
DEVELOPER_UTILS: Joi.bool().default(false),
API_KEYS: Joi.string().default(''),
AUTH_STRATEGY: Joi.string().default(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/auth/auth.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const createAuthGuard = (rawStrategy: string): IAuthGuard => {
*
* @throws if given invalid values
*/
const parseAuthStrategyConfig = (rawStrategyConfig: string): AuthStrategy[] => {
export const parseAuthStrategyConfig = (rawStrategyConfig: string): AuthStrategy[] => {
const givenStrategies = rawStrategyConfig.split(',').map(strategy => strategy.trim());

const filteredStrategies = givenStrategies.filter(isStrategyKey);
Expand Down
20 changes: 19 additions & 1 deletion src/claims/claims.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DeepMocked } from '@golevelup/ts-jest';
import { Test } from '@nestjs/testing';
import { ClaimType } from '@polymeshassociation/polymesh-sdk/types';
import { ClaimType, ScopeType } from '@polymeshassociation/polymesh-sdk/types';

import { ClaimsController } from '~/claims/claims.controller';
import { ClaimsService } from '~/claims/claims.service';
Expand Down Expand Up @@ -76,4 +76,22 @@ describe('ClaimsController', () => {
expect(result).toEqual({ ...txResult, results: undefined });
});
});

describe('addInvestorUniqueness', () => {
it('should call addInvestorUniqueness method and return transaction data', async () => {
mockClaimsService.addInvestorUniqueness.mockResolvedValue({ ...txResult, result: undefined });
const mockArgs = {
scope: { type: ScopeType.Identity, value: did },
cddId: '0x1',
proof: 'proof',
scopeId: 'id',
signer,
};
const result = await controller.addInvestorUniqueness(mockArgs);

expect(mockClaimsService.addInvestorUniqueness).toHaveBeenCalledWith(mockArgs);

expect(result).toEqual({ ...txResult, results: undefined });
});
});
});
21 changes: 21 additions & 0 deletions src/claims/claims.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Body, Controller, HttpStatus, Post } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';

import { ClaimsService } from '~/claims/claims.service';
import { AddInvestorUniquenessDto } from '~/claims/dto/add-investor-uniqueness.dto';
import { ModifyClaimsDto } from '~/claims/dto/modify-claims.dto';
import { ApiTransactionFailedResponse, ApiTransactionResponse } from '~/common/decorators/swagger';
import { TransactionQueueModel } from '~/common/models/transaction-queue.model';
Expand Down Expand Up @@ -77,4 +78,24 @@ export class ClaimsController {

return handleServiceResult(serviceResult);
}

@ApiOperation({
summary: 'Add Investor uniqueness Claims to the signing Identity',
description: 'This endpoint will add Investor uniqueness Claims to the signing Identity',
})
@ApiTransactionResponse({
description: 'Transaction response',
type: TransactionQueueModel,
})
@ApiTransactionFailedResponse({
[HttpStatus.UNPROCESSABLE_ENTITY]: ['Account does not have the required roles or permissions'],
})
@Post('add-investor-uniqueness')
async addInvestorUniqueness(
@Body() args: AddInvestorUniquenessDto
): Promise<TransactionResponseModel> {
const serviceResult = await this.claimsService.addInvestorUniqueness(args);

return handleServiceResult(serviceResult);
}
}
120 changes: 118 additions & 2 deletions src/claims/claims.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Test, TestingModule } from '@nestjs/testing';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';
import { ClaimData, ClaimType, ResultSet, TxTags } from '@polymeshassociation/polymesh-sdk/types';
import {
ClaimData,
ClaimType,
ResultSet,
ScopeType,
TxTags,
} from '@polymeshassociation/polymesh-sdk/types';

import { ClaimsService } from '~/claims/claims.service';
import { POLYMESH_API } from '~/polymesh/polymesh.consts';
Expand All @@ -16,7 +22,7 @@ describe('ClaimsService', () => {
let polymeshService: PolymeshService;
let mockTransactionsService: MockTransactionsService;

const { did, signer } = testValues;
const { did, signer, ticker } = testValues;

const mockModifyClaimsArgs = {
claims: [
Expand Down Expand Up @@ -181,4 +187,114 @@ describe('ClaimsService', () => {
);
});
});

describe('findCddClaimsByDid', () => {
const date = new Date().toISOString();
const mockCddClaims = [
{
target: did,
issuer: did,
issuedAt: date,
expiry: date,
claim: {
type: 'Accredited',
scope: {
type: 'Identity',
value: did,
},
},
},
];

it('should return a list of CDD Claims for given DID', async () => {
mockPolymeshApi.claims.getCddClaims.mockResolvedValue(mockCddClaims);

const result = await claimsService.findCddClaimsByDid(did);

expect(result).toBe(mockCddClaims);

expect(mockPolymeshApi.claims.getCddClaims).toHaveBeenCalledWith({
target: did,
includeExpired: true,
});
});

it('should return a list of CDD Claims for given DID without including expired claims', async () => {
mockPolymeshApi.claims.getCddClaims.mockResolvedValue(mockCddClaims);

const result = await claimsService.findCddClaimsByDid(did, false);

expect(result).toBe(mockCddClaims);

expect(mockPolymeshApi.claims.getCddClaims).toHaveBeenCalledWith({
target: did,
includeExpired: false,
});
});
});

describe('findClaimScopesByDid', () => {
it('should return claim scopes for the target identity', async () => {
const mockClaims = [
{
ticker,
scope: {
type: 'Identity',
value: '0x9'.padEnd(66, '1'),
},
},
];

mockPolymeshApi.claims.getClaimScopes.mockResolvedValue(mockClaims);

const result = await claimsService.findClaimScopesByDid(did);

expect(result).toBe(mockClaims);

expect(mockPolymeshApi.claims.getClaimScopes).toHaveBeenCalledWith({ target: did });
});
});

describe('addInvestorUniqueness', () => {
it('should run a addInvestorUniquenessClaim procedure and return the queue results', async () => {
const mockTransactions = {
blockHash: '0x1',
txHash: '0x2',
blockNumber: new BigNumber(1),
tag: TxTags.identity.AddInvestorUniquenessClaim,
};

const mockArgs = {
scope: { type: ScopeType.Identity, value: did },
cddId: '0x1',
proof: 'proof',
scopeId: 'id',
};
const mockTransaction = new MockTransaction(mockTransactions);

mockTransactionsService.submit.mockResolvedValue(mockTransaction);

const result = await claimsService.addInvestorUniqueness({ signer, ...mockArgs });

expect(result).toBe(mockTransaction);

expect(mockTransactionsService.submit).toHaveBeenCalledWith(
mockPolymeshApi.claims.addInvestorUniquenessClaim,
mockArgs,
{ signer }
);
});
});

describe('getInvestorUniqueness', () => {
it('should run a getInvestorUniquenessClaims procedure and return the result', async () => {
const claimsResult = [] as ClaimData[];

mockPolymeshApi.claims.getInvestorUniquenessClaims.mockResolvedValue(claimsResult);

const result = await claimsService.getInvestorUniquenessClaims(did, true);

expect(result).toBe(claimsResult);
});
});
});
45 changes: 45 additions & 0 deletions src/claims/claims.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import { Injectable } from '@nestjs/common';
import { BigNumber } from '@polymeshassociation/polymesh-sdk';
import {
AddClaimsParams,
AddInvestorUniquenessClaimParams,
CddClaim,
ClaimData,
ClaimScope,
ClaimType,
InvestorUniquenessClaim,
ModifyClaimsParams,
ResultSet,
RevokeClaimsParams,
Scope,
} from '@polymeshassociation/polymesh-sdk/types';

import { AddInvestorUniquenessDto } from '~/claims/dto/add-investor-uniqueness.dto';
import { ModifyClaimsDto } from '~/claims/dto/modify-claims.dto';
import { extractTxBase, ServiceReturn } from '~/common/utils';
import { PolymeshService } from '~/polymesh/polymesh.service';
Expand Down Expand Up @@ -83,4 +88,44 @@ export class ClaimsService {

return this.transactionsService.submit(revokeClaims, args as RevokeClaimsParams, base);
}

public async findClaimScopesByDid(target: string): Promise<ClaimScope[]> {
return this.polymeshService.polymeshApi.claims.getClaimScopes({
target,
});
}

public async addInvestorUniqueness(
modifyClaimsDto: AddInvestorUniquenessDto
): ServiceReturn<void> {
const { base, args } = extractTxBase(modifyClaimsDto);

const { addInvestorUniquenessClaim } = this.polymeshService.polymeshApi.claims;

return this.transactionsService.submit(
addInvestorUniquenessClaim,
args as AddInvestorUniquenessClaimParams,
base
);
}

public async findCddClaimsByDid(
target: string,
includeExpired = true
): Promise<ClaimData<CddClaim>[]> {
return await this.polymeshService.polymeshApi.claims.getCddClaims({
target,
includeExpired,
});
}

public async getInvestorUniquenessClaims(
target: string,
includeExpired = true
): Promise<ClaimData<InvestorUniquenessClaim>[]> {
return await this.polymeshService.polymeshApi.claims.getInvestorUniquenessClaims({
target,
includeExpired,
});
}
}
Loading

0 comments on commit 8f14d88

Please sign in to comment.