From d652e7a36d72d8de9af89fe888900b5d67c7e412 Mon Sep 17 00:00:00 2001 From: Tomek Marciniak <16132011+mrcnk@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:39:40 +0100 Subject: [PATCH 1/4] feat(utils): add web worker rpc (#4) --- apps/docs/src/pages/utils.mdx | 74 ++++++++++++++ apps/docs/vocs.config.ts | 4 + bun.lockb | Bin 338024 -> 339080 bytes packages/utils/package.json | 3 +- .../utils/src/{src => }/format-mina.spec.ts | 0 packages/utils/src/{src => }/format-mina.ts | 0 .../utils/src/{src => }/format-units.spec.ts | 0 packages/utils/src/{src => }/format-units.ts | 0 packages/utils/src/index.ts | 9 +- .../utils/src/{src => }/parse-mina.spec.ts | 0 packages/utils/src/{src => }/parse-mina.ts | 0 .../utils/src/{src => }/parse-units.spec.ts | 0 packages/utils/src/{src => }/parse-units.ts | 0 packages/utils/src/test/worker.ts | 9 ++ packages/utils/src/worker-rpc.spec.ts | 32 ++++++ packages/utils/src/worker-rpc.ts | 93 ++++++++++++++++++ 16 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 apps/docs/src/pages/utils.mdx rename packages/utils/src/{src => }/format-mina.spec.ts (100%) rename packages/utils/src/{src => }/format-mina.ts (100%) rename packages/utils/src/{src => }/format-units.spec.ts (100%) rename packages/utils/src/{src => }/format-units.ts (100%) rename packages/utils/src/{src => }/parse-mina.spec.ts (100%) rename packages/utils/src/{src => }/parse-mina.ts (100%) rename packages/utils/src/{src => }/parse-units.spec.ts (100%) rename packages/utils/src/{src => }/parse-units.ts (100%) create mode 100644 packages/utils/src/test/worker.ts create mode 100644 packages/utils/src/worker-rpc.spec.ts create mode 100644 packages/utils/src/worker-rpc.ts diff --git a/apps/docs/src/pages/utils.mdx b/apps/docs/src/pages/utils.mdx new file mode 100644 index 0000000..b2c8339 --- /dev/null +++ b/apps/docs/src/pages/utils.mdx @@ -0,0 +1,74 @@ +# Utils [Don't waste time on implementing these yourself.] + +We've implemented some utilities that you might find useful. You can find them in the `@mina-js/utils` package. + +## Units + +Utils library provides functions for unit conversion. + +### formatMina + +Formats micro-Mina to human-readable Mina value. + +```typescript twoslash +import { formatMina } from '@mina-js/utils' + +const mina = formatMina(5_000_000_000n) +// -> "5" +``` + +### parseMina + +Parses human-readable Mina value to micro-Mina. + +```typescript twoslash +import { parseMina } from '@mina-js/utils' + +const mina = parseMina('5') +// -> 5_000_000_000n +``` + +### formatUnit + +```typescript twoslash +import { formatUnits } from '@mina-js/utils' + +const formatted = formatUnits(4200000000000n, 10) +// -> "420" +``` + +### parseUnits + +```typescript twoslash +import { parseUnits } from '@mina-js/utils' + +const parsed = parseUnits("420", 10) +// -> 4200000000000n +``` + +## Web Workers + +Proof related computations can be heavy and can block the main thread. To avoid this, you can use Web Workers to run these computations in a separate thread. We've prepared a JSON-RPC protocol to easily connect the dots. + +```typescript twoslash +// @filename: worker.ts +import { createRpcHandler } from "@mina-js/utils"; + +const { messageHandler } = createRpcHandler({ + methods: { + ping: async () => 'pong', + } +}) + +self.onmessage = messageHandler + +// @filename: index.ts +import { createRpc } from "@mina-js/utils"; + +const worker = new Worker(new URL('./worker.ts', import.meta.url)) +const rpc = createRpc({ worker }) +const response = await rpc.request({ + method: 'ping', + params: [], +}) +``` diff --git a/apps/docs/vocs.config.ts b/apps/docs/vocs.config.ts index 827f167..e730530 100644 --- a/apps/docs/vocs.config.ts +++ b/apps/docs/vocs.config.ts @@ -81,6 +81,10 @@ export default defineConfig({ text: "Roadmap", link: "/roadmap", }, + { + text: "Utils", + link: "/utils", + }, { text: "MinaJS Connect", link: "/connect", diff --git a/bun.lockb b/bun.lockb index 34fa9dcede2412839ede072257482bd01c4606af..7984ec7563cd9455ef308cac847faa0679dbecd2 100755 GIT binary patch delta 52059 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 diff --git a/packages/utils/package.json b/packages/utils/package.json index c363571..e328a9d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -17,7 +17,8 @@ "cleanup": "rimraf dist .turbo" }, "dependencies": { - "mina-signer": "3.0.7" + "mina-signer": "3.0.7", + "superjson": "2.2.1" }, "devDependencies": { "zod": "3.23.8" diff --git a/packages/utils/src/src/format-mina.spec.ts b/packages/utils/src/format-mina.spec.ts similarity index 100% rename from packages/utils/src/src/format-mina.spec.ts rename to packages/utils/src/format-mina.spec.ts diff --git a/packages/utils/src/src/format-mina.ts b/packages/utils/src/format-mina.ts similarity index 100% rename from packages/utils/src/src/format-mina.ts rename to packages/utils/src/format-mina.ts diff --git a/packages/utils/src/src/format-units.spec.ts b/packages/utils/src/format-units.spec.ts similarity index 100% rename from packages/utils/src/src/format-units.spec.ts rename to packages/utils/src/format-units.spec.ts diff --git a/packages/utils/src/src/format-units.ts b/packages/utils/src/format-units.ts similarity index 100% rename from packages/utils/src/src/format-units.ts rename to packages/utils/src/format-units.ts diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e0af0bf..c4581b7 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,7 +1,8 @@ export * from "./types"; export * from "./validation"; -export { formatMina } from "./src/format-mina"; -export { formatUnits } from "./src/format-units"; -export { parseMina } from "./src/parse-mina"; -export { parseUnits } from "./src/parse-units"; +export { formatMina } from "./format-mina"; +export { formatUnits } from "./format-units"; +export { parseMina } from "./parse-mina"; +export { parseUnits } from "./parse-units"; +export { createRpc, createRpcHandler } from "./worker-rpc"; export * as Test from "./test/constants"; diff --git a/packages/utils/src/src/parse-mina.spec.ts b/packages/utils/src/parse-mina.spec.ts similarity index 100% rename from packages/utils/src/src/parse-mina.spec.ts rename to packages/utils/src/parse-mina.spec.ts diff --git a/packages/utils/src/src/parse-mina.ts b/packages/utils/src/parse-mina.ts similarity index 100% rename from packages/utils/src/src/parse-mina.ts rename to packages/utils/src/parse-mina.ts diff --git a/packages/utils/src/src/parse-units.spec.ts b/packages/utils/src/parse-units.spec.ts similarity index 100% rename from packages/utils/src/src/parse-units.spec.ts rename to packages/utils/src/parse-units.spec.ts diff --git a/packages/utils/src/src/parse-units.ts b/packages/utils/src/parse-units.ts similarity index 100% rename from packages/utils/src/src/parse-units.ts rename to packages/utils/src/parse-units.ts diff --git a/packages/utils/src/test/worker.ts b/packages/utils/src/test/worker.ts new file mode 100644 index 0000000..05663c6 --- /dev/null +++ b/packages/utils/src/test/worker.ts @@ -0,0 +1,9 @@ +import { createRpcHandler } from "../worker-rpc"; + +const { messageHandler } = createRpcHandler({ + methods: { + ping: async () => 'pong', + } +}) + +self.onmessage = messageHandler diff --git a/packages/utils/src/worker-rpc.spec.ts b/packages/utils/src/worker-rpc.spec.ts new file mode 100644 index 0000000..19dbdf7 --- /dev/null +++ b/packages/utils/src/worker-rpc.spec.ts @@ -0,0 +1,32 @@ +import { describe, it, expect, mock, beforeAll } from 'bun:test' +import { createRpc, createRpcHandler } from './worker-rpc' + +describe("Worker RPC", () => { + let worker: Worker + + beforeAll(() => { + worker = new Worker(new URL('./test/worker.ts', import.meta.url)) + }) + + it("creates RPC handler", async () => { + const mockedHandler = mock(async () => "pong") + const { messageHandler } = createRpcHandler({ + methods: { + ping: mockedHandler, + } + }) + await messageHandler(new MessageEvent('message', { data: { method: 'ping', params: [] } })) + expect(mockedHandler).toHaveBeenCalled() + }) + + it("exchanges messages with Web Worker", async () => { + const rpc = createRpc({ worker }) + const response = await rpc.request({ method: 'ping', params: [] }) + expect(response.result).toBe('pong') + }) + + it("calls non-existing method", async () => { + const rpc = createRpc({ worker }) + expect(rpc.request({ method: 'pang', params: [] })).rejects.toThrow() + }) +}) diff --git a/packages/utils/src/worker-rpc.ts b/packages/utils/src/worker-rpc.ts new file mode 100644 index 0000000..1da9e2b --- /dev/null +++ b/packages/utils/src/worker-rpc.ts @@ -0,0 +1,93 @@ +import { z } from "zod"; +import superjson from "superjson"; + +const DEFAULT_TIMEOUT = 60000; + +export const RequestSchema = z.object({ + method: z.string(), + params: z.array(z.string()).optional(), +}); + +type RequestParams = z.infer; + +export const ResponseSchema = z + .object({ + id: z.string(), + result: z.any().optional(), + error: z.string().optional(), + }) + .strict(); + +type Response = z.infer; + +export type RequestFn = (params: RequestParams) => Promise; + +export const createRpc = ({ + worker, + timeout, +}: { + worker: Worker; + timeout?: number; +}) => { + const request: RequestFn = async ({ method, params }) => { + let resolved = false; + return new Promise((resolve, reject) => { + console.log('>>>M', method, params) + setTimeout(() => { + if (resolved) return; + return reject(new Error("[WorkerRPC] Timeout reached.")); + }, timeout ?? DEFAULT_TIMEOUT); + const responseListener = (event: MessageEvent) => { + resolved = true; + worker.removeEventListener("message", responseListener); + const data = superjson.parse(event.data); + const response = ResponseSchema.parse(data); + if (response.error) + return reject(new Error(`[WorkerRPC] ${response.error}`)); + return resolve(response); + }; + worker.addEventListener("message", responseListener); + worker.postMessage({ method, params }); + }); + }; + return { + request, + }; +}; + +type Method = (params: string[]) => Promise; +type MethodsMap = Record; + +const respond = (data: unknown) => postMessage(superjson.stringify(data)) + +export const createRpcHandler = ({ methods }: { methods: MethodsMap }) => { + const methodKeys = Object.keys(methods); + if (methodKeys.length === 0) throw new Error("No methods provided."); + const MethodEnum = z.enum(['error', ...methodKeys]); + const ExtendedRequestSchema = RequestSchema.extend({ + method: MethodEnum, + }).strict(); + const ExtendedResponseSchema = ResponseSchema.extend({ + id: MethodEnum, + }).strict(); + const messageHandler = async (event: MessageEvent) => { + try { + const action = ExtendedRequestSchema.parse(event.data) + const callable = methods[action.method] + if (!callable) throw new Error(`Method "${action.method}" not found.`); + const result = await callable(action.params ?? []); + const parsedResult = ExtendedResponseSchema.parse({ + id: action.method, + result, + }); + return respond(parsedResult); + // biome-ignore lint/suspicious/noExplicitAny: Error handling + } catch (error: any) { + return respond(ExtendedResponseSchema.parse({ + id: 'error', + error: `[WorkerRPC] ${error.message}`, + })); + } + }; + return { messageHandler }; +}; From 67c9205b914d5e9da50415e6fb288ad413a3eb0d Mon Sep 17 00:00:00 2001 From: TheMonkeyCoder Date: Fri, 29 Nov 2024 16:29:06 +0330 Subject: [PATCH 2/4] hotfix: fix networkId mismatch issue for Devnet (#5) --- apps/klesia/src/methods/mina.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/klesia/src/methods/mina.ts b/apps/klesia/src/methods/mina.ts index f6d0053..4effa54 100644 --- a/apps/klesia/src/methods/mina.ts +++ b/apps/klesia/src/methods/mina.ts @@ -78,7 +78,7 @@ const networkId = async () => { `, {}, ); - return data.networkID; + return data.networkID === "mina:testnet" ? "mina:devnet" : data.networkID; }; const sendTransaction = async ({ From c15809ee7b9e012a8fd36399bae6bae129fc1c3d Mon Sep 17 00:00:00 2001 From: Tomek Marciniak <16132011+mrcnk@users.noreply.github.com> Date: Fri, 29 Nov 2024 20:24:06 +0100 Subject: [PATCH 3/4] chore(worker rpc): improve error throwing (#6) --- bun.lockb | Bin 339080 -> 339816 bytes packages/utils/package.json | 1 + packages/utils/src/test/worker.ts | 10 +- packages/utils/src/worker-rpc.spec.ts | 54 +++++----- packages/utils/src/worker-rpc.ts | 140 ++++++++++++++------------ 5 files changed, 107 insertions(+), 98 deletions(-) diff --git a/bun.lockb b/bun.lockb index 7984ec7563cd9455ef308cac847faa0679dbecd2..9971bc84a92e3b175828c0b83f589c0d4406a18c 100755 GIT binary patch delta 50692 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 delta 51667 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 QLDN3*V?D6?xVRes1AD(!0{{R3 diff --git a/packages/utils/package.json b/packages/utils/package.json index e328a9d..aa55899 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "mina-signer": "3.0.7", + "serialize-error": "^11.0.3", "superjson": "2.2.1" }, "devDependencies": { diff --git a/packages/utils/src/test/worker.ts b/packages/utils/src/test/worker.ts index 05663c6..1048622 100644 --- a/packages/utils/src/test/worker.ts +++ b/packages/utils/src/test/worker.ts @@ -1,9 +1,9 @@ import { createRpcHandler } from "../worker-rpc"; const { messageHandler } = createRpcHandler({ - methods: { - ping: async () => 'pong', - } -}) + methods: { + ping: async () => "pong", + }, +}); -self.onmessage = messageHandler +self.onmessage = messageHandler; diff --git a/packages/utils/src/worker-rpc.spec.ts b/packages/utils/src/worker-rpc.spec.ts index 19dbdf7..6aee4e8 100644 --- a/packages/utils/src/worker-rpc.spec.ts +++ b/packages/utils/src/worker-rpc.spec.ts @@ -1,32 +1,34 @@ -import { describe, it, expect, mock, beforeAll } from 'bun:test' -import { createRpc, createRpcHandler } from './worker-rpc' +import { beforeAll, describe, expect, it, mock } from "bun:test"; +import { createRpc, createRpcHandler } from "./worker-rpc"; describe("Worker RPC", () => { - let worker: Worker + let worker: Worker; - beforeAll(() => { - worker = new Worker(new URL('./test/worker.ts', import.meta.url)) - }) + beforeAll(() => { + worker = new Worker(new URL("./test/worker.ts", import.meta.url)); + }); - it("creates RPC handler", async () => { - const mockedHandler = mock(async () => "pong") - const { messageHandler } = createRpcHandler({ - methods: { - ping: mockedHandler, - } - }) - await messageHandler(new MessageEvent('message', { data: { method: 'ping', params: [] } })) - expect(mockedHandler).toHaveBeenCalled() - }) + it("creates RPC handler", async () => { + const mockedHandler = mock(async () => "pong"); + const { messageHandler } = createRpcHandler({ + methods: { + ping: mockedHandler, + }, + }); + await messageHandler( + new MessageEvent("message", { data: { method: "ping", params: [] } }), + ); + expect(mockedHandler).toHaveBeenCalled(); + }); - it("exchanges messages with Web Worker", async () => { - const rpc = createRpc({ worker }) - const response = await rpc.request({ method: 'ping', params: [] }) - expect(response.result).toBe('pong') - }) + it("exchanges messages with Web Worker", async () => { + const rpc = createRpc({ worker }); + const response = await rpc.request({ method: "ping", params: [] }); + expect(response.result).toBe("pong"); + }); - it("calls non-existing method", async () => { - const rpc = createRpc({ worker }) - expect(rpc.request({ method: 'pang', params: [] })).rejects.toThrow() - }) -}) + it("calls non-existing method", async () => { + const rpc = createRpc({ worker }); + expect(rpc.request({ method: "pang", params: [] })).rejects.toThrow(); + }); +}); diff --git a/packages/utils/src/worker-rpc.ts b/packages/utils/src/worker-rpc.ts index 1da9e2b..7bdeaa7 100644 --- a/packages/utils/src/worker-rpc.ts +++ b/packages/utils/src/worker-rpc.ts @@ -1,93 +1,99 @@ -import { z } from "zod"; +import { deserializeError, serializeError } from "serialize-error"; import superjson from "superjson"; +import { z } from "zod"; const DEFAULT_TIMEOUT = 60000; export const RequestSchema = z.object({ - method: z.string(), - params: z.array(z.string()).optional(), + method: z.string(), + params: z.array(z.string()).optional(), }); type RequestParams = z.infer; export const ResponseSchema = z - .object({ - id: z.string(), - result: z.any().optional(), - error: z.string().optional(), - }) - .strict(); + .object({ + id: z.string(), + result: z.any().optional(), + error: z.string().optional(), + }) + .strict(); type Response = z.infer; export type RequestFn = (params: RequestParams) => Promise; export const createRpc = ({ - worker, - timeout, + worker, + timeout, }: { - worker: Worker; - timeout?: number; + worker: Worker; + timeout?: number; }) => { - const request: RequestFn = async ({ method, params }) => { - let resolved = false; - return new Promise((resolve, reject) => { - console.log('>>>M', method, params) - setTimeout(() => { - if (resolved) return; - return reject(new Error("[WorkerRPC] Timeout reached.")); - }, timeout ?? DEFAULT_TIMEOUT); - const responseListener = (event: MessageEvent) => { - resolved = true; - worker.removeEventListener("message", responseListener); - const data = superjson.parse(event.data); - const response = ResponseSchema.parse(data); - if (response.error) - return reject(new Error(`[WorkerRPC] ${response.error}`)); - return resolve(response); - }; - worker.addEventListener("message", responseListener); - worker.postMessage({ method, params }); - }); - }; - return { - request, - }; + const request: RequestFn = async ({ method, params }) => { + let resolved = false; + return new Promise((resolve, reject) => { + setTimeout(() => { + if (resolved) return; + return reject(new Error("[WorkerRPC] Timeout reached.")); + }, timeout ?? DEFAULT_TIMEOUT); + const responseListener = (event: MessageEvent) => { + resolved = true; + worker.removeEventListener("message", responseListener); + const data = superjson.parse(event.data); + const response = ResponseSchema.parse(data); + if (response.error) { + const errorObject = superjson.parse(response.error); + const deserializedError = deserializeError(errorObject); + return reject(deserializedError); + } + return resolve(response); + }; + worker.addEventListener("message", responseListener); + worker.postMessage({ method, params }); + }); + }; + return { + request, + }; }; type Method = (params: string[]) => Promise; type MethodsMap = Record; -const respond = (data: unknown) => postMessage(superjson.stringify(data)) +const respond = (data: unknown) => postMessage(superjson.stringify(data)); export const createRpcHandler = ({ methods }: { methods: MethodsMap }) => { - const methodKeys = Object.keys(methods); - if (methodKeys.length === 0) throw new Error("No methods provided."); - const MethodEnum = z.enum(['error', ...methodKeys]); - const ExtendedRequestSchema = RequestSchema.extend({ - method: MethodEnum, - }).strict(); - const ExtendedResponseSchema = ResponseSchema.extend({ - id: MethodEnum, - }).strict(); - const messageHandler = async (event: MessageEvent) => { - try { - const action = ExtendedRequestSchema.parse(event.data) - const callable = methods[action.method] - if (!callable) throw new Error(`Method "${action.method}" not found.`); - const result = await callable(action.params ?? []); - const parsedResult = ExtendedResponseSchema.parse({ - id: action.method, - result, - }); - return respond(parsedResult); - // biome-ignore lint/suspicious/noExplicitAny: Error handling - } catch (error: any) { - return respond(ExtendedResponseSchema.parse({ - id: 'error', - error: `[WorkerRPC] ${error.message}`, - })); - } - }; - return { messageHandler }; + const methodKeys = Object.keys(methods); + if (methodKeys.length === 0) throw new Error("No methods provided."); + const MethodEnum = z.enum(["error", ...methodKeys]); + const ExtendedRequestSchema = RequestSchema.extend({ + method: MethodEnum, + }).strict(); + const ExtendedResponseSchema = ResponseSchema.extend({ + id: MethodEnum, + }).strict(); + const messageHandler = async (event: MessageEvent) => { + try { + const action = ExtendedRequestSchema.parse(event.data); + const callable = methods[action.method]; + if (!callable) throw new Error(`Method "${action.method}" not found.`); + const result = await callable(action.params ?? []); + const parsedResult = ExtendedResponseSchema.parse({ + id: action.method, + result, + }); + return respond(parsedResult); + // biome-ignore lint/suspicious/noExplicitAny: Error handling + } catch (error: any) { + const serializedError = superjson.stringify(serializeError(error)); + return respond( + ExtendedResponseSchema.parse({ + id: "error", + error: serializedError, + }), + ); + } + }; + return { messageHandler }; }; From 2be76ea08e0c454d4bae1a0820bbd2b214fcee33 Mon Sep 17 00:00:00 2001 From: Tomek Marciniak <16132011+mrcnk@users.noreply.github.com> Date: Sun, 1 Dec 2024 10:32:54 +0100 Subject: [PATCH 4/4] feat(accounts): add zkapp command signing (#7) --- .../private-key-to-account.spec.ts.snap | 29 +++++++++++++++++++ .../accounts/private-key-to-account.spec.ts | 29 +++++++++++++++++++ .../src/accounts/private-key-to-account.ts | 9 ++++-- packages/accounts/src/types.ts | 5 ++-- packages/utils/src/types.ts | 4 +++ packages/utils/src/validation.ts | 7 ++++- 6 files changed, 77 insertions(+), 6 deletions(-) diff --git a/packages/accounts/src/accounts/__snapshots__/private-key-to-account.spec.ts.snap b/packages/accounts/src/accounts/__snapshots__/private-key-to-account.spec.ts.snap index 4abf2ea..605ab98 100644 --- a/packages/accounts/src/accounts/__snapshots__/private-key-to-account.spec.ts.snap +++ b/packages/accounts/src/accounts/__snapshots__/private-key-to-account.spec.ts.snap @@ -53,3 +53,32 @@ exports[`signs fields 1`] = ` "signature": "7mXCUvhLhFvG9ptrdfNceCrpThkCUyg1ct2z8uwY7eQbKz7UNmhv33TbuDjTznaypJtXRiMJyQWDnf27TH1FSXG7uJHTKAd9", } `; + +exports[`signs a zkapp command 1`] = ` +{ + "data": { + "feePayer": { + "fee": "100000000", + "feePayer": "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5", + "memo": "Test", + "nonce": "0", + "validUntil": "null", + }, + "zkappCommand": { + "accountUpdates": [], + "feePayer": { + "authorization": "7mXWqNfmqMTM5uSCS2xLfsRBLTjGZKTtpEakdsrdQz1EUgYXogSvKxxtfGbBkqQ2mZRMA3uPAM8riaCF56pkqpZBLr2kNBLa", + "body": { + "fee": "100000000", + "nonce": "0", + "publicKey": "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5", + "validUntil": null, + }, + }, + "memo": "E4YVT4x3A9rUhmjkjGn8ZYBLZn7zK4cfvnMtBYZFdWkg37n2s3nrP", + }, + }, + "publicKey": "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5", + "signature": "7mXWqNfmqMTM5uSCS2xLfsRBLTjGZKTtpEakdsrdQz1EUgYXogSvKxxtfGbBkqQ2mZRMA3uPAM8riaCF56pkqpZBLr2kNBLa", +} +`; diff --git a/packages/accounts/src/accounts/private-key-to-account.spec.ts b/packages/accounts/src/accounts/private-key-to-account.spec.ts index 7ed0724..f370925 100644 --- a/packages/accounts/src/accounts/private-key-to-account.spec.ts +++ b/packages/accounts/src/accounts/private-key-to-account.spec.ts @@ -33,6 +33,35 @@ it("signs a transaction", async () => { expect(signedTransaction).toMatchSnapshot(); }); +it("signs a zkapp command", async () => { + const account = privateKeyToAccount({ + privateKey: Test.accounts[0].privateKey, + }); + const command = { + zkappCommand: { + accountUpdates: [], + memo: "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH", + feePayer: { + body: { + publicKey: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5", + fee: "100000000", + validUntil: "100000", + nonce: "1", + }, + authorization: "", + }, + }, + feePayer: { + feePayer: "B62qmWKtvNQTtUqo1LxfEEDLyWMg59cp6U7c4uDC7aqgaCEijSc3Hx5", + fee: "100000000", + nonce: "0", + memo: "Test", + }, + }; + const signedTransaction = await account.signTransaction({ command }); + expect(signedTransaction).toMatchSnapshot(); +}); + it("creates a nullifier", async () => { const account = privateKeyToAccount({ privateKey: Test.accounts[0].privateKey, diff --git a/packages/accounts/src/accounts/private-key-to-account.ts b/packages/accounts/src/accounts/private-key-to-account.ts index 6d3ccb6..c276eb2 100644 --- a/packages/accounts/src/accounts/private-key-to-account.ts +++ b/packages/accounts/src/accounts/private-key-to-account.ts @@ -29,9 +29,14 @@ export function privateKeyToAccount({ async signMessage({ message }) { return SignedMessageSchema.parse(client.signMessage(message, privateKey)); }, - async signTransaction({ transaction }) { + async signTransaction(signable) { + if ("transaction" in signable) { + return SignedTransactionSchema.parse( + client.signTransaction(signable.transaction, privateKey), + ); + } return SignedTransactionSchema.parse( - client.signTransaction(transaction, privateKey), + client.signTransaction(signable.command as never, privateKey), ); }, async createNullifier({ message }) { diff --git a/packages/accounts/src/types.ts b/packages/accounts/src/types.ts index bc23ebc..f8f2be0 100644 --- a/packages/accounts/src/types.ts +++ b/packages/accounts/src/types.ts @@ -4,6 +4,7 @@ import type { SignedFields, SignedMessage, SignedTransaction, + TransactionOrZkAppCommandProperties, } from "@mina-js/utils"; import type { HDKey } from "@scure/bip32"; import type { Simplify } from "type-fest"; @@ -12,7 +13,6 @@ import type { CreateNullifierParamsSchema, SignFieldsParamsSchema, SignMessageParamsSchema, - SignTransactionParamsSchema, } from "./validation"; export enum MinaKeyConst { @@ -81,7 +81,6 @@ export type { HDKey }; export type SignFieldsParams = z.infer; export type SignMessageParams = z.infer; export type CreateNullifierParams = z.infer; -export type SignTransactionParams = z.infer; /** * Signer methods @@ -92,5 +91,5 @@ export type CreateNullifier = ( params: CreateNullifierParams, ) => Promise; export type SignTransaction = ( - params: SignTransactionParams, + params: TransactionOrZkAppCommandProperties, ) => Promise; diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index ff76188..fc71c49 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -14,6 +14,7 @@ import type { SignedTransactionSchema, StoredCredentialSchema, TransactionBodySchema, + TransactionOrZkAppCommandSchema, TransactionPayloadSchema, TransactionReceiptSchema, ZkAppCommandBodySchema, @@ -32,6 +33,9 @@ export type TransactionPayload = z.infer; export type PartialTransaction = z.infer; export type ZkAppCommandBody = z.infer; export type ZkAppCommandProperties = z.infer; +export type TransactionOrZkAppCommandProperties = z.infer< + typeof TransactionOrZkAppCommandSchema +>; export type Sendable = z.infer; /** diff --git a/packages/utils/src/validation.ts b/packages/utils/src/validation.ts index b3cf68a..44d2188 100644 --- a/packages/utils/src/validation.ts +++ b/packages/utils/src/validation.ts @@ -79,6 +79,11 @@ export const ZkAppCommandPayload = z }) .strict(); +export const TransactionOrZkAppCommandSchema = z.union([ + TransactionPayloadSchema, + ZkAppCommandPayload, +]); + /** * Return type schemas */ @@ -122,7 +127,7 @@ export const NullifierSchema = z export const SignedTransactionSchema = z .object({ - signature: SignatureSchema, + signature: z.union([SignatureSchema, z.string()]), publicKey: PublicKeySchema, data: z.union([TransactionBodySchema, ZkAppCommandBodySchema]), })