From 3aa040afdd08464ade7c7db8d2b95b82f05b84cc Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 7 Apr 2021 15:32:14 -0300 Subject: [PATCH] fix: add support for new investor uniquenes claim v2 --- src/Claims.ts | 2 +- .../__tests__/addInvestorUniquenessClaim.ts | 44 ++++++++++++++----- .../procedures/addInvestorUniquenessClaim.ts | 11 +++-- src/base/Context.ts | 4 +- src/testUtils/mocks/dataSources.ts | 1 + src/types/index.ts | 15 ++++++- src/utils/__tests__/conversion.ts | 26 +++++++++++ src/utils/conversion.ts | 11 +++++ 8 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/Claims.ts b/src/Claims.ts index 3317258175..cc71f30ac8 100644 --- a/src/Claims.ts +++ b/src/Claims.ts @@ -181,7 +181,7 @@ export class Claims { targets?: (string | Identity)[]; trustedClaimIssuers?: (string | Identity)[]; scope?: Scope; - claimTypes?: ClaimType[]; + claimTypes?: Exclude[]; includeExpired?: boolean; size?: number; start?: number; diff --git a/src/api/procedures/__tests__/addInvestorUniquenessClaim.ts b/src/api/procedures/__tests__/addInvestorUniquenessClaim.ts index 092bbac7cd..5777f7fa5a 100644 --- a/src/api/procedures/__tests__/addInvestorUniquenessClaim.ts +++ b/src/api/procedures/__tests__/addInvestorUniquenessClaim.ts @@ -3,6 +3,7 @@ import { IdentityId, InvestorZKProofData, Moment, + Scope as MeshScope, ScopeClaimProof as MeshScopeClaimProof, ScopeId, Ticker, @@ -18,7 +19,7 @@ import { import { Context } from '~/internal'; import { dsMockUtils, entityMockUtils, procedureMockUtils } from '~/testUtils/mocks'; import { Mocked } from '~/testUtils/types'; -import { Claim, ClaimType, ScopeType } from '~/types'; +import { Claim, ClaimType, Scope, ScopeType } from '~/types'; import { ScopeClaimProof } from '~/types/internal'; import * as utilsConversionModule from '~/utils/conversion'; @@ -27,6 +28,7 @@ describe('addInvestorUniquenessClaim procedure', () => { let did: string; let ticker: string; let cddId: string; + let scope: Scope; let scopeId: string; let proof: string; let proofScopeIdWellformed: string; @@ -43,12 +45,15 @@ describe('addInvestorUniquenessClaim procedure', () => { [ScopeClaimProof, string, Context], MeshScopeClaimProof >; + let scopeToMeshScopeStub: sinon.SinonStub<[Scope, Context], MeshScope>; let stringToScopeIdStub: sinon.SinonStub<[string, Context], ScopeId>; let dateToMomentStub: sinon.SinonStub<[Date, Context], Moment>; let rawDid: IdentityId; let rawTicker: Ticker; + let rawScope: MeshScope; let rawScopeId: ScopeId; let rawClaim: MeshClaim; + let rawClaimV2: MeshClaim; let rawProof: InvestorZKProofData; let rawScopeClaimProof: MeshScopeClaimProof; let rawExpiry: Moment; @@ -62,6 +67,7 @@ describe('addInvestorUniquenessClaim procedure', () => { ticker = 'SOME_TOKEN'; cddId = 'someCddId'; + scope = { type: ScopeType.Ticker, value: ticker }; scopeId = 'someScopeId'; proof = 'someProof'; proofScopeIdWellformed = 'someProofScopeIdWellformed'; @@ -91,7 +97,7 @@ describe('addInvestorUniquenessClaim procedure', () => { ); dateToMomentStub = sinon.stub(utilsConversionModule, 'dateToMoment'); stringToScopeIdStub = sinon.stub(utilsConversionModule, 'stringToScopeId'); - + scopeToMeshScopeStub = sinon.stub(utilsConversionModule, 'scopeToMeshScope'); rawDid = dsMockUtils.createMockIdentityId(did); rawTicker = dsMockUtils.createMockTicker(ticker); rawClaim = dsMockUtils.createMockClaim({ @@ -101,6 +107,10 @@ describe('addInvestorUniquenessClaim procedure', () => { dsMockUtils.createMockCddId(cddId), ], }); + rawClaimV2 = dsMockUtils.createMockClaim({ + InvestorUniquenessV2: dsMockUtils.createMockCddId(cddId), + }); + rawScope = dsMockUtils.createMockScope({ Ticker: rawTicker }); rawScopeId = dsMockUtils.createMockScopeId(scopeId); rawProof = dsMockUtils.createMockInvestorZKProofData(proof); rawScopeClaimProof = dsMockUtils.createMockScopeClaimProof({ @@ -126,19 +136,29 @@ describe('addInvestorUniquenessClaim procedure', () => { .withArgs( { type: ClaimType.InvestorUniqueness, - scope: { type: ScopeType.Ticker, value: ticker }, + scope, cddId, scopeId, }, mockContext ) .returns(rawClaim); + claimToMeshClaimStub + .withArgs( + { + type: ClaimType.InvestorUniquenessV2, + cddId, + }, + mockContext + ) + .returns(rawClaimV2); stringToInvestorZKProofDataStub.withArgs(proof, mockContext).returns(rawProof); scopeClaimProofToMeshScopeClaimProofStub .withArgs(scopeClaimProof, scopeId, mockContext) .returns(rawScopeClaimProof); dateToMomentStub.withArgs(expiry, mockContext).returns(rawExpiry); stringToScopeIdStub.withArgs(scopeId, mockContext).returns(rawScopeId); + scopeToMeshScopeStub.withArgs(scope, mockContext).returns(rawScope); }); afterEach(() => { @@ -163,7 +183,7 @@ describe('addInvestorUniquenessClaim procedure', () => { ); await prepareAddInvestorUniquenessClaim.call(proc, { - scope: { type: ScopeType.Ticker, value: ticker }, + scope, proof, cddId, scopeId, @@ -181,7 +201,7 @@ describe('addInvestorUniquenessClaim procedure', () => { ); await prepareAddInvestorUniquenessClaim.call(proc, { - scope: { type: ScopeType.Ticker, value: ticker }, + scope, proof, cddId, scopeId, @@ -208,7 +228,7 @@ describe('addInvestorUniquenessClaim procedure', () => { ); await prepareAddInvestorUniquenessClaim.call(proc, { - scope: { type: ScopeType.Ticker, value: ticker }, + scope, proof: scopeClaimProof, cddId, scopeId, @@ -220,13 +240,14 @@ describe('addInvestorUniquenessClaim procedure', () => { addInvestorUniquenessClaimV2Transaction, {}, rawDid, - rawClaim, + rawScope, + rawClaimV2, rawScopeClaimProof, rawExpiry ); await prepareAddInvestorUniquenessClaim.call(proc, { - scope: { type: ScopeType.Ticker, value: ticker }, + scope, proof: scopeClaimProof, cddId, scopeId, @@ -237,7 +258,8 @@ describe('addInvestorUniquenessClaim procedure', () => { addInvestorUniquenessClaimV2Transaction, {}, rawDid, - rawClaim, + rawScope, + rawClaimV2, rawScopeClaimProof, null ); @@ -245,7 +267,7 @@ describe('addInvestorUniquenessClaim procedure', () => { test('should throw an error if the expiry date is in the past', async () => { const commonArgs = { - scope: { type: ScopeType.Ticker, value: ticker }, + scope, cddId, scopeId, expiry: new Date('10/14/1987'), @@ -267,7 +289,7 @@ describe('addInvestorUniquenessClaim procedure', () => { describe('getAuthorization', () => { test('should return the appropriate roles and permissions', () => { const commonArgs = { - scope: { type: ScopeType.Ticker, value: ticker }, + scope, cddId, scopeId, }; diff --git a/src/api/procedures/addInvestorUniquenessClaim.ts b/src/api/procedures/addInvestorUniquenessClaim.ts index 93edb17508..81f58b016c 100644 --- a/src/api/procedures/addInvestorUniquenessClaim.ts +++ b/src/api/procedures/addInvestorUniquenessClaim.ts @@ -6,6 +6,7 @@ import { claimToMeshClaim, dateToMoment, scopeClaimProofToMeshScopeClaimProof, + scopeToMeshScope, stringToIdentityId, stringToInvestorZKProofData, } from '~/utils/conversion'; @@ -43,12 +44,12 @@ export async function prepareAddInvestorUniquenessClaim( } const meshIdentityId = stringToIdentityId(did, context); - const meshClaim = claimToMeshClaim( - { type: ClaimType.InvestorUniqueness, scope, cddId, scopeId }, - context - ); const meshExpiry = expiry ? dateToMoment(expiry, context) : null; if (typeof proof === 'string') { + const meshClaim = claimToMeshClaim( + { type: ClaimType.InvestorUniqueness, scope, cddId, scopeId }, + context + ); this.addTransaction( tx.identity.addInvestorUniquenessClaim, {}, @@ -58,10 +59,12 @@ export async function prepareAddInvestorUniquenessClaim( meshExpiry ); } else { + const meshClaim = claimToMeshClaim({ type: ClaimType.InvestorUniquenessV2, cddId }, context); this.addTransaction( tx.identity.addInvestorUniquenessClaimV2, {}, meshIdentityId, + scopeToMeshScope(scope, context), meshClaim, scopeClaimProofToMeshScopeClaimProof(proof, scopeId, context), meshExpiry diff --git a/src/base/Context.ts b/src/base/Context.ts index 2069b9444e..c72fb8b94f 100644 --- a/src/base/Context.ts +++ b/src/base/Context.ts @@ -671,7 +671,7 @@ export class Context { public async getIdentityClaimsFromMiddleware(args: { targets?: (string | Identity)[]; trustedClaimIssuers?: (string | Identity)[]; - claimTypes?: ClaimType[]; + claimTypes?: Exclude[]; includeExpired?: boolean; size?: number; start?: number; @@ -747,7 +747,7 @@ export class Context { opts: { targets?: (string | Identity)[]; trustedClaimIssuers?: (string | Identity)[]; - claimTypes?: ClaimType[]; + claimTypes?: Exclude[]; includeExpired?: boolean; size?: number; start?: number; diff --git a/src/testUtils/mocks/dataSources.ts b/src/testUtils/mocks/dataSources.ts index 2b3516eaa1..e85f9bb229 100644 --- a/src/testUtils/mocks/dataSources.ts +++ b/src/testUtils/mocks/dataSources.ts @@ -1966,6 +1966,7 @@ export const createMockClaim = ( | { Exempted: Scope } | { Blocked: Scope } | { InvestorUniqueness: [Scope, ScopeId, CddId] } + | { InvestorUniquenessV2: CddId } | 'NoData' ): Claim => createMockEnum(claim) as Claim; diff --git a/src/types/index.ts b/src/types/index.ts index ec26547f98..75f4f9ef2a 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -292,6 +292,7 @@ export enum ClaimType { Blocked = 'Blocked', InvestorUniqueness = 'InvestorUniqueness', NoData = 'NoData', + InvestorUniquenessV2 = 'InvestorUniquenessV2', } export type CddClaim = { type: ClaimType.CustomerDueDiligence; id: string }; @@ -303,6 +304,11 @@ export type InvestorUniquenessClaim = { scopeId: string; }; +export type InvestorUniquenessV2Claim = { + type: ClaimType.InvestorUniquenessV2; + cddId: string; +}; + export type ScopedClaim = | { type: ClaimType.Jurisdiction; code: CountryCode; scope: Scope } | InvestorUniquenessClaim @@ -313,11 +319,12 @@ export type ScopedClaim = | ClaimType.Jurisdiction | ClaimType.CustomerDueDiligence | ClaimType.InvestorUniqueness + | ClaimType.InvestorUniquenessV2 >; scope: Scope; }; -export type UnscopedClaim = { type: ClaimType.NoData } | CddClaim; +export type UnscopedClaim = { type: ClaimType.NoData } | CddClaim | InvestorUniquenessV2Claim; export type Claim = ScopedClaim | UnscopedClaim; @@ -327,7 +334,11 @@ export type Claim = ScopedClaim | UnscopedClaim; export function isScopedClaim(claim: Claim): claim is ScopedClaim { const { type } = claim; - return ![ClaimType.NoData, ClaimType.CustomerDueDiligence].includes(type); + return ![ + ClaimType.NoData, + ClaimType.CustomerDueDiligence, + ClaimType.InvestorUniquenessV2, + ].includes(type); } /** diff --git a/src/utils/__tests__/conversion.ts b/src/utils/__tests__/conversion.ts index bbc5b44ea1..c892860b46 100644 --- a/src/utils/__tests__/conversion.ts +++ b/src/utils/__tests__/conversion.ts @@ -2367,6 +2367,21 @@ describe('claimToMeshClaim and meshClaimToClaim', () => { result = claimToMeshClaim(value, context); expect(result).toBe(fakeResult); + + value = { + type: ClaimType.InvestorUniquenessV2, + cddId: 'someCddId', + }; + + createTypeStub + .withArgs('Claim', { + [value.type]: [stringToCddId(value.cddId, context)], + }) + .returns(fakeResult); + + result = claimToMeshClaim(value, context); + + expect(result).toBe(fakeResult); }); test('meshClaimToClaim should convert a polkadot Claim object to a Claim', () => { @@ -2517,6 +2532,17 @@ describe('claimToMeshClaim and meshClaimToClaim', () => { result = meshClaimToClaim(claim); expect(result).toEqual(fakeResult); + + fakeResult = { + type: ClaimType.InvestorUniquenessV2, + cddId: 'cddId', + }; + claim = dsMockUtils.createMockClaim({ + InvestorUniquenessV2: dsMockUtils.createMockCddId(fakeResult.cddId), + }); + + result = meshClaimToClaim(claim); + expect(result).toEqual(fakeResult); }); }); diff --git a/src/utils/conversion.ts b/src/utils/conversion.ts index 941cba4ec5..9088a927df 100644 --- a/src/utils/conversion.ts +++ b/src/utils/conversion.ts @@ -1504,6 +1504,10 @@ export function claimToMeshClaim(claim: Claim, context: Context): MeshClaim { ); break; } + case ClaimType.InvestorUniquenessV2: { + value = tuple(stringToCddId(claim.cddId, context)); + break; + } default: { value = scopeToMeshScope(claim.scope, context); } @@ -1621,6 +1625,13 @@ export function meshClaimToClaim(claim: MeshClaim): Claim { }; } + if (claim.isInvestorUniquenessV2) { + return { + type: ClaimType.InvestorUniquenessV2, + cddId: cddIdToString(claim.asInvestorUniquenessV2), + }; + } + return { type: ClaimType.Blocked, scope: meshScopeToScope(claim.asBlocked),