Skip to content

Commit

Permalink
feat(sto): add balance fetching methods to Checkpoint entity
Browse files Browse the repository at this point in the history
`allBalances` fetches all balances and can be paginated, `balance` fetches it for a single identity
  • Loading branch information
monitz87 committed Mar 1, 2021
1 parent 3104aa7 commit f281c57
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/Polymesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,9 @@ export class Polymesh {
* Retrieve all the ticker reservations currently owned by an Identity. This doesn't include tokens that
* have already been launched
*
* @param args.owner - identity representation or Identity ID as stored in the blockchain
* @param args.owner - defaults to the current Identity
*
* * @note reservations with unreadable characters in their tickers will be left out
* @note reservations with unreadable characters in their tickers will be left out
*/
public async getTickerReservations(args?: {
owner: string | Identity;
Expand Down
61 changes: 59 additions & 2 deletions src/api/entities/Checkpoint.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import BigNumber from 'bignumber.js';

import { Context, Entity } from '~/internal';
import { balanceToBigNumber, momentToDate, numberToU64, stringToTicker } from '~/utils/conversion';
import { Context, Entity, Identity } from '~/internal';
import { IdentityBalance, PaginationOptions, ResultSet } from '~/types';
import { tuple } from '~/types/utils';
import {
balanceToBigNumber,
identityIdToString,
momentToDate,
numberToU64,
stringToIdentityId,
stringToTicker,
} from '~/utils/conversion';
import { getDid, requestPaginated } from '~/utils/internal';

export interface UniqueIdentifiers {
id: BigNumber;
Expand Down Expand Up @@ -72,4 +82,51 @@ export class Checkpoint extends Entity<UniqueIdentifiers> {

return momentToDate(creationTime);
}

/**
* Retrieve all Tokenholder balances at this Checkpoint
*
* @note supports pagination
*/
public async allBalances(
paginationOpts?: PaginationOptions
): Promise<ResultSet<IdentityBalance>> {
const { context, ticker, id } = this;

const { entries, lastKey: next } = await requestPaginated(
context.polymeshApi.query.checkpoint.balance,
{
arg: tuple(stringToTicker(ticker, context), numberToU64(id, context)),
paginationOpts,
}
);

const data = entries.map(([{ args: [, identityId] }, balance]) => ({
identity: new Identity({ did: identityIdToString(identityId) }, context),
balance: balanceToBigNumber(balance),
}));

return {
data,
next,
};
}

/**
* Retrieve the balance of a specific Tokenholder Identity at this Checkpoint
*
* @param args.identity - defaults to the current Identity
*/
public async balance(args?: { identity: string | Identity }): Promise<BigNumber> {
const { context, ticker, id } = this;

const did = await getDid(args?.identity, context);

const balance = await context.polymeshApi.query.checkpoint.balance(
[stringToTicker(ticker, context), numberToU64(id, context)],
stringToIdentityId(did, context)
);

return balanceToBigNumber(balance);
}
}
2 changes: 1 addition & 1 deletion src/api/entities/SecurityToken/TokenHolders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { requestPaginated } from '~/utils/internal';
*/
export class TokenHolders extends Namespace<SecurityToken> {
/**
* Retrieve all the token holders with balance
* Retrieve all the token holders with their respective balance
*
* @note supports pagination
*/
Expand Down
83 changes: 82 additions & 1 deletion src/api/entities/__tests__/Checkpoint.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { StorageKey } from '@polkadot/types';
import BigNumber from 'bignumber.js';
import sinon from 'sinon';

import { Checkpoint, Context, Entity } from '~/internal';
import { dsMockUtils } from '~/testUtils/mocks';
import { dsMockUtils, entityMockUtils } from '~/testUtils/mocks';
import { tuple } from '~/types/utils';
import * as utilsInternalModule from '~/utils/internal';

jest.mock(
'~/api/entities/Identity',
require('~/testUtils/mocks/entities').mockIdentityModule('~/api/entities/Identity')
);

describe('Checkpoint class', () => {
let context: Context;
Expand All @@ -11,6 +20,7 @@ describe('Checkpoint class', () => {

beforeAll(() => {
dsMockUtils.initMocks();
entityMockUtils.initMocks();

id = new BigNumber(1);
ticker = 'SOME_TICKER';
Expand All @@ -22,10 +32,12 @@ describe('Checkpoint class', () => {

afterEach(() => {
dsMockUtils.reset();
entityMockUtils.reset();
});

afterAll(() => {
dsMockUtils.cleanup();
entityMockUtils.cleanup();
});

test('should extend entity', () => {
Expand Down Expand Up @@ -79,4 +91,73 @@ describe('Checkpoint class', () => {
expect(result).toEqual(new BigNumber(balance).shiftedBy(-6));
});
});

describe('method: allBalances', () => {
test("should return the Checkpoint's tokenholder balances", async () => {
const checkpoint = new Checkpoint({ id, ticker }, context);

dsMockUtils.createQueryStub('checkpoint', 'balance');

const fakeResult = [
{
identity: entityMockUtils.getIdentityInstance({ did: 'someDid' }),
balance: new BigNumber(1000),
},
{
identity: entityMockUtils.getIdentityInstance({ did: 'otherDid' }),
balance: new BigNumber(2000),
},
];

const rawTicker = dsMockUtils.createMockTicker(ticker);
const rawId = dsMockUtils.createMockU64(id.toNumber());
const entries = [
tuple(
({
args: [
tuple(rawTicker, rawId),
dsMockUtils.createMockIdentityId(fakeResult[0].identity.did),
],
} as unknown) as StorageKey,
dsMockUtils.createMockBalance(fakeResult[0].balance.shiftedBy(6).toNumber())
),
tuple(
({
args: [
tuple(rawTicker, rawId),
dsMockUtils.createMockIdentityId(fakeResult[1].identity.did),
],
} as unknown) as StorageKey,
dsMockUtils.createMockBalance(fakeResult[1].balance.shiftedBy(6).toNumber())
),
];

sinon.stub(utilsInternalModule, 'requestPaginated').resolves({ entries, lastKey: null });

const { data } = await checkpoint.allBalances();

expect(data).toEqual(fakeResult);
});
});

describe('method: balance', () => {
test("should return a specific Identity's balance at the Checkpoint", async () => {
const checkpoint = new Checkpoint({ id, ticker }, context);
const balance = 10000000000;

dsMockUtils.createQueryStub('checkpoint', 'balance', {
returnValue: dsMockUtils.createMockBalance(balance),
});

const expected = new BigNumber(balance).shiftedBy(-6);

let result = await checkpoint.balance({ identity: 'someDid' });

expect(result).toEqual(expected);

result = await checkpoint.balance();

expect(result).toEqual(expected);
});
});
});

0 comments on commit f281c57

Please sign in to comment.