diff --git a/.changeset/fair-hairs-bow.md b/.changeset/fair-hairs-bow.md new file mode 100644 index 0000000..9fea335 --- /dev/null +++ b/.changeset/fair-hairs-bow.md @@ -0,0 +1,6 @@ +--- +"@parcnet-js/client-rpc": minor +"@parcnet-js/podspec": minor +--- + +Support new PODValue types diff --git a/.changeset/shaggy-feet-kick.md b/.changeset/shaggy-feet-kick.md new file mode 100644 index 0000000..f8fa1c8 --- /dev/null +++ b/.changeset/shaggy-feet-kick.md @@ -0,0 +1,9 @@ +--- +"@parcnet-js/app-connector": patch +"@parcnet-js/ticket-spec": patch +"@parcnet-js/client-rpc": patch +"@parcnet-js/podspec": patch +"client-web": patch +--- + +Bump dependencies on POD and GPC diff --git a/apps/client-web/package.json b/apps/client-web/package.json index 8c538a4..8027c1e 100644 --- a/apps/client-web/package.json +++ b/apps/client-web/package.json @@ -13,11 +13,11 @@ "@parcnet-js/client-helpers": "workspace:*", "@parcnet-js/client-rpc": "workspace:*", "@parcnet-js/podspec": "workspace:*", - "@pcd/gpc": "^0.3.0", - "@pcd/pod": "^0.4.0", - "@pcd/proto-pod-gpc-artifacts": "^0.9.0", + "@pcd/gpc": "^0.4.0", + "@pcd/pod": "^0.5.0", + "@pcd/proto-pod-gpc-artifacts": "^0.13.0", "@radix-ui/react-dialog": "^1.1.1", - "@semaphore-protocol/core": "^4.4.1", + "@semaphore-protocol/core": "^4.5.0", "@semaphore-protocol/identity": "3.15.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", diff --git a/apps/client-web/src/App.tsx b/apps/client-web/src/App.tsx index 8052f14..fd24896 100644 --- a/apps/client-web/src/App.tsx +++ b/apps/client-web/src/App.tsx @@ -2,7 +2,7 @@ import { listen } from "@parcnet-js/client-helpers/connection/iframe"; import type { Zapp } from "@parcnet-js/client-rpc"; import type { EntriesSchema, ProofConfigPODSchema } from "@parcnet-js/podspec"; import { proofRequest } from "@parcnet-js/podspec"; -import { gpcProve } from "@pcd/gpc"; +import { type GPCProofInputs, gpcProve } from "@pcd/gpc"; import type { POD } from "@pcd/pod"; import { POD_INT_MAX, POD_INT_MIN } from "@pcd/pod"; import type { Dispatch, ReactNode } from "react"; @@ -130,9 +130,10 @@ function ProvePODInfo({ }) .filter( ([_, entry]) => - !!entry.isMemberOf || - !!entry.isNotMemberOf || - !!(entry.type === "int" && entry.inRange) + entry.type !== "null" && + (!!entry.isMemberOf || + !!entry.isNotMemberOf || + !!(entry.type === "int" && entry.inRange)) ); return ( @@ -155,7 +156,7 @@ function ProvePODInfo({ {schema.pod.meta?.labelEntry ? pod.content .asEntries() - [schema.pod.meta.labelEntry].value.toString() + [schema.pod.meta.labelEntry].value?.toString() : pod.signature.substring(0, 16)} ); @@ -171,7 +172,7 @@ function ProvePODInfo({
{entryName}
- {selectedPODEntries?.[entryName].value.toString() ?? "-"} + {selectedPODEntries?.[entryName].value?.toString() ?? "-"}
); @@ -183,7 +184,7 @@ function ProvePODInfo({ {entriesWithConstraints.map(([entryName, entry]) => { return (
- {entry.isMemberOf && ( + {entry.type !== "null" && entry.isMemberOf && (
{entryName} is member of list:{" "} @@ -196,7 +197,7 @@ function ProvePODInfo({
)} - {entry.isNotMemberOf && ( + {entry.type !== "null" && entry.isNotMemberOf && (
{entryName} is not member of list:{" "} @@ -294,7 +295,7 @@ export function Prove({ const prs = proofRequest( proveOperation.proofRequest ).getProofRequest(); - const inputs = { + const inputs: GPCProofInputs = { pods: proveOperation.selectedPods as Record, membershipLists: prs.membershipLists, watermark: prs.watermark, @@ -303,7 +304,6 @@ export function Prove({ externalNullifier: prs.externalNullifier } }; - console.log(inputs); gpcProve( { ...prs.proofConfig, diff --git a/packages/app-connector/package.json b/packages/app-connector/package.json index 88bc047..fedd8d3 100644 --- a/packages/app-connector/package.json +++ b/packages/app-connector/package.json @@ -38,8 +38,8 @@ "dependencies": { "@parcnet-js/client-rpc": "workspace:*", "@parcnet-js/podspec": "workspace:*", - "@pcd/gpc": "^0.3.0", - "@pcd/pod": "^0.4.0", + "@pcd/gpc": "^0.4.0", + "@pcd/pod": "^0.5.0", "nanoevents": "^9.0.0", "valibot": "^0.42.0" }, diff --git a/packages/client-rpc/package.json b/packages/client-rpc/package.json index 102daa8..4c79bb8 100644 --- a/packages/client-rpc/package.json +++ b/packages/client-rpc/package.json @@ -27,8 +27,8 @@ "files": ["dist", "LICENSE"], "dependencies": { "@parcnet-js/podspec": "workspace:*", - "@pcd/gpc": "^0.3.0", - "@pcd/pod": "^0.4.0", + "@pcd/gpc": "^0.4.0", + "@pcd/pod": "^0.5.0", "valibot": "^0.42.0" }, "devDependencies": { diff --git a/packages/client-rpc/src/schema_elements.ts b/packages/client-rpc/src/schema_elements.ts index e008781..a01a64d 100644 --- a/packages/client-rpc/src/schema_elements.ts +++ b/packages/client-rpc/src/schema_elements.ts @@ -18,6 +18,22 @@ export const PODValueSchema = v.variant("type", [ v.object({ type: v.literal("eddsa_pubkey"), value: v.string() + }), + v.object({ + type: v.literal("boolean"), + value: v.boolean() + }), + v.object({ + type: v.literal("date"), + value: v.date() + }), + v.object({ + type: v.literal("bytes"), + value: v.instance(Uint8Array) + }), + v.object({ + type: v.literal("null"), + value: v.null() }) ]); @@ -57,6 +73,30 @@ export const DefinedEntrySchema = v.variant("type", [ isNotMemberOf: v.optional(v.array(PODValueSchema)), isRevealed: v.optional(v.boolean()), equalsEntry: v.optional(v.string()) + }), + v.object({ + type: v.literal("null") + }), + v.object({ + type: v.literal("bytes"), + isMemberOf: v.optional(v.array(PODValueSchema)), + isNotMemberOf: v.optional(v.array(PODValueSchema)) + }), + v.object({ + type: v.literal("date"), + isMemberOf: v.optional(v.array(PODValueSchema)), + isNotMemberOf: v.optional(v.array(PODValueSchema)), + inRange: v.optional( + v.object({ + min: v.bigint(), + max: v.bigint() + }) + ) + }), + v.object({ + type: v.literal("boolean"), + isMemberOf: v.optional(v.array(PODValueSchema)), + isNotMemberOf: v.optional(v.array(PODValueSchema)) }) ]); diff --git a/packages/podspec/package.json b/packages/podspec/package.json index d8d159d..4ede67a 100644 --- a/packages/podspec/package.json +++ b/packages/podspec/package.json @@ -36,8 +36,8 @@ }, "files": ["dist", "./README.md", "./LICENSE"], "dependencies": { - "@pcd/gpc": "^0.3.0", - "@pcd/pod": "^0.4.0" + "@pcd/gpc": "^0.4.0", + "@pcd/pod": "^0.5.0" }, "devDependencies": { "@parcnet-js/eslint-config": "workspace:*", diff --git a/packages/podspec/src/gpc/proof_request.ts b/packages/podspec/src/gpc/proof_request.ts index 04dcc14..646f933 100644 --- a/packages/podspec/src/gpc/proof_request.ts +++ b/packages/podspec/src/gpc/proof_request.ts @@ -140,8 +140,10 @@ function makeProofRequest

( schema.type === "optional" ? schema.innerType : schema; const isRevealed = proofConfigPODSchema.revealed?.[entryName] ?? false; - const isMemberOf = entrySchema.isMemberOf; - const isNotMemberOf = entrySchema.isNotMemberOf; + const isMemberOf = + entrySchema.type === "null" ? undefined : entrySchema.isMemberOf; + const isNotMemberOf = + entrySchema.type === "null" ? undefined : entrySchema.isNotMemberOf; const inRange = (entrySchema.type === "cryptographic" || entrySchema.type === "int") && entrySchema.inRange; @@ -173,11 +175,11 @@ function makeProofRequest

( }; podConfig.entries[entryName] = entryConfig; - if (entrySchema.isMemberOf) { + if (entrySchema.type !== "null" && entrySchema.isMemberOf) { membershipLists[`allowlist_${podName}_${entryName}`] = entrySchema.isMemberOf; } - if (entrySchema.isNotMemberOf) { + if (entrySchema.type !== "null" && entrySchema.isNotMemberOf) { membershipLists[`blocklist_${podName}_${entryName}`] = entrySchema.isNotMemberOf; } diff --git a/packages/podspec/src/parse/entries.ts b/packages/podspec/src/parse/entries.ts index 8c5b318..cfb1f0f 100644 --- a/packages/podspec/src/parse/entries.ts +++ b/packages/podspec/src/parse/entries.ts @@ -8,10 +8,13 @@ import type { PodspecUnexpectedInputEntryIssue } from "../error.js"; import { IssueCode, PodspecError } from "../error.js"; +import { booleanCoercer, checkPODBooleanValue } from "../schemas/boolean.js"; +import { bytesCoercer, checkPODBytesValue } from "../schemas/bytes.js"; import { checkPODCryptographicValue, cryptographicCoercer } from "../schemas/cryptographic.js"; +import { checkPODDateValue, dateCoercer } from "../schemas/dates.js"; import { checkPODEdDSAPublicKeyValue, eddsaPublicKeyCoercer @@ -19,6 +22,7 @@ import { import type { EntriesSchema, EntriesTupleSchema } from "../schemas/entries.js"; import type { EntrySchema } from "../schemas/entry.js"; import { checkPODIntValue, intCoercer } from "../schemas/int.js"; +import { checkPODNullValue, nullCoercer } from "../schemas/null.js"; import { checkPODStringValue, stringCoercer } from "../schemas/string.js"; import type { EntriesOutputType } from "../type_inference.js"; import { deepFreeze } from "../utils.js"; @@ -30,14 +34,22 @@ const COERCERS: Record unknown> = { string: stringCoercer, int: intCoercer, eddsa_pubkey: eddsaPublicKeyCoercer, - cryptographic: cryptographicCoercer + cryptographic: cryptographicCoercer, + boolean: booleanCoercer, + bytes: bytesCoercer, + date: dateCoercer, + null: nullCoercer }; const TYPE_VALIDATORS = { string: checkPODStringValue, int: checkPODIntValue, eddsa_pubkey: checkPODEdDSAPublicKeyValue, - cryptographic: checkPODCryptographicValue + cryptographic: checkPODCryptographicValue, + boolean: checkPODBooleanValue, + bytes: checkPODBytesValue, + date: checkPODDateValue, + null: checkPODNullValue }; /** @@ -61,6 +73,10 @@ const VALID_ENTRY_SCHEMA_TYPES = [ "string", "cryptographic", "eddsa_pubkey", + "boolean", + "bytes", + "date", + "null", "optional" ] as const; @@ -118,7 +134,10 @@ export class EntriesSpec { * @returns A ParseResult containing either a valid result or list of issues. */ public safeParse( - input: Record, + input: Record< + string, + PODValue | string | bigint | number | boolean | Uint8Array | null | Date + >, options: EntriesParseOptions = DEFAULT_ENTRIES_PARSE_OPTIONS, path: string[] = [] ): ParseResult> { @@ -129,7 +148,10 @@ export class EntriesSpec { * As {@link safeParse} but will throw an exception if errors are encountered. */ public parse( - input: Record, + input: Record< + string, + PODValue | string | bigint | number | boolean | Uint8Array | null | Date + >, options: EntriesParseOptions = DEFAULT_ENTRIES_PARSE_OPTIONS, path: string[] = [] ): EntriesOutputType { @@ -191,7 +213,10 @@ export const DEFAULT_ENTRIES_PARSE_OPTIONS: EntriesParseOptions = */ export function safeParseEntries( schema: E, - input: Record, + input: Record< + string, + PODValue | string | bigint | number | boolean | Uint8Array | null | Date + >, options: EntriesParseOptions = DEFAULT_ENTRIES_PARSE_OPTIONS, path: string[] = [] ): ParseResult> { diff --git a/packages/podspec/src/parse/entry.ts b/packages/podspec/src/parse/entry.ts index af8a4fe..930e3e9 100644 --- a/packages/podspec/src/parse/entry.ts +++ b/packages/podspec/src/parse/entry.ts @@ -1,4 +1,8 @@ -import type { PODCryptographicValue, PODIntValue } from "@pcd/pod"; +import type { + PODCryptographicValue, + PODDateValue, + PODIntValue +} from "@pcd/pod"; import { checkBigintBounds } from "@pcd/pod/podChecks"; import type { PodspecBaseIssue, PodspecNotInRangeIssue } from "../error.js"; import { IssueCode } from "../error.js"; @@ -63,12 +67,19 @@ export function parseEntry( } } - const checkedForMatches = safeMembershipChecks(schema, value, options, path); - if (!checkedForMatches.isValid) { - if (options.exitEarly) { - return FAILURE(checkedForMatches.issues); - } else { - issues.push(...checkedForMatches.issues); + if (schema.type !== "null") { + const checkedForMatches = safeMembershipChecks( + schema, + value, + options, + path + ); + if (!checkedForMatches.isValid) { + if (options.exitEarly) { + return FAILURE(checkedForMatches.issues); + } else { + issues.push(...checkedForMatches.issues); + } } } @@ -95,5 +106,17 @@ export function parseEntry( } } + if (schema.type === "date") { + if (schema.inRange) { + const { min, max } = schema.inRange; + checkBigintBounds( + "", + BigInt((value as PODDateValue).value.getTime()), + min, + max + ); + } + } + return issues.length > 0 ? FAILURE(issues) : SUCCESS(value); } diff --git a/packages/podspec/src/parse/parse_utils.ts b/packages/podspec/src/parse/parse_utils.ts index 8d6b1c3..cc9edba 100644 --- a/packages/podspec/src/parse/parse_utils.ts +++ b/packages/podspec/src/parse/parse_utils.ts @@ -1,7 +1,11 @@ import type { + PODBooleanValue, + PODBytesValue, PODCryptographicValue, + PODDateValue, PODEdDSAPublicKeyValue, PODIntValue, + PODNullValue, PODStringValue, PODValue } from "@pcd/pod"; @@ -22,6 +26,7 @@ import type { import { IssueCode } from "../error.js"; import type { EntriesSchema } from "../schemas/entries.js"; import type { DefinedEntrySchema } from "../schemas/entry.js"; +import type { NullSchema } from "../schemas/null.js"; import type { PODTupleSchema } from "../schemas/pod.js"; import type { EntriesParseOptions } from "./entries.js"; import type { EntryParseOptions } from "./entry.js"; @@ -152,7 +157,28 @@ export function safeCheckPublicKeyFormat( * @returns True if the values are equal, false otherwise. */ export function isEqualPODValue(a: PODValue, b: PODValue): boolean { - return a.type === b.type && a.value === b.value; + if (a.type !== b.type) { + return false; + } + + switch (a.type) { + case "string": + case "int": + case "cryptographic": + case "eddsa_pubkey": + case "boolean": + case "null": + return a.value === b.value; + case "date": + return a.value.getTime() === (b as PODDateValue).value.getTime(); + case "bytes": + return ( + a.value.length === (b as PODBytesValue).value.length && + a.value.every( + (byte, index) => byte === (b as PODBytesValue).value[index] + ) + ); + } } /** @@ -165,7 +191,7 @@ export function isEqualPODValue(a: PODValue, b: PODValue): boolean { * @returns A ParseResult containing either a valid result or list of issues. */ export function safeMembershipChecks< - S extends DefinedEntrySchema, + S extends Exclude, T extends PODValue >( schema: S, @@ -303,6 +329,10 @@ export type PODValueNativeTypes = { int: bigint; cryptographic: bigint; eddsa_pubkey: string; + boolean: boolean; + bytes: Uint8Array; + date: Date; + null: null; }; export type PODValueCoerceableNativeTypes = { @@ -310,6 +340,10 @@ export type PODValueCoerceableNativeTypes = { int: bigint | number | boolean; cryptographic: bigint | number | boolean; eddsa_pubkey: string; + boolean: boolean; + bytes: Uint8Array; + date: Date; + null: null; }; /** @@ -320,4 +354,8 @@ export type PODValueTypeNameToPODValue = { int: PODIntValue; cryptographic: PODCryptographicValue; eddsa_pubkey: PODEdDSAPublicKeyValue; + boolean: PODBooleanValue; + bytes: PODBytesValue; + date: PODDateValue; + null: PODNullValue; }; diff --git a/packages/podspec/src/pod_value_utils.ts b/packages/podspec/src/pod_value_utils.ts index 96d0406..9e619d1 100644 --- a/packages/podspec/src/pod_value_utils.ts +++ b/packages/podspec/src/pod_value_utils.ts @@ -1,7 +1,11 @@ import type { + PODBooleanValue, + PODBytesValue, PODCryptographicValue, + PODDateValue, PODEdDSAPublicKeyValue, PODIntValue, + PODNullValue, PODStringValue } from "@pcd/pod"; @@ -56,3 +60,47 @@ export function $c( return value.map((s) => ({ type: "cryptographic", value: BigInt(s) })); } } + +export function $b(value: boolean): PODBooleanValue; +export function $b(value: boolean[]): PODBooleanValue[]; +export function $b( + value: boolean | boolean[] +): PODBooleanValue | PODBooleanValue[] { + if (typeof value === "boolean") { + return { type: "boolean", value }; + } else { + return value.map((b) => ({ type: "boolean", value: b })); + } +} + +export function $n(value: null): PODNullValue; +export function $n(value: null[]): PODNullValue[]; +export function $n(value: null | null[]): PODNullValue | PODNullValue[] { + if (value === null) { + return { type: "null", value: null }; + } else { + return value.map(() => ({ type: "null", value: null })); + } +} + +export function $d(value: Date): PODDateValue; +export function $d(value: Date[]): PODDateValue[]; +export function $d(value: Date | Date[]): PODDateValue | PODDateValue[] { + if (value instanceof Date) { + return { type: "date", value }; + } else { + return value.map((d) => ({ type: "date", value: d })); + } +} + +export function $bs(value: Uint8Array): PODBytesValue; +export function $bs(value: Uint8Array[]): PODBytesValue[]; +export function $bs( + value: Uint8Array | Uint8Array[] +): PODBytesValue | PODBytesValue[] { + if (value instanceof Uint8Array) { + return { type: "bytes", value }; + } else { + return value.map((b) => ({ type: "bytes", value: b })); + } +} diff --git a/packages/podspec/src/schemas/boolean.ts b/packages/podspec/src/schemas/boolean.ts new file mode 100644 index 0000000..6b2edd7 --- /dev/null +++ b/packages/podspec/src/schemas/boolean.ts @@ -0,0 +1,54 @@ +import type { PODBooleanValue, PODValue } from "@pcd/pod"; +import { checkPODValue } from "@pcd/pod/podChecks"; +import type { PodspecInvalidTypeIssue } from "../error.js"; +import { IssueCode } from "../error.js"; +import type { ParseResult } from "../parse/parse_utils.js"; +import { FAILURE, SUCCESS } from "../parse/parse_utils.js"; + +/** + * Schema for a PODBooleanValue. + */ +export interface BooleanSchema { + type: "boolean"; + isMemberOf?: PODBooleanValue[]; + isNotMemberOf?: PODBooleanValue[]; +} + +/** + * Checks if the given input is a PODBytesValue. + * @param data - The input to check. + * @returns A ParseResult wrapping the value + */ +export function checkPODBooleanValue( + data: unknown, + path: string[] +): ParseResult { + try { + checkPODValue("", data as PODValue); + } catch { + const issue = { + code: IssueCode.invalid_type, + expectedType: "boolean", + path: path + } satisfies PodspecInvalidTypeIssue; + return FAILURE([issue]); + } + + return SUCCESS(data as PODBooleanValue); +} + +/** + * @param input - The input to coerce. + * @returns A PODBytesValue or undefined if coercion is not possible. + */ +export function booleanCoercer(input: unknown): PODBooleanValue | undefined { + let value: PODBooleanValue | undefined = undefined; + if (typeof input === "boolean") { + value = { + type: "boolean", + value: input + }; + } + + return value; +} diff --git a/packages/podspec/src/schemas/bytes.ts b/packages/podspec/src/schemas/bytes.ts new file mode 100644 index 0000000..f85ee8a --- /dev/null +++ b/packages/podspec/src/schemas/bytes.ts @@ -0,0 +1,55 @@ +import type { PODBytesValue, PODName, PODValue } from "@pcd/pod"; +import { checkPODValue } from "@pcd/pod/podChecks"; +import type { PodspecInvalidTypeIssue } from "../error.js"; +import { IssueCode } from "../error.js"; +import type { ParseResult } from "../parse/parse_utils.js"; +import { FAILURE, SUCCESS } from "../parse/parse_utils.js"; + +/** + * Schema for a PODBytesValue. + */ +export interface BytesSchema { + type: "bytes"; + isMemberOf?: PODBytesValue[]; + isNotMemberOf?: PODBytesValue[]; + equalsEntry?: PODName; +} + +/** + * Checks if the given input is a PODBytesValue. + * @param data - The input to check. + * @returns A ParseResult wrapping the value + */ +export function checkPODBytesValue( + data: unknown, + path: string[] +): ParseResult { + try { + checkPODValue("", data as PODValue); + } catch { + const issue = { + code: IssueCode.invalid_type, + expectedType: "bytes", + path: path + } satisfies PodspecInvalidTypeIssue; + return FAILURE([issue]); + } + + return SUCCESS(data as PODBytesValue); +} + +/** + * @param input - The input to coerce. + * @returns A PODBytesValue or undefined if coercion is not possible. + */ +export function bytesCoercer(input: unknown): PODBytesValue | undefined { + let value: PODBytesValue | undefined = undefined; + if (input instanceof Uint8Array) { + value = { + type: "bytes", + value: input + }; + } + + return value; +} diff --git a/packages/podspec/src/schemas/dates.ts b/packages/podspec/src/schemas/dates.ts new file mode 100644 index 0000000..22c354f --- /dev/null +++ b/packages/podspec/src/schemas/dates.ts @@ -0,0 +1,55 @@ +import type { PODDateValue, PODValue } from "@pcd/pod"; +import { checkPODValue } from "@pcd/pod/podChecks"; +import type { PodspecInvalidTypeIssue } from "../error.js"; +import { IssueCode } from "../error.js"; +import type { ParseResult } from "../parse/parse_utils.js"; +import { FAILURE, SUCCESS } from "../parse/parse_utils.js"; + +/** + * Schema for a PODDateValue. + */ +export interface DateSchema { + type: "date"; + isMemberOf?: PODDateValue[]; + isNotMemberOf?: PODDateValue[]; + inRange?: { min: bigint; max: bigint }; +} + +/** + * Checks if the given input is a PODBytesValue. + * @param data - The input to check. + * @returns A ParseResult wrapping the value + */ +export function checkPODDateValue( + data: unknown, + path: string[] +): ParseResult { + try { + checkPODValue("", data as PODValue); + } catch { + const issue = { + code: IssueCode.invalid_type, + expectedType: "date", + path: path + } satisfies PodspecInvalidTypeIssue; + return FAILURE([issue]); + } + + return SUCCESS(data as PODDateValue); +} + +/** + * @param input - The input to coerce. + * @returns A PODDateValue or undefined if coercion is not possible. + */ +export function dateCoercer(input: unknown): PODDateValue | undefined { + let value: PODDateValue | undefined = undefined; + if (input instanceof Date) { + value = { + type: "date", + value: input + }; + } + + return value; +} diff --git a/packages/podspec/src/schemas/entry.ts b/packages/podspec/src/schemas/entry.ts index 5b97c6c..a8a98d2 100644 --- a/packages/podspec/src/schemas/entry.ts +++ b/packages/podspec/src/schemas/entry.ts @@ -1,6 +1,10 @@ +import type { BooleanSchema } from "./boolean.js"; +import type { BytesSchema } from "./bytes.js"; import type { CryptographicSchema } from "./cryptographic.js"; +import type { DateSchema } from "./dates.js"; import type { EdDSAPublicKeySchema } from "./eddsa_pubkey.js"; import type { IntSchema } from "./int.js"; +import type { NullSchema } from "./null.js"; import type { StringSchema } from "./string.js"; /** @@ -10,7 +14,11 @@ export type DefinedEntrySchema = | StringSchema | CryptographicSchema | IntSchema - | EdDSAPublicKeySchema; + | EdDSAPublicKeySchema + | BooleanSchema + | BytesSchema + | DateSchema + | NullSchema; /** * Schema for an optional entry. diff --git a/packages/podspec/src/schemas/null.ts b/packages/podspec/src/schemas/null.ts new file mode 100644 index 0000000..ba650ca --- /dev/null +++ b/packages/podspec/src/schemas/null.ts @@ -0,0 +1,52 @@ +import type { PODNullValue, PODValue } from "@pcd/pod"; +import { checkPODValue } from "@pcd/pod/podChecks"; +import type { PodspecInvalidTypeIssue } from "../error.js"; +import { IssueCode } from "../error.js"; +import type { ParseResult } from "../parse/parse_utils.js"; +import { FAILURE, SUCCESS } from "../parse/parse_utils.js"; + +/** + * Schema for a PODNullValue. + */ +export interface NullSchema { + type: "null"; +} + +/** + * Checks if the given input is a PODNullValue. + * @param data - The input to check. + * @returns A ParseResult wrapping the value + */ +export function checkPODNullValue( + data: unknown, + path: string[] +): ParseResult { + try { + checkPODValue("", data as PODValue); + } catch { + const issue = { + code: IssueCode.invalid_type, + expectedType: "null", + path: path + } satisfies PodspecInvalidTypeIssue; + return FAILURE([issue]); + } + + return SUCCESS(data as PODNullValue); +} + +/** + * @param input - The input to coerce. + * @returns A PODNullValue or undefined if coercion is not possible. + */ +export function nullCoercer(input: unknown): PODNullValue | undefined { + let value: PODNullValue | undefined = undefined; + if (input === null) { + value = { + type: "null", + value: input + }; + } + + return value; +} diff --git a/packages/podspec/src/utils.ts b/packages/podspec/src/utils.ts index 6a809e7..b28d813 100644 --- a/packages/podspec/src/utils.ts +++ b/packages/podspec/src/utils.ts @@ -6,6 +6,9 @@ export function deepFreeze(obj: T): T { Object.freeze(obj); Object.values(obj).forEach((value) => { + if (value instanceof Uint8Array) { + return; + } deepFreeze(value); }); diff --git a/packages/podspec/test/podspec.spec.ts b/packages/podspec/test/podspec.spec.ts index 1d7a3d0..9a3f0f7 100644 --- a/packages/podspec/test/podspec.spec.ts +++ b/packages/podspec/test/podspec.spec.ts @@ -10,7 +10,7 @@ import type { } from "../src/error.js"; import { IssueCode } from "../src/error.js"; import * as p from "../src/index.js"; -import { $c, $i, $s } from "../src/pod_value_utils.js"; +import { $b, $bs, $c, $i, $s } from "../src/pod_value_utils.js"; import type { EntriesTupleSchema } from "../src/schemas/entries.js"; import { GPC_NPM_ARTIFACTS_PATH } from "./constants.js"; import { generateKeyPair, generateRandomHex } from "./utils.js"; @@ -35,6 +35,24 @@ describe("podspec should work", function () { }, publicKey: { type: "eddsa_pubkey" + }, + isActive: { + type: "boolean", + isMemberOf: [$b(true)] + }, + noneExistent: { + type: "null" + }, + byteSequence: { + type: "bytes", + isMemberOf: [$bs(new Uint8Array([1, 2, 3]))] + }, + registrationDate: { + type: "date", + inRange: { + min: BigInt(new Date("2024-01-01").getTime()), + max: BigInt(new Date("2024-12-31").getTime()) + } } }); @@ -58,6 +76,22 @@ describe("podspec should work", function () { publicKey: { type: "eddsa_pubkey", value: publicKey + }, + isActive: { + type: "boolean", + value: true + }, + noneExistent: { + type: "null", + value: null + }, + byteSequence: { + type: "bytes", + value: new Uint8Array([1, 2, 3]) + }, + registrationDate: { + type: "date", + value: new Date("2024-05-01") } }); @@ -73,6 +107,16 @@ describe("podspec should work", function () { type: "eddsa_pubkey", value: publicKey }); + expect(result.value.isActive).to.eql({ type: "boolean", value: true }); + expect(result.value.noneExistent).to.eql({ type: "null", value: null }); + expect(result.value.byteSequence).to.eql({ + type: "bytes", + value: new Uint8Array([1, 2, 3]) + }); + expect(result.value.registrationDate).to.eql({ + type: "date", + value: new Date("2024-05-01") + }); }); /** @@ -98,6 +142,24 @@ describe("podspec should work", function () { }, publicKey: { type: "eddsa_pubkey" + }, + isActive: { + type: "boolean", + isMemberOf: [$b(true)] + }, + noneExistent: { + type: "null" + }, + byteSequence: { + type: "bytes", + isMemberOf: [$bs(new Uint8Array([1, 2, 3]))] + }, + registrationDate: { + type: "date", + inRange: { + min: BigInt(new Date("2024-01-01").getTime()), + max: BigInt(new Date("2024-12-31").getTime()) + } } }); @@ -108,7 +170,11 @@ describe("podspec should work", function () { firstName: "test", age: 41, // numbers can be coerced to bigint semaphoreId: 1000n, - publicKey: publicKey + publicKey: publicKey, + isActive: true, + noneExistent: null, + byteSequence: new Uint8Array([1, 2, 3]), + registrationDate: new Date("2024-05-01") }, { coerce: true } ); diff --git a/packages/ticket-spec/package.json b/packages/ticket-spec/package.json index 2fcab84..f339be4 100644 --- a/packages/ticket-spec/package.json +++ b/packages/ticket-spec/package.json @@ -32,9 +32,9 @@ "devDependencies": { "@parcnet-js/eslint-config": "workspace:*", "@parcnet-js/typescript-config": "workspace:*", - "@pcd/gpc": "^0.3.0", - "@pcd/pod": "^0.4.0", - "@pcd/proto-pod-gpc-artifacts": "^0.9.0", + "@pcd/gpc": "^0.4.0", + "@pcd/pod": "^0.5.0", + "@pcd/proto-pod-gpc-artifacts": "^0.13.0", "@semaphore-protocol/core": "^4.0.3", "@semaphore-protocol/identity": "^3.15.2", "@types/uuid": "^9.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index add30a9..a081a93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,20 +46,20 @@ importers: specifier: workspace:* version: link:../../packages/podspec '@pcd/gpc': - specifier: ^0.3.0 - version: 0.3.0(typescript@5.5.4) - '@pcd/pod': specifier: ^0.4.0 - version: 0.4.0 + version: 0.4.0(typescript@5.5.4) + '@pcd/pod': + specifier: ^0.5.0 + version: 0.5.0 '@pcd/proto-pod-gpc-artifacts': - specifier: ^0.9.0 - version: 0.9.0 + specifier: ^0.13.0 + version: 0.13.0 '@radix-ui/react-dialog': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@semaphore-protocol/core': - specifier: ^4.4.1 - version: 4.4.1 + specifier: ^4.5.0 + version: 4.5.0 '@semaphore-protocol/identity': specifier: 3.15.2 version: 3.15.2 @@ -258,11 +258,11 @@ importers: specifier: workspace:* version: link:../podspec '@pcd/gpc': - specifier: ^0.3.0 - version: 0.3.0(typescript@5.5.4) - '@pcd/pod': specifier: ^0.4.0 - version: 0.4.0 + version: 0.4.0(typescript@5.5.4) + '@pcd/pod': + specifier: ^0.5.0 + version: 0.5.0 nanoevents: specifier: ^9.0.0 version: 9.0.0 @@ -354,11 +354,11 @@ importers: specifier: workspace:* version: link:../podspec '@pcd/gpc': - specifier: ^0.3.0 - version: 0.3.0(typescript@5.5.4) - '@pcd/pod': specifier: ^0.4.0 - version: 0.4.0 + version: 0.4.0(typescript@5.5.4) + '@pcd/pod': + specifier: ^0.5.0 + version: 0.5.0 valibot: specifier: ^0.42.0 version: 0.42.0(typescript@5.5.4) @@ -424,11 +424,11 @@ importers: packages/podspec: dependencies: '@pcd/gpc': - specifier: ^0.3.0 - version: 0.3.0(typescript@5.5.4) - '@pcd/pod': specifier: ^0.4.0 - version: 0.4.0 + version: 0.4.0(typescript@5.5.4) + '@pcd/pod': + specifier: ^0.5.0 + version: 0.5.0 devDependencies: '@parcnet-js/eslint-config': specifier: workspace:* @@ -477,14 +477,14 @@ importers: specifier: workspace:* version: link:../typescript-config '@pcd/gpc': - specifier: ^0.3.0 - version: 0.3.0(typescript@5.6.2) - '@pcd/pod': specifier: ^0.4.0 - version: 0.4.0 + version: 0.4.0(typescript@5.6.2) + '@pcd/pod': + specifier: ^0.5.0 + version: 0.5.0 '@pcd/proto-pod-gpc-artifacts': - specifier: ^0.9.0 - version: 0.9.0 + specifier: ^0.13.0 + version: 0.13.0 '@semaphore-protocol/core': specifier: ^4.0.3 version: 4.0.3 @@ -1460,24 +1460,33 @@ packages: resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} engines: {node: '>= 10.0.0'} - '@pcd/gpc@0.3.0': - resolution: {integrity: sha512-gaDwb76PYYm+qJUZu+gYWbpJKjbEAI+UPO+yaPYCURLPK+8iUMB3xIv6F3CCJNICQdpcwOVMpnWOu+5wzzwqhA==} + '@pcd/gpc@0.4.0': + resolution: {integrity: sha512-VE95hTf/Fi/j0Lz6s15cULnQAqaeHaMgRn8wR8xmxA99Bv9KEPD7KZkkrV20WtIf9/Rc+YuFIYEaBFakl4D8Ng==} - '@pcd/gpcircuits@0.4.0': - resolution: {integrity: sha512-rn1pkRTQit/maD80bqB2fb84yN22iTWvZWIjgOV6Y84jAZ1uyU4hfbEUJ4q6pdgb4vENiFu9g3pHGge7My9ZTQ==} + '@pcd/gpcircuits@0.5.0': + resolution: {integrity: sha512-+liYDmxPBEX8SGGPB95/oJliT3Sj+WKeXOldA+7AulqtDEuF+u266NcGOkLqOA0bRPFtzAYO2fQJTvWaK+ws+A==} '@pcd/pod@0.4.0': resolution: {integrity: sha512-A90GK1cv/t3pxB9YiiLIXDsJldp3YcmCJchRSbVvFfA9Q2pleumNRpFadwmweLqGf5Er9n1C7AWtiEt07K3rIw==} + '@pcd/pod@0.5.0': + resolution: {integrity: sha512-Zm8G6BXXjFtSBooYi4cHWAe44US3NjdsPtKmv1Zpcl0EejxYG0wU6GrUpnhSwJfjEpGm35Wes9BUT7wHThGnGg==} + '@pcd/proto-pod-gpc-artifacts@0.11.0': resolution: {integrity: sha512-k/lASCefq1vUyqRirHUAc+yiZAMhSfTJx51qnyImXl6ArW8LtNWRyeoTql2BjY9u3BM/mWN279S5+NtghwnsDw==} - '@pcd/proto-pod-gpc-artifacts@0.9.0': - resolution: {integrity: sha512-DipHMqcwpwCGy0/4hpENYjhKPcxVDEM4Koe13L1QpDYlOVVlUfsV9Y5ObpjtZELH4Q8jLWEW2tnMW9vR+c388w==} + '@pcd/proto-pod-gpc-artifacts@0.13.0': + resolution: {integrity: sha512-SFKV8gmFCyZ6WIOcJPXCdx4I1gNavIw+5u7TFU8L6/DqtUPWZ1/SubyAChb7aTetfwNgJTyid/VL9fEkJYSThA==} + + '@pcd/semaphore-identity-v3-wrapper@0.1.0': + resolution: {integrity: sha512-NlLT6Pu+ua0agmPO2bulQiF5vaNv1XbGwSyrTEH/eONq1I0LL5Yd2qdPpZbUnnCUE+Wa6yi4jUqB6i6vh8kv8g==} '@pcd/util@0.8.0': resolution: {integrity: sha512-KG1V8O+o8Awr9iHH9I1eVeqHGlm3F6zqzvOJzXKe/bViE8A31DuiZoeHCVPFRA5+03d+qY4tWQJKOxYGQL6Kww==} + '@pcd/util@0.9.0': + resolution: {integrity: sha512-PI9XR9DY7Okn8AJyOfFPhSihewh5VVTyFf5Hm+qaH09t0MlV8ZbMAo9hbiyB5NtHJo7fEEM5BHTRCPpMeVEJcA==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1755,14 +1764,14 @@ packages: '@semaphore-protocol/core@4.0.3': resolution: {integrity: sha512-XwFSV8B8JYOS7nXDPNSQ8Uy/Yw2MPyAhcMLToAJsu6HG8rwIG5I6F6/MKgDm4IhUJnE1h22fipoteekjBMVqSg==} - '@semaphore-protocol/core@4.4.1': - resolution: {integrity: sha512-A0Xr4QRoTCGnE17GCUFCUvdn7hulZwNU4457iKm2157/UKcLwM9LWkl5VfY4uji0S/NH1vX6X40Xdml2Y5Nz0A==} + '@semaphore-protocol/core@4.5.0': + resolution: {integrity: sha512-DQNLJIS4YGYnkDDtywpLf1gbQLWRhNm3X3dYGxODujApaATYQaPsFo6HHgHycMRIVgxrQwiAzSCAkTR8SNNgRg==} '@semaphore-protocol/group@4.0.3': resolution: {integrity: sha512-ElxMN4vio301EJ6VjnfEpagG8KQn/Ck7BuBwpwHS7neDYcJkKYfRHCOd8OR/mg4dNVenflHkgIO8WTgCz+2n5A==} - '@semaphore-protocol/group@4.4.1': - resolution: {integrity: sha512-qrNnPi7DQfNPs1DSNFvbnarfzK9OB7mMDzalT53FNeSiY7vNEPt068n6WAEbLV0fmDe2O52Rhoprw6Aw6VhB3A==} + '@semaphore-protocol/group@4.5.0': + resolution: {integrity: sha512-8EKglTaLJ1jyKYtp9QgopyNi5BZ6bSal6qUSHXP0/LThXfbtPyiCTl0UvC9Vg0XZMeZUpu/leRgzKkOSeJ7zMg==} '@semaphore-protocol/identity@3.15.2': resolution: {integrity: sha512-MJ1MO5QL+oX+OFK2rHAPjQ6+kKgGxCsVJLNdn1soRawxbrxH9A6tV9AsVHV0DN4saegQ4qaOOy1XO1PAN6PiQA==} @@ -1770,8 +1779,8 @@ packages: '@semaphore-protocol/identity@4.0.3': resolution: {integrity: sha512-IfGpE00gWnuM0c41g3rY1uU0he8X8JOrerqXjGzrsW0sXRe/jkxL/jln6zufVTGleN/mGdP9CkqXh7Ca7QjAiw==} - '@semaphore-protocol/identity@4.4.1': - resolution: {integrity: sha512-YqhvsMTJB5tN7umXWwNfkqikJlj27qrHqD4wm+6bCIV4KrJnowY5mQVsxzKNrLeAp5nzLC4QrVxGi5CODKYedA==} + '@semaphore-protocol/identity@4.5.0': + resolution: {integrity: sha512-TIKxF2Lir1LppDQDJU6Z/aJUkocHT03BLpzv5vFEdCo/IT4g/4BhbFp2UQui7HyDE+JgMfUASXfScbFfo/5ULA==} '@semaphore-protocol/proof@4.0.3': resolution: {integrity: sha512-egqXei3IEPNKHUxd3/9AbI/1z1nrp1DA5DtzdHI36m1RP0GOE/k4gpwaSGQQqqbUuuGYYnrZZj7bmhphfAy43A==} @@ -1779,17 +1788,17 @@ packages: '@semaphore-protocol/group': 4.0.3 '@semaphore-protocol/identity': 4.0.3 - '@semaphore-protocol/proof@4.4.1': - resolution: {integrity: sha512-GD/MHSK7xSrZt76u1hTBw7ugorALjDLcJW2lfO0xe+3VQZDjqbbyA4K8A0pz6ticJuNzwyH9p/X19QUWp9Ncuw==} + '@semaphore-protocol/proof@4.5.0': + resolution: {integrity: sha512-/95XcIkud+3QOYxw7QB3wAS28EzbYyJsrqwmQgRy02Xk7b9aDvKZGXcdQ/pXMAjXc1D5mTPDOuJwnTtNtzrOcA==} peerDependencies: - '@semaphore-protocol/group': 4.4.1 - '@semaphore-protocol/identity': 4.4.1 + '@semaphore-protocol/group': 4.5.0 + '@semaphore-protocol/identity': 4.5.0 '@semaphore-protocol/utils@4.0.3': resolution: {integrity: sha512-IMyL8C68fHbe5h1QyfZxfxDlxmB1e0TLkBKnEJHnTsNW7nKpzJNAPjcloQ/bbLwWj7SsaeOu+eMQCDPmqSzbQw==} - '@semaphore-protocol/utils@4.4.1': - resolution: {integrity: sha512-0ASKABpBo3lbyPM73sArkBh6uM+9SnbXA4d1Uj1LkYIdwPESaijJHMWdM+Zn0w8lKLPBTF0oW/vIcBjD5uCl8g==} + '@semaphore-protocol/utils@4.5.0': + resolution: {integrity: sha512-6dfQZJvS5JFxdcKUYQTcfptoNohylVDWf6ID+mt8T9jtwgJilDCxkCuCul21lDRxfaChTVVvCm0SYsH+wkroZw==} '@shikijs/core@1.16.3': resolution: {integrity: sha512-yETIvrETCeC39gSPIiSADmjri9FwKmxz0QvONMtTIUYlKZe90CJkvcjPksayC2VQOtzOJonEiULUa8v8crUQvA==} @@ -6932,39 +6941,43 @@ snapshots: '@parcel/watcher-win32-x64': 2.4.1 optional: true - '@pcd/gpc@0.3.0(typescript@5.5.4)': + '@pcd/gpc@0.4.0(typescript@5.5.4)': dependencies: - '@pcd/gpcircuits': 0.4.0 - '@pcd/pod': 0.4.0 - '@pcd/util': 0.8.0 - '@semaphore-protocol/identity': 3.15.2 + '@pcd/gpcircuits': 0.5.0 + '@pcd/pod': 0.5.0 + '@pcd/semaphore-identity-v3-wrapper': 0.1.0 + '@pcd/util': 0.9.0 + '@semaphore-protocol/core': 4.5.0 json-bigint: 1.0.0 lodash: 4.17.21 - semaphore-identity-v4: '@semaphore-protocol/identity@4.4.1' snarkjs: 0.7.4 url-join: 4.0.1 valibot: 0.42.1(typescript@5.5.4) transitivePeerDependencies: + - bufferutil - typescript + - utf-8-validate - '@pcd/gpc@0.3.0(typescript@5.6.2)': + '@pcd/gpc@0.4.0(typescript@5.6.2)': dependencies: - '@pcd/gpcircuits': 0.4.0 - '@pcd/pod': 0.4.0 - '@pcd/util': 0.8.0 - '@semaphore-protocol/identity': 3.15.2 + '@pcd/gpcircuits': 0.5.0 + '@pcd/pod': 0.5.0 + '@pcd/semaphore-identity-v3-wrapper': 0.1.0 + '@pcd/util': 0.9.0 + '@semaphore-protocol/core': 4.5.0 json-bigint: 1.0.0 lodash: 4.17.21 - semaphore-identity-v4: '@semaphore-protocol/identity@4.4.1' snarkjs: 0.7.4 url-join: 4.0.1 valibot: 0.42.1(typescript@5.6.2) transitivePeerDependencies: + - bufferutil - typescript + - utf-8-validate - '@pcd/gpcircuits@0.4.0': + '@pcd/gpcircuits@0.5.0': dependencies: - '@pcd/pod': 0.4.0 + '@pcd/pod': 0.5.0 fastfile: 0.0.20 snarkjs: 0.7.4 url-join: 4.0.1 @@ -6978,9 +6991,22 @@ snapshots: js-sha256: 0.10.1 poseidon-lite: 0.3.0 + '@pcd/pod@0.5.0': + dependencies: + '@pcd/util': 0.9.0 + '@zk-kit/eddsa-poseidon': 1.0.4 + '@zk-kit/lean-imt': 2.2.1 + '@zk-kit/utils': 1.2.1 + js-sha256: 0.10.1 + poseidon-lite: 0.3.0 + '@pcd/proto-pod-gpc-artifacts@0.11.0': {} - '@pcd/proto-pod-gpc-artifacts@0.9.0': {} + '@pcd/proto-pod-gpc-artifacts@0.13.0': {} + + '@pcd/semaphore-identity-v3-wrapper@0.1.0': + dependencies: + '@semaphore-protocol/identity': 3.15.2 '@pcd/util@0.8.0': dependencies: @@ -6990,6 +7016,14 @@ snapshots: secure-random: 1.1.2 uuid: 9.0.1 + '@pcd/util@0.9.0': + dependencies: + buffer: 6.0.3 + email-validator: 2.0.4 + js-sha256: 0.10.1 + secure-random: 1.1.2 + uuid: 9.0.1 + '@pkgjs/parseargs@0.11.0': optional: true @@ -7208,11 +7242,11 @@ snapshots: - bufferutil - utf-8-validate - '@semaphore-protocol/core@4.4.1': + '@semaphore-protocol/core@4.5.0': dependencies: - '@semaphore-protocol/group': 4.4.1 - '@semaphore-protocol/identity': 4.4.1 - '@semaphore-protocol/proof': 4.4.1(@semaphore-protocol/group@4.4.1)(@semaphore-protocol/identity@4.4.1) + '@semaphore-protocol/group': 4.5.0 + '@semaphore-protocol/identity': 4.5.0 + '@semaphore-protocol/proof': 4.5.0(@semaphore-protocol/group@4.5.0)(@semaphore-protocol/identity@4.5.0) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -7222,7 +7256,7 @@ snapshots: '@zk-kit/lean-imt': 2.1.0 '@zk-kit/utils': 1.0.0 - '@semaphore-protocol/group@4.4.1': + '@semaphore-protocol/group@4.5.0': dependencies: '@zk-kit/lean-imt': 2.2.1 '@zk-kit/utils': 1.2.1 @@ -7243,7 +7277,7 @@ snapshots: '@zk-kit/utils': 1.2.0 poseidon-lite: 0.2.0 - '@semaphore-protocol/identity@4.4.1': + '@semaphore-protocol/identity@4.5.0': dependencies: '@zk-kit/baby-jubjub': 1.0.3 '@zk-kit/eddsa-poseidon': 1.0.4 @@ -7263,11 +7297,11 @@ snapshots: - bufferutil - utf-8-validate - '@semaphore-protocol/proof@4.4.1(@semaphore-protocol/group@4.4.1)(@semaphore-protocol/identity@4.4.1)': + '@semaphore-protocol/proof@4.5.0(@semaphore-protocol/group@4.5.0)(@semaphore-protocol/identity@4.5.0)': dependencies: - '@semaphore-protocol/group': 4.4.1 - '@semaphore-protocol/identity': 4.4.1 - '@semaphore-protocol/utils': 4.4.1 + '@semaphore-protocol/group': 4.5.0 + '@semaphore-protocol/identity': 4.5.0 + '@semaphore-protocol/utils': 4.5.0 '@zk-kit/artifacts': 1.8.0 '@zk-kit/utils': 1.2.1 ethers: 6.10.0 @@ -7283,7 +7317,7 @@ snapshots: - bufferutil - utf-8-validate - '@semaphore-protocol/utils@4.4.1': + '@semaphore-protocol/utils@4.5.0': dependencies: ethers: 6.13.2 transitivePeerDependencies: