Skip to content

Commit

Permalink
fix: move getMySigningKeys to context
Browse files Browse the repository at this point in the history
  • Loading branch information
shuffledex committed Aug 10, 2020
1 parent b0850cd commit c178ca6
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 91 deletions.
37 changes: 11 additions & 26 deletions 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';
Expand Down Expand Up @@ -34,7 +34,7 @@ import {
MiddlewareConfig,
NetworkProperties,
ResultSet,
Signer as MeshSigner,
Signer,
SignerType,
SubCallback,
TickerReservationStatus,
Expand All @@ -48,7 +48,6 @@ import {
createClaim,
linkTypeToMeshLinkType,
moduleAddressToString,
signatoryToSigner,
signerToSignatory,
stringToTicker,
textToString,
Expand All @@ -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;
}

Expand Down Expand Up @@ -738,34 +737,20 @@ export class Polymesh {
*
* @note can be subscribed to
*/
public async getMySigningKeys(): Promise<MeshSigner[]>;
public async getMySigningKeys(callback: SubCallback<MeshSigner[]>): Promise<UnsubCallback>;
public async getMySigningKeys(): Promise<Signer[]>;
public async getMySigningKeys(callback: SubCallback<Signer[]>): Promise<UnsubCallback>;

// eslint-disable-next-line require-jsdoc
public async getMySigningKeys(
callback?: SubCallback<MeshSigner[]>
): Promise<MeshSigner[] | UnsubCallback> {
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<Signer[]>
): Promise<Signer[] | UnsubCallback> {
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
Expand Down
82 changes: 20 additions & 62 deletions 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';
Expand All @@ -17,6 +17,7 @@ import {
AccountBalance,
ClaimTargets,
ClaimType,
Signer,
SignerType,
SubCallback,
TickerReservationStatus,
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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<Signer[]>;
const result = await polymesh.getMySigningKeys(callback);

expect(result).toBe(unsubCallback);
sinon.assert.calledWithExactly(callback, fakeResult);
expect(result).toEqual(unsubCallback);
sinon.assert.calledWithExactly(getSigningKeysStub, callback);
});
});

Expand Down
94 changes: 92 additions & 2 deletions 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(
Expand Down Expand Up @@ -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 = {
Expand Down
32 changes: 32 additions & 0 deletions src/context/index.ts
Expand Up @@ -19,6 +19,7 @@ import {
ErrorCode,
KeyringPair,
PlainTransactionArgument,
Signer,
SimpleEnumTransactionArgument,
SubCallback,
TransactionArgument,
Expand All @@ -29,6 +30,7 @@ import {
balanceToBigNumber,
identityIdToString,
posRatioToBigNumber,
signatoryToSigner,
stringToAccountKey,
stringToIdentityId,
textToString,
Expand Down Expand Up @@ -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<Signer[]>;
public async getSigningKeys(callback: SubCallback<Signer[]>): Promise<UnsubCallback>;

// eslint-disable-next-line require-jsdoc
public async getSigningKeys(callback?: SubCallback<Signer[]>): Promise<Signer[] | UnsubCallback> {
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
*
Expand Down
12 changes: 11 additions & 1 deletion src/testUtils/mocks/dataSources.ts
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit c178ca6

Please sign in to comment.