Skip to content

Commit 5dfb95f

Browse files
legobeatGudahtt
authored andcommitted
feat(controller-utils): support bn.js v4 input to BN functions (#4844)
1 parent 9a807d7 commit 5dfb95f

File tree

4 files changed

+68
-10
lines changed

4 files changed

+68
-10
lines changed

packages/controller-utils/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@
5353
"@metamask/utils": "^10.0.0",
5454
"@spruceid/siwe-parser": "2.1.0",
5555
"@types/bn.js": "^5.1.5",
56+
"@types/bnjs4": "npm:@types/bn.js@^4.11.6",
5657
"bignumber.js": "^9.1.2",
5758
"bn.js": "^5.2.1",
59+
"bnjs4": "npm:bn.js@^4.12.0",
5860
"eth-ens-namehash": "^2.0.8",
5961
"fast-deep-equal": "^3.1.3"
6062
},

packages/controller-utils/src/util.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import EthQuery from '@metamask/eth-query';
22
import BigNumber from 'bignumber.js';
33
import BN from 'bn.js';
4+
import BN4 from 'bnjs4';
45
import nock from 'nock';
56

67
import { FakeProvider } from '../../../tests/fake-provider';
@@ -32,11 +33,27 @@ describe('util', () => {
3233

3334
it('bNToHex', () => {
3435
expect(util.BNToHex(new BN('1337'))).toBe('0x539');
36+
expect(util.BNToHex(new BN4('1337'))).toBe('0x539');
3537
expect(util.BNToHex(new BigNumber('1337'))).toBe('0x539');
3638
});
3739

3840
it('fractionBN', () => {
3941
expect(util.fractionBN(new BN('1337'), 9, 10).toNumber()).toBe(1203);
42+
expect(util.fractionBN(new BN4('1337'), 9, 10).toNumber()).toBe(1203);
43+
// Ensure return values use the same bn.js implementation as input by detection using non-typed API
44+
/* eslint-disable @typescript-eslint/no-explicit-any */
45+
expect(
46+
(util.fractionBN(new BN4('1337'), 9, 10) as any)._strip,
47+
).toBeUndefined();
48+
expect(
49+
(util.fractionBN(new BN4('1337'), 9, 10) as any).strip,
50+
).toBeDefined();
51+
expect(
52+
(util.fractionBN(new BN('1337'), 9, 10) as any)._strip,
53+
).toBeDefined();
54+
expect(
55+
(util.fractionBN(new BN('1337'), 9, 10) as any).strip,
56+
).toBeUndefined();
4057
});
4158

4259
it('getBuyURL', () => {

packages/controller-utils/src/util.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '@metamask/utils';
1111
import type { BigNumber } from 'bignumber.js';
1212
import BN from 'bn.js';
13+
import BN4 from 'bnjs4';
1314
import ensNamehash from 'eth-ens-namehash';
1415
import deepEqual from 'fast-deep-equal';
1516

@@ -69,10 +70,31 @@ export function isSafeChainId(chainId: Hex): boolean {
6970
*/
7071
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
7172
// eslint-disable-next-line @typescript-eslint/naming-convention
72-
export function BNToHex(inputBn: BN | BigNumber) {
73+
export function BNToHex(inputBn: BN | BN4 | BigNumber): string {
7374
return add0x(inputBn.toString(16));
7475
}
7576

77+
function getBNImplementation(targetBN: BN4): typeof BN4;
78+
function getBNImplementation(targetBN: BN): typeof BN;
79+
/**
80+
* Return the bn.js library responsible for the BN in question
81+
* @param targetBN - A BN instance
82+
* @returns A bn.js instance
83+
*/
84+
function getBNImplementation(targetBN: BN | BN4): typeof BN4 | typeof BN {
85+
return Object.keys(targetBN).includes('_strip') ? BN4 : BN;
86+
}
87+
88+
export function fractionBN(
89+
targetBN: BN,
90+
numerator: number | string,
91+
denominator: number | string,
92+
): BN;
93+
export function fractionBN(
94+
targetBN: BN4,
95+
numerator: number | string,
96+
denominator: number | string,
97+
): BN4;
7698
/**
7799
* Used to multiply a BN by a fraction.
78100
*
@@ -82,12 +104,16 @@ export function BNToHex(inputBn: BN | BigNumber) {
82104
* @returns Product of the multiplication.
83105
*/
84106
export function fractionBN(
85-
targetBN: BN,
107+
targetBN: BN | BN4,
86108
numerator: number | string,
87109
denominator: number | string,
88-
) {
89-
const numBN = new BN(numerator);
90-
const denomBN = new BN(denominator);
110+
): BN | BN4 {
111+
// @ts-expect-error - Signature overload confusion
112+
const BNImplementation = getBNImplementation(targetBN);
113+
114+
const numBN = new BNImplementation(numerator);
115+
const denomBN = new BNImplementation(denominator);
116+
// @ts-expect-error - BNImplementation gets unexpected typed
91117
return targetBN.mul(numBN).div(denomBN);
92118
}
93119

@@ -192,18 +218,20 @@ export function hexToText(hex: string) {
192218
}
193219
}
194220

221+
export function fromHex(value: string | BN): BN;
222+
export function fromHex(value: BN4): BN4;
195223
/**
196224
* Parses a hex string and converts it into a number that can be operated on in a bignum-safe,
197225
* base-10 way.
198226
*
199227
* @param value - A base-16 number encoded as a string.
200228
* @returns The number as a BN object in base-16 mode.
201229
*/
202-
export function fromHex(value: string | BN): BN {
230+
export function fromHex(value: string | BN | BN4): BN | BN4 {
203231
if (BN.isBN(value)) {
204232
return value;
205233
}
206-
return new BN(hexToBN(value).toString(10));
234+
return new BN(hexToBN(value as string).toString(10), 10);
207235
}
208236

209237
/**
@@ -212,14 +240,14 @@ export function fromHex(value: string | BN): BN {
212240
* @param value - An integer, an integer encoded as a base-10 string, or a BN.
213241
* @returns The integer encoded as a hex string.
214242
*/
215-
export function toHex(value: number | bigint | string | BN): Hex {
243+
export function toHex(value: number | bigint | string | BN | BN4): Hex {
216244
if (typeof value === 'string' && isStrictHexString(value)) {
217245
return value;
218246
}
219247
const hexString =
220248
BN.isBN(value) || typeof value === 'bigint'
221249
? value.toString(16)
222-
: new BN(value.toString(), 10).toString(16);
250+
: new BN(value.toString(10), 10).toString(16);
223251
return `0x${hexString}`;
224252
}
225253

yarn.lock

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2338,9 +2338,11 @@ __metadata:
23382338
"@metamask/utils": "npm:^10.0.0"
23392339
"@spruceid/siwe-parser": "npm:2.1.0"
23402340
"@types/bn.js": "npm:^5.1.5"
2341+
"@types/bnjs4": "npm:@types/bn.js@^4.11.6"
23412342
"@types/jest": "npm:^27.4.1"
23422343
bignumber.js: "npm:^9.1.2"
23432344
bn.js: "npm:^5.2.1"
2345+
bnjs4: "npm:bn.js@^4.12.0"
23442346
deepmerge: "npm:^4.2.2"
23452347
eth-ens-namehash: "npm:^2.0.8"
23462348
fast-deep-equal: "npm:^3.1.3"
@@ -4333,6 +4335,15 @@ __metadata:
43334335
languageName: node
43344336
linkType: hard
43354337

4338+
"@types/bnjs4@npm:@types/bn.js@^4.11.6":
4339+
version: 4.11.6
4340+
resolution: "@types/bn.js@npm:4.11.6"
4341+
dependencies:
4342+
"@types/node": "npm:*"
4343+
checksum: 10/9ff3e7a1539a953c381c0d30ea2049162e3cab894cda91ee10f3a84d603f9afa2b2bc2a38fe9b427de94b6e2b7b77aefd217c1c7b07a10ae8d7499f9d6697a41
4344+
languageName: node
4345+
linkType: hard
4346+
43364347
"@types/debug@npm:^4.1.7":
43374348
version: 4.1.12
43384349
resolution: "@types/debug@npm:4.1.12"
@@ -5421,7 +5432,7 @@ __metadata:
54215432
languageName: node
54225433
linkType: hard
54235434

5424-
"bn.js@npm:^4.11.9":
5435+
"bn.js@npm:^4.11.9, bnjs4@npm:bn.js@^4.12.0":
54255436
version: 4.12.0
54265437
resolution: "bn.js@npm:4.12.0"
54275438
checksum: 10/10f8db196d3da5adfc3207d35d0a42aa29033eb33685f20ba2c36cadfe2de63dad05df0a20ab5aae01b418d1c4b3d4d205273085262fa020d17e93ff32b67527

0 commit comments

Comments
 (0)