diff --git a/CHANGELOG.md b/CHANGELOG.md index 514599e57..41695f0a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Changes: - Add `arrayZip` to combine a key + value array into entries-like - Assert `chainCode` inputs to `derive*`, protecting against misuse +- Adjust base library usage of `for` vs `reduce/map` - Adjust testnet detection in `@polkadot/networks` - Bump Ledger libraries to latest versions diff --git a/packages/keyring/src/keyring.ts b/packages/keyring/src/keyring.ts index bfbcee41a..ab0dfb2c4 100644 --- a/packages/keyring/src/keyring.ts +++ b/packages/keyring/src/keyring.ts @@ -262,11 +262,7 @@ export class Keyring implements KeyringInstance { * @description Returns an array list of all the public keys associated with each of the keyring pair values that are stored in the keyring pair dictionary. */ public getPublicKeys (): Uint8Array[] { - return this.#pairs - .all() - .map(({ publicKey }): Uint8Array => - publicKey - ); + return this.#pairs.all().map(({ publicKey }) => publicKey); } /** diff --git a/packages/keyring/src/testing.ts b/packages/keyring/src/testing.ts index 1f92b6343..7c08fc9bf 100644 --- a/packages/keyring/src/testing.ts +++ b/packages/keyring/src/testing.ts @@ -121,7 +121,7 @@ export function createTestKeyring (options: KeyringOptions = {}, isDerived = tru const keyring = new Keyring(options); const pairs: PairDef[] = (options.type && options.type === 'ethereum') ? PAIRSETHEREUM : PAIRSSR25519; - pairs.forEach(({ name, publicKey, secretKey, seed, type }): void => { + for (const { name, publicKey, secretKey, seed, type } of pairs) { if (!name && !seed) { throw new Error('Testing pair should have either a name or a seed'); } @@ -139,7 +139,7 @@ export function createTestKeyring (options: KeyringOptions = {}, isDerived = tru pair.lock = (): void => { // we don't have lock/unlock functionality here }; - }); + } return keyring; } diff --git a/packages/keyring/src/testingPairs.ts b/packages/keyring/src/testingPairs.ts index bf1b46433..39d942131 100644 --- a/packages/keyring/src/testingPairs.ts +++ b/packages/keyring/src/testingPairs.ts @@ -15,11 +15,9 @@ export function createTestPairs (options?: KeyringOptions, isDerived = true): Te const pairs = keyring.getPairs(); const map: TestKeyringMap = { nobody: nobody() }; - return pairs.reduce((result, pair): TestKeyringMap => { - const { name } = pair.meta; + for (const p of pairs) { + map[p.meta.name as string] = p; + } - result[name as string] = pair; - - return result; - }, map); + return map; } diff --git a/packages/util-crypto/src/address/derive.ts b/packages/util-crypto/src/address/derive.ts index ee4fe27ee..7d0dbb510 100644 --- a/packages/util-crypto/src/address/derive.ts +++ b/packages/util-crypto/src/address/derive.ts @@ -7,7 +7,6 @@ import type { Prefix } from './types'; import { assert } from '@polkadot/util'; import { keyExtractPath } from '../key'; -import { DeriveJunction } from '../key/DeriveJunction'; import { schnorrkelDerivePublic } from '../schnorrkel'; import { decodeAddress } from './decode'; import { encodeAddress } from './encode'; @@ -21,9 +20,13 @@ import { encodeAddress } from './encode'; export function deriveAddress (who: HexString | Uint8Array | string, suri: string, ss58Format?: Prefix): string { const { path } = keyExtractPath(suri); - assert(path.length && !path.some((path) => path.isHard), 'Expected suri to contain a combination of non-hard paths'); + assert(path.length && !path.some((p) => p.isHard), 'Expected suri to contain a combination of non-hard paths'); - return encodeAddress(path.reduce((publicKey: Uint8Array, path: DeriveJunction): Uint8Array => { - return schnorrkelDerivePublic(publicKey, path.chainCode); - }, decodeAddress(who)), ss58Format); + let publicKey = decodeAddress(who); + + for (const { chainCode } of path) { + publicKey = schnorrkelDerivePublic(publicKey, chainCode); + } + + return encodeAddress(publicKey, ss58Format); } diff --git a/packages/util-crypto/src/hd/ethereum/index.ts b/packages/util-crypto/src/hd/ethereum/index.ts index f395d808c..b21a96669 100644 --- a/packages/util-crypto/src/hd/ethereum/index.ts +++ b/packages/util-crypto/src/hd/ethereum/index.ts @@ -44,7 +44,7 @@ function deriveChild (hd: CodedKeypair, index: number): CodedKeypair { export function hdEthereum (seed: Uint8Array, path = ''): Keypair { const I = hmacSha512(MASTER_SECRET, seed); - const hd = createCoded(I.slice(0, 32), I.slice(32)); + let hd = createCoded(I.slice(0, 32), I.slice(32)); if (!path || path === 'm' || path === 'M' || path === "m'" || path === "M'") { return hd; @@ -52,16 +52,15 @@ export function hdEthereum (seed: Uint8Array, path = ''): Keypair { assert(hdValidatePath(path), 'Invalid derivation path'); - return path - .split('/') - .slice(1) - .reduce((hd: CodedKeypair, c): CodedKeypair => - deriveChild( - hd, parseInt(c, 10) + ( - (c.length > 1) && c.endsWith("'") - ? HARDENED - : 0 - ) - ), hd - ); + const parts = path.split('/').slice(1); + + for (const p of parts) { + hd = deriveChild(hd, parseInt(p, 10) + ( + (p.length > 1) && p.endsWith("'") + ? HARDENED + : 0 + )); + } + + return hd; } diff --git a/packages/util-crypto/src/hd/ledger/index.ts b/packages/util-crypto/src/hd/ledger/index.ts index 1f859220e..fa0e8869e 100644 --- a/packages/util-crypto/src/hd/ledger/index.ts +++ b/packages/util-crypto/src/hd/ledger/index.ts @@ -12,27 +12,28 @@ import { ledgerDerivePrivate } from './derivePrivate'; import { ledgerMaster } from './master'; export function hdLedger (_mnemonic: string, path: string): Keypair { - const parts = _mnemonic + const words = _mnemonic .split(' ') .map((s) => s.trim()) .filter((s) => s); - assert([12, 24, 25].includes(parts.length), 'Expected a mnemonic with 24 words (or 25 including a password)'); + assert([12, 24, 25].includes(words.length), 'Expected a mnemonic with 24 words (or 25 including a password)'); - const [mnemonic, password] = parts.length === 25 - ? [parts.slice(0, 24).join(' '), parts[24]] - : [parts.join(' '), '']; + const [mnemonic, password] = words.length === 25 + ? [words.slice(0, 24).join(' '), words[24]] + : [words.join(' '), '']; assert(mnemonicValidate(mnemonic), 'Invalid mnemonic passed to ledger derivation'); assert(hdValidatePath(path), 'Invalid derivation path'); - return naclKeypairFromSeed( - path - .split('/') - .slice(1) - .map((n) => parseInt(n.replace(/'$/, ''), 10)) - .map((n) => (n < HARDENED) ? (n + HARDENED) : n) - .reduce((x, n) => ledgerDerivePrivate(x, n), ledgerMaster(mnemonic, password)) - .slice(0, 32) - ); + const parts = path.split('/').slice(1); + let seed = ledgerMaster(mnemonic, password); + + for (const p of parts) { + const n = parseInt(p.replace(/'$/, ''), 10); + + seed = ledgerDerivePrivate(seed, (n < HARDENED) ? (n + HARDENED) : n); + } + + return naclKeypairFromSeed(seed.slice(0, 32)); } diff --git a/packages/util-crypto/src/hd/validatePath.ts b/packages/util-crypto/src/hd/validatePath.ts index b0f928f1a..aa5cc19c6 100644 --- a/packages/util-crypto/src/hd/validatePath.ts +++ b/packages/util-crypto/src/hd/validatePath.ts @@ -10,9 +10,15 @@ export function hdValidatePath (path: string): boolean { const parts = path.split('/').slice(1); - return parts.every((n) => /^\d+'?$/.test(n)) && ( - !parts - .map((n) => parseInt(n.replace(/'$/, ''), 10)) - .some((n) => isNaN(n) || (n >= HARDENED) || (n < 0)) - ); + for (const p of parts) { + const n = /^\d+'?$/.test(p) + ? parseInt(p.replace(/'$/, ''), 10) + : Number.NaN; + + if (isNaN(n) || (n >= HARDENED) || (n < 0)) { + return false; + } + } + + return true; } diff --git a/packages/util-crypto/src/key/extractPath.ts b/packages/util-crypto/src/key/extractPath.ts index ffe07c423..d757243e6 100644 --- a/packages/util-crypto/src/key/extractPath.ts +++ b/packages/util-crypto/src/key/extractPath.ts @@ -23,9 +23,9 @@ export function keyExtractPath (derivePath: string): ExtractResult { if (parts) { constructed = parts.join(''); - parts.forEach((value: string): void => { - path.push(DeriveJunction.from(value.substr(1))); - }); + for (const p of parts) { + path.push(DeriveJunction.from(p.substr(1))); + } } assert(constructed === derivePath, () => `Re-constructed path "${constructed}" does not match input`); diff --git a/packages/util-crypto/src/key/fromPath.ts b/packages/util-crypto/src/key/fromPath.ts index 66143f603..0a2125211 100644 --- a/packages/util-crypto/src/key/fromPath.ts +++ b/packages/util-crypto/src/key/fromPath.ts @@ -18,8 +18,11 @@ const generators = { export function keyFromPath (pair: Keypair, path: DeriveJunction[], type: KeypairType): Keypair { const keyHdkd = generators[type]; + let result = pair; - return path.reduce((pair, junction): Keypair => { - return keyHdkd(pair, junction); - }, pair); + for (const junction of path) { + result = keyHdkd(result, junction); + } + + return result; } diff --git a/packages/util/src/array/flatten.ts b/packages/util/src/array/flatten.ts index 3160e7e98..06b55629b 100644 --- a/packages/util/src/array/flatten.ts +++ b/packages/util/src/array/flatten.ts @@ -20,15 +20,19 @@ */ export function arrayFlatten (arrays: T[][]): T[] { // pre-allocate based on the combined size - const output = new Array(arrays.reduce((length, array) => length + array.length, 0)); + let size = 0; + + for (const a of arrays) { + size += a.length; + } + + const output = new Array(size); let index = -1; - for (let a = 0; a < arrays.length; a++) { - const array = arrays[a]; - + for (const a of arrays) { // instead of pushing, we just set the entries - for (let e = 0; e < array.length; e++) { - output[++index] = array[e]; + for (let e = 0; e < a.length; e++) { + output[++index] = a[e]; } } diff --git a/packages/util/src/array/range.ts b/packages/util/src/array/range.ts index 7e95314b4..f048b7662 100644 --- a/packages/util/src/array/range.ts +++ b/packages/util/src/array/range.ts @@ -21,5 +21,11 @@ import { assert } from '../assert'; export function arrayRange (size: number, startAt = 0): number[] { assert(size > 0, 'Expected non-zero, positive number as a range size'); - return new Array(size).fill(0).map((_, i) => i + startAt); + const result = new Array(size).fill(0); + + for (let i = 0; i < result.length; i++) { + result[i] = i + startAt; + } + + return result; } diff --git a/packages/util/src/bn/max.spec.ts b/packages/util/src/bn/max.spec.ts index 2481a58df..cf477e57d 100644 --- a/packages/util/src/bn/max.spec.ts +++ b/packages/util/src/bn/max.spec.ts @@ -9,4 +9,10 @@ describe('bnMax', (): void => { bnMax(new BN(1), new BN(2), new BN(3)) ).toEqual(new BN(3)); }); + + it('finds BN maximum', (): void => { + expect( + bnMax(new BN(2), new BN(3), new BN(1)) + ).toEqual(new BN(3)); + }); }); diff --git a/packages/util/src/bn/min.spec.ts b/packages/util/src/bn/min.spec.ts index be3374c32..194b1419e 100644 --- a/packages/util/src/bn/min.spec.ts +++ b/packages/util/src/bn/min.spec.ts @@ -6,7 +6,7 @@ import { BN, bnMin } from '.'; describe('bnMin', (): void => { it('finds BN minimum', (): void => { expect( - bnMin(new BN(1), new BN(2), new BN(3)) + bnMin(new BN(2), new BN(1), new BN(3)) ).toEqual(new BN(1)); }); }); diff --git a/packages/util/src/bn/util.ts b/packages/util/src/bn/util.ts index 384a11d8d..ac9f49f93 100644 --- a/packages/util/src/bn/util.ts +++ b/packages/util/src/bn/util.ts @@ -7,5 +7,11 @@ import { BN } from './bn'; export function checkMaxMin (type: 'max' | 'min', items: BN[]): BN { assert(items.length >= 1, 'Must provide one or more BN arguments'); - return items.reduce((a, v) => BN[type](a, v), items[0]); + let result = items[0]; + + for (const v of items) { + result = BN[type](result, v); + } + + return result; } diff --git a/packages/util/src/logger.ts b/packages/util/src/logger.ts index 554a3e48f..6bbc883e7 100644 --- a/packages/util/src/logger.ts +++ b/packages/util/src/logger.ts @@ -24,11 +24,13 @@ const logTo = { function formatOther (value: unknown): unknown { if (value && isObject(value) && value.constructor === Object) { - return Object.keys(value).reduce((result: Record, key): Record => { - result[key] = loggerFormat(value[key]); + const result: Record = {}; - return result; - }, {}); + for (const k of Object.keys(value)) { + result[k] = loggerFormat(value[k]); + } + + return result; } return value; diff --git a/packages/util/src/versionDetect.ts b/packages/util/src/versionDetect.ts index 2f7e7a106..ff061f29b 100644 --- a/packages/util/src/versionDetect.ts +++ b/packages/util/src/versionDetect.ts @@ -44,7 +44,13 @@ function getEntry (name: string): VersionPath[] { } function getVersionLength (all: { version: string }[]): number { - return all.reduce((max, { version }) => Math.max(max, version.length), 0); + let length = 0; + + for (const { version } of all) { + length = Math.max(length, version.length); + } + + return length; } /** @internal */ diff --git a/packages/x-randomvalues/src/node.ts b/packages/x-randomvalues/src/node.ts index f23f7b901..3a43afd4d 100644 --- a/packages/x-randomvalues/src/node.ts +++ b/packages/x-randomvalues/src/node.ts @@ -5,10 +5,12 @@ import crypto from 'crypto'; export { packageInfo } from './packageInfo'; -export function getRandomValues (arr: T): T { - return crypto.randomBytes(arr.length).reduce((arr, value, index) => { - arr[index] = value; +export function getRandomValues (output: T): T { + const bytes = crypto.randomBytes(output.length); - return arr; - }, arr); + for (let i = 0; i < bytes.length; i++) { + output[i] = bytes[i]; + } + + return output; } diff --git a/packages/x-randomvalues/src/react-native.ts b/packages/x-randomvalues/src/react-native.ts index 01d44bc0b..c111b2a99 100644 --- a/packages/x-randomvalues/src/react-native.ts +++ b/packages/x-randomvalues/src/react-native.ts @@ -19,18 +19,18 @@ interface RNExt { } } -function getRandomValuesNative (arr: T): T { - return Buffer - .from((NativeModules as RNExt).RNGetRandomValues.getRandomBase64(arr.length), 'base64') - .reduce((arr, byte, index): T => { - arr[index] = byte; +function getRandomValuesNative (output: T): T { + const bytes = Buffer.from((NativeModules as RNExt).RNGetRandomValues.getRandomBase64(output.length), 'base64'); - return arr; - }, arr); + for (let i = 0; i < bytes.length; i++) { + output[i] = bytes[i]; + } + + return output; } -function getRandomValuesGlobal (arr: T): T { - return crypto.getRandomValues(arr); +function getRandomValuesGlobal (output: T): T { + return crypto.getRandomValues(output); } export const getRandomValues = ( diff --git a/packages/x-textdecoder/src/fallback.ts b/packages/x-textdecoder/src/fallback.ts index 97ddcd475..24b2118ac 100644 --- a/packages/x-textdecoder/src/fallback.ts +++ b/packages/x-textdecoder/src/fallback.ts @@ -9,8 +9,12 @@ export class TextDecoder { } decode (value: Uint8Array): string { - return value.reduce((str, code): string => { - return str + String.fromCharCode(code); - }, ''); + let result = ''; + + for (const c of value) { + result += String.fromCharCode(c); + } + + return result; } }