Change initialU8aLength to non-getter (#4170)

* Change initialU8aLength to non-getter

* Remove time comments

* Adjust Compact shortcut

* Adjust

* Move isU8a check first in decoding

* #initialLength for Compact

* Compact re-adjust

* Split decodeU8aVec

* decodeVec opt

* Fix compare

* Adjust

* Additional objectSpread

* Additional objectSpread

* isU8a always first

* Comment time logs

* Convert String right at point of using

* Optimize Text from Text

* Fix Text test

* Additional ordering updates

* Enum adjustments

* Reorder Option

* Adjust

* Remove comments

* Adjust
This commit is contained in:
Jaco
2021-11-05 16:19:38 +02:00
committed by GitHub
parent 72b4b51915
commit 4e64e3d654
66 changed files with 560 additions and 720 deletions
@@ -3,17 +3,15 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
import kusama from './kusama';
import polkadot from './polkadot';
import substrate from './substrate';
export default {
rpc: {},
types: {
// Not 100% sure it is relevant, however the order here is the same
// as exposed in the typegen lookup order
...substrate,
...polkadot,
...kusama
}
// Not 100% sure it is relevant, however the order here is the same
// as exposed in the typegen lookup order
types: objectSpread({}, substrate, polkadot, kusama)
} as Definitions;
+2 -9
View File
@@ -21,7 +21,7 @@ export abstract class AbstractArray<T extends Codec> extends Array<T> implements
public createdAtHash?: Hash;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
protected constructor (registry: Registry, values: T[], initialU8aLength?: number) {
super(values.length);
@@ -32,7 +32,7 @@ export abstract class AbstractArray<T extends Codec> extends Array<T> implements
}
this.registry = registry;
this.#initialU8aLength = initialU8aLength;
this.initialU8aLength = initialU8aLength;
}
/**
@@ -50,13 +50,6 @@ export abstract class AbstractArray<T extends Codec> extends Array<T> implements
return total;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description returns a hash of the contents
*/
+18 -30
View File
@@ -6,7 +6,7 @@ import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyNumber, INumber, Registry } from '../types';
import type { UIntBitLength } from './types';
import { assert, BN, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_QUINTILL, BN_ZERO, bnToBn, bnToHex, bnToU8a, formatBalance, formatNumber, hexToBn, isHex, isString, isU8a, stringify, u8aToBn } from '@polkadot/util';
import { assert, BN, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_QUINTILL, BN_ZERO, bnToBn, bnToHex, bnToU8a, formatBalance, formatNumber, hexToBn, isBn, isHex, isU8a, stringify, u8aToBn } from '@polkadot/util';
export const DEFAULT_UINT_BITS = 64;
@@ -26,31 +26,26 @@ function toPercentage (value: BN, divisor: BN): string {
return `${(value.mul(MUL_P).div(divisor).toNumber() / 100).toFixed(2)}%`;
}
/** @internal */
function decodeAbstracIntU8a (value: Uint8Array, bitLength: UIntBitLength, isNegative: boolean): string {
if (!value.length) {
return '0';
}
try {
// NOTE When passing u8a in (typically from decoded data), it is always Little Endian
return u8aToBn(value.subarray(0, bitLength / 8), { isLe: true, isNegative }).toString();
} catch (error) {
throw new Error(`AbstractInt: failed on ${stringify(value)}:: ${(error as Error).message}`);
}
}
/** @internal */
function decodeAbstractInt (value: AnyNumber, bitLength: UIntBitLength, isNegative: boolean): string {
// This function returns a string, which will be passed in the BN
// constructor. It would be ideal to actually return a BN, but there's a
// bug: https://github.com/indutny/bn.js/issues/206.
if (isHex(value, -1, true)) {
if (isU8a(value)) {
if (!value.length) {
return '0';
}
try {
// NOTE When passing u8a in (typically from decoded data), it is always Little Endian
return u8aToBn(value.subarray(0, bitLength / 8), { isLe: true, isNegative }).toString();
} catch (error) {
throw new Error(`AbstractInt: failed on ${stringify(value)}:: ${(error as Error).message}`);
}
} else if (isBn(value)) {
return value.toString();
} else if (isHex(value, -1, true)) {
return hexToBn(value, { isLe: false, isNegative }).toString();
} else if (isU8a(value)) {
return decodeAbstracIntU8a(value, bitLength, isNegative);
} else if (isString(value)) {
return new BN(value.toString(), 10).toString();
}
return bnToBn(value).toString();
@@ -66,9 +61,9 @@ export abstract class AbstractInt extends BN implements INumber {
public createdAtHash?: Hash;
readonly #bitLength: UIntBitLength;
readonly encodedLength: number;
readonly #byteLength: number;
readonly #bitLength: UIntBitLength;
readonly #isSigned: boolean;
@@ -77,7 +72,7 @@ export abstract class AbstractInt extends BN implements INumber {
this.registry = registry;
this.#bitLength = bitLength;
this.#byteLength = this.#bitLength / 8;
this.encodedLength = this.#bitLength / 8;
this.#isSigned = isSigned;
const isPositive = this.gte(BN_ZERO);
@@ -87,13 +82,6 @@ export abstract class AbstractInt extends BN implements INumber {
assert(super.bitLength() <= maxBits, () => `${this.toRawType()}: Input too large. Found input with ${super.bitLength()} bits, expected ${maxBits}`);
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
return this.#byteLength;
}
/**
* @description returns a hash of the contents
*/
+11 -18
View File
@@ -62,7 +62,7 @@ function decodeSet<V extends Codec> (registry: Registry, valType: Constructor<V>
const ValClass = typeToConstructor(registry, valType);
if (isHex(value) || isU8a(value)) {
if (isU8a(value) || isHex(value)) {
return decodeSetFromU8a<V>(registry, ValClass, u8aToU8a(value));
} else if (Array.isArray(value) || value instanceof Set) {
return decodeSetFromSet<V>(registry, ValClass, value);
@@ -76,7 +76,7 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements ISet<V>
public createdAtHash?: Hash;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
readonly #ValClass: Constructor<V>;
@@ -86,7 +86,7 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements ISet<V>
super(sortSet(values));
this.registry = registry;
this.#initialU8aLength = decodedLength;
this.initialU8aLength = decodedLength;
this.#ValClass = typeToConstructor(registry, valType);
}
@@ -104,20 +104,13 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements ISet<V>
public get encodedLength (): number {
let len = compactToU8a(this.size).length;
this.forEach((v: V) => {
for (const v of this.values()) {
len += v.encodedLength;
});
}
return len;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description Returns a hash of the value
*/
@@ -159,9 +152,9 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements ISet<V>
public toHuman (isExtended?: boolean): AnyJson {
const json: AnyJson = [];
this.forEach((v: V) => {
for (const v of this.values()) {
json.push(v.toHuman(isExtended));
});
}
return json;
}
@@ -172,9 +165,9 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements ISet<V>
public toJSON (): AnyJson {
const json: AnyJson = [];
this.forEach((v: V) => {
for (const v of this.values()) {
json.push(v.toJSON());
});
}
return json;
}
@@ -204,9 +197,9 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements ISet<V>
encoded.push(compactToU8a(this.size));
}
this.forEach((v: V) => {
for (const v of this.values()) {
encoded.push(v.toU8a(isBare));
});
}
return u8aConcat(...encoded);
}
+2 -9
View File
@@ -14,14 +14,14 @@ export abstract class Base<T extends Codec> implements Codec {
public createdAtHash?: Hash;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
protected readonly _raw: T;
protected constructor (registry: Registry, value: T, initialU8aLength?: number) {
this.registry = registry;
this._raw = value;
this.#initialU8aLength = initialU8aLength;
this.initialU8aLength = initialU8aLength;
}
/**
@@ -31,13 +31,6 @@ export abstract class Base<T extends Codec> implements Codec {
return this.toU8a().length;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description returns a hash of the contents
*/
+5 -10
View File
@@ -23,9 +23,9 @@ export class Compact<T extends INumber> implements ICompact<T> {
public createdAtHash?: Hash;
readonly #Type: Constructor<T>;
readonly initialU8aLength?: number;
readonly #initialU8aLength?: number;
readonly #Type: Constructor<T>;
readonly #raw: T;
@@ -35,7 +35,7 @@ export class Compact<T extends INumber> implements ICompact<T> {
const [raw, decodedLength] = Compact.decodeCompact<T>(registry, this.#Type, value);
this.#initialU8aLength = decodedLength;
this.initialU8aLength = decodedLength;
this.#raw = raw;
}
@@ -51,6 +51,8 @@ export class Compact<T extends INumber> implements ICompact<T> {
public static decodeCompact<T extends INumber> (registry: Registry, Type: Constructor<T>, value: Compact<T> | AnyNumber): [T, number] {
if (value instanceof Compact) {
return [new Type(registry, value.#raw), 0];
} else if (value instanceof Type) {
return [value, 0];
} else if (isString(value) || isNumber(value) || isBn(value) || isBigInt(value)) {
return [new Type(registry, value), 0];
}
@@ -67,13 +69,6 @@ export class Compact<T extends INumber> implements ICompact<T> {
return this.toU8a().length;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description returns a hash of the contents
*/
+3 -3
View File
@@ -11,10 +11,10 @@ import { BN, bnToBn, bnToHex, bnToU8a, isString, isU8a, u8aToBn } from '@polkado
const BITLENGTH: UIntBitLength = 64;
function decodeDate (value: CodecDate | Date | AnyNumber): Date {
if (value instanceof Date) {
return value;
} else if (isU8a(value)) {
if (isU8a(value)) {
value = u8aToBn(value.subarray(0, BITLENGTH / 8), true);
} else if (value instanceof Date) {
return value;
} else if (isString(value)) {
value = new BN(value.toString(), 10, 'le');
}
+1 -1
View File
@@ -423,7 +423,7 @@ describe('Enum', (): void => {
});
it('encodes a single entry correctly (with embedded encoding)', (): void => {
const Test = Enum.with({ A: 'Address' });
const Test = Enum.with({ A: 'MultiAddress' });
const test = new Test(registry, registry.createType('AccountId', '0x0001020304050607080910111213141516171819202122232425262728293031'), 0);
expect(test.toHex()).toEqual(
+5 -12
View File
@@ -170,7 +170,7 @@ export class Enum implements IEnum {
readonly #entryIndex: number;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
readonly #indexes: number[];
@@ -193,7 +193,7 @@ export class Enum implements IEnum {
this.#raw = decoded.value;
if (this.#raw.initialU8aLength) {
this.#initialU8aLength = 1 + this.#raw.initialU8aLength;
this.initialU8aLength = 1 + this.#raw.initialU8aLength;
}
}
@@ -228,13 +228,6 @@ export class Enum implements IEnum {
return 1 + this.#raw.encodedLength;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description returns a hash of the contents
*/
@@ -311,12 +304,12 @@ export class Enum implements IEnum {
*/
public eq (other?: unknown): boolean {
// cater for the case where we only pass the enum index
if (isNumber(other)) {
if (isU8a(other)) {
return !this.toU8a().some((entry, index) => entry !== other[index]);
} else if (isNumber(other)) {
return this.toNumber() === other;
} else if (this.#isBasic && isString(other)) {
return this.type === other;
} else if (isU8a(other)) {
return !this.toU8a().some((entry, index) => entry !== other[index]);
} else if (isHex(other)) {
return this.toHex() === other;
} else if (other instanceof Enum) {
+12 -19
View File
@@ -38,7 +38,7 @@ function decodeMapFromU8a<K extends Codec, V extends Codec> (registry: Registry,
function decodeMapFromMap<K extends Codec, V extends Codec> (registry: Registry, KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Map<any, any>): [Map<K, V>, number] {
const output = new Map<K, V>();
value.forEach((val: unknown, key: unknown) => {
for (const [key, val] of value.entries()) {
const isComplex = KeyClass.prototype instanceof AbstractArray ||
KeyClass.prototype instanceof Struct ||
KeyClass.prototype instanceof Enum;
@@ -57,7 +57,7 @@ function decodeMapFromMap<K extends Codec, V extends Codec> (registry: Registry,
throw error;
}
});
}
return [output, 0];
}
@@ -103,7 +103,7 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
readonly #ValClass: Constructor<V>;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
readonly #type: string;
@@ -113,9 +113,9 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
super(type === 'BTreeMap' ? sortMap(decoded) : decoded);
this.registry = registry;
this.initialU8aLength = decodedLength;
this.#KeyClass = typeToConstructor(registry, keyType);
this.#ValClass = typeToConstructor(registry, valType);
this.#initialU8aLength = decodedLength;
this.#type = type;
}
@@ -125,20 +125,13 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
public get encodedLength (): number {
let len = compactToU8a(this.size).length;
this.forEach((v: V, k: K) => {
for (const [k, v] of this.entries()) {
len += v.encodedLength + k.encodedLength;
});
}
return len;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description Returns a hash of the value
*/
@@ -173,9 +166,9 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
public toHuman (isExtended?: boolean): Record<string, AnyJson> {
const json: Record<string, AnyJson> = {};
this.forEach((v: V, k: K) => {
for (const [k, v] of this.entries()) {
json[k.toString()] = v.toHuman(isExtended);
});
}
return json;
}
@@ -186,9 +179,9 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
public toJSON (): Record<string, AnyJson> {
const json: Record<string, AnyJson> = {};
this.forEach((v: V, k: K) => {
for (const [k, v] of this.entries()) {
json[k.toString()] = v.toJSON();
});
}
return json;
}
@@ -218,9 +211,9 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
encoded.push(compactToU8a(this.size));
}
this.forEach((v: V, k: K) => {
for (const [k, v] of this.entries()) {
encoded.push(k.toU8a(isBare), v.toU8a(isBare));
});
}
return u8aConcat(...encoded);
}
+3 -8
View File
@@ -10,13 +10,6 @@ import { assert, isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util';
import { Null } from '../primitive/Null';
import { typeToConstructor } from './utils';
/** @internal */
function decodeOptionU8a (registry: Registry, Type: Constructor, value: Uint8Array): Codec {
return !value.length || value[0] === 0
? new Null(registry)
: new Type(registry, value.subarray(1));
}
/** @internal */
function decodeOption (registry: Registry, typeName: Constructor | string, value?: unknown): Codec {
if (isNull(value) || isUndefined(value) || value instanceof Null || value === '0x') {
@@ -34,7 +27,9 @@ function decodeOption (registry: Registry, typeName: Constructor | string, value
} else if (isU8a(value)) {
// the isU8a check happens last in the if-tree - since the wrapped value
// may be an instance of it, so Type and Option checks go in first
return decodeOptionU8a(registry, Type, value);
return !value.length || value[0] === 0
? new Null(registry)
: new Type(registry, value.subarray(1));
}
return new Type(registry, value);
+2 -9
View File
@@ -21,13 +21,13 @@ export class Raw extends Uint8Array implements IU8a {
public createdAtHash?: Hash;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
constructor (registry: Registry, value?: AnyU8a, initialU8aLength?: number) {
super(u8aToU8a(value));
this.registry = registry;
this.#initialU8aLength = initialU8aLength;
this.initialU8aLength = initialU8aLength;
}
/**
@@ -37,13 +37,6 @@ export class Raw extends Uint8Array implements IU8a {
return this.length;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description returns a hash of the contents
*/
+3 -3
View File
@@ -63,12 +63,12 @@ function decodeSet (setValues: SetValues, value: string[] | Set<string> | Uint8A
const byteLength = bitLength / 8;
if (isString(value)) {
return decodeSet(setValues, u8aToU8a(value), byteLength);
} else if (isU8a(value)) {
if (isU8a(value)) {
return value.length === 0
? []
: decodeSetNumber(setValues, u8aToBn(value.subarray(0, byteLength), { isLe: true }));
} else if (isString(value)) {
return decodeSet(setValues, u8aToU8a(value), byteLength);
} else if (value instanceof Set || Array.isArray(value)) {
const input = Array.isArray(value)
? value
+10 -13
View File
@@ -74,6 +74,10 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
return raw;
}
function decodeZip (k: string, v: Codec): [string, Codec] {
return [k, v];
}
/**
* Decode input to pass into constructor.
*
@@ -91,12 +95,12 @@ function decodeStructFromObject (registry: Registry, Types: ConstructorDef, valu
* @internal
*/
function decodeStruct (registry: Registry, Types: ConstructorDef, value: unknown, jsonMap: Map<string, string>): [Iterable<[string, Codec]>, number] {
if (isHex(value)) {
return decodeStruct(registry, Types, hexToU8a(value), jsonMap);
} else if (isU8a(value)) {
return decodeU8a<Codec, [string, Codec]>(registry, value, Types, 0, (k, v) => [k, v]);
if (isU8a(value)) {
return decodeU8a(registry, value, Types, decodeZip);
} else if (value instanceof Struct) {
return [value as Iterable<[string, Codec]>, 0];
} else if (isHex(value)) {
return decodeStruct(registry, Types, hexToU8a(value), jsonMap);
}
// We assume from here that value is a JS object (Array, Map, Object)
@@ -124,7 +128,7 @@ export class Struct<
public createdAtHash?: Hash;
readonly #initialU8aLength?: number;
readonly initialU8aLength?: number;
readonly #jsonMap: Map<keyof S, string>;
@@ -137,7 +141,7 @@ export class Struct<
super(decoded);
this.registry = registry;
this.#initialU8aLength = decodedLength;
this.initialU8aLength = decodedLength;
this.#jsonMap = jsonMap;
this.#Types = mapToTypeMap(registry, Types);
}
@@ -220,13 +224,6 @@ export class Struct<
return total;
}
/**
* @description The length of the initial encoded value (Only available when constructed from a Uint8Array)
*/
public get initialU8aLength (): number | undefined {
return this.#initialU8aLength;
}
/**
* @description returns a hash of the contents
*/
+12 -13
View File
@@ -4,26 +4,25 @@
import type { AnyU8a, Constructor, Registry } from '../types';
import type { U8aBitLength } from './types';
import { assert, isString, u8aToU8a } from '@polkadot/util';
import { assert, isU8a, u8aToU8a } from '@polkadot/util';
import { Raw } from './Raw';
/** @internal */
function decodeU8aFixed (value: AnyU8a, bitLength: U8aBitLength): [AnyU8a, number] {
if (Array.isArray(value) || isString(value)) {
return decodeU8aFixed(u8aToU8a(value), bitLength);
if (isU8a(value)) {
const byteLength = bitLength / 8;
if (!value || !value.length) {
return [new Uint8Array(byteLength), 0];
}
assert(value.length >= byteLength, () => `Expected at least ${byteLength} bytes (${bitLength} bits), found ${value.length} bytes`);
return [value.subarray(0, byteLength), byteLength];
}
const byteLength = bitLength / 8;
const u8a = new Uint8Array(byteLength);
if (!value || !value.length) {
return [u8a, 0];
}
assert(value.length >= byteLength, () => `Expected at least ${byteLength} bytes (${bitLength} bits), found ${value.length} bytes`);
return [value.subarray(0, byteLength), byteLength];
return decodeU8aFixed(u8aToU8a(value), bitLength);
}
/**
+38 -38
View File
@@ -7,12 +7,48 @@ import type { Codec, Constructor, Registry } from '../types';
import { assert, compactFromU8a, logger, u8aToU8a } from '@polkadot/util';
import { AbstractArray } from './AbstractArray';
import { decodeU8a, typeToConstructor } from './utils';
import { decodeU8aVec, typeToConstructor } from './utils';
const MAX_LENGTH = 64 * 1024;
const l = logger('Vec');
export function decodeVec<T extends Codec> (registry: Registry, Type: Constructor<T>, value: Uint8Array | HexString | unknown[], length = -1): [T[], number, number] {
if (Array.isArray(value)) {
const result = new Array<T>(value.length);
for (let i = 0; i < value.length; i++) {
const entry = value[i];
try {
result[i] = entry instanceof Type
? entry
: new Type(registry, entry);
} catch (error) {
l.error(`Unable to decode on index ${i}`, (error as Error).message);
throw error;
}
}
return [result, 0, 0];
}
const u8a = u8aToU8a(value);
let offset = 0;
if (length === -1) {
const [_offset, _length] = compactFromU8a(u8a);
assert(_length.lten(MAX_LENGTH), () => `Vec length ${_length.toString()} exceeds ${MAX_LENGTH}`);
length = _length.toNumber();
offset = _offset;
}
return decodeU8aVec(registry, u8a, offset, Type, length);
}
/**
* @name Vec
* @description
@@ -25,49 +61,13 @@ export class Vec<T extends Codec> extends AbstractArray<T> {
constructor (registry: Registry, Type: Constructor<T> | string, value: Uint8Array | HexString | unknown[] = []) {
const Clazz = typeToConstructor<T>(registry, Type);
const [values, decodedLength] = Vec.decodeVec(registry, Clazz, value);
const [values, decodedLength] = decodeVec(registry, Clazz, value);
super(registry, values, decodedLength);
this.#Type = Clazz;
}
/** @internal */
public static decodeVec<T extends Codec> (registry: Registry, Type: Constructor<T>, value: Uint8Array | HexString | unknown[], length = -1): [T[], number, number] {
if (Array.isArray(value)) {
return [
value.map((entry: unknown, index: number): T => {
try {
return entry instanceof Type
? entry
: new Type(registry, entry);
} catch (error) {
l.error(`Unable to decode on index ${index}`, (error as Error).message);
throw error;
}
}),
0, 0
];
}
const u8a = u8aToU8a(value);
let offset = 0;
if (length === -1) {
const [_offset, _length] = compactFromU8a(u8a);
assert(_length.lten(MAX_LENGTH), () => `Vec length ${_length.toString()} exceeds ${MAX_LENGTH}`);
length = _length.toNumber();
offset = _offset;
}
const [decoded, decodedLength] = decodeU8a(registry, u8a.subarray(offset), Type, length);
return [decoded as T[], decodedLength + offset, decodedLength];
}
public static with<O extends Codec> (Type: Constructor<O> | string): Constructor<Vec<O>> {
return class extends Vec<O> {
constructor (registry: Registry, value?: any[]) {
+2 -2
View File
@@ -8,11 +8,11 @@ import { assert, u8aConcat } from '@polkadot/util';
import { AbstractArray } from './AbstractArray';
import { typeToConstructor } from './utils';
import { Vec } from './Vec';
import { decodeVec } from './Vec';
/** @internal */
function decodeVecFixed<T extends Codec> (registry: Registry, Type: Constructor<T>, length: number, value: Uint8Array | HexString | unknown[]): [T[], number] {
const [values,, decodedLengthNoOffset] = Vec.decodeVec(registry, Type, value, length);
const [values,, decodedLengthNoOffset] = decodeVec(registry, Type, value, length);
while (values.length < length) {
values.push(new Type(registry));
+36 -16
View File
@@ -3,9 +3,9 @@
import type { Codec, Constructor, Registry } from '../../types';
import { isFunction, u8aToHex } from '@polkadot/util';
import { u8aToHex } from '@polkadot/util';
function formatFailure (error: Error, key: string, type: string, u8a: Uint8Array): string {
function formatFailure (error: Error, type: string, u8a: Uint8Array, key?: string): string {
return `decodeU8a: failed at ${u8aToHex(u8a)}…${key ? ` on ${key}` : ''}${type ? `: ${type}` : ''}:: ${error.message}`;
}
@@ -25,21 +25,17 @@ function getRawType (registry: Registry, Type: Constructor): string {
* @param result - The result array (will be returned with values pushed)
* @param types - The array of Constructor to decode the U8a against.
*/
export function decodeU8a <T extends Codec = Codec, E = T> (registry: Registry, u8a: Uint8Array, types: Constructor | Constructor[] | { [index: string]: Constructor }, count?: number, zip?: (key: string, value: T) => E): [E[], number] {
const [Type, Types, keys]: [Constructor | null, Constructor[], string[]] = isFunction(types)
? [types, [], []]
: Array.isArray(types)
? [null, types, []]
: [null, Object.values(types), Object.keys(types)];
export function decodeU8a <T extends Codec = Codec, E = T> (registry: Registry, u8a: Uint8Array, types: Constructor[] | { [index: string]: Constructor }, zip?: (key: string, value: T) => E): [E[], number] {
const [Types, keys]: [Constructor[], string[]] = Array.isArray(types)
? [types, []]
: [Object.values(types), Object.keys(types)];
count = count || Types.length;
const result = new Array<E>(count);
const result = new Array<E>(Types.length);
let offset = 0;
for (let i = 0; i < count; i++) {
for (let i = 0; i < Types.length; i++) {
try {
const value = new (Type || Types[i])(registry, u8a.subarray(offset));
const value = new Types[i](registry, u8a.subarray(offset));
offset += value.initialU8aLength || value.encodedLength;
result[i] = zip
@@ -48,12 +44,36 @@ export function decodeU8a <T extends Codec = Codec, E = T> (registry: Registry,
} catch (error) {
throw new Error(formatFailure(
error as Error,
keys[i],
getRawType(registry, Type || Types[i]),
u8a.subarray(offset, offset + 8)
getRawType(registry, Types[i]),
u8a.subarray(offset, offset + 8),
keys[i]
));
}
}
return [result, offset];
}
// Split from decodeU8a since this is specialized to 1 instance ... yes duplication, but
// since we have to do less checks (and these are intensive anyway), much faster
export function decodeU8aVec <T extends Codec = Codec> (registry: Registry, u8a: Uint8Array, start: number, Type: Constructor<T>, count: number): [T[], number, number] {
const result = new Array<T>(count);
let offset = start;
for (let i = 0; i < count; i++) {
try {
const value = new Type(registry, u8a.subarray(offset));
offset += value.initialU8aLength || value.encodedLength;
result[i] = value;
} catch (error) {
throw new Error(formatFailure(
error as Error,
getRawType(registry, Type),
u8a.subarray(offset, offset + 8)
));
}
}
return [result, offset, offset - start];
}
+1 -1
View File
@@ -4,7 +4,7 @@
export { compareArray } from './compareArray';
export { compareMap } from './compareMap';
export { compareSet } from './compareSet';
export { decodeU8a } from './decodeU8a';
export { decodeU8a, decodeU8aVec } from './decodeU8a';
export { defineProperty } from './defineProperty';
export { mapToTypeMap } from './mapToTypeMap';
export { typeToConstructor } from './typeToConstructor';
+15 -20
View File
@@ -4,7 +4,7 @@
import type { Registry } from '../types/registry';
import type { TypeDef } from './types';
import { assert, isNumber, isUndefined, stringify } from '@polkadot/util';
import { assert, isNumber, isUndefined, objectSpread, stringify } from '@polkadot/util';
import { TypeDefInfo } from './types';
@@ -44,7 +44,7 @@ function encodeSubTypes (registry: Registry, sub: TypeDef[], asEnum?: boolean, e
assert(names.every((n) => !!n), () => `Subtypes does not have consistent names, ${names.join(', ')}`);
const inner: Record<string, string> = { ...(extra as Record<string, string>) };
const inner: Record<string, string> = objectSpread({}, extra);
for (let i = 0; i < sub.length; i++) {
const def = sub[i];
@@ -102,10 +102,9 @@ const encoders: Record<TypeDefInfo, (registry: Registry, typeDef: TypeDef) => st
assert(sub && Array.isArray(sub), 'Unable to encode Set type');
return stringify({
_set: sub.reduce((all, { index, name }, count): Record<string, number> => ({
...all,
[`${name || `Unknown${index || count}`}`]: index || count
}), { _bitLength: length || 8 } as Record<string, number>)
_set: sub.reduce((all, { index, name }, count) =>
objectSpread(all, { [`${name || `Unknown${index || count}`}`]: index || count }),
{ _bitLength: length || 8 })
});
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -114,16 +113,15 @@ const encoders: Record<TypeDefInfo, (registry: Registry, typeDef: TypeDef) => st
[TypeDefInfo.Struct]: (registry: Registry, { alias, sub }: TypeDef): string => {
assert(sub && Array.isArray(sub), 'Unable to encode Struct type');
return encodeSubTypes(registry, sub, false, {
...(
alias
? { _alias: [...alias.entries()].reduce<Record<string, string>>((all, [k, v]) => ({
...all,
[k]: v
}), {}) }
: {}
)
});
return encodeSubTypes(registry, sub, false,
alias
? {
_alias: [...alias.entries()].reduce<Record<string, string>>((all, [k, v]) =>
objectSpread(all, { [k]: v }), {}
)
}
: {}
);
},
[TypeDefInfo.Tuple]: (registry: Registry, { sub }: TypeDef): string => {
assert(sub && Array.isArray(sub), 'Unable to encode Tuple type');
@@ -159,8 +157,5 @@ export function encodeTypeDef (registry: Registry, typeDef: TypeDef): string {
}
export function withTypeString (registry: Registry, typeDef: Omit<TypeDef, 'type'>): TypeDef {
return {
...typeDef,
type: encodeType(registry, typeDef as TypeDef, false)
};
return objectSpread({}, typeDef, { type: encodeType(registry, typeDef as TypeDef, false) });
}
+4 -5
View File
@@ -3,7 +3,7 @@
import type { TypeDef } from './types';
import { assert, isNumber, isString } from '@polkadot/util';
import { assert, isNumber, isString, objectSpread } from '@polkadot/util';
import { sanitize } from './sanitize';
import { TypeDefInfo } from './types';
@@ -51,10 +51,9 @@ function _decodeEnum (value: TypeDef, details: string[] | Record<string, string>
type: 'Null'
}));
} else if (isRustEnum(details)) {
value.sub = Object.entries(details).map(([name, typeOrObj], index): TypeDef => ({
...getTypeDef(getTypeString(typeOrObj || 'Null'), { name }, count),
index
}));
value.sub = Object.entries(details).map(([name, typeOrObj], index): TypeDef =>
objectSpread({}, getTypeDef(getTypeString(typeOrObj || 'Null'), { name }, count), { index })
);
} else {
value.sub = Object.entries(details).map(([name, index]): TypeDef => ({
index,
+3 -6
View File
@@ -6,7 +6,7 @@ import type { ChainProperties, CodecHash, DispatchErrorModule, Hash, MetadataLat
import type { CallFunction, Codec, CodecHasher, Constructor, DetectCodec, DetectConstructor, RegisteredTypes, Registry, RegistryError, RegistryTypes } from '../types';
import type { CreateOptions } from './types';
import { assert, assertReturn, BN_ZERO, formatBalance, isFunction, isString, isU8a, lazyMethod, logger, stringCamelCase, stringify } from '@polkadot/util';
import { assert, assertReturn, BN_ZERO, formatBalance, isFunction, isString, isU8a, lazyMethod, logger, objectSpread, stringCamelCase, stringify } from '@polkadot/util';
import { blake2AsU8a } from '@polkadot/util-crypto';
import { DoNotConstruct } from '../codec/DoNotConstruct';
@@ -87,10 +87,7 @@ function injectEvents (registry: Registry, { lookup, pallets }: MetadataLatest,
lazyMethod(result, version >= 12 ? index.toNumber() : i, () =>
lazyVariants(lookup, events.unwrap(), getVariantStringIdx, (variant: SiVariant): Constructor<GenericEventData> => {
const meta = registry.createType('EventMetadataLatest', {
...variant,
args: getFieldArgs(lookup, variant.fields)
});
const meta = registry.createType('EventMetadataLatest', objectSpread({}, variant, { args: getFieldArgs(lookup, variant.fields) }));
return class extends GenericEventData {
constructor (registry: Registry, value: Uint8Array) {
@@ -171,7 +168,7 @@ export class TypeRegistry implements Registry {
public createdAtHash?: Hash;
constructor (createdAtHash?: Hash | Uint8Array | string) {
this.#knownDefaults = { Json, Metadata, Raw, ...baseTypes };
this.#knownDefaults = objectSpread({ Json, Metadata, Raw }, baseTypes);
this.#knownDefinitions = definitions as unknown as Record<string, { types: RegistryTypes }>;
this.init();
+4 -4
View File
@@ -60,10 +60,10 @@ export class GenericEthereumLookupSource extends Base<GenericEthereumAccountId |
? value._raw
: value instanceof GenericEthereumAccountId || value instanceof GenericAccountIndex
? value
: isBn(value) || isNumber(value) || isBigInt(value)
? registry.createType('AccountIndex', value)
: Array.isArray(value) || isHex(value) || isU8a(value)
? decodeU8a(registry, u8aToU8a(value))
: isU8a(value) || Array.isArray(value) || isHex(value)
? decodeU8a(registry, u8aToU8a(value))
: isBn(value) || isNumber(value) || isBigInt(value)
? registry.createType('AccountIndex', value)
: decodeString(registry, value);
}
+8 -8
View File
@@ -67,10 +67,10 @@ export class MortalEra extends Tuple {
/** @internal */
private static _decodeMortalEra (registry: Registry, value?: MortalMethod | Uint8Array | number[] | string): MortalEraValue {
if (!value) {
return [new U64(registry), new U64(registry)];
} else if (isU8a(value) || isHex(value) || Array.isArray(value)) {
if (isU8a(value) || isHex(value) || Array.isArray(value)) {
return MortalEra._decodeMortalU8a(registry, u8aToU8a(value));
} else if (!value) {
return [new U64(registry), new U64(registry)];
} else if (isObject(value)) {
return MortalEra._decodeMortalObject(registry, value);
}
@@ -208,16 +208,16 @@ export class GenericExtrinsicEra extends Enum implements IExtrinsicEra {
/** @internal */
// eslint-disable-next-line @typescript-eslint/ban-types
private static _decodeExtrinsicEra (value: IExtrinsicEra | MortalMethod | MortalEnumDef | ImmortalEnumDef | Uint8Array | string = new Uint8Array()): Uint8Array | Object | undefined {
if (!value) {
if (isU8a(value)) {
return (!value.length || value[0] === 0)
? new Uint8Array([0])
: new Uint8Array([1, value[0], value[1]]);
} else if (!value) {
return new Uint8Array([0]);
} else if (value instanceof GenericExtrinsicEra) {
return GenericExtrinsicEra._decodeExtrinsicEra(value.toU8a());
} else if (isHex(value)) {
return GenericExtrinsicEra._decodeExtrinsicEra(hexToU8a(value));
} else if (isU8a(value)) {
return (!value.length || value[0] === 0)
? new Uint8Array([0])
: new Uint8Array([1, value[0], value[1]]);
} else if (isObject(value)) {
const entries = Object.entries(value as MortalEnumDef).map(([k, v]): [string, any] => [k.toLowerCase(), v]);
const mortal = entries.find(([k]) => k.toLowerCase() === 'mortalera');
@@ -23,14 +23,14 @@ describe('ExtrinsicPayload', (): void => {
const a = new ExtrinsicPayload(registry, TEST, { version: 4 });
const b = new ExtrinsicPayload(registry, a.toU8a(), { version: 4 });
expect(a).toEqual(b);
expect(a.toJSON()).toEqual(b.toJSON());
});
it('creates and can re-create from itself (hex)', (): void => {
const a = new ExtrinsicPayload(registry, TEST, { version: 4 });
const b = new ExtrinsicPayload(registry, a.toHex(), { version: 4 });
expect(a).toEqual(b);
expect(a.toJSON()).toEqual(b.toJSON());
});
it('handles toU8a(true) correctly', (): void => {
+23 -26
View File
@@ -5,7 +5,7 @@ import type { HexString } from '@polkadot/util/types';
import type { Address, Balance, BlockNumber, Call, ExtrinsicEra, Hash, Index, RuntimeVersion } from '../interfaces';
import type { Codec, ISignerPayload, Registry, SignerPayloadJSON, SignerPayloadRaw } from '../types';
import { u8aToHex } from '@polkadot/util';
import { objectSpread, u8aToHex } from '@polkadot/util';
import { Compact } from '../codec/Compact';
import { Option } from '../codec/Option';
@@ -51,24 +51,18 @@ export class GenericSignerPayload extends Struct implements ISignerPayload, Sign
private readonly _extraTypes: Record<string, string>;
constructor (registry: Registry, value?: HexString | { [x: string]: unknown; } | Map<unknown, unknown> | unknown[]) {
const extensionTypes = {
...registry.getSignedExtensionTypes(),
...registry.getSignedExtensionExtra()
};
const extensionTypes = objectSpread<Record<string, string>>({}, registry.getSignedExtensionTypes(), registry.getSignedExtensionExtra());
super(registry, {
...extensionTypes,
...knownTypes
}, value);
super(registry, objectSpread<Record<string, string>>({}, extensionTypes, knownTypes), value);
this._extraTypes = {};
// add all extras that are not in the base types
this._extraTypes = Object.entries(extensionTypes).reduce<Record<string, string>>((map, [key, type]) => {
for (const [key, type] of Object.entries(extensionTypes)) {
if (!knownTypes[key]) {
map[key] = type;
this._extraTypes[key] = type;
}
return map;
}, {});
}
}
get address (): Address {
@@ -119,19 +113,22 @@ export class GenericSignerPayload extends Struct implements ISignerPayload, Sign
* @description Creates an representation of the structure as an ISignerPayload JSON
*/
public toPayload (): SignerPayloadJSON {
return {
// add any explicit overrides we may have
...(Object.keys(this._extraTypes).reduce<Record<string, string>>((map, key) => {
const value = this.get(key) as Codec;
const isOption = value instanceof Option;
const result: Record<string, string> = {};
const keys = Object.keys(this._extraTypes);
// Don't include Option.isNone
if (!isOption || value.isSome) {
map[key] = value.toHex();
}
// add any explicit overrides we may have
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = this.get(key) as Codec;
const isOption = value instanceof Option;
return map;
}, {})),
// Don't include Option.isNone
if (!isOption || value.isSome) {
result[key] = value.toHex();
}
}
return objectSpread(result, {
// the known defaults as managed explicitly and has different
// formatting in cases, e.g. we mostly expose a hex format here
address: this.address.toString(),
@@ -146,7 +143,7 @@ export class GenericSignerPayload extends Struct implements ISignerPayload, Sign
tip: this.tip.toHex(),
transactionVersion: this.runtimeVersion.transactionVersion.toHex(),
version: this.version.toNumber()
};
});
}
/**
@@ -3,6 +3,8 @@
import type { ExtDef, ExtInfo, ExtTypes } from './types';
import { objectSpread } from '@polkadot/util';
import { polkadot } from './polkadot';
import { shell } from './shell';
import { statemint } from './statemint';
@@ -12,12 +14,7 @@ import { substrate } from './substrate';
// we define the extra fields not as a Tuple, but rather as a struct so they can be named. These will be expanded
// into the various fields when added to the payload (we only support V4 onwards with these, V3 and earlier are
// deemed fixed and non-changeable)
export const allExtensions: ExtDef = {
...substrate,
...polkadot,
...shell,
...statemint
};
export const allExtensions: ExtDef = objectSpread({}, substrate, polkadot, shell, statemint);
// the v4 signed extensions prior to the point of exposing these to the metadata.
// This may not match 100% with the current defaults and are used when not specified
@@ -36,7 +33,7 @@ export const fallbackExtensions = [
export function findUnknownExtensions (extensions: string[], userExtensions: ExtDef = {}): string[] {
const names = [...Object.keys(allExtensions), ...Object.keys(userExtensions)];
return extensions.filter((key) => !names.includes(key));
return extensions.filter((k) => !names.includes(k));
}
export function expandExtensionTypes (extensions: string[], type: keyof ExtInfo, userExtensions: ExtDef = {}): ExtTypes {
@@ -44,5 +41,5 @@ export function expandExtensionTypes (extensions: string[], type: keyof ExtInfo,
// Always allow user extensions first - these should provide overrides
.map((key) => userExtensions[key] || allExtensions[key])
.filter((info): info is ExtInfo => !!info)
.reduce((result, info): ExtTypes => ({ ...result, ...info[type] }), {});
.reduce((result, info): ExtTypes => objectSpread(result, info[type]), {});
}
@@ -7,6 +7,8 @@ import type { ExtrinsicEra } from '../../interfaces/extrinsics';
import type { AssetId, Balance, Hash, Index } from '../../interfaces/runtime';
import type { ExtrinsicPayloadValue, IKeyringPair, Registry } from '../../types';
import { objectSpread } from '@polkadot/util';
import { Compact } from '../../codec/Compact';
import { Enum } from '../../codec/Enum';
import { Option } from '../../codec/Option';
@@ -25,11 +27,11 @@ export class GenericExtrinsicPayloadV4 extends Struct {
#signOptions: SignOptions;
constructor (registry: Registry, value?: ExtrinsicPayloadValue | Uint8Array | HexString) {
super(registry, {
method: 'Bytes',
...registry.getSignedExtensionTypes(),
...registry.getSignedExtensionExtra()
}, value);
super(registry, objectSpread(
{ method: 'Bytes' },
registry.getSignedExtensionTypes(),
registry.getSignedExtensionExtra()
), value);
// Do detection for the type of extrinsic, in the case of MultiSignature this is an
// enum, in the case of AnySignature, this is a Hash only (may be 64 or 65 bytes)
@@ -7,7 +7,7 @@ import type { Address, AssetId, Balance, Call, Index } from '../../interfaces/ru
import type { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, Registry, SignatureOptions } from '../../types';
import type { ExtrinsicSignatureOptions } from '../types';
import { assert, isU8a, stringify, u8aConcat, u8aToHex } from '@polkadot/util';
import { assert, isU8a, objectSpread, stringify, u8aConcat, u8aToHex } from '@polkadot/util';
import { Compact } from '../../codec/Compact';
import { Enum } from '../../codec/Enum';
@@ -32,12 +32,15 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
#fakePrefix: Uint8Array;
constructor (registry: Registry, value?: GenericExtrinsicSignatureV4 | Uint8Array, { isSigned }: ExtrinsicSignatureOptions = {}) {
super(registry, {
signer: 'Address',
// eslint-disable-next-line sort-keys
signature: 'ExtrinsicSignature',
...registry.getSignedExtensionTypes()
}, GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned));
super(
registry,
objectSpread(
// eslint-disable-next-line sort-keys
{ signer: 'Address', signature: 'ExtrinsicSignature' },
registry.getSignedExtensionTypes()
),
GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned)
);
this.#fakePrefix = registry.createType('ExtrinsicSignature') instanceof Enum
? FAKE_SOME
+3 -3
View File
@@ -10,10 +10,10 @@ import { U8aFixed } from '../codec/U8aFixed';
/** @internal */
function decodeAccountId (value?: AnyU8a | AnyString): Uint8Array {
if (!value) {
return new Uint8Array();
} else if (isU8a(value) || Array.isArray(value)) {
if (isU8a(value) || Array.isArray(value)) {
return u8aToU8a(value);
} else if (!value) {
return new Uint8Array();
} else if (isHex(value)) {
return hexToU8a(value);
} else if (isString(value)) {
+12 -13
View File
@@ -4,7 +4,7 @@
import type { FunctionMetadataLatest } from '../interfaces/metadata';
import type { AnyJson, AnyTuple, AnyU8a, ArgsDef, CallBase, CallFunction, Codec, IMethod, InterfaceTypes, Registry } from '../types';
import { isHex, isObject, isU8a, u8aToU8a } from '@polkadot/util';
import { isHex, isObject, isU8a, objectSpread, u8aToU8a } from '@polkadot/util';
import { Struct } from '../codec/Struct';
import { U8aFixed } from '../codec/U8aFixed';
@@ -87,7 +87,7 @@ function decodeCallViaU8a (registry: Registry, value: Uint8Array, _meta?: Functi
* @internal
*/
function decodeCall (registry: Registry, value: unknown | DecodedMethod | Uint8Array | string = new Uint8Array(), _meta?: FunctionMetadataLatest): DecodedMethod {
if (isHex(value) || isU8a(value)) {
if (isU8a(value) || isHex(value)) {
return decodeCallViaU8a(registry, u8aToU8a(value), _meta);
} else if (isObject(value) && value.callIndex && value.args) {
return decodeCallViaObject(registry, value as DecodedMethod, _meta);
@@ -216,18 +216,17 @@ export class GenericCall<A extends AnyTuple = AnyTuple> extends Struct implement
// swallow
}
return {
args: this.argsEntries.reduce<Record<string, AnyJson>>((args, [n, a]) => ({
...args,
[n]: a.toHuman(isExpanded)
}), {}),
method: call?.method,
section: call?.section,
...(isExpanded && call
return objectSpread(
{
args: this.argsEntries.reduce<Record<string, AnyJson>>((args, [n, a]) =>
objectSpread(args, { [n]: a.toHuman(isExpanded) }), {}),
method: call?.method,
section: call?.section
},
isExpanded && call
? { docs: call.meta.docs.map((d) => d.toString()) }
: {}
)
};
: null
);
}
/**
+11 -8
View File
@@ -6,6 +6,8 @@ import type { EventMetadataLatest } from '../interfaces/metadata';
import type { EventId } from '../interfaces/system';
import type { AnyJson, Codec, Constructor, IEvent, IEventData, InterfaceTypes, Registry } from '../types';
import { objectSpread } from '@polkadot/util';
import { Struct } from '../codec/Struct';
import { Tuple } from '../codec/Tuple';
import { Null } from '../primitive/Null';
@@ -154,14 +156,15 @@ export class GenericEvent extends Struct implements IEvent<Codec[]> {
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
*/
public override toHuman (isExpanded?: boolean): Record<string, AnyJson> {
return {
method: this.method,
section: this.section,
...(isExpanded
return objectSpread(
{
method: this.method,
section: this.section
},
isExpanded
? { docs: this.meta.docs.map((d) => d.toString()) }
: {}
),
...super.toHuman(isExpanded)
};
: null,
super.toHuman(isExpanded)
);
}
}
+6 -5
View File
@@ -23,16 +23,17 @@ function decodeU8a (registry: Registry, u8a: Uint8Array): unknown {
}
function decodeMultiAny (registry: Registry, value?: unknown): unknown {
if (value instanceof GenericMultiAddress) {
return value;
} else if (value instanceof GenericAccountId) {
if (value instanceof GenericAccountId) {
return { Id: value };
} else if (isU8a(value)) {
// NOTE This is after the AccountId check (which is U8a)
return decodeU8a(registry, value);
} else if (value instanceof GenericMultiAddress) {
return value;
} else if (value instanceof GenericAccountIndex || isBn(value) || isNumber(value)) {
return { Index: isNumber(value) ? value : value.toNumber() };
} else if (isString(value)) {
return decodeU8a(registry, decodeAddress(value.toString()));
} else if (isU8a(value)) {
return decodeU8a(registry, value);
}
return value;
@@ -7,7 +7,7 @@ import type { SiField, SiLookupTypeId, SiPath, SiType, SiTypeDefArray, SiTypeDef
import type { Text, Type } from '../../primitive';
import type { Registry, TypeDef } from '../../types';
import { assert, isNumber, isString, stringCamelCase, stringify, stringUpperFirst } from '@polkadot/util';
import { assert, isNumber, isString, objectSpread, stringCamelCase, stringify, stringUpperFirst } from '@polkadot/util';
import { Struct } from '../../codec/Struct';
import { withTypeString } from '../../create/encodeTypes';
@@ -259,12 +259,16 @@ export class GenericPortableRegistry extends Struct {
#types: Record<number, PortableType>;
constructor (registry: Registry, value?: Uint8Array) {
// console.time('PortableRegistry')
super(registry, {
types: 'Vec<PortableType>'
}, value);
this.#names = extractNames(this, this.types);
this.#types = extractTypeMap(this.types);
// console.timeEnd('PortableRegistry')
}
public get names (): string[] {
@@ -403,11 +407,7 @@ export class GenericPortableRegistry extends Struct {
throw new Error(`PortableRegistry: ${lookupIndex}${namespace ? ` (${namespace})` : ''}: Error extracting ${stringify(type)}: ${(error as Error).message}`);
}
return {
docs: sanitizeDocs(type.docs),
namespace,
...typeDef
};
return objectSpread({ docs: sanitizeDocs(type.docs), namespace }, typeDef);
}
#extractArray (_: number, { len: length, type }: SiTypeDefArray): TypeDef {
@@ -454,16 +454,18 @@ export class GenericPortableRegistry extends Struct {
} else if (['Range', 'RangeInclusive'].includes(specialVariant)) {
return withTypeString(this.registry, {
info: TypeDefInfo.Range,
sub: fields.map(({ name, type, typeName }, index) => ({
name: name.isSome
? name.unwrap().toString()
: ['start', 'end'][index],
...this.#createSiDef(type),
...(typeName.isSome
? { typeName: sanitize(typeName.unwrap()) }
: {}
)
}))
sub: fields.map(({ name, type, typeName }, index) =>
objectSpread(
{
name: name.isSome
? name.unwrap().toString()
: ['start', 'end'][index]
},
this.#createSiDef(type),
typeName.isSome
? { typeName: sanitize(typeName.unwrap()) }
: null
))
});
} else if (path.length) {
if (path[path.length - 1].toString() === 'WrapperOpaque') {
@@ -521,44 +523,41 @@ export class GenericPortableRegistry extends Struct {
} else if (isTuple && fields.length === 1) {
const typeDef = this.#createSiDef(fields[0].type);
return {
...typeDef,
...(lookupIndex === -1
return objectSpread(
{},
typeDef,
lookupIndex === -1
? {}
: {
lookupIndex,
lookupName: this.#names[lookupIndex],
lookupNameRoot: typeDef.lookupName
}
),
...(fields[0].typeName.isSome
},
fields[0].typeName.isSome
? { typeName: sanitize(fields[0].typeName.unwrap()) }
: {}
)
};
: null
);
}
const [sub, alias] = this.#extractFieldsAlias(fields);
return withTypeString(this.registry, {
info: isTuple // Tuple check first
? TypeDefInfo.Tuple
: TypeDefInfo.Struct,
...(
alias.size
? { alias }
: {}
),
...(
lookupIndex === -1
? {}
: {
lookupIndex,
lookupName: this.#names[lookupIndex]
}
),
sub
});
return withTypeString(this.registry, objectSpread(
{
info: isTuple // Tuple check first
? TypeDefInfo.Tuple
: TypeDefInfo.Struct
},
alias.size
? { alias }
: null,
lookupIndex === -1
? {}
: {
lookupIndex,
lookupName: this.#names[lookupIndex]
},
{ sub }
));
}
#extractFieldsAlias (fields: SiField[]): [TypeDef[], Map<string, string>] {
@@ -587,15 +586,17 @@ export class GenericPortableRegistry extends Struct {
alias.set(nameField, nameOrig);
}
sub[i] = {
...typeDef,
docs: sanitizeDocs(docs),
name: nameField,
...(typeName.isSome
sub[i] = objectSpread(
{},
typeDef,
{
docs: sanitizeDocs(docs),
name: nameField
},
typeName.isSome
? { typeName: sanitize(typeName.unwrap()) }
: {}
)
};
: null
);
}
}
@@ -603,11 +604,14 @@ export class GenericPortableRegistry extends Struct {
}
#extractHistoric (_: number, type: Type): TypeDef {
return {
...getTypeDef(type),
displayName: type.toString(),
isFromSi: true
};
return objectSpread(
{},
getTypeDef(type),
{
displayName: type.toString(),
isFromSi: true
}
);
}
#extractPrimitive (_: number, type: SiType): TypeDef {
@@ -675,10 +679,9 @@ export class GenericPortableRegistry extends Struct {
} else if (specialVariant === 'Result') {
return withTypeString(this.registry, {
info: TypeDefInfo.Result,
sub: params.map(({ type }, index) => ({
name: ['Ok', 'Error'][index],
...this.#createSiDef(type.unwrap())
}))
sub: params.map(({ type }, index) =>
objectSpread({ name: ['Ok', 'Error'][index] }, this.#createSiDef(type.unwrap()))
)
});
} else if (variants.length === 0) {
return {
@@ -709,11 +712,15 @@ export class GenericPortableRegistry extends Struct {
});
}
sub.push({
...this.#extractFields(-1, fields),
index: index.toNumber(),
name: name.toString()
});
sub.push(
objectSpread(
this.#extractFields(-1, fields),
{
index: index.toNumber(),
name: name.toString()
}
)
);
});
return withTypeString(this.registry, {
+3 -3
View File
@@ -48,12 +48,12 @@ function decodeVoteType (registry: Registry, value: VoteType): Uint8Array {
/** @internal */
function decodeVote (registry: Registry, value?: InputTypes): Uint8Array {
if (isUndefined(value) || value instanceof Boolean || isBoolean(value)) {
if (isU8a(value)) {
return decodeVoteU8a(value);
} else if (isUndefined(value) || value instanceof Boolean || isBoolean(value)) {
return decodeVoteBool(new Bool(registry, value).isTrue);
} else if (isNumber(value)) {
return decodeVoteBool(value < 0);
} else if (isU8a(value)) {
return decodeVoteU8a(value);
}
return decodeVoteType(registry, value);
@@ -3,6 +3,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
// order important in structs... :)
/* eslint-disable sort-keys */
@@ -116,9 +118,7 @@ const ContractProjectInfo = {
export default {
rpc: {},
types: {
...layout,
...spec,
types: objectSpread({}, layout, spec, {
ContractProjectInfo,
ContractMetadataV0,
ContractMetadataV1,
@@ -129,11 +129,7 @@ export default {
}
},
ContractMetadataLatest: 'ContractMetadataV1',
ContractProjectV0: {
metadataVersion: 'Text',
...ContractProjectInfo,
...ContractMetadataV0
},
ContractProjectV0: objectSpread({ metadataVersion: 'Text' }, ContractProjectInfo, ContractMetadataV0),
ContractProject: '(ContractProjectInfo, ContractMetadata)',
ContractProjectContract: {
_alias: {
@@ -157,5 +153,5 @@ export default {
compiler: 'Text',
wasm: 'Raw'
}
}
})
} as Definitions;
@@ -22,7 +22,5 @@ const dmpQueue = {
export default {
rpc: {},
types: {
...dmpQueue
}
types: dmpQueue
} as Definitions;
@@ -8,6 +8,8 @@
import type { DefinitionsTypes } from '../../types';
import { objectSpread } from '@polkadot/util';
import { rpc } from './rpc';
const V0: DefinitionsTypes = {
@@ -84,10 +86,7 @@ const V2: DefinitionsTypes = {
}
};
const types: DefinitionsTypes = {
...V0,
...V1,
...V2,
const types: DefinitionsTypes = objectSpread({}, V0, V1, V2, {
EthereumAccountId: 'GenericEthereumAccountId',
EthereumAddress: 'GenericEthereumAccountId',
EthereumLookupSource: 'GenericEthereumLookupSource',
@@ -328,6 +327,6 @@ const types: DefinitionsTypes = {
target: 'H256',
number: 'Option<u64>'
}
};
});
export default { rpc, types };
+4 -4
View File
@@ -5,6 +5,8 @@
import type { DefinitionsRpc } from '../../types';
import { objectSpread } from '@polkadot/util';
// We use aliasSection here to override since these are in another namespace
const netRpc: DefinitionsRpc = {
listening: {
@@ -41,9 +43,7 @@ const web3Rpc: DefinitionsRpc = {
}
};
export const rpc: DefinitionsRpc = {
...netRpc,
...web3Rpc,
export const rpc: DefinitionsRpc = objectSpread({}, netRpc, web3Rpc, {
accounts: {
description: 'Returns accounts list.',
params: [],
@@ -476,4 +476,4 @@ export const rpc: DefinitionsRpc = {
],
type: 'bool'
}
};
});
+3 -1
View File
@@ -3,6 +3,8 @@
import type { DefinitionRpcExt, DefinitionRpcSub } from '../types';
import { objectSpread } from '@polkadot/util';
import * as definitions from './definitions';
const jsonrpc: Record<string, Record<string, DefinitionRpcExt>> = {};
@@ -24,7 +26,7 @@ Object
jsonrpc[section] = {};
}
jsonrpc[section][method] = ({ ...def, isSubscription, jsonrpc: `${section}_${method}`, method, section });
jsonrpc[section][method] = objectSpread({}, def, { isSubscription, jsonrpc: `${section}_${method}`, method, section });
});
});
@@ -6,6 +6,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
import { AllHashers } from './hashers';
import { v9 } from './v9';
import { v10 } from './v10';
@@ -18,14 +20,7 @@ export { AllHashers };
export default {
rpc: {},
types: {
...v9,
...v10,
...v11,
...v12,
...v13,
...v14,
types: objectSpread({}, v9, v10, v11, v12, v13, v14, {
// registry mapping to latest
PortableRegistry: 'PortableRegistryV14',
PortableType: 'PortableTypeV14',
@@ -70,5 +65,5 @@ export default {
V14: 'MetadataV14'
}
}
}
})
} as Definitions;
+6 -13
View File
@@ -4,7 +4,9 @@
// order important in structs... :)
/* eslint-disable sort-keys */
import type { DefinitionsTypes } from '../../types';
import type { DefinitionsTypes, DefinitionTypeStruct } from '../../types';
import { objectSpread } from '@polkadot/util';
import { Si1Variant } from '../scaleInfo/v1';
@@ -17,23 +19,14 @@ export const v14: DefinitionsTypes = {
},
// compatibility with earlier layouts, i.e. don't break previous users
ErrorMetadataV14: {
...Si1Variant,
args: 'Vec<Type>'
},
EventMetadataV14: {
...Si1Variant,
args: 'Vec<Type>'
},
ErrorMetadataV14: objectSpread<DefinitionTypeStruct>({}, Si1Variant, { args: 'Vec<Type>' }),
EventMetadataV14: objectSpread<DefinitionTypeStruct>({}, Si1Variant, { args: 'Vec<Type>' }),
FunctionArgumentMetadataV14: {
name: 'Text',
type: 'Type',
typeName: 'Option<Type>'
},
FunctionMetadataV14: {
...Si1Variant,
args: 'Vec<FunctionArgumentMetadataV14>'
},
FunctionMetadataV14: objectSpread<DefinitionTypeStruct>({}, Si1Variant, { args: 'Vec<FunctionArgumentMetadataV14>' }),
// V14
ExtrinsicMetadataV14: {
@@ -6,6 +6,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
import hrmpTypes from './hrmp';
import slotTypes from './slots';
@@ -75,12 +77,7 @@ const disputeTypes = {
export default {
rpc: {},
types: {
...cumulusTypes,
...disputeTypes,
...hrmpTypes,
...proposeTypes,
...slotTypes,
types: objectSpread({}, cumulusTypes, disputeTypes, hrmpTypes, proposeTypes, slotTypes, {
AbridgedCandidateReceipt: {
parachainIndex: 'ParaId',
relayParent: 'Hash',
@@ -429,5 +426,5 @@ export default {
MessagingStateSnapshotEgressEntry: '(ParaId, AbridgedHrmpChannel)',
SystemInherentData: 'ParachainInherentData',
VecInboundHrmpMessage: 'Vec<InboundHrmpMessage>'
}
})
} as Definitions;
@@ -1,6 +1,8 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { objectSpread } from '@polkadot/util';
// order important in structs... :)
/* eslint-disable sort-keys */
@@ -36,8 +38,7 @@ const oldTypes = {
SubId: 'u32'
};
export default {
...oldTypes,
export default objectSpread({}, oldTypes, {
AuctionIndex: 'u32',
LeasePeriod: 'BlockNumber',
LeasePeriodOf: 'BlockNumber',
@@ -48,4 +49,4 @@ export default {
WinningDataEntry: 'Option<(AccountId, ParaId, BalanceOf)>',
WinnersData: 'Vec<WinnersDataTuple>',
WinnersDataTuple: '(AccountId, ParaId, BalanceOf, SlotRange)'
};
});
@@ -6,6 +6,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
const numberTypes = {
Fixed64: 'Int<64, Fixed64>',
FixedI64: 'Int<64, FixedI64>',
@@ -24,8 +26,7 @@ const numberTypes = {
export default {
rpc: {},
types: {
...numberTypes,
types: objectSpread({}, numberTypes, {
AccountId: 'AccountId32',
AccountId20: 'GenericEthereumAccountId',
AccountId32: 'GenericAccountId',
@@ -184,5 +185,5 @@ export default {
SealV0: '(u64, Signature)',
Seal: '(ConsensusEngineId, Bytes)',
Consensus: '(ConsensusEngineId, Bytes)'
}
})
} as Definitions;
@@ -3,6 +3,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
import { v0 } from './v0';
import { v1 } from './v1';
@@ -11,10 +13,7 @@ import { v1 } from './v1';
export default {
rpc: {},
types: {
...v0,
...v1,
types: objectSpread({}, v0, v1, {
// latest mappings
SiField: 'Si1Field',
SiLookupTypeId: 'Si1LookupTypeId',
@@ -31,5 +30,5 @@ export default {
SiTypeParameter: 'Si1TypeParameter',
SiTypeDefVariant: 'Si1TypeDefVariant',
SiVariant: 'Si1Variant'
}
})
} as Definitions;
@@ -6,6 +6,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
// The runtime definition of SessionKeys are passed as a Trait to session
// Defined in `node/runtime/src/lib.rs` as follow
// impl_opaque_keys! {
@@ -37,8 +39,7 @@ const keyTypes = {
export default {
rpc: {},
types: {
...keyTypes,
types: objectSpread({}, keyTypes, {
FullIdentification: 'Exposure',
IdentificationTuple: '(ValidatorId, FullIdentification)',
MembershipProof: {
@@ -48,5 +49,5 @@ export default {
},
SessionIndex: 'u32',
ValidatorCount: 'u32'
}
})
} as Definitions;
@@ -6,6 +6,8 @@
import type { Definitions } from '../../types';
import { objectSpread } from '@polkadot/util';
const deprecated = {
Points: 'u32',
EraPoints: {
@@ -172,9 +174,7 @@ const phragmen = {
export default {
rpc: {},
types: {
...deprecated,
...phragmen,
types: objectSpread({}, deprecated, phragmen, {
ActiveEraInfo: {
index: 'EraIndex',
start: 'Option<Moment>'
@@ -298,5 +298,5 @@ export default {
unstakeThreshold: 'Compact<u32>',
validatorPayment: 'Compact<Balance>'
}
}
})
} as Definitions;
@@ -7,6 +7,7 @@
import type { Definitions } from '../../types';
import { mapXcmTypes } from '@polkadot/types-known';
import { objectSpread } from '@polkadot/util';
import { v0 } from './v0';
import { v1 } from './v1';
@@ -81,13 +82,7 @@ const location = {
export default {
rpc: {},
types: {
...location,
...xcm,
...v0,
...v1,
...v2,
...mapXcmTypes(XCM_LATEST),
types: objectSpread({}, location, xcm, v0, v1, v2, mapXcmTypes(XCM_LATEST), {
DoubleEncodedCall: {
encoded: 'Vec<u8>'
},
@@ -164,5 +159,5 @@ export default {
}
},
XcmVersion: 'u32'
}
})
} as Definitions;
+1 -1
View File
@@ -27,7 +27,7 @@ function toU8a (value: Uint8Array | string = EMPTY_U8A): Uint8Array {
}
function decodeMetadata (registry: Registry, _value?: Uint8Array | string | Map<string, unknown> | Record<string, unknown>): MetadataVersioned {
if (!_value || isU8a(_value) || isHex(_value)) {
if (isU8a(_value) || !_value || isHex(_value)) {
const value = toU8a(_value);
const version = value[VERSION_IDX];
@@ -6,7 +6,7 @@ import type { Text, u8 } from '../../../primitive';
import type { Registry } from '../../../types';
import type { Errors, IsError } from '../types';
import { lazyMethod, stringCamelCase } from '@polkadot/util';
import { lazyMethod, objectSpread, stringCamelCase } from '@polkadot/util';
import { lazyVariants } from '../../../create/lazy';
import { objectNameToString } from '../util';
@@ -20,12 +20,10 @@ interface ItemMeta {
}
export function variantToMeta (lookup: PortableRegistry, variant: SiVariant): ItemMeta {
return {
...variant,
args: variant.fields.map(({ type }) =>
lookup.getTypeDef(type).type
)
};
return objectSpread(
{ args: variant.fields.map(({ type }) => lookup.getTypeDef(type).type) },
variant
);
}
/** @internal */
@@ -18,10 +18,7 @@ export function createUnchecked (registry: Registry, section: string, callIndex:
const extrinsicFn = (...args: any[]): Call => {
assert(expectedArgs.length === args.length, () => `Extrinsic ${section}.${funcName} expects ${expectedArgs.length} arguments, got ${args.length}.`);
return registry.createType('Call', {
args,
callIndex
}, callMetadata);
return registry.createType('Call', { args, callIndex }, callMetadata);
};
extrinsicFn.is = <A extends AnyTuple> (tx: IMethod<AnyTuple>): tx is IMethod<A> =>
@@ -5,7 +5,7 @@ import type { MetadataLatest, PalletMetadataLatest, PortableRegistry, SiVariant
import type { CallFunction, Registry } from '../../../types';
import type { Extrinsics } from '../types';
import { lazyMethod, stringCamelCase } from '@polkadot/util';
import { lazyMethod, objectSpread, stringCamelCase } from '@polkadot/util';
import { lazyVariants } from '../../../create/lazy';
import { getSiName } from '../../util';
@@ -23,21 +23,22 @@ export function createCallFunction (registry: Registry, lookup: PortableRegistry
for (let a = 0; a < fields.length; a++) {
const { name, type, typeName } = fields[a];
args[a] = {
name: stringCamelCase(name.unwrapOr(`param${a}`)),
type: getSiName(lookup, type),
...(typeName.isSome
args[a] = objectSpread(
{
name: stringCamelCase(name.unwrapOr(`param${a}`)),
type: getSiName(lookup, type)
},
typeName.isSome
? { typeName: typeName.unwrap() }
: {}
)
};
: null
);
}
return createUnchecked(
registry,
sectionName,
new Uint8Array([sectionIndex, index.toNumber()]),
registry.createType('FunctionMetadataLatest', { ...variant, args })
registry.createType('FunctionMetadataLatest', objectSpread({ args }, variant))
);
}
@@ -6,7 +6,7 @@ import type { SiLookupTypeId } from '../../../interfaces/scaleInfo';
import type { StorageEntry } from '../../../primitive/types';
import type { Registry } from '../../../types';
import { assert, compactAddLength, compactStripLength, isUndefined, stringCamelCase, stringLowerFirst, u8aConcat, u8aToU8a } from '@polkadot/util';
import { assert, compactAddLength, compactStripLength, isUndefined, objectSpread, stringCamelCase, stringLowerFirst, u8aConcat, u8aToU8a } from '@polkadot/util';
import { xxhashAsU8a } from '@polkadot/util-crypto';
import { Raw } from '../../../codec';
@@ -79,10 +79,7 @@ function expandWithMeta ({ meta, method, prefix, section }: CreateItemFn, _stora
// explicitly add the actual method in the toJSON, this gets used to determine caching and without it
// instances (e.g. collective) will not work since it is only matched on param meta
storageFn.toJSON = (): any => ({
...(meta.toJSON() as Record<string, unknown>),
storage: { method, prefix, section }
});
storageFn.toJSON = (): any => objectSpread({ storage: { method, prefix, section } }, meta.toJSON());
return storageFn;
}
+3 -3
View File
@@ -9,10 +9,10 @@ import { isU8a, u8aToHex } from '@polkadot/util';
/** @internal */
function decodeBool (value: any): boolean {
if (value instanceof Boolean) {
return value.valueOf();
} else if (isU8a(value)) {
if (isU8a(value)) {
return value[0] === 1;
} else if (value instanceof Boolean) {
return value.valueOf();
}
return !!value;
+3 -3
View File
@@ -30,10 +30,10 @@ function decodeDataU8a (registry: Registry, value: Uint8Array): [undefined | Uin
/** @internal */
function decodeData (registry: Registry, value?: Record<string, any> | Uint8Array | Enum | string): [any, number | undefined] {
if (!value) {
return [undefined, undefined];
} else if (isU8a(value) || isString(value)) {
if (isU8a(value) || isString(value)) {
return decodeDataU8a(registry, u8aToU8a(value));
} else if (!value) {
return [undefined, undefined];
}
// assume we have an Enum or an object input, handle this via the normal Enum decoding
+4 -5
View File
@@ -52,16 +52,15 @@ export function unwrapStorageType (registry: Registry, type: StorageEntryTypeLat
/** @internal */
function decodeStorageKey (value?: string | Uint8Array | StorageKey | StorageEntry | [StorageEntry, unknown[]?]): Decoded {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
if (value instanceof StorageKey) {
if (isU8a(value) || !value || isString(value)) {
// let Bytes handle these inputs
return { key: value };
} else if (value instanceof StorageKey) {
return {
key: value,
method: value.method,
section: value.section
};
} else if (!value || isString(value) || isU8a(value)) {
// let Bytes handle these inputs
return { key: value };
} else if (isFunction(value)) {
return {
key: value(),
+4 -4
View File
@@ -5,7 +5,7 @@ import type { HexString } from '@polkadot/util/types';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyU8a, Codec, Registry } from '../types';
import { assert, compactAddLength, compactFromU8a, hexToU8a, isHex, isString, stringToU8a, u8aToHex, u8aToString } from '@polkadot/util';
import { assert, compactAddLength, compactFromU8a, hexToU8a, isHex, isString, isU8a, stringToU8a, u8aToHex, u8aToString } from '@polkadot/util';
import { Raw } from '../codec/Raw';
@@ -13,9 +13,7 @@ const MAX_LENGTH = 128 * 1024;
/** @internal */
function decodeText (value?: null | Text | string | AnyU8a | { toString: () => string }): [string, number] {
if (isHex(value)) {
return [u8aToString(hexToU8a(value)), 0];
} else if (value instanceof Uint8Array) {
if (isU8a(value)) {
if (!value.length) {
return ['', 0];
}
@@ -33,6 +31,8 @@ function decodeText (value?: null | Text | string | AnyU8a | { toString: () => s
assert(total <= value.length, () => `Text: required length less than remainder, expected at least ${total}, found ${value.length}`);
return [u8aToString(value.subarray(offset, total)), total];
} else if (isHex(value)) {
return [u8aToString(hexToU8a(value)), 0];
}
return [value ? value.toString() : '', 0];