CreateType is typed, add createTypeUnsafe just in case (#1199)
* Use unsafe internally * Add comments * Remove <> in createType * Fix lint * Fix classOf * Remove createType from Text * Fix lint * Fix Fallback type * Fix fallback in createType
This commit is contained in:
committed by
Jaco Greeff
parent
ec0b9a84a3
commit
441148889d
@@ -20,9 +20,9 @@ import { drr } from '../util/drr';
|
||||
type Result = [AccountId | undefined, BlockNumber | undefined, [Balance?, Balance?, BalanceLock[]?, Option<VestingSchedule>?, Index?]];
|
||||
|
||||
const EMPTY_ACCOUNT = new AccountId();
|
||||
const ZERO = createType<Balance>('Balance', 0);
|
||||
const ZERO = createType('Balance', 0);
|
||||
|
||||
function calcBalances ([accountId = EMPTY_ACCOUNT, bestNumber = ZERO, [freeBalance = ZERO, reservedBalance = ZERO, locks = [], vesting = new Option<VestingSchedule>(ClassOf<VestingSchedule>('VestingSchedule'), null), accountNonce = ZERO]]: Result): DerivedBalances {
|
||||
function calcBalances ([accountId = EMPTY_ACCOUNT, bestNumber = ZERO, [freeBalance = ZERO, reservedBalance = ZERO, locks = [], vesting = new Option<VestingSchedule>(ClassOf('VestingSchedule'), null), accountNonce = ZERO]]: Result): DerivedBalances {
|
||||
let lockedBalance = ZERO;
|
||||
|
||||
if (Array.isArray(locks)) {
|
||||
@@ -35,7 +35,7 @@ function calcBalances ([accountId = EMPTY_ACCOUNT, bestNumber = ZERO, [freeBalan
|
||||
}
|
||||
|
||||
// offset = balance locked at genesis, perBlock is the unlock amount
|
||||
const { offset, perBlock } = vesting.unwrapOr(createType<VestingSchedule>('VestingSchedule'));
|
||||
const { offset, perBlock } = vesting.unwrapOr(createType('VestingSchedule'));
|
||||
const vestedNow: BN = perBlock.mul(bestNumber);
|
||||
const vestedBalance: BN = vestedNow.gt(offset)
|
||||
? freeBalance
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Balance } from '@polkadot/types/interfaces';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
@@ -28,7 +26,7 @@ export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | nu
|
||||
map(([votersFor, votes, balances]): DerivedReferendumVote[] =>
|
||||
votersFor.map((accountId, index): DerivedReferendumVote => ({
|
||||
accountId,
|
||||
balance: balances[index].votingBalance || createType<Balance>('Balance', 0),
|
||||
balance: balances[index].votingBalance || createType('Balance', 0),
|
||||
vote: votes[index] || new Vote(0)
|
||||
} as unknown as DerivedReferendumVote))
|
||||
),
|
||||
|
||||
@@ -44,7 +44,7 @@ export function voterPositions (api: ApiInterfaceRx): () => Observable<DerivedVo
|
||||
result[accountId.toString()] = {
|
||||
globalIndex: setSize.muln(setIndex).addn(index),
|
||||
index: new BN(index),
|
||||
setIndex: createType<SetIndex>('SetIndex', setIndex)
|
||||
setIndex: createType('SetIndex', setIndex)
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength
|
||||
const groupedResult = groupByEra(unlockingChunks);
|
||||
const results = Object.entries(groupedResult).map(([eraString, value]): { value: BN; remainingBlocks: BN } => ({
|
||||
value,
|
||||
remainingBlocks: remainingBlocks(createType<BlockNumber>('BlockNumber', eraString), eraLength, bestNumber)
|
||||
remainingBlocks: remainingBlocks(createType('BlockNumber', eraString), eraLength, bestNumber)
|
||||
}));
|
||||
|
||||
return results.length ? results : undefined;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AnyJsonObject } from '@polkadot/types/types';
|
||||
* @description
|
||||
* A [[ReferendumInfo]] with an additional `index` field
|
||||
*/
|
||||
export default class ReferendumInfoExtended extends ClassOf<ReferendumInfo>('ReferendumInfo') {
|
||||
export default class ReferendumInfoExtended extends ClassOf('ReferendumInfo') {
|
||||
private _index: ReferendumIndex;
|
||||
|
||||
public constructor (value: ReferendumInfo | ReferendumInfoExtended, index?: BN | number) {
|
||||
@@ -21,7 +21,7 @@ export default class ReferendumInfoExtended extends ClassOf<ReferendumInfo>('Ref
|
||||
|
||||
this._index = value instanceof ReferendumInfoExtended
|
||||
? value.index
|
||||
: createType<ReferendumIndex>('ReferendumIndex', index);
|
||||
: createType('ReferendumIndex', index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { Constants, ConstantCodec, ModuleConstants } from '../types';
|
||||
|
||||
import { createType } from '@polkadot/types';
|
||||
import { createTypeUnsafe } from '@polkadot/types/codec/createType';
|
||||
import Metadata from '@polkadot/types/Metadata';
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
@@ -23,7 +23,7 @@ export default function fromMetadata (metadata: Metadata): Constants {
|
||||
|
||||
// For access, we change the index names, i.e. Democracy.EnactmentPeriod -> democracy.enactmentPeriod
|
||||
result[stringCamelCase(name.toString())] = moduleMetadata.constants.reduce((newModule, meta): ModuleConstants => {
|
||||
const codec = createType(meta.type, meta.value);
|
||||
const codec = createTypeUnsafe(meta.type.toString(), meta.value);
|
||||
|
||||
// This is not a perfect idea, however as it stands with number-only constants on the metadata
|
||||
// does not have any effect. However, this could become problematic in cases where items are
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
import { Codec } from '@polkadot/types/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { createType, Bytes, Compact, StorageKey, U8a } from '@polkadot/types';
|
||||
import { Bytes, Compact, StorageKey, U8a } from '@polkadot/types';
|
||||
import { createTypeUnsafe } from '@polkadot/types/codec/createType';
|
||||
import { PlainType, StorageEntryMetadata, StorageEntryModifier, StorageEntryType } from '@polkadot/types/Metadata/v6/Storage';
|
||||
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
|
||||
import { assert, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat } from '@polkadot/util';
|
||||
@@ -69,9 +70,9 @@ export default function createFunction ({ meta, method, prefix, section }: Creat
|
||||
const [key1, key2] = arg as [CreateArgType, CreateArgType];
|
||||
const type1 = meta.type.asDoubleMap.key1.toString();
|
||||
const type2 = meta.type.asDoubleMap.key2.toString();
|
||||
const param1Encoded = u8aConcat(key, createType(type1, key1).toU8a(true));
|
||||
const param1Encoded = u8aConcat(key, createTypeUnsafe(type1, key1).toU8a(true));
|
||||
const param1Hashed = hasher(param1Encoded);
|
||||
const param2Hashed = key2Hasher(createType(type2, key2).toU8a(true));
|
||||
const param2Hashed = key2Hasher(createTypeUnsafe(type2, key2).toU8a(true));
|
||||
|
||||
return Compact.addLengthPrefix(u8aConcat(param1Hashed, param2Hashed));
|
||||
}
|
||||
@@ -80,7 +81,7 @@ export default function createFunction ({ meta, method, prefix, section }: Creat
|
||||
assert(!isUndefined(arg) && !isNull(arg), `${meta.name} expects one argument`);
|
||||
|
||||
const type = meta.type.asMap.key.toString();
|
||||
const param = createType(type, arg).toU8a();
|
||||
const param = createTypeUnsafe(type, arg).toU8a();
|
||||
|
||||
key = u8aConcat(key, param);
|
||||
}
|
||||
@@ -111,7 +112,7 @@ export default function createFunction ({ meta, method, prefix, section }: Creat
|
||||
name: meta.name,
|
||||
modifier: new StorageEntryModifier('Required'),
|
||||
type: new StorageEntryType(new PlainType(meta.type.asMap.key), 0),
|
||||
fallback: new Bytes(createType(meta.type.asMap.key).toHex()),
|
||||
fallback: new Bytes(createTypeUnsafe(meta.type.asMap.key.toString()).toHex()),
|
||||
documentation: meta.documentation
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export interface ISubmittableResult {
|
||||
readonly isError: boolean;
|
||||
readonly isFinalized: boolean;
|
||||
|
||||
findRecord (section: string, method: string): EventRecord | undefined;
|
||||
findRecord(section: string, method: string): EventRecord | undefined;
|
||||
}
|
||||
|
||||
export type SumbitableResultResult<ApiType> =
|
||||
@@ -93,17 +93,17 @@ export class SubmittableResult implements ISubmittableResult {
|
||||
}
|
||||
|
||||
export interface SubmittableExtrinsic<ApiType> extends IExtrinsic {
|
||||
send (): SumbitableResultResult<ApiType>;
|
||||
send(): SumbitableResultResult<ApiType>;
|
||||
|
||||
send (statusCb: Callback<ISubmittableResult>): SumbitableResultSubscription<ApiType>;
|
||||
send(statusCb: Callback<ISubmittableResult>): SumbitableResultSubscription<ApiType>;
|
||||
|
||||
sign (account: IKeyringPair, _options: Partial<SignatureOptions>): this;
|
||||
sign(account: IKeyringPair, _options: Partial<SignatureOptions>): this;
|
||||
|
||||
signAndSend (account: IKeyringPair | string | AccountId | Address, options?: Partial<SignerOptions>): SumbitableResultResult<ApiType>;
|
||||
signAndSend(account: IKeyringPair | string | AccountId | Address, options?: Partial<SignerOptions>): SumbitableResultResult<ApiType>;
|
||||
|
||||
signAndSend (account: IKeyringPair | string | AccountId | Address, statusCb: Callback<ISubmittableResult>): SumbitableResultSubscription<ApiType>;
|
||||
signAndSend(account: IKeyringPair | string | AccountId | Address, statusCb: Callback<ISubmittableResult>): SumbitableResultSubscription<ApiType>;
|
||||
|
||||
signAndSend (account: IKeyringPair | string | AccountId | Address, options: Partial<SignerOptions>, statusCb?: Callback<ISubmittableResult>): SumbitableResultSubscription<ApiType>;
|
||||
signAndSend(account: IKeyringPair | string | AccountId | Address, options: Partial<SignerOptions>, statusCb?: Callback<ISubmittableResult>): SumbitableResultSubscription<ApiType>;
|
||||
}
|
||||
|
||||
export default function createSubmittableExtrinsic<ApiType> (
|
||||
@@ -251,7 +251,7 @@ export default function createSubmittableExtrinsic<ApiType> (
|
||||
// if we have a nonce already, don't retrieve the latest, use what is there
|
||||
isUndefined(options.nonce)
|
||||
? api.query.system.accountNonce<Index>(address)
|
||||
: of(createType<Index>('Index', options.nonce)),
|
||||
: of(createType('Index', options.nonce)),
|
||||
// if we have an era provided already or eraLength is <= 0 (immortal)
|
||||
// don't get the latest block, just pass null, handle in mergeMap
|
||||
(isUndefined(options.era) || (isNumber(options.era) && options.era > 0))
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ConstantCodec } from '@polkadot/api-metadata/consts/types';
|
||||
import testKeyring from '@polkadot/keyring/testingPairs';
|
||||
import { IExtrinsic, IMethod } from '@polkadot/types/types';
|
||||
import { createType, Header } from '@polkadot/types';
|
||||
import { createTypeUnsafe } from '@polkadot/types/codec/createType';
|
||||
|
||||
import { SubmittableResult } from './';
|
||||
|
||||
@@ -95,8 +96,11 @@ export default async function test (): Promise<void> {
|
||||
|
||||
// check correct types with `createType`
|
||||
const balance = createType('Balance', 2);
|
||||
const overridden = createType<Index>('Gas', 2);
|
||||
const gas = createType('Gas', 2);
|
||||
const vec = createType('Vec<u32>', 2);
|
||||
console.log(balance, overridden, gas, vec);
|
||||
const compact = createType('Compact<u32>', 2);
|
||||
// const random = createType('RandomType', 2); // This one should deliberately show a TS error
|
||||
|
||||
const gasUnsafe = createTypeUnsafe('Gas', 2);
|
||||
const overriddenUnsafe = createTypeUnsafe<Header>('Gas', 2);
|
||||
console.log(balance, gas, compact, gasUnsafe, overriddenUnsafe);
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ describeE2E({
|
||||
// assume the account Alice is only used in test(the balance of Alice does not change in this test case)
|
||||
const key = api.query.balances.freeBalance.key(keyring.alice_stash.address);
|
||||
const balanceData = await api.rpc.state.getStorage(key) as Option<any>;
|
||||
const balanceRPC = createType<Balance>('Balance', balanceData.unwrapOr(undefined));
|
||||
const balanceRPC = createType('Balance', balanceData.unwrapOr(undefined));
|
||||
|
||||
const balance = await api.query.balances.freeBalance(keyring.alice_stash.address);
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ describeE2E()('Promise e2e queries', (wsUrl): void => {
|
||||
it('gets correct key', async (): Promise<void> => {
|
||||
const key = api.query.session.currentIndex.key();
|
||||
const sessionIndexData = await api.rpc.state.getStorage(key) as Option<any>;
|
||||
const sessionIndexRPC = createType<SessionIndex>('SessionIndex', sessionIndexData.unwrapOr(undefined));
|
||||
const sessionIndexRPC = createType('SessionIndex', sessionIndexData.unwrapOr(undefined));
|
||||
|
||||
expect(sessionIndexRPC.toNumber()).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
@@ -12,7 +12,8 @@ import memoizee from 'memoizee';
|
||||
import { combineLatest, from, Observable, Observer, of, throwError } from 'rxjs';
|
||||
import { catchError, map, publishReplay, refCount, switchMap } from 'rxjs/operators';
|
||||
import interfaces from '@polkadot/jsonrpc';
|
||||
import { ClassOf, Option, StorageKey, Vec, createClass, createType } from '@polkadot/types';
|
||||
import { ClassOf, Option, StorageKey, Vec, createClass } from '@polkadot/types';
|
||||
import { createTypeUnsafe } from '@polkadot/types/codec/createType';
|
||||
import { ExtError, assert, isFunction, isNull, isNumber, logger } from '@polkadot/util';
|
||||
|
||||
const l = logger('rpc-core');
|
||||
@@ -261,12 +262,12 @@ export default class Rpc implements RpcInterface {
|
||||
assert(inputs.length >= reqArgCount && inputs.length <= method.params.length, `Expected ${method.params.length} parameters${optText}, ${inputs.length} found instead`);
|
||||
|
||||
return inputs.map((input, index): Codec =>
|
||||
createType(method.params[index].type, input)
|
||||
createTypeUnsafe(method.params[index].type, input)
|
||||
);
|
||||
}
|
||||
|
||||
private formatOutput (method: RpcMethod, params: Codec[], result?: any): Codec | (Codec | null | undefined)[] {
|
||||
const base = createType(method.type as string, result);
|
||||
const base = createTypeUnsafe(method.type as string, result);
|
||||
|
||||
if (method.type === 'StorageData') {
|
||||
const key = params[0] as StorageKey;
|
||||
@@ -309,11 +310,11 @@ export default class Rpc implements RpcInterface {
|
||||
if (meta.modifier.isOptional) {
|
||||
return new Option(
|
||||
createClass(type),
|
||||
isNull ? null : createType(type, base, true)
|
||||
isNull ? null : createTypeUnsafe(type, base, true)
|
||||
);
|
||||
}
|
||||
|
||||
return createType(type, isNull ? meta.fallback : base, true);
|
||||
return createTypeUnsafe(type, isNull ? meta.fallback : base, true);
|
||||
}
|
||||
|
||||
private formatStorageSet (key: StorageKey, base: StorageChangeSet): Codec {
|
||||
@@ -336,10 +337,10 @@ export default class Rpc implements RpcInterface {
|
||||
if (meta.modifier.isOptional) {
|
||||
return new Option(
|
||||
createClass(type),
|
||||
value.isNone ? null : createType(type, value.unwrap(), true)
|
||||
value.isNone ? null : createTypeUnsafe(type, value.unwrap(), true)
|
||||
);
|
||||
}
|
||||
|
||||
return createType(type, value.unwrapOr(meta.fallback), true);
|
||||
return createTypeUnsafe(type, value.unwrapOr(meta.fallback), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import '../../injector';
|
||||
|
||||
import extrinsicsFromMeta from '@polkadot/api-metadata/extrinsics/fromMetadata';
|
||||
|
||||
import createType from '../../codec/createType';
|
||||
import { createTypeUnsafe } from '../../codec/createType';
|
||||
import Metadata from '../Metadata';
|
||||
import Method from '../../primitive/Method';
|
||||
import { MetadataInterface } from '../types';
|
||||
@@ -62,7 +62,7 @@ export function defaultValues (rpcData: string): void {
|
||||
mod.storage.unwrap().items.forEach(({ fallback, name, type }): void => {
|
||||
it(`creates default types for ${mod.name}.${name}, type ${type}`, (): void => {
|
||||
expect(
|
||||
(): Codec => createType(type.toString(), fallback)
|
||||
(): Codec => createTypeUnsafe(type.toString(), fallback)
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
import '../injector';
|
||||
|
||||
import { Balance, BlockNumber } from '../interfaces/runtime';
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
import createType, { ClassOf } from '../codec/createType';
|
||||
@@ -66,7 +64,7 @@ describe('Compact', (): void => {
|
||||
|
||||
it('encondes a large balance', (): void => {
|
||||
expect(
|
||||
Compact.encodeU8a(createType<Balance>('Balance', '0x5af3107a4000'))
|
||||
Compact.encodeU8a(createType('Balance', '0x5af3107a4000'))
|
||||
).toEqual(
|
||||
new Uint8Array([
|
||||
3 + ((6 - 4) << 2),
|
||||
@@ -111,13 +109,13 @@ describe('Compact', (): void => {
|
||||
describe('constructor', (): void => {
|
||||
it('has the correct bitLength for constructor values (BlockNumber)', (): void => {
|
||||
expect(
|
||||
new Compact(ClassOf<BlockNumber>('BlockNumber'), 0xfffffff9).bitLength()
|
||||
new Compact(ClassOf('BlockNumber'), 0xfffffff9).bitLength()
|
||||
).toEqual(64);
|
||||
});
|
||||
|
||||
it('has the correct encodedLength for constructor values (BlockNumber)', (): void => {
|
||||
expect(
|
||||
new Compact(ClassOf<BlockNumber>('BlockNumber'), 0xfffffff9).encodedLength
|
||||
new Compact(ClassOf('BlockNumber'), 0xfffffff9).encodedLength
|
||||
).toEqual(5);
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import extrinsics from '@polkadot/api-metadata/extrinsics/static';
|
||||
import AccountId from '../primitive/AccountId';
|
||||
import Method from '../primitive/Method';
|
||||
import Text from '../primitive/Text';
|
||||
import createType from './createType';
|
||||
import { createTypeUnsafe } from './createType';
|
||||
import Vec from './Vec';
|
||||
import Tuple from './Tuple';
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('Vec', (): void => {
|
||||
});
|
||||
|
||||
it.skip('decodes a complex type via construction', (): void => {
|
||||
const test = createType('Vec<(PropIndex, Proposal, AccountId)>', new Uint8Array([
|
||||
const test = createTypeUnsafe('Vec<(PropIndex, Proposal, AccountId)>', new Uint8Array([
|
||||
4, 10, 0, 0, 0, 0, 3, 80, 123, 10, 9, 34, 48, 120, 52, 50, 34, 58, 32, 34, 48, 120, 52, 51, 34, 10, 125, 10, 209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79
|
||||
]));
|
||||
const first = (test as Vec<Codec>)[0] as Tuple;
|
||||
|
||||
@@ -6,8 +6,7 @@ import '../injector';
|
||||
|
||||
import { Codec, Constructor } from '../types';
|
||||
|
||||
import createType, { TypeDef, TypeDefInfo, createClass, getTypeClass, getTypeDef, typeSplit, ClassOf } from './createType';
|
||||
import Text from '../primitive/Text';
|
||||
import createType, { TypeDef, TypeDefInfo, createClass, createTypeUnsafe, getTypeClass, getTypeDef, typeSplit, ClassOf } from './createType';
|
||||
import CodecSet from './Set';
|
||||
|
||||
describe('typeSplit', (): void => {
|
||||
@@ -221,26 +220,12 @@ describe('createClass', (): void => {
|
||||
|
||||
expect(a).toBe(b);
|
||||
});
|
||||
|
||||
it('should memoize from Text', (): void => {
|
||||
const a = createClass(new Text('TrieId'));
|
||||
const b = createClass(new Text('TrieId'));
|
||||
|
||||
expect(a).toBe(b);
|
||||
});
|
||||
|
||||
it('should memoize from string/Text combo', (): void => {
|
||||
const a = createClass(new Text('AuthorityWeight'));
|
||||
const b = createClass('AuthorityWeight');
|
||||
|
||||
expect(a).toBe(b);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createType', (): void => {
|
||||
it('allows creation of a Struct', (): void => {
|
||||
expect(
|
||||
createType('{"balance":"Balance","index":"u32"}', {
|
||||
createTypeUnsafe('{"balance":"Balance","index":"u32"}', {
|
||||
balance: 1234,
|
||||
index: '0x10'
|
||||
}).toJSON()
|
||||
@@ -252,31 +237,31 @@ describe('createType', (): void => {
|
||||
|
||||
it('allows creation of a Enum (simple)', (): void => {
|
||||
expect(
|
||||
createType('{"_enum": ["A", "B", "C"]}', 1).toJSON()
|
||||
createTypeUnsafe('{"_enum": ["A", "B", "C"]}', 1).toJSON()
|
||||
).toEqual({ B: null });
|
||||
});
|
||||
|
||||
it('allows creation of a Enum (parametrised)', (): void => {
|
||||
expect(
|
||||
createType('{"_enum": {"A": null, "B": "u32", "C": null} }', 1).toJSON()
|
||||
createTypeUnsafe('{"_enum": {"A": null, "B": "u32", "C": null} }', 1).toJSON()
|
||||
).toEqual({ B: 0 });
|
||||
});
|
||||
|
||||
it('allows creation of a Set', (): void => {
|
||||
expect(
|
||||
createType<CodecSet>('{"_set": { "A": 1, "B": 2, "C": 4, "D": 8, "E": 16, "G": 32, "H": 64, "I": 128 } }', 1 + 4 + 16 + 64).strings
|
||||
createTypeUnsafe<CodecSet>('{"_set": { "A": 1, "B": 2, "C": 4, "D": 8, "E": 16, "G": 32, "H": 64, "I": 128 } }', 1 + 4 + 16 + 64).strings
|
||||
).toEqual(['A', 'C', 'E', 'H']);
|
||||
});
|
||||
|
||||
it('allows creation of a [u8; 8]', (): void => {
|
||||
expect(
|
||||
createType('[u8; 8]', [0x12, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67, 0x00]).toHex()
|
||||
createTypeUnsafe('[u8; 8]', [0x12, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67, 0x00]).toHex()
|
||||
).toEqual('0x1200230045006700');
|
||||
});
|
||||
|
||||
it('allows creation of a [u16; 4]', (): void => {
|
||||
expect(
|
||||
createType('[u16; 4]', [0x1200, 0x2300, 0x4500, 0x6700]).toU8a()
|
||||
createTypeUnsafe('[u16; 4]', [0x1200, 0x2300, 0x4500, 0x6700]).toU8a()
|
||||
).toEqual(new Uint8Array([0x00, 0x12, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67]));
|
||||
});
|
||||
|
||||
@@ -284,7 +269,7 @@ describe('createType', (): void => {
|
||||
const base = createType('StorageData', null);
|
||||
|
||||
expect(
|
||||
(): Codec => createType('DoubleMap<Vec<(BlockNumber,EventIndex)>>', base, true)
|
||||
(): Codec => createTypeUnsafe('DoubleMap<Vec<(BlockNumber,EventIndex)>>', base, true)
|
||||
).toThrow(/ Input doesn't match output, received 0x, created 0x00/);
|
||||
});
|
||||
|
||||
@@ -292,7 +277,7 @@ describe('createType', (): void => {
|
||||
const base = createType('StorageData', null);
|
||||
|
||||
expect(
|
||||
(): Codec => createType('Vec<(BlockNumber,EventIndex)>', base, true)
|
||||
(): Codec => createTypeUnsafe('Vec<(BlockNumber,EventIndex)>', base, true)
|
||||
).toThrow(/Input doesn't match output, received 0x, created 0x00/);
|
||||
});
|
||||
|
||||
@@ -313,7 +298,7 @@ describe('createType', (): void => {
|
||||
it('instanceof should work (complex type)', (): void => {
|
||||
const complexType = '{"balance":"Balance","account_id":"AccountId","log":"(u64, u32)","fromSrml":"Gas"}';
|
||||
|
||||
const value = createType(complexType, {
|
||||
const value = createTypeUnsafe(complexType, {
|
||||
balance: 123,
|
||||
accountId: '',
|
||||
log: [456, 789],
|
||||
|
||||
@@ -8,7 +8,6 @@ import { assert } from '@polkadot/util';
|
||||
import { InterfaceRegistry } from '../interfaceRegistry';
|
||||
import { Codec, Constructor } from '../types';
|
||||
import Null from '../primitive/Null';
|
||||
import Text from '../primitive/Text';
|
||||
import Compact from './Compact';
|
||||
import Enum from './Enum';
|
||||
import Linkage from './Linkage';
|
||||
@@ -22,6 +21,9 @@ import Vec from './Vec';
|
||||
import VecFixed from './VecFixed';
|
||||
import getRegistry from './typeRegistry';
|
||||
|
||||
// Type which says: if `K` is in the InterfaceRegistry, then return InterfaceRegistry[K], else fallback to T
|
||||
type FromReg<T extends Codec, K extends string> = K extends keyof InterfaceRegistry ? InterfaceRegistry[K] : T
|
||||
|
||||
export enum TypeDefInfo {
|
||||
Compact,
|
||||
DoubleMap,
|
||||
@@ -135,7 +137,7 @@ function _decodeSet (value: TypeDef, details: Record<string, number>): TypeDef {
|
||||
return value;
|
||||
}
|
||||
|
||||
export function getTypeDef (_type: Text | string, name?: string): TypeDef {
|
||||
export function getTypeDef (_type: string, name?: string): TypeDef {
|
||||
const type = _type.toString().trim();
|
||||
const value: TypeDef = {
|
||||
info: TypeDefInfo.Plain,
|
||||
@@ -202,27 +204,33 @@ export function getTypeDef (_type: Text | string, name?: string): TypeDef {
|
||||
}
|
||||
|
||||
// Memoized helper of the `createClass` function below
|
||||
const memoizedCreateClass = memoizee(<T extends Codec = Codec, K extends Text | string = Text | string>(
|
||||
const memoizedCreateClass = memoizee(<T extends Codec = Codec, K extends string = string>(
|
||||
type: K
|
||||
): Constructor<K extends keyof InterfaceRegistry ? InterfaceRegistry[K] : T> => {
|
||||
): Constructor<FromReg<T, K>> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
return getTypeClass<K extends keyof InterfaceRegistry ? InterfaceRegistry[K] : T>(
|
||||
return getTypeClass<FromReg<T, K>>(
|
||||
getTypeDef(type)
|
||||
);
|
||||
}, {
|
||||
length: 1,
|
||||
// Normalize args so that different args that should be cached
|
||||
// together are cached together.
|
||||
// E.g.: `createClass('abc') === createClass(new Text('abc'));`
|
||||
normalizer: JSON.stringify
|
||||
});
|
||||
}, { length: 1 });
|
||||
|
||||
export function createClass<T extends Codec = Codec, K extends Text | string = Text | string> (
|
||||
export function createClass<T extends Codec = Codec, K extends string = string> (
|
||||
type: K
|
||||
): Constructor<K extends keyof InterfaceRegistry ? InterfaceRegistry[K] : T> {
|
||||
): Constructor<FromReg<T, K>> {
|
||||
return memoizedCreateClass(type);
|
||||
}
|
||||
|
||||
// An unsafe version of the `createType` below. It's unsafe because the `type`
|
||||
// argument here can be any string, which, if not parseable, will yield a
|
||||
// runtime error.
|
||||
export function ClassOfUnsafe<T extends Codec = Codec, K extends string = string> (name: K): Constructor<FromReg<T, K>> {
|
||||
return createClass<T, K>(name);
|
||||
}
|
||||
|
||||
// alias for createClass
|
||||
export function ClassOf<K extends keyof InterfaceRegistry> (name: K): Constructor<InterfaceRegistry[K]> {
|
||||
return ClassOfUnsafe<Codec, K>(name) as Constructor<InterfaceRegistry[K]>;
|
||||
}
|
||||
|
||||
// create an array of constructors from the input
|
||||
export function getTypeClassMap (defs: TypeDef[]): { [index: string]: Constructor } {
|
||||
return defs.reduce((result, sub): Record<string, Constructor> => {
|
||||
@@ -320,12 +328,7 @@ export function getTypeClass<T extends Codec = Codec> (value: TypeDef, Fallback?
|
||||
throw new Error(`Unable to determine type from ${JSON.stringify(value)}`);
|
||||
}
|
||||
|
||||
// alias for createClass
|
||||
export function ClassOf<T extends Codec = Codec, K extends Text | string = Text | string> (name: string): Constructor<T> {
|
||||
return createClass<T>(name);
|
||||
}
|
||||
|
||||
function initType<T extends Codec = Codec, K extends Text | string = Text | string> (Type: Constructor<T>, value?: any, isPedantic?: boolean): T {
|
||||
function initType<T extends Codec = Codec, K extends string = string> (Type: Constructor<FromReg<T, K>>, value?: any, isPedantic?: boolean): FromReg<T, K> {
|
||||
try {
|
||||
const created = new Type(value);
|
||||
|
||||
@@ -349,21 +352,41 @@ function initType<T extends Codec = Codec, K extends Text | string = Text | stri
|
||||
return created;
|
||||
} catch (error) {
|
||||
if (Type.Fallback) {
|
||||
return initType(Type.Fallback, value, isPedantic);
|
||||
return initType(Type.Fallback as Constructor<FromReg<T, K>>, value, isPedantic);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export default function createType<T extends Codec = Codec, K extends Text | string = Text | string> (
|
||||
// An unsafe version of the `createType` below. It's unsafe because the `type`
|
||||
// argument here can be any string, which, if not parseable, will yield a
|
||||
// runtime error.
|
||||
export function createTypeUnsafe<T extends Codec = Codec, K extends string = string> (
|
||||
type: K,
|
||||
value?: any,
|
||||
isPedantic?: boolean
|
||||
): K extends keyof InterfaceRegistry ? InterfaceRegistry[K] : T {
|
||||
): FromReg<T, K> {
|
||||
try {
|
||||
return initType(createClass<T, K>(type), value, isPedantic);
|
||||
} catch (error) {
|
||||
throw new Error(`createType(${type}):: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a `type` with a given `value`.
|
||||
* @param type - A recognizable string representing the type to create an
|
||||
* instance from
|
||||
* @param value - The value to instantiate the type with
|
||||
* @param isPedantic - Double-check that the input's encoding matches the
|
||||
* output's one. Slower, but ensures that we have a 100% grasp on the actual
|
||||
* provided value
|
||||
*/
|
||||
export default function createType<K extends keyof InterfaceRegistry> (
|
||||
type: K,
|
||||
value?: any,
|
||||
isPedantic?: boolean
|
||||
): InterfaceRegistry[K] {
|
||||
return createTypeUnsafe<Codec, K>(type, value, isPedantic) as InterfaceRegistry[K];
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
import '../../injector';
|
||||
|
||||
import { KeyValue } from './types';
|
||||
|
||||
import createType from '../../codec/createType';
|
||||
|
||||
describe('KeyValue', (): void => {
|
||||
@@ -34,7 +32,7 @@ describe('KeyValue', (): void => {
|
||||
});
|
||||
|
||||
it('exposes the properties for key/value', (): void => {
|
||||
const [key, value] = createType<KeyValue>('KeyValue', ['0x11223344', '0x998877665544332211']);
|
||||
const [key, value] = createType('KeyValue', ['0x11223344', '0x998877665544332211']);
|
||||
|
||||
expect(key.toHex()).toEqual('0x11223344');
|
||||
expect(value.toHex()).toEqual('0x998877665544332211');
|
||||
|
||||
@@ -119,7 +119,7 @@ export default class Event extends Struct {
|
||||
section.events.unwrap().forEach((meta, methodIndex): void => {
|
||||
const methodName = meta.name.toString();
|
||||
const eventIndex = new Uint8Array([sectionIndex, methodIndex]);
|
||||
const typeDef = meta.args.map((arg): TypeDef => getTypeDef(arg));
|
||||
const typeDef = meta.args.map((arg): TypeDef => getTypeDef(arg.toString()));
|
||||
const Types = typeDef.map((typeDef): Constructor<Codec> => getTypeClass(typeDef, Unconstructable.with(typeDef)));
|
||||
|
||||
EventTypes[eventIndex.toString()] = class extends EventData {
|
||||
|
||||
@@ -123,7 +123,7 @@ export default class ExtrinsicSignatureV1 extends Struct implements IExtrinsicSi
|
||||
era: era || IMMORTAL_ERA,
|
||||
blockHash
|
||||
});
|
||||
const signature = createType<Signature>('Signature', payload.sign(account));
|
||||
const signature = createType('Signature', payload.sign(account));
|
||||
|
||||
return this.injectSignature(signer, signature, payload);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export default class ExtrinsicSignatureV2 extends Struct implements IExtrinsicSi
|
||||
nonce,
|
||||
tip: tip || 0
|
||||
});
|
||||
const signature = createType<Signature>('Signature', payload.sign(account));
|
||||
const signature = createType('Signature', payload.sign(account));
|
||||
|
||||
return this.injectSignature(signer, signature, payload);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ export default class Method extends Struct implements IMethod {
|
||||
private static getArgsDef (meta: FunctionMetadataV7): ArgsDef {
|
||||
return Method.filterOrigin(meta).reduce((result, { name, type }): ArgsDef => {
|
||||
const Type = getTypeClass(
|
||||
getTypeDef(type)
|
||||
getTypeDef(type.toString())
|
||||
);
|
||||
result[name.toString()] = Type;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export default class Vote extends U8a {
|
||||
const conviction = decoded[0] & 0b01111111;
|
||||
|
||||
this._aye = new Bool(msb);
|
||||
this._conviction = createType<Conviction>('Conviction', conviction);
|
||||
this._conviction = createType('Conviction', conviction);
|
||||
}
|
||||
|
||||
private static decodeVote (value?: any): Uint8Array {
|
||||
@@ -48,7 +48,7 @@ export default class Vote extends U8a {
|
||||
: new Uint8Array([0b0]);
|
||||
} else if (isObject(value) && !isUndefined(value.aye) && !isUndefined(value.conviction)) {
|
||||
const aye = new Bool(value.aye);
|
||||
const convictionIndex = createType<Conviction>('Conviction', value.conviction).index;
|
||||
const convictionIndex = createType('Conviction', value.conviction).index;
|
||||
|
||||
const result = convictionIndex | (aye.eq(true) ? 0b1 << 7 : 0b0);
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ export interface IHash extends U8a { }
|
||||
export type CodecTo = 'toHex' | 'toJSON' | 'toString' | 'toU8a';
|
||||
|
||||
export interface Constructor<T = Codec> {
|
||||
Fallback?: Constructor<T>;
|
||||
Fallback?: Constructor<Codec>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
new(...value: any[]): T;
|
||||
|
||||
Reference in New Issue
Block a user