Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "zk-keyless-wallet-contracts"]
path = zk-keyless-wallet-contracts
url = https://github.com/WalletZkApp/zk-keyless-wallet-contracts.git
203 changes: 203 additions & 0 deletions app/[locale]/guardian-registration/GuardianZkappWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import {
AccountUpdate,
Field,
MerkleTree,
Mina,
PrivateKey,
PublicKey,
UInt32,
fetchAccount,
} from "snarkyjs";

type Transaction = Awaited<ReturnType<typeof Mina.transaction>>;

// ---------------------------------------------------------------------------------------
import { Guardian } from "../../../zk-keyless-wallet-contracts/src/guardians/Guardian";
import { GuardianZkApp } from "../../../zk-keyless-wallet-contracts/src/guardians/GuardianZkApp";
import { MerkleWitness32 } from "../../../zk-keyless-wallet-contracts/src/storage/offchain-storage";

const GUARDIAN_SERVICE_PRIVATE_KEY =
process.env.GUARDIAN_SERVICE_PRIVATE_KEY ||
"EKEviwcuN5yafPnPvroeeR3L9zbYUgkqvYMXaqqWz4KMNQpgUKy5";

const state: any = {
Guardian: null as null | typeof Guardian,
GuardianZkApp: null as null | typeof GuardianZkApp,
MerkleWitness32: null as null | typeof MerkleWitness32,
zkapp: null as null | GuardianZkApp,
transaction: null as null | Transaction,
guardian: null as null | Guardian,
guardianTree: null as null | MerkleTree,
guardianWitness: null as null | MerkleWitness32,
};

// ---------------------------------------------------------------------------------------

const functions = {
setActiveInstanceToBerkeley: async (args: {}) => {
const Berkeley = Mina.Network(
"https://proxy.berkeley.minaexplorer.com/graphql"
);
console.log("Berkeley Instance Created");
Mina.setActiveInstance(Berkeley);
},
loadContract: async (args: {}) => {
const { GuardianZkApp } = await import(
"../../../zk-keyless-wallet-contracts/build/src/guardians/index"
);
state.GuardianZkApp = GuardianZkApp;
state.guardianTree = new MerkleTree(32);
},
compileContract: async (args: {}) => {
await state.GuardianZkApp!.compile();
},
fetchAccount: async (args: {
publicKey58: string;
isGuardian: boolean;
nullifierMessage: string;
}) => {
const publicKey = PublicKey.fromBase58(args.publicKey58);
let guardian: Guardian | null = null;
if (args.isGuardian) {
const { Guardian } = await import(
"../../../zk-keyless-wallet-contracts/build/src/guardians/Guardian.js"
);
const { MerkleWitness32 } = await import(
"../../../zk-keyless-wallet-contracts/build/src/storage/offchain-storage.js"
);
state.Guardian = Guardian;
state.MerkleWitness32 = MerkleWitness32;
const nullifierMessageField: Field = Field(args.nullifierMessage);
guardian = Guardian.from(publicKey, nullifierMessageField);
state.guardian = guardian;
console.log("guardian hash", guardian.hash().toString());

const counter = state.zkapp!.counter.getAndAssertEquals();
console.log("counter", counter.toString());
const newGuardianTree: MerkleTree = state.guardianTree!;
newGuardianTree.setLeaf(counter.toBigint(), guardian.hash());
state.guardianTree = newGuardianTree;
console.log("guardian tree", state.guardianTree!.getRoot().toString());

let w = newGuardianTree.getWitness(counter.toBigint());
let witness = new MerkleWitness32(w);
state.guardianWitness = witness;
console.log("guardian witness", state.guardianWitness!.toJSON());
}
return await fetchAccount({ publicKey });
},
initZkappInstance: async (args: { publicKey58: string }) => {
const publicKey = PublicKey.fromBase58(args.publicKey58);
state.zkapp = new state.GuardianZkApp!(publicKey);
},
getOwner: async (args: {}) => {
const owner = await state.zkapp!.owner.getAndAssertEquals();
return JSON.stringify(owner.toJSON());
},
getNullifierRoot: async (args: {}) => {
const nullifierRoot = await state.zkapp!.nullifierRoot.getAndAssertEquals();
return JSON.stringify(nullifierRoot.toJSON());
},
getCommittedGuardians: async (args: {}) => {
const committedGuardians =
await state.zkapp!.committedGuardians.getAndAssertEquals();
return JSON.stringify(committedGuardians.toJSON());
},
getApprovedGuardians: async (args: {}) => {
const approvedGuardians =
await state.zkapp!.approvedGuardians.getAndAssertEquals();
return JSON.stringify(approvedGuardians.toJSON());
},
getGuardiansCounter: async (args: {}) => {
const counter: UInt32 = await state.zkapp!.counter.getAndAssertEquals();
return JSON.stringify(counter.toJSON());
},
createRegisterGuardianTransaction: async (args: {
privateKey58: string;
feePayerAddress58: string;
}) => {
const feePayer: PublicKey = PublicKey.fromBase58(args.feePayerAddress58);
console.log("feePayer", feePayer);
const randomPrivateKey: PrivateKey = PrivateKey.fromBase58(
args.privateKey58
);
console.log("randomPrivateKey", randomPrivateKey);
const transaction = await Mina.transaction(feePayer, async () => {
const response = await fetchAccount({ publicKey: feePayer });
if (response.error) {
AccountUpdate.fundNewAccount(feePayer);
}
state.zkapp!.registerGuardian(
state.guardian!.hash(),
state.guardianTree!.getRoot()
);
});
transaction.sign([randomPrivateKey]);
state.transaction = transaction;
},
createApproveGuardianTransaction: async (args: {
privateKey58: string;
feePayerAddress58: string;
}) => {
const feePayer: PublicKey = PublicKey.fromBase58(args.feePayerAddress58);
console.log("feePayer", feePayer);
const randomPrivateKey: PrivateKey = PrivateKey.fromBase58(
args.privateKey58
);
console.log("randomPrivateKey", randomPrivateKey);
const guardianServicePrivateKey: PrivateKey = PrivateKey.fromBase58(
GUARDIAN_SERVICE_PRIVATE_KEY
);
const transaction = await Mina.transaction(feePayer, async () => {
const response = await fetchAccount({ publicKey: feePayer });
if (response.error) {
AccountUpdate.fundNewAccount(feePayer);
}
state.zkapp!.approveGuardian(
guardianServicePrivateKey,
state.guardian!.hash(),
state.guardianTree!.getRoot()
);
});
transaction.sign([randomPrivateKey]);
state.transaction = transaction;
},
proveUpdateTransaction: async (args: {}) => {
await state.transaction!.prove();
},
getTransactionJSON: async (args: {}) => {
return state.transaction!.toJSON();
},
};

// ---------------------------------------------------------------------------------------

export type GuardianWorkerFunctions = keyof typeof functions;

export type GuardianZkappWorkerRequest = {
id: number;
fn: GuardianWorkerFunctions;
args: any;
};

export type GuardianZkappWorkerReponse = {
id: number;
data: any;
};

if (typeof window !== "undefined") {
addEventListener(
"message",
async (event: MessageEvent<GuardianZkappWorkerRequest>) => {
const returnData = await functions[event.data.fn](event.data.args);

const message: GuardianZkappWorkerReponse = {
id: event.data.id,
data: returnData,
};
postMessage(message);
}
);
}

console.log("Web Worker Successfully Initialized.");
137 changes: 137 additions & 0 deletions app/[locale]/guardian-registration/GuardianZkappWorkerClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { fetchAccount, PublicKey, Field, UInt32, PrivateKey } from "snarkyjs";

import type {
GuardianZkappWorkerRequest,
GuardianZkappWorkerReponse,
GuardianWorkerFunctions,
} from "./GuardianZkappWorker";

export default class GuardianZkappWorkerClient {
// ---------------------------------------------------------------------------------------

setActiveInstanceToBerkeley() {
return this._call("setActiveInstanceToBerkeley", {});
}

loadContract() {
return this._call("loadContract", {});
}

compileContract() {
return this._call("compileContract", {});
}

fetchAccount(
publicKey: PublicKey,
isGuardian: boolean,
nullifierMessage: string
): ReturnType<typeof fetchAccount> {
const result = this._call("fetchAccount", {
publicKey58: publicKey.toBase58(),
isGuardian: isGuardian,
nullifierMessage: nullifierMessage,
});
return result as ReturnType<typeof fetchAccount>;
}

initZkappInstance(publicKey: PublicKey) {
return this._call("initZkappInstance", {
publicKey58: publicKey.toBase58(),
});
}

async getOwner(): Promise<PublicKey> {
const result = await this._call("getOwner", {});
return PublicKey.fromBase58(JSON.parse(result as string));
}

async getNullifierRoot(): Promise<Field> {
const result = await this._call("getNullifierRoot", {});
return Field.fromJSON(JSON.parse(result as string));
}

async getCommittedGuardians(): Promise<Field> {
const result = await this._call("getCommittedGuardians", {});
return Field.fromJSON(JSON.parse(result as string));
}

async getApprovedGuardians(): Promise<Field> {
const result = await this._call("getApprovedGuardians", {});
return Field.fromJSON(JSON.parse(result as string));
}

async getGuardiansCounter(): Promise<UInt32> {
const result = await this._call("getGuardiansCounter", {});
return UInt32.fromJSON(JSON.parse(result as string));
}

createRegisterGuardianTransaction(
privateKey: PrivateKey,
feePayer: PublicKey
) {
return this._call("createRegisterGuardianTransaction", {
privateKey58: privateKey.toBase58(),
feePayerAddress58: feePayer.toBase58(),
});
}

createApproveGuardianTransaction(
privateKey: PrivateKey,
feePayer: PublicKey
) {
return this._call("createApproveGuardianTransaction", {
privateKey58: privateKey.toBase58(),
guardianAccount58: feePayer.toBase58(),
});
}

proveUpdateTransaction() {
return this._call("proveUpdateTransaction", {});
}

async getTransactionJSON() {
const result = await this._call("getTransactionJSON", {});
return result;
}

// ---------------------------------------------------------------------------------------

worker: Worker;

promises: {
[id: number]: { resolve: (res: any) => void; reject: (err: any) => void };
};

nextId: number;

constructor() {
this.worker = new Worker(
new URL("./guardianZkappWorker.ts", import.meta.url)
);
this.promises = {};
this.nextId = 0;

this.worker.onmessage = (
event: MessageEvent<GuardianZkappWorkerReponse>
) => {
this.promises[event.data.id].resolve(event.data.data);
delete this.promises[event.data.id];
};
}

_call(fn: GuardianWorkerFunctions, args: any) {
return new Promise((resolve, reject) => {
this.promises[this.nextId] = { resolve, reject };

const message: GuardianZkappWorkerRequest = {
id: this.nextId,
fn,
args,
};

this.worker.postMessage(message);

this.nextId++;
});
}
}
Loading