Skip to content

Commit

Permalink
feat: serialize big numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszjasiuk committed Oct 8, 2024
1 parent fc97f7a commit 6f596fb
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 171 deletions.
40 changes: 2 additions & 38 deletions apps/extension/src/extension/ExtensionRequester.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BigNumber from "bignumber.js";
import browser from "webextension-polyfill";

import { deserializeBigNumbers } from "@namada/utils";
import { Message } from "../router";
import { Messenger } from "./ExtensionMessenger";

Expand Down Expand Up @@ -40,7 +40,7 @@ export class ExtensionRequester {
throw error;
}

return fixBigNumbers(result.return);
return deserializeBigNumbers(result.return);
}

async sendMessageToTab<M extends Message<unknown>>(
Expand Down Expand Up @@ -94,39 +94,3 @@ export class ExtensionRequester {
return tabs.map((tab) => tab.id || browser.tabs.TAB_ID_NONE);
}
}

/**
* Searches through an object and creates BigNumbers from any object with
* the _isBigNumber property. This is needed because BigNumbers lose their
* prototype when sent between extension scripts in Firefox.
*
* Returns the object with the BigNumbers reconstructed.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const fixBigNumbers = (result: any): any => {
if (typeof result !== "object" || result === null) {
return result;
}

if (result["_isBigNumber"]) {
return BigNumber(result as BigNumber.Value);
}

const unseenValues = [result];

while (unseenValues.length !== 0) {
const obj = unseenValues.pop();
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === "object" && value !== null) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((value as any)["_isBigNumber"]) {
obj[key] = BigNumber(value as BigNumber.Value);
} else {
unseenValues.push(value);
}
}
});
}

return result;
};
29 changes: 2 additions & 27 deletions apps/extension/src/extension/ExtensionRouter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BigNumber from "bignumber.js";
import { serializeBigNumbers } from "@namada/utils/helpers";
import {
EnvProducer,
MessageSender,
Expand Down Expand Up @@ -61,7 +61,7 @@ export class ExtensionRouter extends Router {
): Promise<Result> {
try {
const result = await this.handleMessage(message, sender);
fixBigNumbers(result);
serializeBigNumbers(result);
return {
return: result,
};
Expand All @@ -77,28 +77,3 @@ export class ExtensionRouter extends Router {
}
}
}

/**
* Searches through an object and adds the _isBigNumber key to any BigNumber
* values. This key is used by the BigNumber constructor to reconstruct a
* BigNumber from a plain object, and is needed because BigNumbers lose their
* prototype when sent between extension scripts in Firefox.
*
* Fixes object in place and returns void.
*/
const fixBigNumbers = (result: unknown): void => {
const unseenValues = [result];

while (unseenValues.length !== 0) {
const value = unseenValues.pop();

if (typeof value === "object" && value !== null) {
if (BigNumber.isBigNumber(value)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(value as any)["_isBigNumber"] = true;
} else {
unseenValues.push(...Object.values(value));
}
}
}
};
2 changes: 1 addition & 1 deletion apps/namadillo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@tanstack/react-query-persist-client": "^5.40.0",
"bignumber.js": "^9.1.1",
"clsx": "^2.1.1",
"comlink": "^4.4.1",
"crypto-browserify": "^3.12.0",
"fp-ts": "^2.16.1",
"framer-motion": "^11.3.28",
Expand All @@ -25,7 +26,6 @@
"jotai": "^2.6.3",
"jotai-tanstack-query": "^0.8.5",
"lodash.debounce": "^4.0.8",
"promise-worker": "^2.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.1.0",
Expand Down
35 changes: 17 additions & 18 deletions apps/namadillo/src/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as Comlink from "comlink";

import { ShieldingTransferMsgValue } from "@namada/types";
import { Toasts } from "App/Common/Toast";
import { AppLayout } from "App/Layout/AppLayout";
Expand All @@ -11,10 +13,13 @@ import { useOnNamadaExtensionAttached } from "hooks/useOnNamadaExtensionAttached
import { useTransactionCallback } from "hooks/useTransactionCallbacks";
import { useTransactionNotifications } from "hooks/useTransactionNotifications";
import { useAtomValue } from "jotai";
import { EncodedTxData, signTx } from "lib/query";
import PromiseWorker from "promise-worker";
import { signTx } from "lib/query";
import { Outlet } from "react-router-dom";
import { ShieldMessageType } from "workers/ShieldWorker";
import { Shield } from "workers/ShieldMessages";
import {
registerTransferHandlers,
ShieldWorkerApi,
} from "workers/ShieldWorker";
import ShieldWorker from "workers/ShieldWorker?worker";
import { ChainLoader } from "./Setup/ChainLoader";

Expand All @@ -28,34 +33,35 @@ export function App(): JSX.Element {

const rpcUrl = useAtomValue(rpcUrlAtom);

const shieldWorker = new PromiseWorker(new ShieldWorker());
registerTransferHandlers();
const shieldWorker = Comlink.wrap<ShieldWorkerApi>(new ShieldWorker());
const { data: account } = useAtomValue(defaultAccountAtom);
const { data: chain } = useAtomValue(chainAtom);
const { data: token } = useAtomValue(nativeTokenAddressAtom);
const indexerUrl = useAtomValue(indexerUrlAtom);
const shiedlingMsgValue = {
const shiedlingMsgValue = new ShieldingTransferMsgValue({
target:
"znam1vue386rsee5c65qsvlm9tgj5lqetz6ejkln3j57utc44w2n8upty57z7lh07myrj3clfxyl9lvn",
data: [
{
source: account?.address || "",
token: token!,
amount: 100 as unknown as BigNumber,
amount: BigNumber(100),
},
],
};
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).buildShieldlingTx = async () => {
await shieldWorker.postMessage({
await shieldWorker.init({
type: "init",
payload: {
rpcUrl,
token: token!,
},
});

const msg: ShieldMessageType = {
const msg: Shield = {
type: "shield",
payload: {
account: account!,
Expand All @@ -69,20 +75,13 @@ export function App(): JSX.Element {
},
};

const encodedTx =
await shieldWorker.postMessage<
Promise<EncodedTxData<ShieldingTransferMsgValue>>
>(msg);
const { payload: encodedTx } = await shieldWorker.shield(msg);

const signedTxs = await signTx("namada", encodedTx, account?.address || "");

await shieldWorker.postMessage({
await shieldWorker.broadcast({
type: "broadcast",
payload: {
sdkInit: {
rpcUrl,
token: token!,
},
encodedTx,
signedTxs,
},
Expand Down
42 changes: 42 additions & 0 deletions apps/namadillo/src/workers/ShieldMessages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import BigNumber from "bignumber.js";

import { Account, ShieldingTransferMsgValue } from "@namada/types";
import { EncodedTxData } from "lib/query";
import { ChainSettings } from "types";
import { WebWorkerMessage } from "./utils";

type InitPayload = {
rpcUrl: string;
token: string;
};

type ShieldPayload = {
account: Account;
gasConfig: {
gasLimit: BigNumber;
gasPrice: BigNumber;
};
shieldingProps: ShieldingTransferMsgValue[];
chain: ChainSettings;
indexerUrl: string;
};

type BroadcastPayload = {
encodedTx: EncodedTxData<ShieldingTransferMsgValue>;
signedTxs: Uint8Array[];
};

export type Init = WebWorkerMessage<"init", InitPayload>;
export type InitDone = WebWorkerMessage<"init-done", null>;

export type Shield = WebWorkerMessage<"shield", ShieldPayload>;
export type ShieldDone = WebWorkerMessage<
"shield-done",
EncodedTxData<ShieldingTransferMsgValue>
>;

export type Broadcast = WebWorkerMessage<"broadcast", BroadcastPayload>;
export type BroadcastDone = WebWorkerMessage<"broadcast-done", null>;

export type ShieldMessageIn = Shield | Broadcast | Init;
export type ShieldMessageOut = ShieldDone | BroadcastDone | InitDone;
Loading

0 comments on commit 6f596fb

Please sign in to comment.