From d32d7e0b3c9f5a42abe2e52df058d66e58935599 Mon Sep 17 00:00:00 2001 From: Julien Fontanel Date: Wed, 26 Aug 2026 15:09:24 +0200 Subject: [PATCH 1/3] feat: add shareable serialization --- packages/snap-networks-utils/CHANGELOG.md | 2 +- packages/snap-networks-utils/package.json | 5 +- packages/snap-networks-utils/src/index.ts | 3 + .../src/serialization/deserialize.test.ts | 95 ++++++++++++++++ .../src/serialization/deserialize.ts | 41 +++++++ .../src/serialization/serialize.test.ts | 105 ++++++++++++++++++ .../src/serialization/serialize.ts | 48 ++++++++ .../src/serialization/types.ts | 17 +++ yarn.lock | 3 + 9 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 packages/snap-networks-utils/src/serialization/deserialize.test.ts create mode 100644 packages/snap-networks-utils/src/serialization/deserialize.ts create mode 100644 packages/snap-networks-utils/src/serialization/serialize.test.ts create mode 100644 packages/snap-networks-utils/src/serialization/serialize.ts create mode 100644 packages/snap-networks-utils/src/serialization/types.ts diff --git a/packages/snap-networks-utils/CHANGELOG.md b/packages/snap-networks-utils/CHANGELOG.md index d1ca633e7..bada0ee00 100644 --- a/packages/snap-networks-utils/CHANGELOG.md +++ b/packages/snap-networks-utils/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `sanitizeControlCharacters` and `sanitizeUri` utilities for validating and sanitizing user-provided strings and URIs. +- Add `serialize`, `deserialize`, and `Serializable` for round-tripping `BigNumber`, `bigint`, `Uint8Array`, and `undefined` through snap state. - Add a `safeMerge` utility for shallowly merging objects. ([#166](https://github.com/MetaMask/internal-snaps/pull/166)) - Add a `UrlStruct` utility for validating safe HTTP, HTTPS, and WebSocket URLs. ([#174](https://github.com/MetaMask/internal-snaps/pull/174)) diff --git a/packages/snap-networks-utils/package.json b/packages/snap-networks-utils/package.json index 2684d632f..4fce8717a 100644 --- a/packages/snap-networks-utils/package.json +++ b/packages/snap-networks-utils/package.json @@ -65,13 +65,16 @@ "@metamask/remote-feature-flag-controller": "^5.0.0", "@metamask/snaps-sdk": "^11.2.0", "@metamask/superstruct": "^3.4.1", - "@metamask/utils": "^11.11.0" + "@metamask/utils": "^11.11.0", + "bignumber.js": "^9.3.1", + "lodash": "^4.17.21" }, "devDependencies": { "@metamask/auto-changelog": "^6.1.1", "@metamask/messenger": "^2.0.0", "@ts-bridge/cli": "^0.6.4", "@types/jest": "^30.0.0", + "@types/lodash": "^4.17.15", "deepmerge": "^4.2.2", "jest": "30.0.3", "ts-jest": "^29.4.1", diff --git a/packages/snap-networks-utils/src/index.ts b/packages/snap-networks-utils/src/index.ts index b2c2a3b75..7e393ea01 100644 --- a/packages/snap-networks-utils/src/index.ts +++ b/packages/snap-networks-utils/src/index.ts @@ -19,3 +19,6 @@ export type { LogMethodDecorator, LoggerDecorators, } from './logger'; +export { serialize } from './serialization/serialize'; +export { deserialize } from './serialization/deserialize'; +export type { Serializable } from './serialization/types'; diff --git a/packages/snap-networks-utils/src/serialization/deserialize.test.ts b/packages/snap-networks-utils/src/serialization/deserialize.test.ts new file mode 100644 index 000000000..b8093c7b3 --- /dev/null +++ b/packages/snap-networks-utils/src/serialization/deserialize.test.ts @@ -0,0 +1,95 @@ +/* eslint-disable jest/prefer-strict-equal */ + +import { BigNumber } from 'bignumber.js'; + +import { deserialize } from './deserialize'; + +describe('deserialize', () => { + it('deserializes primitive values', () => { + expect(deserialize('test')).toBe('test'); + expect(deserialize(42)).toBe(42); + expect(deserialize(true)).toBe(true); + expect(deserialize(null)).toBeNull(); + }); + + it('deserializes special serialized types', () => { + expect(deserialize({ __type: 'undefined' })).toBeUndefined(); + expect( + deserialize({ __type: 'bigint', value: '9007199254740991' }), + ).toStrictEqual(BigInt(9007199254740991)); + expect( + deserialize({ __type: 'BigNumber', value: '123456789.123456789' }), + ).toStrictEqual(new BigNumber('123456789.123456789')); + }); + + it('deserializes arrays with mixed types', () => { + expect( + deserialize([ + 1, + 'hello', + true, + null, + { __type: 'undefined' }, + { __type: 'bigint', value: '9007199254740991' }, + { __type: 'BigNumber', value: '123456789.123456789' }, + ]), + ).toEqual([ + 1, + 'hello', + true, + null, + undefined, + BigInt(9007199254740991), + new BigNumber('123456789.123456789'), + ]); + }); + + it('deserializes objects with nested structures', () => { + const input = { + nested: { + bigNumber: { __type: 'BigNumber', value: '123.456' }, + bigint: { __type: 'bigint', value: '9007199254740991' }, + undefined: { __type: 'undefined' }, + }, + array: [ + { __type: 'BigNumber', value: '789.012' }, + { __type: 'bigint', value: '9007199254740992' }, + ], + }; + + const result = deserialize(input); + + expect(result).toEqual({ + nested: { + bigNumber: new BigNumber('123.456'), + bigint: BigInt('9007199254740991'), + undefined, + }, + array: [new BigNumber('789.012'), BigInt('9007199254740992')], + }); + }); + + it('handles non-undefined falsy values correctly', () => { + const input = { + zero: 0, + emptyString: '', + falseValue: false, + nullValue: null, + }; + + const result = deserialize(input); + + expect(result).toStrictEqual({ + zero: 0, + emptyString: '', + falseValue: false, + nullValue: null, + }); + }); + + it('deserializes Uint8Array', () => { + const input = { __type: 'Uint8Array', value: 'AQID' }; + const result = deserialize(input); + expect(result).toStrictEqual(new Uint8Array([1, 2, 3])); + }); +}); diff --git a/packages/snap-networks-utils/src/serialization/deserialize.ts b/packages/snap-networks-utils/src/serialization/deserialize.ts new file mode 100644 index 000000000..45c6e8e53 --- /dev/null +++ b/packages/snap-networks-utils/src/serialization/deserialize.ts @@ -0,0 +1,41 @@ +import type { Json } from '@metamask/snaps-sdk'; +import { BigNumber } from 'bignumber.js'; + +import type { Serializable } from './types'; + +/** + * Deserializes the passed value from a JSON object back to its original values. + * It transforms the JSON-serializable representation of non-JSON-serializable values back into their original values. + * + * @param serializedValue - The value to deserialize. + * @returns The deserialized value. + */ +export const deserialize = (serializedValue: Json): Serializable => + JSON.parse(JSON.stringify(serializedValue), (_key, value) => { + if (!value) { + return value; + } + + if (value.__type === 'undefined') { + return undefined; + } + + if (value.__type === 'BigNumber') { + return new BigNumber(value.value); + } + + if (value.__type === 'bigint') { + return BigInt(value.value); + } + + if (value.__type === 'Uint8Array') { + const binaryString = atob(value.value); + const bytes = new Uint8Array(binaryString.length); + for (let index = 0; index < binaryString.length; index++) { + bytes[index] = binaryString.charCodeAt(index); + } + return bytes; + } + + return value; + }); diff --git a/packages/snap-networks-utils/src/serialization/serialize.test.ts b/packages/snap-networks-utils/src/serialization/serialize.test.ts new file mode 100644 index 000000000..28d9adbad --- /dev/null +++ b/packages/snap-networks-utils/src/serialization/serialize.test.ts @@ -0,0 +1,105 @@ +import { BigNumber } from 'bignumber.js'; + +import { serialize } from './serialize'; + +describe('serialize', () => { + it('serializes primitive values', () => { + expect(serialize('test')).toBe('test'); + expect(serialize(42)).toBe(42); + expect(serialize(true)).toBe(true); + expect(serialize(null)).toBeNull(); + expect(serialize(undefined)).toStrictEqual({ __type: 'undefined' }); + }); + + it('serializes special types', () => { + expect(serialize(BigInt(9007199254740991))).toStrictEqual({ + __type: 'bigint', + value: '9007199254740991', + }); + expect(serialize(new BigNumber('123456789.123456789'))).toStrictEqual({ + __type: 'BigNumber', + value: '123456789.123456789', + }); + }); + + it('serializes arrays with mixed types', () => { + const input = [undefined, new BigNumber('123'), BigInt('456')]; + const result = serialize(input); + expect(result).toStrictEqual([ + { __type: 'undefined' }, + { __type: 'BigNumber', value: '123' }, + { __type: 'bigint', value: '456' }, + ]); + }); + + it('serializes objects with nested structures', () => { + const input = { + nested: { + bigNumber: new BigNumber('123.456'), + bigint: BigInt('9007199254740991'), + undefined, + }, + array: [new BigNumber('789.012'), BigInt('9007199254740992')], + }; + + const result = serialize(input); + + expect(result).toStrictEqual({ + nested: { + bigNumber: { __type: 'BigNumber', value: '123.456' }, + bigint: { __type: 'bigint', value: '9007199254740991' }, + undefined: { __type: 'undefined' }, + }, + array: [ + { __type: 'BigNumber', value: '789.012' }, + { __type: 'bigint', value: '9007199254740992' }, + ], + }); + }); + + it('serializes empty objects and arrays', () => { + const input = { + emptyObject: {}, + emptyArray: [], + }; + + const result = serialize(input); + + expect(result).toStrictEqual(input); + }); + + it('serializes deeply nested structures', () => { + const input = { + level1: { + level2: { + level3: { + bigint: BigInt('123'), + undefined, + }, + }, + }, + }; + + const result = serialize(input); + + expect(result).toStrictEqual({ + level1: { + level2: { + level3: { + bigint: { __type: 'bigint', value: '123' }, + undefined: { __type: 'undefined' }, + }, + }, + }, + }); + }); + + it('serializes Uint8Array', () => { + const input = new Uint8Array([1, 2, 3]); + const result = serialize(input); + expect(result).toStrictEqual({ + __type: 'Uint8Array', + value: 'AQID', + }); + }); +}); diff --git a/packages/snap-networks-utils/src/serialization/serialize.ts b/packages/snap-networks-utils/src/serialization/serialize.ts new file mode 100644 index 000000000..882f61eca --- /dev/null +++ b/packages/snap-networks-utils/src/serialization/serialize.ts @@ -0,0 +1,48 @@ +import type { Json } from '@metamask/snaps-sdk'; +import { BigNumber } from 'bignumber.js'; +import { cloneDeepWith } from 'lodash'; + +import type { Serializable } from './types'; + +/** + * Serializes the passed value to a JSON object so it can be stored in JSON-serializable storage like the snap state and interface context. + * It transforms non-JSON-serializable values into a specific JSON-serializable representation that can be deserialized later. + * + * @param value - The value to serialize. + * @returns The serialized value. + */ +export const serialize = (value: Serializable): Json => + cloneDeepWith(value, (val: unknown) => { + if (val === undefined) { + return { + __type: 'undefined', + }; + } + + if (val instanceof BigNumber) { + return { + __type: 'BigNumber', + value: val.toString(), + }; + } + + if (typeof val === 'bigint') { + return { + __type: 'bigint', + value: val.toString(), + }; + } + + if (val instanceof Uint8Array) { + const binaryString = Array.from(val, (byte) => + String.fromCharCode(byte), + ).join(''); + return { + __type: 'Uint8Array', + value: btoa(binaryString), + }; + } + + // Return undefined to let lodash handle the cloning of other values + return undefined; + }); diff --git a/packages/snap-networks-utils/src/serialization/types.ts b/packages/snap-networks-utils/src/serialization/types.ts new file mode 100644 index 000000000..ba1a14540 --- /dev/null +++ b/packages/snap-networks-utils/src/serialization/types.ts @@ -0,0 +1,17 @@ +import type { Json } from '@metamask/snaps-sdk'; +import type { BigNumber } from 'bignumber.js'; + +/** + * A primitive value that can be serialized to JSON using the `serialize` function. + */ +export type Serializable = + | Json + | undefined + | null + | bigint + | BigNumber + | Uint8Array + | Serializable[] + | { + [prop: string]: Serializable; + }; diff --git a/yarn.lock b/yarn.lock index dd3c61cec..b6e1138bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3314,8 +3314,11 @@ __metadata: "@metamask/utils": "npm:^11.11.0" "@ts-bridge/cli": "npm:^0.6.4" "@types/jest": "npm:^30.0.0" + "@types/lodash": "npm:^4.17.15" + bignumber.js: "npm:^9.3.1" deepmerge: "npm:^4.2.2" jest: "npm:30.0.3" + lodash: "npm:^4.17.21" ts-jest: "npm:^29.4.1" tsx: "npm:^4.20.5" typedoc: "npm:^0.25.13" From 856edc3a88b27036a54fc60cd18e8fbf8a78e3e3 Mon Sep 17 00:00:00 2001 From: Julien Fontanel Date: Wed, 26 Aug 2026 15:16:32 +0200 Subject: [PATCH 2/3] chore: update changelog with PR number --- packages/snap-networks-utils/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/snap-networks-utils/CHANGELOG.md b/packages/snap-networks-utils/CHANGELOG.md index 93077688f..c84a9b8c9 100644 --- a/packages/snap-networks-utils/CHANGELOG.md +++ b/packages/snap-networks-utils/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `serialize`, `deserialize`, and `Serializable` for round-tripping `BigNumber`, `bigint`, `Uint8Array`, and `undefined` through snap state. +- Add helpers `serialize`, `deserialize`, and `Serializable` for round-tripping `BigNumber`, `bigint`, `Uint8Array`, and `undefined` through snap state ([#197](https://github.com/MetaMask/internal-snaps/pull/197)) - Add origin permission helpers ([#193](https://github.com/MetaMask/internal-snaps/pull/193)) - `createOriginPermissions` for building origin-to-method maps - `validateOrigin` for checking an origin against a permission map From 9512b2f3ba2236c87c1b10537a55bfd68f4ed3f0 Mon Sep 17 00:00:00 2001 From: Julien Fontanel Date: Thu, 27 Aug 2026 15:03:59 +0200 Subject: [PATCH 3/3] chore: move the functions to the same file --- packages/snap-networks-utils/src/index.ts | 3 +- .../src/serialization/deserialize.test.ts | 95 ------------------- .../src/serialization/deserialize.ts | 41 -------- ...erialize.test.ts => serialization.test.ts} | 94 +++++++++++++++++- .../{serialize.ts => serialization.ts} | 37 ++++++++ 5 files changed, 131 insertions(+), 139 deletions(-) delete mode 100644 packages/snap-networks-utils/src/serialization/deserialize.test.ts delete mode 100644 packages/snap-networks-utils/src/serialization/deserialize.ts rename packages/snap-networks-utils/src/serialization/{serialize.test.ts => serialization.test.ts} (51%) rename packages/snap-networks-utils/src/serialization/{serialize.ts => serialization.ts} (55%) diff --git a/packages/snap-networks-utils/src/index.ts b/packages/snap-networks-utils/src/index.ts index 9a2808824..23ea5b520 100644 --- a/packages/snap-networks-utils/src/index.ts +++ b/packages/snap-networks-utils/src/index.ts @@ -21,8 +21,7 @@ export type { LogMethodDecorator, LoggerDecorators, } from './logger'; -export { serialize } from './serialization/serialize'; -export { deserialize } from './serialization/deserialize'; +export { serialize, deserialize } from './serialization/serialization'; export type { Serializable } from './serialization/types'; export { createOriginPermissions, diff --git a/packages/snap-networks-utils/src/serialization/deserialize.test.ts b/packages/snap-networks-utils/src/serialization/deserialize.test.ts deleted file mode 100644 index b8093c7b3..000000000 --- a/packages/snap-networks-utils/src/serialization/deserialize.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* eslint-disable jest/prefer-strict-equal */ - -import { BigNumber } from 'bignumber.js'; - -import { deserialize } from './deserialize'; - -describe('deserialize', () => { - it('deserializes primitive values', () => { - expect(deserialize('test')).toBe('test'); - expect(deserialize(42)).toBe(42); - expect(deserialize(true)).toBe(true); - expect(deserialize(null)).toBeNull(); - }); - - it('deserializes special serialized types', () => { - expect(deserialize({ __type: 'undefined' })).toBeUndefined(); - expect( - deserialize({ __type: 'bigint', value: '9007199254740991' }), - ).toStrictEqual(BigInt(9007199254740991)); - expect( - deserialize({ __type: 'BigNumber', value: '123456789.123456789' }), - ).toStrictEqual(new BigNumber('123456789.123456789')); - }); - - it('deserializes arrays with mixed types', () => { - expect( - deserialize([ - 1, - 'hello', - true, - null, - { __type: 'undefined' }, - { __type: 'bigint', value: '9007199254740991' }, - { __type: 'BigNumber', value: '123456789.123456789' }, - ]), - ).toEqual([ - 1, - 'hello', - true, - null, - undefined, - BigInt(9007199254740991), - new BigNumber('123456789.123456789'), - ]); - }); - - it('deserializes objects with nested structures', () => { - const input = { - nested: { - bigNumber: { __type: 'BigNumber', value: '123.456' }, - bigint: { __type: 'bigint', value: '9007199254740991' }, - undefined: { __type: 'undefined' }, - }, - array: [ - { __type: 'BigNumber', value: '789.012' }, - { __type: 'bigint', value: '9007199254740992' }, - ], - }; - - const result = deserialize(input); - - expect(result).toEqual({ - nested: { - bigNumber: new BigNumber('123.456'), - bigint: BigInt('9007199254740991'), - undefined, - }, - array: [new BigNumber('789.012'), BigInt('9007199254740992')], - }); - }); - - it('handles non-undefined falsy values correctly', () => { - const input = { - zero: 0, - emptyString: '', - falseValue: false, - nullValue: null, - }; - - const result = deserialize(input); - - expect(result).toStrictEqual({ - zero: 0, - emptyString: '', - falseValue: false, - nullValue: null, - }); - }); - - it('deserializes Uint8Array', () => { - const input = { __type: 'Uint8Array', value: 'AQID' }; - const result = deserialize(input); - expect(result).toStrictEqual(new Uint8Array([1, 2, 3])); - }); -}); diff --git a/packages/snap-networks-utils/src/serialization/deserialize.ts b/packages/snap-networks-utils/src/serialization/deserialize.ts deleted file mode 100644 index 45c6e8e53..000000000 --- a/packages/snap-networks-utils/src/serialization/deserialize.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { Json } from '@metamask/snaps-sdk'; -import { BigNumber } from 'bignumber.js'; - -import type { Serializable } from './types'; - -/** - * Deserializes the passed value from a JSON object back to its original values. - * It transforms the JSON-serializable representation of non-JSON-serializable values back into their original values. - * - * @param serializedValue - The value to deserialize. - * @returns The deserialized value. - */ -export const deserialize = (serializedValue: Json): Serializable => - JSON.parse(JSON.stringify(serializedValue), (_key, value) => { - if (!value) { - return value; - } - - if (value.__type === 'undefined') { - return undefined; - } - - if (value.__type === 'BigNumber') { - return new BigNumber(value.value); - } - - if (value.__type === 'bigint') { - return BigInt(value.value); - } - - if (value.__type === 'Uint8Array') { - const binaryString = atob(value.value); - const bytes = new Uint8Array(binaryString.length); - for (let index = 0; index < binaryString.length; index++) { - bytes[index] = binaryString.charCodeAt(index); - } - return bytes; - } - - return value; - }); diff --git a/packages/snap-networks-utils/src/serialization/serialize.test.ts b/packages/snap-networks-utils/src/serialization/serialization.test.ts similarity index 51% rename from packages/snap-networks-utils/src/serialization/serialize.test.ts rename to packages/snap-networks-utils/src/serialization/serialization.test.ts index 28d9adbad..1d645ea28 100644 --- a/packages/snap-networks-utils/src/serialization/serialize.test.ts +++ b/packages/snap-networks-utils/src/serialization/serialization.test.ts @@ -1,6 +1,6 @@ import { BigNumber } from 'bignumber.js'; -import { serialize } from './serialize'; +import { deserialize, serialize } from './serialization'; describe('serialize', () => { it('serializes primitive values', () => { @@ -103,3 +103,95 @@ describe('serialize', () => { }); }); }); + +/* eslint-disable jest/prefer-strict-equal */ +describe('deserialize', () => { + it('deserializes primitive values', () => { + expect(deserialize('test')).toBe('test'); + expect(deserialize(42)).toBe(42); + expect(deserialize(true)).toBe(true); + expect(deserialize(null)).toBeNull(); + }); + + it('deserializes special serialized types', () => { + expect(deserialize({ __type: 'undefined' })).toBeUndefined(); + expect( + deserialize({ __type: 'bigint', value: '9007199254740991' }), + ).toStrictEqual(BigInt(9007199254740991)); + expect( + deserialize({ __type: 'BigNumber', value: '123456789.123456789' }), + ).toStrictEqual(new BigNumber('123456789.123456789')); + }); + + it('deserializes arrays with mixed types', () => { + expect( + deserialize([ + 1, + 'hello', + true, + null, + { __type: 'undefined' }, + { __type: 'bigint', value: '9007199254740991' }, + { __type: 'BigNumber', value: '123456789.123456789' }, + ]), + ).toEqual([ + 1, + 'hello', + true, + null, + undefined, + BigInt(9007199254740991), + new BigNumber('123456789.123456789'), + ]); + }); + + it('deserializes objects with nested structures', () => { + const input = { + nested: { + bigNumber: { __type: 'BigNumber', value: '123.456' }, + bigint: { __type: 'bigint', value: '9007199254740991' }, + undefined: { __type: 'undefined' }, + }, + array: [ + { __type: 'BigNumber', value: '789.012' }, + { __type: 'bigint', value: '9007199254740992' }, + ], + }; + + const result = deserialize(input); + + expect(result).toEqual({ + nested: { + bigNumber: new BigNumber('123.456'), + bigint: BigInt('9007199254740991'), + undefined, + }, + array: [new BigNumber('789.012'), BigInt('9007199254740992')], + }); + }); + + it('handles non-undefined falsy values correctly', () => { + const input = { + zero: 0, + emptyString: '', + falseValue: false, + nullValue: null, + }; + + const result = deserialize(input); + + expect(result).toStrictEqual({ + zero: 0, + emptyString: '', + falseValue: false, + nullValue: null, + }); + }); + + it('deserializes Uint8Array', () => { + const input = { __type: 'Uint8Array', value: 'AQID' }; + const result = deserialize(input); + expect(result).toStrictEqual(new Uint8Array([1, 2, 3])); + }); +}); +/* eslint-enable jest/prefer-strict-equal */ diff --git a/packages/snap-networks-utils/src/serialization/serialize.ts b/packages/snap-networks-utils/src/serialization/serialization.ts similarity index 55% rename from packages/snap-networks-utils/src/serialization/serialize.ts rename to packages/snap-networks-utils/src/serialization/serialization.ts index 882f61eca..6b5aaf7f6 100644 --- a/packages/snap-networks-utils/src/serialization/serialize.ts +++ b/packages/snap-networks-utils/src/serialization/serialization.ts @@ -46,3 +46,40 @@ export const serialize = (value: Serializable): Json => // Return undefined to let lodash handle the cloning of other values return undefined; }); + +/** + * Deserializes the passed value from a JSON object back to its original values. + * It transforms the JSON-serializable representation of non-JSON-serializable values back into their original values. + * + * @param serializedValue - The value to deserialize. + * @returns The deserialized value. + */ +export const deserialize = (serializedValue: Json): Serializable => + JSON.parse(JSON.stringify(serializedValue), (_key, value) => { + if (!value) { + return value; + } + + if (value.__type === 'undefined') { + return undefined; + } + + if (value.__type === 'BigNumber') { + return new BigNumber(value.value); + } + + if (value.__type === 'bigint') { + return BigInt(value.value); + } + + if (value.__type === 'Uint8Array') { + const binaryString = atob(value.value); + const bytes = new Uint8Array(binaryString.length); + for (let index = 0; index < binaryString.length; index++) { + bytes[index] = binaryString.charCodeAt(index); + } + return bytes; + } + + return value; + });