Skip to content

Commit

Permalink
fix: update polkadot-js api to 7.2.1 (#809)
Browse files Browse the repository at this point in the history
* update polkadot-js api to 7.2.1

* update PalletAssetsAssetBalance -> Account

* refactor the mock data for assets to keep things DRY

* lint and set proper return types for exported mock test-helpers

* fix: comment

* fix logic to avoid breaking changes

* fix pallet testing refactor

* refactor logic to avoid breaking changes

* cleanup code readability in asset-balances service

* Update return type and return value

* update inline docs

* update comment grumbles

* update inline docs for added asset types
  • Loading branch information
TarikGul committed Jan 21, 2022
1 parent 05f97bb commit 3553fb8
Show file tree
Hide file tree
Showing 7 changed files with 441 additions and 355 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"test:test-release": "yarn start:test-release"
},
"dependencies": {
"@polkadot/api": "^7.0.1",
"@polkadot/api": "^7.2.1",
"@polkadot/apps-config": "0.98.2-164",
"@polkadot/util-crypto": "^8.2.2",
"@polkadot/x-rxjs": "^6.11.1",
Expand All @@ -76,11 +76,11 @@
"tsc-watch": "^4.4.0"
},
"resolutions": {
"@polkadot/api": "7.0.1",
"@polkadot/api": "7.2.1",
"@polkadot/keyring": "8.2.2",
"@polkadot/networks": "8.2.2",
"@polkadot/types": "7.0.1",
"@polkadot/types-known": "7.0.1",
"@polkadot/types": "7.2.1",
"@polkadot/types-known": "7.2.1",
"@polkadot/util": "8.2.2",
"@polkadot/util-crypto": "8.2.2",
"@polkadot/wasm-crypto": "4.5.1",
Expand Down
148 changes: 8 additions & 140 deletions src/services/accounts/AccountsAssetsService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,155 +1,23 @@
import { ApiPromise } from '@polkadot/api';
import { ApiDecoration } from '@polkadot/api/types';
import { AssetId, Hash } from '@polkadot/types/interfaces';
import { PalletAssetsAssetBalance } from '@polkadot/types/lookup';
import { Hash } from '@polkadot/types/interfaces';

import { sanitizeNumbers } from '../../sanitize/sanitizeNumbers';
import { statemintV1 } from '../../test-helpers/metadata/statemintMetadata';
import { rococoRegistry } from '../../test-helpers/registries';
import { createApiWithAugmentations } from '../../test-helpers/typeFactory';
import { TypeFactory } from '../../test-helpers/typeFactory';
import { blockHash789629, defaultMockApi } from '../test-helpers/mock';
import {
assetApprovals,
assetsAccount,
assetsInfoKeysInjected,
assetsMetadata,
} from '../test-helpers/mock/assets/mockAssetData';
import { AccountsAssetsService } from './AccountsAssetsService';

const statemintApiV1 = createApiWithAugmentations(statemintV1);
const statemintTypeFactory = new TypeFactory(statemintApiV1);

const falseBool = rococoRegistry.createType('bool', false);
const trueBool = rococoRegistry.createType('bool', true);
const assetTBalanceOne = rococoRegistry.createType('u64', 10000000);
const assetTBalanceTwo = rococoRegistry.createType('u64', 20000000);

const accountIdOne = rococoRegistry.createType(
'AccountId',
'1TYrFCWxwHA5bhiXf6uLvPfG6eEvrzzL7uiPK3Yc6yHLUqc'
);
const accountIdTwo = rococoRegistry.createType(
'AccountId',
'13NXiLYYzVEjXxU3eaZNcrjEX9vPyVDNNpURCzK8Bj9BiCWH'
);
const balanceOfTwo = rococoRegistry.createType('BalanceOf', 2000000);

const assetsInfo = () =>
Promise.resolve().then(() => {
const responseObj = {
owner: accountIdOne,
issue: accountIdTwo,
admin: accountIdTwo,
freezer: accountIdTwo,
supply: assetTBalanceOne,
deposit: balanceOfTwo,
minBalance: rococoRegistry.createType('u64', 10000),
isSufficient: trueBool,
accounts: rococoRegistry.createType('u32', 10),
sufficients: rococoRegistry.createType('u32', 15),
approvals: rococoRegistry.createType('u32', 20),
isFrozen: falseBool,
};

return rococoRegistry.createType('AssetDetails', responseObj);
});

const assetsMetadata = () =>
Promise.resolve().then(() => {
const responseObj = {
deposit: balanceOfTwo,
name: rococoRegistry.createType('Bytes', 'statemint'),
symbol: rococoRegistry.createType('Bytes', 'DOT'),
decimals: rococoRegistry.createType('u8', 10),
isFrozen: falseBool,
};

return rococoRegistry.createType('AssetMetadata', responseObj);
});

const assetBalanceObjOne = {
balance: assetTBalanceOne,
isFrozen: falseBool,
sufficient: trueBool,
};

const assetBalanceObjTwo = {
balance: assetTBalanceTwo,
isFrozen: trueBool,
sufficient: trueBool,
};

const assetBalanceObjThree = {
balance: assetTBalanceTwo,
isFrozen: falseBool,
sufficient: falseBool,
};

const assetBalanceFactory = {
'10': assetBalanceObjOne as unknown as PalletAssetsAssetBalance,
'20': assetBalanceObjTwo as unknown as PalletAssetsAssetBalance,
'30': assetBalanceObjThree as unknown as PalletAssetsAssetBalance,
};

const assetStorageKeyOne = statemintTypeFactory.storageKey(
10,
'AssetId',
statemintApiV1.query.assets.asset
);

const assetStorageKeyTwo = statemintTypeFactory.storageKey(
20,
'AssetId',
statemintApiV1.query.assets.asset
);

const assetStorageKeyThree = statemintTypeFactory.storageKey(
30,
'AssetId',
statemintApiV1.query.assets.asset
);

const assetsAccountKeysAt = () =>
Promise.resolve().then(() => {
return [assetStorageKeyOne, assetStorageKeyTwo, assetStorageKeyThree];
});

/**
* Attach `keys` to mockApi.query.assets.asset
*/
Object.assign(assetsInfo, {
keys: assetsAccountKeysAt,
});

/**
* @param assetId options are 10, 20, 30
*/
const assetsAccount = (assetId: number | AssetId, _address: string) => {
const id =
typeof assetId === 'number' ? assetId : parseInt(assetId.toString());

switch (id) {
case 10:
return assetBalanceFactory[10];
case 20:
return assetBalanceFactory[20];
case 30:
return assetBalanceFactory[30];
default:
return;
}
};

const assetApprovals = () =>
Promise.resolve().then(() => {
const assetObj = {
amount: assetTBalanceOne,
deposit: balanceOfTwo,
};
return rococoRegistry.createType('Option<AssetApproval>', assetObj);
});

const historicApi = {
query: {
assets: {
account: assetsAccount,
approvals: assetApprovals,
asset: assetsInfo,
asset: assetsInfoKeysInjected(),
metadata: assetsMetadata,
},
},
Expand Down
88 changes: 83 additions & 5 deletions src/services/accounts/AccountsAssetsService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ApiDecoration } from '@polkadot/api/types';
import { bool, StorageKey } from '@polkadot/types';
import { bool, Null, Struct, u128 } from '@polkadot/types';
import { StorageKey } from '@polkadot/types';
import { AssetId, BlockHash } from '@polkadot/types/interfaces';
import { BadRequest } from 'http-errors';

Expand All @@ -10,6 +11,33 @@ import {
} from '../../types/responses';
import { AbstractService } from '../AbstractService';

/**
* These two types (`PalletAssetsAssetBalance, LegacyPalletAssetsAssetBalance`) are necessary for any
* runtime pre 9160. It excludes the `reason` field which v9160 introduces via the following PR.
* https://github.com/paritytech/substrate/pull/10382/files#diff-9acae09f48474b7f0b96e7a3d66644e0ce5179464cbb0e00671ad09aa3f73a5fR88
*
* `LegacyPalletAssetsAssetBalance` which is the oldest historic type here had a `isSufficient`
* key. It was then updated to be `sufficient` which we represent here within `PalletAssetsAssetBalance`.
*
* v9160 removes the `sufficient` key typed as a boolean, and instead
* replaces it with a `reason` key. `reason` is an enum and has the following values
* in polkadot-js: (`isConsumer`, `isSufficient`, `isDepositHeld`, `asDepositHeld`, `isDepositRefunded`, `type`).
*
* For v9160 and future runtimes, the returned type is `PalletAssetsAssetAccount`.
*/
interface PalletAssetsAssetBalance extends Struct {
readonly balance: u128;
readonly isFrozen: bool;
readonly sufficient: bool;
readonly extra: Null;
}

interface LegacyPalletAssetsAssetBalance extends Struct {
readonly balance: u128;
readonly isFrozen: bool;
readonly isSufficient: bool;
}

export class AccountsAssetsService extends AbstractService {
/**
* Fetch all the `AssetBalance`s alongside their `AssetId`'s for a given array of queried `AssetId`'s.
Expand Down Expand Up @@ -125,12 +153,62 @@ export class AccountsAssetsService extends AbstractService {
address
);

/**
* The following checks for three different cases:
*/

// 1. Via runtime v9160 the updated storage introduces a `reason` field,
// and polkadot-js wraps the newly returned `PalletAssetsAssetAccount` in an `Option`.
if (assetBalance.isSome) {
const balanceProps = assetBalance.unwrap();

return {
assetId,
balance: balanceProps.balance,
isFrozen: balanceProps.isFrozen,
isSufficient: balanceProps.reason.isSufficient,
};
}

// 2. `query.assets.account()` return `PalletAssetsAssetBalance` which exludes `reasons` but has
// `sufficient` as a key.
if ((assetBalance as unknown as PalletAssetsAssetBalance).sufficient) {
const balanceProps =
assetBalance as unknown as PalletAssetsAssetBalance;

return {
assetId,
balance: balanceProps.balance,
isFrozen: balanceProps.isFrozen,
isSufficient: balanceProps.sufficient,
};
}

// 3. The older legacy type of `PalletAssetsAssetBalance` has a key of `isSufficient` instead
// of `sufficient`.
if (assetBalance['isSufficient'] as bool) {
const balanceProps =
assetBalance as unknown as LegacyPalletAssetsAssetBalance;

return {
assetId,
balance: balanceProps.balance,
isFrozen: balanceProps.isFrozen,
isSufficient: balanceProps.isSufficient,
};
}

/**
* This return value wont ever be reached as polkadot-js defaults the
* `balance` value to `0`, `isFrozen` to false, and `isSufficient` to false.
* This ensures that the typescript compiler is happy, but we also follow along
* with polkadot-js/substrate convention.
*/
return {
assetId,
balance: assetBalance.balance,
isFrozen: assetBalance.isFrozen,
isSufficient:
assetBalance.sufficient || (assetBalance['isSufficient'] as bool),
balance: historicApi.registry.createType('u128', 0),
isFrozen: historicApi.registry.createType('bool', false),
isSufficient: historicApi.registry.createType('bool', false),
};
})
);
Expand Down
Loading

0 comments on commit 3553fb8

Please sign in to comment.