Skip to content

Convert bigNumber to bigint #908

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/server/routes/backend-wallet/sign-typed-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { arbitrumSepolia } from "thirdweb/chains";
import { isSmartBackendWallet } from "../../../shared/db/wallets/get-wallet-details";
import { getWalletDetails } from "../../../shared/db/wallets/get-wallet-details";
import { walletDetailsToAccount } from "../../../shared/utils/account";
import { transformBigNumbers } from "../../../shared/utils/bignumber";
import { getChain } from "../../../shared/utils/chain";
import { createCustomError } from "../../middleware/error";
import { standardResponseSchema } from "../../schemas/shared-api-schemas";
Expand Down Expand Up @@ -47,6 +48,9 @@ export async function signTypedData(fastify: FastifyInstance) {
const { "x-backend-wallet-address": walletAddress } =
request.headers as Static<typeof walletHeaderSchema>;

// Transform any BigNumber objects in the value to stringified bigints
const transformedValue = transformBigNumbers(value);

const walletDetails = await getWalletDetails({
address: walletAddress,
});
Expand Down Expand Up @@ -79,7 +83,7 @@ export async function signTypedData(fastify: FastifyInstance) {
domain,
types,
primaryType: parsedPrimaryType,
message: value,
message: transformedValue,
} as never);

reply.status(StatusCodes.OK).send({
Expand Down
66 changes: 66 additions & 0 deletions src/shared/utils/bignumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Utility functions for handling BigNumber objects in payloads
*/

/**
* Interface representing a BigNumber object as it comes from the frontend
*/
interface BigNumberObject {
type: "BigNumber";
hex: string;
}

/**
* Type guard to check if an object is a BigNumber object
*/
function isBigNumberObject(obj: unknown): obj is BigNumberObject {
return (
typeof obj === "object" &&
obj !== null &&
"type" in obj &&
"hex" in obj &&
obj.type === "BigNumber" &&
typeof obj.hex === "string"
);
}

/**
* Converts a BigNumber object to a stringified bigint
*/
function bigNumberToStringifiedBigInt(bigNumberObj: BigNumberObject): string {
// Convert hex string to bigint, then to string
return BigInt(bigNumberObj.hex).toString();
}
Comment on lines +30 to +33
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for invalid hex strings.

The BigInt() constructor will throw a SyntaxError if the hex string is malformed. This could cause runtime errors when processing user input.

 function bigNumberToStringifiedBigInt(bigNumberObj: BigNumberObject): string {
-  // Convert hex string to bigint, then to string
-  return BigInt(bigNumberObj.hex).toString();
+  try {
+    // Convert hex string to bigint, then to string
+    return BigInt(bigNumberObj.hex).toString();
+  } catch (error) {
+    throw new Error(`Invalid hex string in BigNumber object: ${bigNumberObj.hex}`);
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function bigNumberToStringifiedBigInt(bigNumberObj: BigNumberObject): string {
// Convert hex string to bigint, then to string
return BigInt(bigNumberObj.hex).toString();
}
function bigNumberToStringifiedBigInt(bigNumberObj: BigNumberObject): string {
try {
// Convert hex string to bigint, then to string
return BigInt(bigNumberObj.hex).toString();
} catch (error) {
throw new Error(`Invalid hex string in BigNumber object: ${bigNumberObj.hex}`);
}
}
🤖 Prompt for AI Agents
In src/shared/utils/bignumber.ts around lines 30 to 33, the function
bigNumberToStringifiedBigInt directly converts a hex string to BigInt without
handling potential errors. To fix this, wrap the BigInt conversion in a
try-catch block to catch SyntaxError exceptions caused by malformed hex strings,
and handle the error gracefully, such as returning a default value or throwing a
custom error with a clear message.


/**
* Recursively transforms all BigNumber objects in an arbitrary object/array
* into stringified bigints
*/
export function transformBigNumbers(obj: unknown): unknown {
// Handle null/undefined
if (obj === null || obj === undefined) {
return obj;
}

// Handle BigNumber objects
if (isBigNumberObject(obj)) {
return bigNumberToStringifiedBigInt(obj);
}

// Handle arrays
if (Array.isArray(obj)) {
return obj.map(transformBigNumbers);
}

// Handle objects
if (typeof obj === "object") {
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = transformBigNumbers(value);
}
return result;
}

// Handle primitives (string, number, boolean, etc.)
return obj;
}
Comment on lines +39 to +66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add protection against circular references.

The recursive function could cause stack overflow with circular references. Consider adding a WeakSet to track visited objects.

-export function transformBigNumbers(obj: unknown): unknown {
+export function transformBigNumbers(obj: unknown, visited = new WeakSet()): unknown {
   // Handle null/undefined
   if (obj === null || obj === undefined) {
     return obj;
   }

+  // Handle circular references
+  if (typeof obj === "object" && visited.has(obj as object)) {
+    return obj;
+  }
+
   // Handle BigNumber objects
   if (isBigNumberObject(obj)) {
     return bigNumberToStringifiedBigInt(obj);
   }

   // Handle arrays
   if (Array.isArray(obj)) {
+    visited.add(obj);
-    return obj.map(transformBigNumbers);
+    return obj.map(item => transformBigNumbers(item, visited));
   }

   // Handle objects
   if (typeof obj === "object") {
+    visited.add(obj);
     const result: Record<string, unknown> = {};
     for (const [key, value] of Object.entries(obj)) {
-      result[key] = transformBigNumbers(value);
+      result[key] = transformBigNumbers(value, visited);
     }
     return result;
   }

   // Handle primitives (string, number, boolean, etc.)
   return obj;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function transformBigNumbers(obj: unknown): unknown {
// Handle null/undefined
if (obj === null || obj === undefined) {
return obj;
}
// Handle BigNumber objects
if (isBigNumberObject(obj)) {
return bigNumberToStringifiedBigInt(obj);
}
// Handle arrays
if (Array.isArray(obj)) {
return obj.map(transformBigNumbers);
}
// Handle objects
if (typeof obj === "object") {
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = transformBigNumbers(value);
}
return result;
}
// Handle primitives (string, number, boolean, etc.)
return obj;
}
export function transformBigNumbers(
obj: unknown,
visited = new WeakSet<object>()
): unknown {
// Handle null/undefined
if (obj === null || obj === undefined) {
return obj;
}
// Handle circular references
if (typeof obj === "object" && visited.has(obj as object)) {
return obj;
}
// Handle BigNumber objects
if (isBigNumberObject(obj)) {
return bigNumberToStringifiedBigInt(obj);
}
// Handle arrays
if (Array.isArray(obj)) {
visited.add(obj);
return obj.map(item => transformBigNumbers(item, visited));
}
// Handle objects
if (typeof obj === "object") {
visited.add(obj);
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = transformBigNumbers(value, visited);
}
return result;
}
// Handle primitives (string, number, boolean, etc.)
return obj;
}
🤖 Prompt for AI Agents
In src/shared/utils/bignumber.ts between lines 39 and 66, the
transformBigNumbers function lacks protection against circular references, which
can cause infinite recursion and stack overflow. Fix this by adding a WeakSet
parameter to track visited objects during recursion. Before processing an object
or array, check if it has already been visited; if so, return it directly to
avoid reprocessing. Pass this WeakSet through recursive calls to maintain state
across the traversal.

Loading