diff --git a/src/Polymesh.ts b/src/Polymesh.ts index 24fe0da235..c4737af5b8 100644 --- a/src/Polymesh.ts +++ b/src/Polymesh.ts @@ -1,5 +1,5 @@ import { ApiPromise, WsProvider } from '@polkadot/api'; -import { Signer } from '@polkadot/api/types'; +import { Signer as PolkadotSigner } from '@polkadot/api/types'; import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory'; import { ApolloClient, ApolloQueryResult } from 'apollo-client'; import { ApolloLink } from 'apollo-link'; @@ -34,7 +34,7 @@ import { MiddlewareConfig, NetworkProperties, ResultSet, - Signer as MeshSigner, + Signer, SignerType, SubCallback, TickerReservationStatus, @@ -48,7 +48,6 @@ import { createClaim, linkTypeToMeshLinkType, moduleAddressToString, - signatoryToSigner, signerToSignatory, stringToTicker, textToString, @@ -58,12 +57,12 @@ import { } from '~/utils'; import { Governance } from './Governance'; -import { DidRecord, Link } from './polkadot/polymesh'; +import { Link } from './polkadot/polymesh'; import { TREASURY_MODULE_ADDRESS } from './utils/constants'; interface ConnectParamsBase { nodeUrl: string; - signer?: Signer; + signer?: PolkadotSigner; middleware?: MiddlewareConfig; } @@ -738,34 +737,20 @@ export class Polymesh { * * @note can be subscribed to */ - public async getMySigningKeys(): Promise; - public async getMySigningKeys(callback: SubCallback): Promise; + public async getMySigningKeys(): Promise; + public async getMySigningKeys(callback: SubCallback): Promise; // eslint-disable-next-line require-jsdoc public async getMySigningKeys( - callback?: SubCallback - ): Promise { - const { - context: { - polymeshApi: { - query: { identity }, - }, - }, - context, - } = this; - - const { did } = context.getCurrentIdentity(); - - const assembleResult = ({ signing_items: signingItems }: DidRecord): MeshSigner[] => { - return signingItems.map(({ signer: rawSigner }) => signatoryToSigner(rawSigner)); - }; + callback?: SubCallback + ): Promise { + const { context } = this; if (callback) { - return identity.didRecords(did, records => callback(assembleResult(records))); + return context.getSigningKeys(callback); } - const didRecords = await identity.didRecords(did); - return assembleResult(didRecords); + return context.getSigningKeys(); } // TODO @monitz87: remove when the dApp team no longer needs it diff --git a/src/__tests__/Polymesh.ts b/src/__tests__/Polymesh.ts index efd8cebfac..8a35dc10cd 100644 --- a/src/__tests__/Polymesh.ts +++ b/src/__tests__/Polymesh.ts @@ -1,9 +1,9 @@ import { Keyring } from '@polkadot/api'; -import { Signer } from '@polkadot/api/types'; +import { Signer as PolkadotSigner } from '@polkadot/api/types'; import { ApolloLink, GraphQLRequest } from 'apollo-link'; import * as apolloLinkContextModule from 'apollo-link-context'; import BigNumber from 'bignumber.js'; -import { DidRecord, Signatory, TxTags } from 'polymesh-types/types'; +import { TxTags } from 'polymesh-types/types'; import sinon from 'sinon'; import { Identity, TickerReservation } from '~/api/entities'; @@ -17,6 +17,7 @@ import { AccountBalance, ClaimTargets, ClaimType, + Signer, SignerType, SubCallback, TickerReservationStatus, @@ -161,7 +162,7 @@ describe('Polymesh Class', () => { test('should set an optional signer for the polkadot API', async () => { const accountSeed = 'Alice'.padEnd(32, ' '); const createStub = dsMockUtils.getContextCreateStub(); - const signer = 'signer' as Signer; + const signer = 'signer' as PolkadotSigner; await Polymesh.connect({ nodeUrl: 'wss://some.url', @@ -1148,80 +1149,37 @@ describe('Polymesh Class', () => { }); describe('method: getMySigningKeys', () => { - const did = 'someDid'; - const accountKey = 'someAccountKey'; - const fakeResult = [ - { value: did, type: SignerType.Identity }, - { value: accountKey, type: SignerType.AccountKey }, - ]; - const signerIdentityId = dsMockUtils.createMockSignatory({ - Identity: dsMockUtils.createMockIdentityId(did), - }); - const signerAccountKey = dsMockUtils.createMockSignatory({ - AccountKey: dsMockUtils.createMockAccountKey(accountKey), - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let signatoryToSignerStub: sinon.SinonStub<[Signatory], any>; - let didRecordsStub: sinon.SinonStub; - let rawDidRecord: DidRecord; - - beforeAll(() => { - signatoryToSignerStub = sinon.stub(utilsModule, 'signatoryToSigner'); - signatoryToSignerStub.withArgs(signerIdentityId).returns(fakeResult[0]); - signatoryToSignerStub.withArgs(signerAccountKey).returns(fakeResult[1]); - }); - - beforeEach(() => { - didRecordsStub = dsMockUtils.createQueryStub('identity', 'didRecords'); - /* eslint-disable @typescript-eslint/camelcase */ - rawDidRecord = dsMockUtils.createMockDidRecord({ - roles: [], - master_key: dsMockUtils.createMockAccountKey(), - signing_items: [ - dsMockUtils.createMockSigningItem({ - signer: signerIdentityId, - signer_type: dsMockUtils.createMockSignatoryType(), - permissions: [], - }), - dsMockUtils.createMockSigningItem({ - signer: signerAccountKey, - signer_type: dsMockUtils.createMockSignatoryType(), - permissions: [], - }), - ], - }); - /* eslint-enabled @typescript-eslint/camelcase */ - }); - test('should return a list of Signers', async () => { + const fakeResult = [ + { + type: SignerType.AccountKey, + value: '0xdummy', + }, + ]; + const polymesh = await Polymesh.connect({ nodeUrl: 'wss://some.url', }); - didRecordsStub.returns(rawDidRecord); - const result = await polymesh.getMySigningKeys(); expect(result).toEqual(fakeResult); }); test('should allow subscription', async () => { - const polymesh = await Polymesh.connect({ - nodeUrl: 'wss://some.url', - }); - const unsubCallback = 'unsubCallBack'; - didRecordsStub.callsFake(async (_, cbFunc) => { - cbFunc(rawDidRecord); - return unsubCallback; + const getSigningKeysStub = dsMockUtils + .getContextInstance() + .getSigningKeys.resolves(unsubCallback); + + const polymesh = await Polymesh.connect({ + nodeUrl: 'wss://some.url', }); - const callback = sinon.stub(); + const callback = (() => [] as unknown) as SubCallback; const result = await polymesh.getMySigningKeys(callback); - - expect(result).toBe(unsubCallback); - sinon.assert.calledWithExactly(callback, fakeResult); + expect(result).toEqual(unsubCallback); + sinon.assert.calledWithExactly(getSigningKeysStub, callback); }); }); diff --git a/src/context/__tests__/index.ts b/src/context/__tests__/index.ts index 4cea9b2519..26a2f3b085 100644 --- a/src/context/__tests__/index.ts +++ b/src/context/__tests__/index.ts @@ -1,12 +1,12 @@ import BigNumber from 'bignumber.js'; -import { ProtocolOp, TxTags } from 'polymesh-types/types'; +import { DidRecord, ProtocolOp, Signatory, TxTags } from 'polymesh-types/types'; import sinon from 'sinon'; import { Identity } from '~/api/entities'; import { Context } from '~/context'; import { dsMockUtils } from '~/testUtils/mocks'; import { createMockAccountKey } from '~/testUtils/mocks/dataSources'; -import { TransactionArgumentType } from '~/types'; +import { SignerType, TransactionArgumentType } from '~/types'; import * as utilsModule from '~/utils'; jest.mock( @@ -721,6 +721,96 @@ describe('Context class', () => { }); }); + describe('method: getSigningKeys', () => { + const did = 'someDid'; + const accountKey = 'someAccountKey'; + const fakeResult = [ + { value: did, type: SignerType.Identity }, + { value: accountKey, type: SignerType.AccountKey }, + ]; + const signerIdentityId = dsMockUtils.createMockSignatory({ + Identity: dsMockUtils.createMockIdentityId(did), + }); + const signerAccountKey = dsMockUtils.createMockSignatory({ + AccountKey: dsMockUtils.createMockAccountKey(accountKey), + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let signatoryToSignerStub: sinon.SinonStub<[Signatory], any>; + let didRecordsStub: sinon.SinonStub; + let rawDidRecord: DidRecord; + + beforeAll(() => { + signatoryToSignerStub = sinon.stub(utilsModule, 'signatoryToSigner'); + signatoryToSignerStub.withArgs(signerIdentityId).returns(fakeResult[0]); + signatoryToSignerStub.withArgs(signerAccountKey).returns(fakeResult[1]); + }); + + beforeEach(() => { + didRecordsStub = dsMockUtils.createQueryStub('identity', 'didRecords'); + /* eslint-disable @typescript-eslint/camelcase */ + rawDidRecord = dsMockUtils.createMockDidRecord({ + roles: [], + master_key: dsMockUtils.createMockAccountKey(), + signing_items: [ + dsMockUtils.createMockSigningItem({ + signer: signerIdentityId, + signer_type: dsMockUtils.createMockSignatoryType(), + permissions: [], + }), + dsMockUtils.createMockSigningItem({ + signer: signerAccountKey, + signer_type: dsMockUtils.createMockSignatoryType(), + permissions: [], + }), + ], + }); + /* eslint-enabled @typescript-eslint/camelcase */ + + dsMockUtils.createQueryStub('identity', 'keyToIdentityIds', { + returnValue: dsMockUtils.createMockOption( + dsMockUtils.createMockLinkedKeyInfo({ + Unique: dsMockUtils.createMockIdentityId('someDid'), + }) + ), + }); + }); + + test('should return a list of Signers', async () => { + const context = await Context.create({ + polymeshApi: dsMockUtils.getApiInstance(), + middlewareApi: dsMockUtils.getMiddlewareApi(), + seed: 'Alice'.padEnd(32, ' '), + }); + + didRecordsStub.returns(rawDidRecord); + + const result = await context.getSigningKeys(); + expect(result).toEqual(fakeResult); + }); + + test('should allow subscription', async () => { + const context = await Context.create({ + polymeshApi: dsMockUtils.getApiInstance(), + middlewareApi: dsMockUtils.getMiddlewareApi(), + seed: 'Alice'.padEnd(32, ' '), + }); + + const unsubCallback = 'unsubCallBack'; + + didRecordsStub.callsFake(async (_, cbFunc) => { + cbFunc(rawDidRecord); + return unsubCallback; + }); + + const callback = sinon.stub(); + const result = await context.getSigningKeys(callback); + + expect(result).toBe(unsubCallback); + sinon.assert.calledWithExactly(callback, fakeResult); + }); + }); + describe('method: getTransactionArguments', () => { test('should return a representation of the arguments of a transaction', async () => { const pair = { diff --git a/src/context/index.ts b/src/context/index.ts index 885f60673b..91fc885609 100644 --- a/src/context/index.ts +++ b/src/context/index.ts @@ -19,6 +19,7 @@ import { ErrorCode, KeyringPair, PlainTransactionArgument, + Signer, SimpleEnumTransactionArgument, SubCallback, TransactionArgument, @@ -29,6 +30,7 @@ import { balanceToBigNumber, identityIdToString, posRatioToBigNumber, + signatoryToSigner, stringToAccountKey, stringToIdentityId, textToString, @@ -514,6 +516,36 @@ export class Context { }); } + /** + * Retrieve the list of signing keys related to the account + * + * @note can be subscribed to + */ + public async getSigningKeys(): Promise; + public async getSigningKeys(callback: SubCallback): Promise; + + // eslint-disable-next-line require-jsdoc + public async getSigningKeys(callback?: SubCallback): Promise { + const { + polymeshApi: { + query: { identity }, + }, + } = this; + + const { did } = this.getCurrentIdentity(); + + const assembleResult = ({ signing_items: signingItems }: DidRecord): Signer[] => { + return signingItems.map(({ signer: rawSigner }) => signatoryToSigner(rawSigner)); + }; + + if (callback) { + return identity.didRecords(did, records => callback(assembleResult(records))); + } + + const didRecords = await identity.didRecords(did); + return assembleResult(didRecords); + } + /** * Retrieve the middleware client * diff --git a/src/testUtils/mocks/dataSources.ts b/src/testUtils/mocks/dataSources.ts index da9cfa8ff3..1b66609c24 100644 --- a/src/testUtils/mocks/dataSources.ts +++ b/src/testUtils/mocks/dataSources.ts @@ -72,7 +72,7 @@ import sinon, { SinonStub, SinonStubbedInstance } from 'sinon'; import { Context } from '~/context'; import { Mocked } from '~/testUtils/types'; -import { AccountBalance, KeyringPair } from '~/types'; +import { AccountBalance, KeyringPair, SignerType } from '~/types'; import { Extrinsics, GraphqlQuery, PolymeshTx, Queries } from '~/types/internal'; import { Mutable } from '~/types/utils'; @@ -400,6 +400,16 @@ function configureContext(opts: ContextOptions): void { getInvalidDids: sinon.stub().resolves(opts.invalidDids), getTransactionFees: sinon.stub().resolves(opts.transactionFee), getTransactionArguments: sinon.stub().returns([]), + getSigningKeys: sinon.stub().returns( + opts.withSeed + ? [ + { + type: SignerType.AccountKey, + value: opts.currentPairAddress, + }, + ] + : [] + ), } as unknown) as MockContext; Object.assign(mockInstanceContainer.contextInstance, contextInstance);