From 22b966be76196e75618b6358b259957acdc918bb Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Sat, 24 Sep 2022 13:05:41 +0800 Subject: [PATCH] Explorer: replace usages of bn.js with BigInt (#28040) --- explorer/src/__tests__/lamportsToSol.ts | 24 +++++++------- .../account/StakeAccountSection.tsx | 17 +++++----- explorer/src/components/common/Epoch.tsx | 2 +- .../src/components/instruction/serum/types.ts | 32 +++++++++---------- explorer/src/utils/index.tsx | 14 ++++---- explorer/src/validators/accounts/stake.ts | 10 +++--- explorer/src/validators/bignum.ts | 7 ---- explorer/src/validators/number.ts | 11 +++++++ 8 files changed, 59 insertions(+), 58 deletions(-) delete mode 100644 explorer/src/validators/bignum.ts create mode 100644 explorer/src/validators/number.ts diff --git a/explorer/src/__tests__/lamportsToSol.ts b/explorer/src/__tests__/lamportsToSol.ts index fdca7f63e9..7972fa93d8 100644 --- a/explorer/src/__tests__/lamportsToSol.ts +++ b/explorer/src/__tests__/lamportsToSol.ts @@ -1,28 +1,28 @@ import { expect } from "chai"; import { lamportsToSol, LAMPORTS_PER_SOL } from "utils"; -import BN from "bn.js"; describe("lamportsToSol", () => { it("0 lamports", () => { - expect(lamportsToSol(new BN(0))).to.eq(0.0); + expect(lamportsToSol(0)).to.eq(0.0); + expect(lamportsToSol(BigInt(0))).to.eq(0.0); }); it("1 lamport", () => { - expect(lamportsToSol(new BN(1))).to.eq(0.000000001); - expect(lamportsToSol(new BN(-1))).to.eq(-0.000000001); + expect(lamportsToSol(1)).to.eq(0.000000001); + expect(lamportsToSol(BigInt(1))).to.eq(0.000000001); + expect(lamportsToSol(-1)).to.eq(-0.000000001); + expect(lamportsToSol(BigInt(-1))).to.eq(-0.000000001); }); it("1 SOL", () => { - expect(lamportsToSol(new BN(LAMPORTS_PER_SOL))).to.eq(1.0); - expect(lamportsToSol(new BN(-LAMPORTS_PER_SOL))).to.eq(-1.0); + expect(lamportsToSol(LAMPORTS_PER_SOL)).to.eq(1.0); + expect(lamportsToSol(BigInt(LAMPORTS_PER_SOL))).to.eq(1.0); + expect(lamportsToSol(-LAMPORTS_PER_SOL)).to.eq(-1.0); + expect(lamportsToSol(BigInt(-LAMPORTS_PER_SOL))).to.eq(-1.0); }); it("u64::MAX lamports", () => { - expect(lamportsToSol(new BN(2).pow(new BN(64)))).to.eq( - 18446744073.709551615 - ); - expect(lamportsToSol(new BN(2).pow(new BN(64)).neg())).to.eq( - -18446744073.709551615 - ); + expect(lamportsToSol(2n ** 64n)).to.eq(18446744073.709551615); + expect(lamportsToSol(-(2n ** 64n))).to.eq(-18446744073.709551615); }); }); diff --git a/explorer/src/components/account/StakeAccountSection.tsx b/explorer/src/components/account/StakeAccountSection.tsx index 49385820a2..47c9e7e2fd 100644 --- a/explorer/src/components/account/StakeAccountSection.tsx +++ b/explorer/src/components/account/StakeAccountSection.tsx @@ -9,11 +9,10 @@ import { StakeMeta, StakeAccountType, } from "validators/accounts/stake"; -import BN from "bn.js"; import { StakeActivationData } from "@solana/web3.js"; import { Epoch } from "components/common/Epoch"; -const MAX_EPOCH = new BN(2).pow(new BN(64)).sub(new BN(1)); +const U64_MAX = BigInt("0xffffffffffffffff"); export function StakeAccountSection({ account, @@ -163,11 +162,11 @@ function DelegationCard({ const delegation = stakeAccount?.stake?.delegation; if (delegation) { voterPubkey = delegation.voter; - if (!delegation.activationEpoch.eq(MAX_EPOCH)) { - activationEpoch = delegation.activationEpoch.toNumber(); + if (delegation.activationEpoch !== U64_MAX) { + activationEpoch = delegation.activationEpoch; } - if (!delegation.deactivationEpoch.eq(MAX_EPOCH)) { - deactivationEpoch = delegation.deactivationEpoch.toNumber(); + if (delegation.deactivationEpoch !== U64_MAX) { + deactivationEpoch = delegation.deactivationEpoch; } } const { stake } = stakeAccount; @@ -297,10 +296,10 @@ function isFullyInactivated( } const delegatedStake = stake.delegation.stake; - const inactiveStake = new BN(activation.inactive); + const inactiveStake = BigInt(activation.inactive); return ( - !stake.delegation.deactivationEpoch.eq(MAX_EPOCH) && - delegatedStake.eq(inactiveStake) + stake.delegation.deactivationEpoch !== U64_MAX && + delegatedStake === inactiveStake ); } diff --git a/explorer/src/components/common/Epoch.tsx b/explorer/src/components/common/Epoch.tsx index c3bb2fd644..1d8547c132 100644 --- a/explorer/src/components/common/Epoch.tsx +++ b/explorer/src/components/common/Epoch.tsx @@ -4,7 +4,7 @@ import { clusterPath } from "utils/url"; import { Copyable } from "./Copyable"; type Props = { - epoch: number; + epoch: number | bigint; link?: boolean; }; export function Epoch({ epoch, link }: Props) { diff --git a/explorer/src/components/instruction/serum/types.ts b/explorer/src/components/instruction/serum/types.ts index 4e077b644d..83af721e63 100644 --- a/explorer/src/components/instruction/serum/types.ts +++ b/explorer/src/components/instruction/serum/types.ts @@ -7,7 +7,7 @@ import { TransactionInstruction, } from "@solana/web3.js"; import { enums, number, type, Infer, create } from "superstruct"; -import { BigNumFromString } from "validators/bignum"; +import { BigIntFromString } from "validators/number"; const SERUM_PROGRAM_IDS = [ "4ckmDgGdxQoPDLUkDT3vHgSAkzA3QRdNq5ywwY4sUSJn", @@ -60,11 +60,11 @@ export type InitializeMarket = { }; export const InitializeMarketInstruction = type({ - baseLotSize: BigNumFromString, - quoteLotSize: BigNumFromString, + baseLotSize: BigIntFromString, + quoteLotSize: BigIntFromString, feeRateBps: number(), - quoteDustThreshold: BigNumFromString, - vaultSignerNonce: BigNumFromString, + quoteDustThreshold: BigIntFromString, + vaultSignerNonce: BigIntFromString, }); export function decodeInitializeMarket( @@ -110,10 +110,10 @@ export type NewOrder = { export const NewOrderInstruction = type({ side: Side, - limitPrice: BigNumFromString, - maxQuantity: BigNumFromString, + limitPrice: BigIntFromString, + maxQuantity: BigIntFromString, orderType: OrderType, - clientId: BigNumFromString, + clientId: BigIntFromString, }); export function decodeNewOrder(ix: TransactionInstruction): NewOrder { @@ -208,7 +208,7 @@ export type CancelOrder = { export const CancelOrderInstruction = type({ side: Side, - orderId: BigNumFromString, + orderId: BigIntFromString, openOrdersSlot: number(), }); @@ -272,7 +272,7 @@ export type CancelOrderByClientId = { }; export const CancelOrderByClientIdInstruction = type({ - clientId: BigNumFromString, + clientId: BigIntFromString, }); export function decodeCancelOrderByClientId( @@ -355,12 +355,12 @@ export type NewOrderV3 = { export const NewOrderV3Instruction = type({ side: Side, - limitPrice: BigNumFromString, - maxBaseQuantity: BigNumFromString, - maxQuoteQuantity: BigNumFromString, + limitPrice: BigIntFromString, + maxBaseQuantity: BigIntFromString, + maxQuoteQuantity: BigIntFromString, selfTradeBehavior: SelfTradeBehavior, orderType: OrderType, - clientId: BigNumFromString, + clientId: BigIntFromString, limit: number(), }); @@ -399,7 +399,7 @@ export type CancelOrderV2 = { export const CancelOrderV2Instruction = type({ side: Side, - orderId: BigNumFromString, + orderId: BigIntFromString, }); export function decodeCancelOrderV2(ix: TransactionInstruction): CancelOrderV2 { @@ -434,7 +434,7 @@ export type CancelOrderByClientIdV2 = { }; export const CancelOrderByClientIdV2Instruction = type({ - clientId: BigNumFromString, + clientId: BigIntFromString, }); export function decodeCancelOrderByClientIdV2( diff --git a/explorer/src/utils/index.tsx b/explorer/src/utils/index.tsx index 4eb7ee1508..6b7fb70bfb 100644 --- a/explorer/src/utils/index.tsx +++ b/explorer/src/utils/index.tsx @@ -1,4 +1,3 @@ -import BN from "bn.js"; import { HumanizeDuration, HumanizeDurationLanguage, @@ -36,7 +35,6 @@ export function microLamportsToLamports( return microLamports / MICRO_LAMPORTS_PER_LAMPORT; } - console.log(microLamports); const microLamportsString = microLamports.toString().padStart(7, "0"); const splitIndex = microLamportsString.length - 6; const lamportString = @@ -56,17 +54,17 @@ export function microLamportsToLamportsString( ); } -export function lamportsToSol(lamports: number | BN): number { +export function lamportsToSol(lamports: number | bigint): number { if (typeof lamports === "number") { - return Math.abs(lamports) / LAMPORTS_PER_SOL; + return lamports / LAMPORTS_PER_SOL; } let signMultiplier = 1; - if (lamports.isNeg()) { + if (lamports < 0) { signMultiplier = -1; } - const absLamports = lamports.abs(); + const absLamports = lamports < 0 ? -lamports : lamports; const lamportsString = absLamports.toString(10).padStart(10, "0"); const splitIndex = lamportsString.length - 9; const solString = @@ -77,7 +75,7 @@ export function lamportsToSol(lamports: number | BN): number { } export function lamportsToSolString( - lamports: number | BN, + lamports: number | bigint, maximumFractionDigits: number = 9 ): string { const sol = lamportsToSol(lamports); @@ -92,7 +90,7 @@ export function SolBalance({ lamports, maximumFractionDigits = 9, }: { - lamports: number | BN; + lamports: number | bigint; maximumFractionDigits?: number; }) { return ( diff --git a/explorer/src/validators/accounts/stake.ts b/explorer/src/validators/accounts/stake.ts index e431026083..239e378012 100644 --- a/explorer/src/validators/accounts/stake.ts +++ b/explorer/src/validators/accounts/stake.ts @@ -2,7 +2,7 @@ import { Infer, number, nullable, enums, type } from "superstruct"; import { PublicKeyFromString } from "validators/pubkey"; -import { BigNumFromString } from "validators/bignum"; +import { BigIntFromString } from "validators/number"; export type StakeAccountType = Infer; export const StakeAccountType = enums([ @@ -14,7 +14,7 @@ export const StakeAccountType = enums([ export type StakeMeta = Infer; export const StakeMeta = type({ - rentExemptReserve: BigNumFromString, + rentExemptReserve: BigIntFromString, authorized: type({ staker: PublicKeyFromString, withdrawer: PublicKeyFromString, @@ -33,9 +33,9 @@ export const StakeAccountInfo = type({ type({ delegation: type({ voter: PublicKeyFromString, - stake: BigNumFromString, - activationEpoch: BigNumFromString, - deactivationEpoch: BigNumFromString, + stake: BigIntFromString, + activationEpoch: BigIntFromString, + deactivationEpoch: BigIntFromString, warmupCooldownRate: number(), }), creditsObserved: number(), diff --git a/explorer/src/validators/bignum.ts b/explorer/src/validators/bignum.ts deleted file mode 100644 index 3203803ba0..0000000000 --- a/explorer/src/validators/bignum.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { coerce, instance, string } from "superstruct"; -import BN from "bn.js"; - -export const BigNumFromString = coerce(instance(BN), string(), (value) => { - if (typeof value === "string") return new BN(value, 10); - throw new Error("invalid big num"); -}); diff --git a/explorer/src/validators/number.ts b/explorer/src/validators/number.ts new file mode 100644 index 0000000000..b7038baa24 --- /dev/null +++ b/explorer/src/validators/number.ts @@ -0,0 +1,11 @@ +import { bigint, coerce, number, string } from "superstruct"; + +export const BigIntFromString = coerce(bigint(), string(), (value): bigint => { + if (typeof value === "string") return BigInt(value); + throw new Error("invalid bigint"); +}); + +export const NumberFromString = coerce(number(), string(), (value): number => { + if (typeof value === "string") return Number(value); + throw new Error("invalid number"); +});