Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into feature/presentation
Browse files Browse the repository at this point in the history
  • Loading branch information
martonmoro committed Dec 3, 2024
2 parents de77460 + 2be76ea commit 9a9de63
Show file tree
Hide file tree
Showing 24 changed files with 311 additions and 16 deletions.
74 changes: 74 additions & 0 deletions apps/docs/src/pages/utils.mdx
Original file line number Diff line number Diff line change
@@ -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: [],
})
```
4 changes: 4 additions & 0 deletions apps/docs/vocs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export default defineConfig({
text: "Roadmap",
link: "/roadmap",
},
{
text: "Utils",
link: "/utils",
},
{
text: "MinaJS Connect",
link: "/connect",
Expand Down
2 changes: 1 addition & 1 deletion apps/klesia/src/methods/mina.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const networkId = async () => {
`,
{},
);
return data.networkID;
return data.networkID === "mina:testnet" ? "mina:devnet" : data.networkID;
};

const sendTransaction = async ({
Expand Down
Binary file modified bun.lockb
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -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",
}
`;
29 changes: 29 additions & 0 deletions packages/accounts/src/accounts/private-key-to-account.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 7 additions & 2 deletions packages/accounts/src/accounts/private-key-to-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) {
Expand Down
5 changes: 2 additions & 3 deletions packages/accounts/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -12,7 +13,6 @@ import type {
CreateNullifierParamsSchema,
SignFieldsParamsSchema,
SignMessageParamsSchema,
SignTransactionParamsSchema,
} from "./validation";

export enum MinaKeyConst {
Expand Down Expand Up @@ -81,7 +81,6 @@ export type { HDKey };
export type SignFieldsParams = z.infer<typeof SignFieldsParamsSchema>;
export type SignMessageParams = z.infer<typeof SignMessageParamsSchema>;
export type CreateNullifierParams = z.infer<typeof CreateNullifierParamsSchema>;
export type SignTransactionParams = z.infer<typeof SignTransactionParamsSchema>;

/**
* Signer methods
Expand All @@ -92,5 +91,5 @@ export type CreateNullifier = (
params: CreateNullifierParams,
) => Promise<Nullifier>;
export type SignTransaction = (
params: SignTransactionParams,
params: TransactionOrZkAppCommandProperties,
) => Promise<SignedTransaction>;
10 changes: 6 additions & 4 deletions packages/providers/src/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@ export const StorePrivateCredentialRequestParamsSchema =
export const PresentationRequestParamsSchema = RequestWithContext.extend({
method: z.literal("mina_requestPresentation"),
params: z.array(
z.object({
presentationRequest: PresentationRequestSchema,
zkAppAccount: zkAppAccountSchema.optional(),
}).strict(),
z
.object({
presentationRequest: PresentationRequestSchema,
zkAppAccount: zkAppAccountSchema.optional(),
})
.strict(),
),
}).strict();

Expand Down
4 changes: 3 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"cleanup": "rimraf dist .turbo"
},
"dependencies": {
"mina-signer": "3.0.7"
"mina-signer": "3.0.7",
"serialize-error": "^11.0.3",
"superjson": "2.2.1"
},
"devDependencies": {
"zod": "3.23.8"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 5 additions & 4 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -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";
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions packages/utils/src/test/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createRpcHandler } from "../worker-rpc";

const { messageHandler } = createRpcHandler({
methods: {
ping: async () => "pong",
},
});

self.onmessage = messageHandler;
4 changes: 4 additions & 0 deletions packages/utils/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
SignedTransactionSchema,
StoredCredentialSchema,
TransactionBodySchema,
TransactionOrZkAppCommandSchema,
TransactionPayloadSchema,
TransactionReceiptSchema,
ZkAppCommandBodySchema,
Expand All @@ -33,6 +34,9 @@ export type TransactionPayload = z.infer<typeof TransactionPayloadSchema>;
export type PartialTransaction = z.infer<typeof PartialTransactionSchema>;
export type ZkAppCommandBody = z.infer<typeof ZkAppCommandBodySchema>;
export type ZkAppCommandProperties = z.infer<typeof ZkAppCommandPayload>;
export type TransactionOrZkAppCommandProperties = z.infer<
typeof TransactionOrZkAppCommandSchema
>;
export type Sendable = z.infer<typeof SendableSchema>;

/**
Expand Down
6 changes: 5 additions & 1 deletion packages/utils/src/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ export const FieldsAndPassphraseSchema = z
passphrase: z.string(),
})
.strict();
export const TransactionOrZkAppCommandSchema = z.union([
TransactionPayloadSchema,
ZkAppCommandPayload,
]);

/**
* Return type schemas
Expand Down Expand Up @@ -131,7 +135,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]),
})
Expand Down
34 changes: 34 additions & 0 deletions packages/utils/src/worker-rpc.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { beforeAll, describe, expect, it, mock } 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();
});
});
Loading

0 comments on commit 9a9de63

Please sign in to comment.