Skip to content

Commit a9d6774

Browse files
authored
Validation for mina_requestPresentation (#3)
* feat(providers): validation for presentation request * chore(providers): add PresentationRequestReturnSchema * chore(providers): export PresentationRequest type * chore(utils): export types * feat(docs): add test for presentation request * chore(docs): add new sample credential * feat(providers): validation for mina_signFieldsWithPassphrase * chore(providers): rename * feat(docs): add test for mina_signFieldsWithPassphrase * chore(docs): sample data * chore(docs): remove result stringify * chore(docs and providers): change validation and add more sample data * minor: import different sample credential * fix(providers): fix validation and add sample data * chore(docs): add sample request * chore(utils): update validation * fix(utils): PresentationRequestSchema claims * chore(docs): update sample data * chore(utils): add zkAppAccount to presentation request * feat: use schemas from mina-credentials * chore(providers): import mina-credentials/validation, bump mina-credentials * chore(providers): remove signFieldsWithPassphrase schemas from RPC type * chore(providers): remove signFieldsWithPassphraseRequest * chore(providers and utils): remove unused
1 parent bb02936 commit a9d6774

File tree

8 files changed

+1510
-234
lines changed

8 files changed

+1510
-234
lines changed

apps/docs/src/components/sample-data.ts

Lines changed: 1358 additions & 0 deletions
Large diffs are not rendered by default.

apps/docs/src/components/test-zkapp.tsx

Lines changed: 110 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,16 @@ import { createStore } from "@mina-js/connect";
22
import { useLocalStorage, useObjectState } from "@uidotdev/usehooks";
33
import { clsx } from "clsx";
44
import { useState, useSyncExternalStore } from "react";
5+
import {
6+
sampleCredentialRecursiveUpdated,
7+
samplePresentationRequestHttpsFromExampleUpdated,
8+
} from "./sample-data";
59

610
const store = createStore();
711

8-
const sampleCredential = {
9-
version: "v0",
10-
witness: {
11-
type: "simple",
12-
issuer: {
13-
_type: "PublicKey",
14-
value: "B62qqMxueXzenrchT5CKC5eCSmfcbHic9wJd9GEdHVcd9uCWrjPJjHS",
15-
},
16-
issuerSignature: {
17-
_type: "Signature",
18-
value: {
19-
r: "27355434072539307953235904941558417174103383443074165997458891331674091021280",
20-
s: "22156398191479529717864137276005168653180340733374387165875910835098679659803",
21-
},
22-
},
23-
},
24-
credential: {
25-
owner: {
26-
_type: "PublicKey",
27-
value: "B62qqCMx9YvvjhMFVcRXBqHtAbjWWUhyA9HmgpYCehLHTGKgXsxiZpz",
28-
},
29-
data: {
30-
age: {
31-
_type: "Field",
32-
value: "25",
33-
},
34-
},
35-
},
12+
const sampleSignFieldsWithPassphrase = {
13+
fields: ["1", "2", "3"],
14+
passphrase: "1234",
3615
};
3716

3817
export const TestZkApp = () => {
@@ -42,8 +21,13 @@ export const TestZkApp = () => {
4221
);
4322
const [message, setMessage] = useState("A message to sign");
4423
const [fields, setFields] = useState('["1", "2", "3"]');
24+
const [signFieldsWithPassphraseInput, setSignFieldsWithPassphraseInput] =
25+
useState(JSON.stringify(sampleSignFieldsWithPassphrase, null, 2));
4526
const [credentialInput, setCredentialInput] = useState(
46-
JSON.stringify(sampleCredential, null, 2),
27+
JSON.stringify(sampleCredentialRecursiveUpdated, null, 2),
28+
);
29+
const [presentationRequest, setPresentationRequest] = useState(
30+
JSON.stringify(samplePresentationRequestHttpsFromExampleUpdated, null, 2),
4731
);
4832
const [transactionBody, setTransactionBody] = useObjectState({
4933
to: "B62qnVUL6A53E4ZaGd3qbTr6RCtEZYTu3kTijVrrquNpPo4d3MuJ3nb",
@@ -58,9 +42,11 @@ export const TestZkApp = () => {
5842
mina_getBalance: "",
5943
mina_sign: "",
6044
mina_signFields: "",
45+
mina_signFieldsWithPassphrase: "",
6146
mina_signTransaction: "",
6247
mina_switchChain: "",
6348
mina_storePrivateCredential: "",
49+
mina_requestPresentation: "",
6450
});
6551
const providers = useSyncExternalStore(store.subscribe, store.getProviders);
6652
const provider = providers.find(
@@ -85,6 +71,24 @@ export const TestZkApp = () => {
8571
}
8672
};
8773

74+
const requestPresentation = async () => {
75+
if (!provider) return;
76+
try {
77+
const parsedRequest = JSON.parse(presentationRequest);
78+
const { result } = await provider.request({
79+
method: "mina_requestPresentation",
80+
params: [parsedRequest],
81+
});
82+
setResults(() => ({
83+
mina_requestPresentation: result,
84+
}));
85+
} catch (error) {
86+
setResults(() => ({
87+
mina_requestPresentation: `Error: ${error.message}`,
88+
}));
89+
}
90+
};
91+
8892
const fetchAccounts = async () => {
8993
if (!provider) return;
9094
const { result } = await provider.request({
@@ -132,6 +136,23 @@ export const TestZkApp = () => {
132136
mina_signFields: JSON.stringify(result, undefined, "\t"),
133137
}));
134138
};
139+
const signFieldsWithPassphrase = async () => {
140+
if (!provider) return;
141+
try {
142+
const parsedInput = JSON.parse(signFieldsWithPassphraseInput);
143+
const { result } = await provider.request({
144+
method: "mina_signFieldsWithPassphrase",
145+
params: [parsedInput],
146+
});
147+
setResults(() => ({
148+
mina_signFieldsWithPassphrase: JSON.stringify(result, null, 2),
149+
}));
150+
} catch (error) {
151+
setResults(() => ({
152+
mina_signFieldsWithPassphrase: `Error: ${error.message}`,
153+
}));
154+
}
155+
};
135156
const createNullifier = async () => {
136157
if (!provider) return;
137158
const parsedFields = JSON.parse(fields);
@@ -479,6 +500,66 @@ export const TestZkApp = () => {
479500
</div>
480501
</div>
481502
</section>
503+
<section className="card bg-neutral">
504+
<div className="card-body gap-4">
505+
<h2 className="card-title">Request Presentation</h2>
506+
<p>mina_requestPresentation</p>
507+
<div className="flex flex-col gap-2">
508+
<div className="flex flex-col gap-4">
509+
<textarea
510+
value={presentationRequest}
511+
onChange={(event) => setPresentationRequest(event.target.value)}
512+
className="textarea textarea-bordered h-48 font-mono text-sm"
513+
placeholder="Enter presentation request JSON..."
514+
/>
515+
<button
516+
type="button"
517+
className="btn btn-primary"
518+
onClick={requestPresentation}
519+
>
520+
Request Presentation
521+
</button>
522+
</div>
523+
<label>Result</label>
524+
<textarea
525+
value={results.mina_requestPresentation}
526+
readOnly
527+
className="textarea textarea-bordered h-24 resize-none font-mono"
528+
/>
529+
</div>
530+
</div>
531+
</section>
532+
<section className="card bg-neutral">
533+
<div className="card-body gap-4">
534+
<h2 className="card-title">Sign Fields With Passphrase</h2>
535+
<p>mina_signFieldsWithPassphrase</p>
536+
<div className="flex flex-col gap-2">
537+
<div className="flex flex-col gap-4">
538+
<textarea
539+
value={signFieldsWithPassphraseInput}
540+
onChange={(event) =>
541+
setSignFieldsWithPassphraseInput(event.target.value)
542+
}
543+
className="textarea textarea-bordered h-48 font-mono text-sm"
544+
placeholder="Enter fields and passphrase JSON..."
545+
/>
546+
<button
547+
type="button"
548+
className="btn btn-primary"
549+
onClick={signFieldsWithPassphrase}
550+
>
551+
Sign Fields With Passphrase
552+
</button>
553+
</div>
554+
<label>Result</label>
555+
<textarea
556+
value={results.mina_signFieldsWithPassphrase}
557+
readOnly
558+
className="textarea textarea-bordered h-24 resize-none font-mono"
559+
/>
560+
</div>
561+
</div>
562+
</section>
482563
</main>
483564
);
484565
};

bun.lockb

3.24 KB
Binary file not shown.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,8 @@
2020
"typescript": "5.5.4"
2121
},
2222
"workspaces": ["packages/*", "apps/*"],
23-
"packageManager": "[email protected]"
23+
"packageManager": "[email protected]",
24+
"resolutions": {
25+
"zod": "3.23.8"
26+
}
2427
}

packages/providers/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
"test": "bun test",
1717
"cleanup": "rimraf dist .turbo"
1818
},
19+
"dependencies": {
20+
"mina-credentials": "0.2.6"
21+
},
1922
"devDependencies": {
2023
"@mina-js/utils": "workspace:*"
2124
},

packages/providers/src/validation.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ import {
77
SignedFieldsSchema,
88
SignedMessageSchema,
99
SignedTransactionSchema,
10-
StoredCredentialSchema,
1110
TransactionPayloadSchema,
1211
TransactionReceiptSchema,
1312
TypedSendableSchema,
1413
ZkAppCommandPayload,
14+
zkAppAccountSchema,
1515
} from "@mina-js/utils";
1616
import { z } from "zod";
1717

18+
import {
19+
PresentationRequestSchema,
20+
StoredCredentialSchema,
21+
} from "mina-credentials/validation";
22+
1823
export const SwitchChainRequestParams = z
1924
.object({
2025
networkId: z.string(),
@@ -89,8 +94,21 @@ export const GetStateRequestParamsSchema = RequestWithContext.extend({
8994
export const StorePrivateCredentialRequestParamsSchema =
9095
RequestWithContext.extend({
9196
method: z.literal("mina_storePrivateCredential"),
92-
params: z.array(StoredCredentialSchema),
97+
// biome-ignore lint/suspicious/noExplicitAny: nested types from mina-credentials
98+
params: z.array(StoredCredentialSchema as z.ZodType<any>),
9399
}).strict();
100+
export const PresentationRequestParamsSchema = RequestWithContext.extend({
101+
method: z.literal("mina_requestPresentation"),
102+
params: z.array(
103+
z
104+
.object({
105+
// biome-ignore lint/suspicious/noExplicitAny: nested types from mina-credentials
106+
presentationRequest: PresentationRequestSchema as z.ZodType<any>,
107+
zkAppAccount: zkAppAccountSchema.optional(),
108+
})
109+
.strict(),
110+
),
111+
}).strict();
94112

95113
// Returns
96114
export const AccountsRequestReturnSchema = z
@@ -183,6 +201,12 @@ export const StorePrivateCredentialReturnSchema = z
183201
result: z.object({ success: z.boolean() }).strict(),
184202
})
185203
.strict();
204+
export const PresentationRequestReturnSchema = z
205+
.object({
206+
method: z.literal("mina_requestPresentation"),
207+
result: z.object({ presentation: z.string() }).strict(),
208+
})
209+
.strict();
186210

187211
export const RpcReturnTypesUnion = z.discriminatedUnion("method", [
188212
AccountsRequestReturnSchema,
@@ -200,6 +224,7 @@ export const RpcReturnTypesUnion = z.discriminatedUnion("method", [
200224
SetStateRequestReturnSchema,
201225
GetStateRequestReturnSchema,
202226
StorePrivateCredentialReturnSchema,
227+
PresentationRequestReturnSchema,
203228
]);
204229

205230
export const ProviderRequestParamsUnion = z.discriminatedUnion("method", [
@@ -218,6 +243,7 @@ export const ProviderRequestParamsUnion = z.discriminatedUnion("method", [
218243
SetStateRequestParamsSchema,
219244
GetStateRequestParamsSchema,
220245
StorePrivateCredentialRequestParamsSchema,
246+
PresentationRequestParamsSchema,
221247
]);
222248
export type RpcReturnTypesUnionType = z.infer<typeof RpcReturnTypesUnion>;
223249
export type ResultType<M extends string> = {

packages/utils/src/types.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import type {
1212
SignedFieldsSchema,
1313
SignedMessageSchema,
1414
SignedTransactionSchema,
15-
StoredCredentialSchema,
1615
TransactionBodySchema,
1716
TransactionOrZkAppCommandSchema,
1817
TransactionPayloadSchema,
@@ -57,4 +56,3 @@ export type KlesiaRpcResponseType = z.infer<typeof KlesiaRpcResponseSchema>;
5756
/**
5857
* Private Credential types
5958
*/
60-
export type StoredPrivateCredential = z.infer<typeof StoredCredentialSchema>;

0 commit comments

Comments
 (0)