diff --git a/src/server/routes/backend-wallet/sign-typed-data.ts b/src/server/routes/backend-wallet/sign-typed-data.ts index 42eeb652..b415b1d5 100644 --- a/src/server/routes/backend-wallet/sign-typed-data.ts +++ b/src/server/routes/backend-wallet/sign-typed-data.ts @@ -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"; @@ -47,6 +48,9 @@ export async function signTypedData(fastify: FastifyInstance) { const { "x-backend-wallet-address": walletAddress } = request.headers as Static; + // Transform any BigNumber objects in the value to stringified bigints + const transformedValue = transformBigNumbers(value); + const walletDetails = await getWalletDetails({ address: walletAddress, }); @@ -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({ diff --git a/src/shared/utils/bignumber.ts b/src/shared/utils/bignumber.ts new file mode 100644 index 00000000..800b0f3b --- /dev/null +++ b/src/shared/utils/bignumber.ts @@ -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(); +} + +/** + * 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 = {}; + for (const [key, value] of Object.entries(obj)) { + result[key] = transformBigNumbers(value); + } + return result; + } + + // Handle primitives (string, number, boolean, etc.) + return obj; +} \ No newline at end of file