From ddadd2b8bc9f3b3bdd946b4745a7b0765bc055cf Mon Sep 17 00:00:00 2001 From: Jeremias Diaz Date: Thu, 7 May 2020 21:25:06 -0400 Subject: [PATCH] feat: finish implementation and tests --- src/Polymesh.ts | 2 +- .../SecurityToken/Compliance/Rules.ts | 6 +- .../Compliance/TrustedClaimIssuers.ts | 2 +- .../Compliance/__tests__/Rules.ts | 4 +- .../__tests__/TrustedClaimIssuers.ts | 2 +- src/api/entities/SecurityToken/Transfers.ts | 21 ++-- .../SecurityToken/__tests__/Transfers.ts | 100 +++++++++++++++++- src/api/procedures/__tests__/setTokenRules.ts | 9 +- .../__tests__/setTokenTrustedClaimIssuers.ts | 14 ++- src/api/procedures/setTokenRules.ts | 12 ++- .../procedures/setTokenTrustedClaimIssuers.ts | 6 +- src/context/index.ts | 1 - src/testUtils/mocks/polkadot.ts | 33 +++--- src/utils/__tests__/index.ts | 92 +++++++++++++++- src/utils/constants.ts | 1 + src/utils/index.ts | 49 +++------ 16 files changed, 274 insertions(+), 80 deletions(-) diff --git a/src/Polymesh.ts b/src/Polymesh.ts index 51d599ed06..174412ad75 100644 --- a/src/Polymesh.ts +++ b/src/Polymesh.ts @@ -14,7 +14,7 @@ import { signerToSignatory, tickerToString, valueToDid } from '~/utils'; * Main entry point of the Polymesh SDK */ export class Polymesh { - private context: Context = {} as Context; + public context: Context = {} as Context; /** * @hidden diff --git a/src/api/entities/SecurityToken/Compliance/Rules.ts b/src/api/entities/SecurityToken/Compliance/Rules.ts index f78259a5dd..e685c20697 100644 --- a/src/api/entities/SecurityToken/Compliance/Rules.ts +++ b/src/api/entities/SecurityToken/Compliance/Rules.ts @@ -36,7 +36,7 @@ export class Rules extends Namespace { parent: { ticker }, context: { polymeshApi: { - query: { generalTm }, + query: { complianceManager }, }, }, context, @@ -44,8 +44,8 @@ export class Rules extends Namespace { // TODO: queryMulti const rawTicker = stringToTicker(ticker, context); const [tokenRules, defaultClaimIssuers] = await Promise.all([ - generalTm.assetRulesMap(rawTicker), - generalTm.trustedClaimIssuer(rawTicker), + complianceManager.assetRulesMap(rawTicker), + complianceManager.trustedClaimIssuer(rawTicker), ]); return tokenRules.rules.map(assetTransferRule => { diff --git a/src/api/entities/SecurityToken/Compliance/TrustedClaimIssuers.ts b/src/api/entities/SecurityToken/Compliance/TrustedClaimIssuers.ts index 02a1c79d93..62d19bf1e0 100644 --- a/src/api/entities/SecurityToken/Compliance/TrustedClaimIssuers.ts +++ b/src/api/entities/SecurityToken/Compliance/TrustedClaimIssuers.ts @@ -33,7 +33,7 @@ export class TrustedClaimIssuers extends Namespace { parent: { ticker }, } = this; - const claimIssuers = await context.polymeshApi.query.generalTm.trustedClaimIssuer( + const claimIssuers = await context.polymeshApi.query.complianceManager.trustedClaimIssuer( stringToTicker(ticker, context) ); diff --git a/src/api/entities/SecurityToken/Compliance/__tests__/Rules.ts b/src/api/entities/SecurityToken/Compliance/__tests__/Rules.ts index 4c1274b443..a5d896eba4 100644 --- a/src/api/entities/SecurityToken/Compliance/__tests__/Rules.ts +++ b/src/api/entities/SecurityToken/Compliance/__tests__/Rules.ts @@ -125,7 +125,7 @@ describe('Rules class', () => { issuers: [], }); - polkadotMockUtils.createQueryStub('generalTm', 'assetRulesMap', { + polkadotMockUtils.createQueryStub('complianceManager', 'assetRulesMap', { returnValue: { rules: [ polkadotMockUtils.createMockAssetTransferRule({ @@ -163,7 +163,7 @@ describe('Rules class', () => { }, }); - polkadotMockUtils.createQueryStub('generalTm', 'trustedClaimIssuer', { + polkadotMockUtils.createQueryStub('complianceManager', 'trustedClaimIssuer', { returnValue: defaultClaimIssuers, }); diff --git a/src/api/entities/SecurityToken/Compliance/__tests__/TrustedClaimIssuers.ts b/src/api/entities/SecurityToken/Compliance/__tests__/TrustedClaimIssuers.ts index 738ec56ca0..892327116e 100644 --- a/src/api/entities/SecurityToken/Compliance/__tests__/TrustedClaimIssuers.ts +++ b/src/api/entities/SecurityToken/Compliance/__tests__/TrustedClaimIssuers.ts @@ -84,7 +84,7 @@ describe('TrustedClaimIssuers class', () => { stringToTickerStub.withArgs(ticker, context).returns(rawTicker); polkadotMockUtils - .createQueryStub('generalTm', 'trustedClaimIssuer') + .createQueryStub('complianceManager', 'trustedClaimIssuer') .withArgs(rawTicker) .resolves(claimIssuers); diff --git a/src/api/entities/SecurityToken/Transfers.ts b/src/api/entities/SecurityToken/Transfers.ts index 89d05338c9..ac5a814864 100644 --- a/src/api/entities/SecurityToken/Transfers.ts +++ b/src/api/entities/SecurityToken/Transfers.ts @@ -1,12 +1,13 @@ -import { u8 } from '@polkadot/types'; import BigNumber from 'bignumber.js'; import { Identity } from '~/api/entities/Identity'; import { toggleFreezeTransfers } from '~/api/procedures'; import { Namespace, TransactionQueue } from '~/base'; +import { CanTransferResult } from '~/polkadot'; import { TransferStatus } from '~/types'; import { boolToBoolean, + canTransferResultToTransferStatus, numberToBalance, stringToAccountId, stringToIdentityId, @@ -14,6 +15,7 @@ import { u8ToTransferStatus, valueToDid, } from '~/utils'; +import { DUMMY_ACCOUNT_ID } from '~/utils/constants'; import { SecurityToken } from './'; @@ -63,6 +65,10 @@ export class Transfers extends Namespace { /** * Check whether it is possible to transfer a certain amount of this asset between two identities + * + * @param args.from - sender identity (optional, defaults to the current identity) + * @param args.to - receiver identity + * @param args.amount - amount of tokens to transfer */ public async canTransfer(args: { from?: string | Identity; @@ -72,7 +78,7 @@ export class Transfers extends Namespace { const { parent: { ticker }, context: { - polymeshApi: { rpc, query }, + polymeshApi: { rpc }, }, context, } = this; @@ -86,13 +92,10 @@ export class Transfers extends Namespace { * The RPC requires a sender account ID (although it's not being used at the moment). We use the current account * or a dummy account (Alice's in testnet) if the SDK was instanced without one */ - const senderAddress = - context.currentPair?.address || '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'; - - const hash = await query.system.parentHash(); + const senderAddress = context.currentPair?.address || DUMMY_ACCOUNT_ID; // eslint-disable-next-line @typescript-eslint/no-explicit-any - const status: u8 = await (rpc as any).asset.canTransfer( + const res: CanTransferResult = await (rpc as any).asset.canTransfer( stringToAccountId(senderAddress, context), stringToTicker(ticker, context), stringToIdentityId(fromDid, context), @@ -100,8 +103,6 @@ export class Transfers extends Namespace { numberToBalance(amount, context) ); - console.log('STATUS', status); - - return u8ToTransferStatus(status); + return canTransferResultToTransferStatus(res); } } diff --git a/src/api/entities/SecurityToken/__tests__/Transfers.ts b/src/api/entities/SecurityToken/__tests__/Transfers.ts index c691dc3c66..3222edaf0e 100644 --- a/src/api/entities/SecurityToken/__tests__/Transfers.ts +++ b/src/api/entities/SecurityToken/__tests__/Transfers.ts @@ -1,11 +1,17 @@ -import sinon from 'sinon'; +import { AccountId, Balance } from '@polkadot/types/interfaces'; +import BigNumber from 'bignumber.js'; +import sinon, { SinonStub } from 'sinon'; import { toggleFreezeTransfers } from '~/api/procedures'; import { Params } from '~/api/procedures/toggleFreezeTransfers'; import { Namespace, TransactionQueue } from '~/base'; import { Context } from '~/context'; +import { IdentityId, Ticker } from '~/polkadot'; import { entityMockUtils, polkadotMockUtils } from '~/testUtils/mocks'; import { Mocked } from '~/testUtils/types'; +import { TransferStatus } from '~/types'; +import * as utilsModule from '~/utils'; +import { DUMMY_ACCOUNT_ID } from '~/utils/constants'; import { SecurityToken } from '../'; import { Transfers } from '../Transfers'; @@ -14,7 +20,7 @@ describe('Transfers class', () => { let mockContext: Mocked; let mockSecurityToken: Mocked; let transfers: Transfers; - let prepareStub: sinon.SinonStub< + let prepareStub: SinonStub< [Params, Context], Promise> >; @@ -85,4 +91,94 @@ describe('Transfers class', () => { expect(result).toBe(boolValue); }); }); + + describe('method: canTransfer', () => { + let stringToAccountIdStub: SinonStub<[string, Context], AccountId>; + let stringToTickerStub: SinonStub<[string, Context], Ticker>; + let stringToIdentityIdStub: SinonStub<[string, Context], IdentityId>; + let numberToBalanceStub: SinonStub<[number | BigNumber, Context], Balance>; + + let statusCode: number; + let fromDid: string; + let toDid: string; + let ticker: string; + let amount: BigNumber; + let accountId: string; + + let rawAccountId: AccountId; + let rawFromDid: IdentityId; + let rawToDid: IdentityId; + let rawTicker: Ticker; + let rawAmount: Balance; + + beforeAll(() => { + stringToAccountIdStub = sinon.stub(utilsModule, 'stringToAccountId'); + stringToTickerStub = sinon.stub(utilsModule, 'stringToTicker'); + stringToIdentityIdStub = sinon.stub(utilsModule, 'stringToIdentityId'); + numberToBalanceStub = sinon.stub(utilsModule, 'numberToBalance'); + + statusCode = 81; + fromDid = 'fromDid'; + toDid = 'toDid'; + ({ ticker } = mockSecurityToken); + amount = new BigNumber(100); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + accountId = mockContext.currentPair?.address!; + + rawAccountId = polkadotMockUtils.createMockAccountId(accountId); + rawFromDid = polkadotMockUtils.createMockIdentityId(fromDid); + rawToDid = polkadotMockUtils.createMockIdentityId(toDid); + rawTicker = polkadotMockUtils.createMockTicker(ticker); + rawAmount = polkadotMockUtils.createMockBalance(amount.toNumber()); + }); + + beforeEach(() => { + stringToAccountIdStub.withArgs(accountId, mockContext).returns(rawAccountId); + stringToTickerStub.withArgs(ticker, mockContext).returns(rawTicker); + stringToIdentityIdStub.withArgs(fromDid, mockContext).returns(rawFromDid); + stringToIdentityIdStub.withArgs(toDid, mockContext).returns(rawToDid); + numberToBalanceStub.withArgs(amount, mockContext).returns(rawAmount); + }); + + test('should return a status value representing whether the transaction can be made from the current identity', async () => { + const currentDid = mockContext.getCurrentIdentity().did; + + const rawCurrentDid = polkadotMockUtils.createMockIdentityId(currentDid); + const rawDummyAccountId = polkadotMockUtils.createMockAccountId(DUMMY_ACCOUNT_ID); + + stringToIdentityIdStub.withArgs(currentDid, mockContext).returns(rawCurrentDid); + + // also test the case where the SDK was instanced without an account + mockContext.currentPair = undefined; + stringToAccountIdStub.withArgs(DUMMY_ACCOUNT_ID, mockContext).returns(rawDummyAccountId); + + const rawResponse = polkadotMockUtils.createMockCanTransferResult({ + Ok: polkadotMockUtils.createMockU8(statusCode), + }); + + polkadotMockUtils + .createRpcStub('asset', 'canTransfer') + .withArgs(rawDummyAccountId, rawTicker, rawCurrentDid, rawToDid, rawAmount) + .returns(rawResponse); + + const result = await transfers.canTransfer({ to: toDid, amount }); + + expect(result).toBe(TransferStatus.Success); + }); + + test('should return a status value representing whether the transaction can be made from another identity', async () => { + const rawResponse = polkadotMockUtils.createMockCanTransferResult({ + Ok: polkadotMockUtils.createMockU8(statusCode), + }); + + polkadotMockUtils + .createRpcStub('asset', 'canTransfer') + .withArgs(rawAccountId, rawTicker, rawFromDid, rawToDid, rawAmount) + .returns(rawResponse); + + const result = await transfers.canTransfer({ from: fromDid, to: toDid, amount }); + + expect(result).toBe(TransferStatus.Success); + }); + }); }); diff --git a/src/api/procedures/__tests__/setTokenRules.ts b/src/api/procedures/__tests__/setTokenRules.ts index da303f4ff4..9e15ab1dc5 100644 --- a/src/api/procedures/__tests__/setTokenRules.ts +++ b/src/api/procedures/__tests__/setTokenRules.ts @@ -73,12 +73,15 @@ describe('setTokenTrustedClaimIssuers procedure', () => { beforeEach(() => { addTransactionStub = procedureMockUtils.getAddTransactionStub(); - assetRulesMapStub = polkadotMockUtils.createQueryStub('generalTm', 'assetRulesMap', { + assetRulesMapStub = polkadotMockUtils.createQueryStub('complianceManager', 'assetRulesMap', { returnValue: [], }); - resetActiveRulesTransaction = polkadotMockUtils.createTxStub('generalTm', 'resetActiveRules'); - addActiveRuleTransaction = polkadotMockUtils.createTxStub('generalTm', 'addActiveRule'); + resetActiveRulesTransaction = polkadotMockUtils.createTxStub( + 'complianceManager', + 'resetActiveRules' + ); + addActiveRuleTransaction = polkadotMockUtils.createTxStub('complianceManager', 'addActiveRule'); mockContext = polkadotMockUtils.getContextInstance(); diff --git a/src/api/procedures/__tests__/setTokenTrustedClaimIssuers.ts b/src/api/procedures/__tests__/setTokenTrustedClaimIssuers.ts index 9a8f1b90d2..a86e1b6b24 100644 --- a/src/api/procedures/__tests__/setTokenTrustedClaimIssuers.ts +++ b/src/api/procedures/__tests__/setTokenTrustedClaimIssuers.ts @@ -54,19 +54,23 @@ describe('setTokenTrustedClaimIssuers procedure', () => { beforeEach(() => { addTransactionStub = procedureMockUtils.getAddTransactionStub(); - trustedClaimIssuerStub = polkadotMockUtils.createQueryStub('generalTm', 'trustedClaimIssuer', { - returnValue: [], - }); + trustedClaimIssuerStub = polkadotMockUtils.createQueryStub( + 'complianceManager', + 'trustedClaimIssuer', + { + returnValue: [], + } + ); didRecordsStub = polkadotMockUtils.createQueryStub('identity', 'didRecords', { size: 1, }); removeDefaultTrustedClaimIssuersBatchTransaction = polkadotMockUtils.createTxStub( - 'generalTm', + 'complianceManager', 'removeDefaultTrustedClaimIssuersBatch' ); addDefaultTrustedClaimIssuersBatchTransaction = polkadotMockUtils.createTxStub( - 'generalTm', + 'complianceManager', 'addDefaultTrustedClaimIssuersBatch' ); diff --git a/src/api/procedures/setTokenRules.ts b/src/api/procedures/setTokenRules.ts index 3723ff2e35..bc4f6909cc 100644 --- a/src/api/procedures/setTokenRules.ts +++ b/src/api/procedures/setTokenRules.ts @@ -30,7 +30,7 @@ export async function prepareSetTokenRules( const rawTicker = stringToTicker(ticker, context); - const currentRulesRaw = await query.generalTm.assetRulesMap(rawTicker); + const currentRulesRaw = await query.complianceManager.assetRulesMap(rawTicker); const currentRules = currentRulesRaw.rules.map(rule => assetTransferRuleToRule(rule).conditions); @@ -61,11 +61,17 @@ export async function prepareSetTokenRules( }); if (currentRules.length) { - this.addTransaction(tx.generalTm.resetActiveRules, {}, rawTicker); + this.addTransaction(tx.complianceManager.resetActiveRules, {}, rawTicker); } rawRules.forEach(({ senderRules, receiverRules }) => { - this.addTransaction(tx.generalTm.addActiveRule, {}, rawTicker, senderRules, receiverRules); + this.addTransaction( + tx.complianceManager.addActiveRule, + {}, + rawTicker, + senderRules, + receiverRules + ); }); return new SecurityToken({ ticker }, context); diff --git a/src/api/procedures/setTokenTrustedClaimIssuers.ts b/src/api/procedures/setTokenTrustedClaimIssuers.ts index 06638319ba..5be8637b74 100644 --- a/src/api/procedures/setTokenTrustedClaimIssuers.ts +++ b/src/api/procedures/setTokenTrustedClaimIssuers.ts @@ -31,7 +31,7 @@ export async function prepareSetTokenTrustedClaimIssuers( const rawTicker = stringToTicker(ticker, context); - const rawCurrentClaimIssuers = await query.generalTm.trustedClaimIssuer(rawTicker); + const rawCurrentClaimIssuers = await query.complianceManager.trustedClaimIssuer(rawTicker); const currentClaimIssuers = rawCurrentClaimIssuers.map(issuer => identityIdToString(issuer)); if ( @@ -76,7 +76,7 @@ export async function prepareSetTokenTrustedClaimIssuers( if (rawCurrentClaimIssuers.length) { this.addTransaction( - tx.generalTm.removeDefaultTrustedClaimIssuersBatch, + tx.complianceManager.removeDefaultTrustedClaimIssuersBatch, {}, rawTicker, rawCurrentClaimIssuers @@ -85,7 +85,7 @@ export async function prepareSetTokenTrustedClaimIssuers( if (rawNewClaimIssuers.length) { this.addTransaction( - tx.generalTm.addDefaultTrustedClaimIssuersBatch, + tx.complianceManager.addDefaultTrustedClaimIssuersBatch, {}, rawTicker, rawNewClaimIssuers diff --git a/src/context/index.ts b/src/context/index.ts index db6475506a..99fa2e133a 100644 --- a/src/context/index.ts +++ b/src/context/index.ts @@ -111,7 +111,6 @@ export class Context { currentPair.publicKey ); const did = identityIds.unwrap().asUnique; - console.log('ADDRESS', currentPair.address); return new Context({ polymeshApi, keyring, pair: { currentPair, did } }); } catch (err) { diff --git a/src/testUtils/mocks/polkadot.ts b/src/testUtils/mocks/polkadot.ts index c7b53d7d51..06dda650bb 100644 --- a/src/testUtils/mocks/polkadot.ts +++ b/src/testUtils/mocks/polkadot.ts @@ -5,6 +5,7 @@ import { ApiPromise, Keyring } from '@polkadot/api'; import { bool, Bytes, Enum, Option, u8, u32, u64 } from '@polkadot/types'; import { AccountData, + AccountId, AccountInfo, Balance, DispatchError, @@ -28,6 +29,7 @@ import { AuthIdentifier, Authorization, AuthorizationData, + CanTransferResult, CddStatus, Claim, Document, @@ -861,6 +863,13 @@ export const createMockTicker = (ticker?: string): Ticker => createMockU8ACodec( export const createMockAccountKey = (accountKey?: string): AccountKey => createMockU8ACodec(accountKey) as AccountKey; +/** + * @hidden + * NOTE: `isEmpty` will be set to true if no value is passed + */ +export const createMockAccountId = (accountId?: string): AccountId => + createMockStringCodec(accountId) as AccountId; + /** * @hidden * NOTE: `isEmpty` will be set to true if no value is passed @@ -1268,16 +1277,13 @@ export const createMockEventRecord = (data: unknown[]): EventRecord => */ export const createMockLinkedKeyInfo = ( linkedKeyInfo?: { Unique: IdentityId } | { Group: IdentityId[] } -): LinkedKeyInfo => { - return createMockEnum(linkedKeyInfo) as LinkedKeyInfo; -}; +): LinkedKeyInfo => createMockEnum(linkedKeyInfo) as LinkedKeyInfo; /** * @hidden */ -export const createMockCddStatus = (cddStatus?: { Ok: IdentityId } | { Err: Bytes }): CddStatus => { - return createMockEnum(cddStatus) as CddStatus; -}; +export const createMockCddStatus = (cddStatus?: { Ok: IdentityId } | { Err: Bytes }): CddStatus => + createMockEnum(cddStatus) as CddStatus; /** * @hidden @@ -1302,9 +1308,7 @@ export const createMockClaim = ( | { Whitelisted: Scope } | { Blacklisted: Scope } | 'NoData' -): Claim => { - return createMockEnum(claim) as Claim; -}; +): Claim => createMockEnum(claim) as Claim; /** * @hidden @@ -1316,9 +1320,7 @@ export const createMockRuleType = ( | { IsAbsent: Claim } | { IsAnyOf: Claim[] } | { IsNoneOf: Claim[] } -): RuleType => { - return createMockEnum(ruleType) as RuleType; -}; +): RuleType => createMockEnum(ruleType) as RuleType; /** * @hidden @@ -1363,3 +1365,10 @@ export const createMockAssetTransferRule = ( * NOTE: `isEmpty` will be set to true if no value is passed */ export const createMockScope = (did?: string): Scope => createMockStringCodec(did) as Scope; + +/** + * @hidden + */ +export const createMockCanTransferResult = ( + canTransferResult?: { Ok: u8 } | { Err: Bytes } +): CanTransferResult => createMockEnum(canTransferResult) as CanTransferResult; diff --git a/src/utils/__tests__/index.ts b/src/utils/__tests__/index.ts index 68dc6ef168..a843330316 100644 --- a/src/utils/__tests__/index.ts +++ b/src/utils/__tests__/index.ts @@ -1,5 +1,5 @@ import { bool, Bytes, u64 } from '@polkadot/types'; -import { Balance, Moment } from '@polkadot/types/interfaces'; +import { AccountId, Balance, Moment } from '@polkadot/types/interfaces'; import { ISubmittableResult } from '@polkadot/types/types'; import * as decodeAddressModule from '@polkadot/util-crypto/address/decode'; import * as encodeAddressModule from '@polkadot/util-crypto/address/encode'; @@ -38,10 +38,12 @@ import { ConditionType, KnownTokenType, TokenIdentifierType, + TransferStatus, } from '~/types'; import { SignerType } from '~/types/internal'; import { + accountIdToString, accountKeyToString, assetIdentifierToString, assetTransferRuleToRule, @@ -54,6 +56,7 @@ import { booleanToBool, boolToBoolean, bytesToString, + canTransferResultToTransferStatus, cddStatusToBoolean, claimToMeshClaim, dateToMoment, @@ -77,6 +80,7 @@ import { serialize, signatoryToSigner, signerToSignatory, + stringToAccountId, stringToAccountKey, stringToAssetIdentifier, stringToBytes, @@ -94,6 +98,7 @@ import { tokenIdentifierTypeToIdentifierType, tokenNameToString, tokenTypeToAssetType, + u8ToTransferStatus, u64ToBigNumber, unserialize, unwrapValues, @@ -493,6 +498,43 @@ describe('stringToTokenName and tokenNameToString', () => { }); }); +describe('stringToAccountId and accountIdToSting', () => { + beforeAll(() => { + polkadotMockUtils.initMocks(); + }); + + afterEach(() => { + polkadotMockUtils.reset(); + }); + + afterAll(() => { + polkadotMockUtils.cleanup(); + }); + + test('stringToAccountId should convert a string to a polkadot AccountId object', () => { + const value = 'someAccountId'; + const fakeResult = ('convertedAccountId' as unknown) as AccountId; + const context = polkadotMockUtils.getContextInstance(); + + polkadotMockUtils + .getCreateTypeStub() + .withArgs('AccountId', value) + .returns(fakeResult); + + const result = stringToAccountId(value, context); + + expect(result).toEqual(fakeResult); + }); + + test('accountIdToSting should convert a polkadot AccountId object to a string', () => { + const fakeResult = 'someAccountId'; + const accountId = polkadotMockUtils.createMockAccountId(fakeResult); + + const result = accountIdToString(accountId); + expect(result).toEqual(fakeResult); + }); +}); + describe('booleanToBool and boolToBoolean', () => { beforeAll(() => { polkadotMockUtils.initMocks(); @@ -1636,3 +1678,51 @@ describe('ruleToAssetTransferRule and assetTransferRuleToRule', () => { expect(result.conditions).toEqual(expect.arrayContaining(fakeResult.conditions)); }); }); + +describe('u8ToTransferStatus', () => { + test('u8ToTransferStatus should convert a polkadot u8 object to a TransferStatus', () => { + let result = u8ToTransferStatus(polkadotMockUtils.createMockU8(80)); + + expect(result).toBe(TransferStatus.Failure); + + result = u8ToTransferStatus(polkadotMockUtils.createMockU8(81)); + + expect(result).toBe(TransferStatus.Success); + + result = u8ToTransferStatus(polkadotMockUtils.createMockU8(82)); + + expect(result).toBe(TransferStatus.InsufficientBalance); + + result = u8ToTransferStatus(polkadotMockUtils.createMockU8(86)); + + expect(result).toBe(TransferStatus.InvalidReceiver); + + result = u8ToTransferStatus(polkadotMockUtils.createMockU8(164)); + + expect(result).toBe(TransferStatus.FundsLimitReached); + + const fakeStatusCode = 1; + expect(() => u8ToTransferStatus(polkadotMockUtils.createMockU8(fakeStatusCode))).toThrow( + `Unsupported status code "${fakeStatusCode}". Please report this issue to the Polymath team` + ); + }); +}); + +describe('canTransferResultToTransferStatus', () => { + test('canTransferResultToTransferStatus should convert a polkadot CanTransferResult object to a TransferStatus', () => { + const errorMsg = 'someError'; + expect(() => + canTransferResultToTransferStatus( + polkadotMockUtils.createMockCanTransferResult({ + Err: polkadotMockUtils.createMockBytes(errorMsg), + }) + ) + ).toThrow(`Error while checking transfer validity: ${errorMsg}`); + + const result = canTransferResultToTransferStatus( + polkadotMockUtils.createMockCanTransferResult({ Ok: polkadotMockUtils.createMockU8(81) }) + ); + + expect(result).toBe(TransferStatus.Success); + }); +}); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 4abe306d3d..97e9e83cc7 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -2,3 +2,4 @@ import BigNumber from 'bignumber.js'; export const MAX_DECIMALS = 6; export const MAX_TOKEN_AMOUNT = new BigNumber(Math.pow(10, 12)); +export const DUMMY_ACCOUNT_ID = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'; diff --git a/src/utils/index.ts b/src/utils/index.ts index 570f3202bc..a9980d7a49 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -13,6 +13,7 @@ import { AssetType, AuthIdentifier, AuthorizationData, + CanTransferResult, CddStatus, Claim as MeshClaim, Document, @@ -388,38 +389,6 @@ export function u64ToBigNumber(value: u64): BigNumber { return new BigNumber(value.toString()); } -/** - * @hidden - */ -export function transferStatusCodeToU8(status: TransferStatus, context: Context): u8 { - let code: number; - - switch (status) { - case TransferStatus.Success: { - code = 81; - break; - } - case TransferStatus.InsufficientBalance: { - code = 82; - break; - } - case TransferStatus.InvalidReceiver: { - code = 86; - break; - } - case TransferStatus.FundsLimitReached: { - code = 164; - break; - } - case TransferStatus.Failure: - default: { - code = 80; - } - } - - return context.polymeshApi.createType('u8', code); -} - /** * @hidden */ @@ -646,6 +615,22 @@ export function cddStatusToBoolean(cddStatus: CddStatus): boolean { return false; } +/** + * @hidden + */ +export function canTransferResultToTransferStatus( + canTransferResult: CanTransferResult +): TransferStatus { + if (canTransferResult.isErr) { + throw new PolymeshError({ + code: ErrorCode.FatalError, + message: `Error while checking transfer validity: ${bytesToString(canTransferResult.asErr)}`, + }); + } + + return u8ToTransferStatus(canTransferResult.asOk); +} + /** * @hidden */