Skip to content

Commit

Permalink
Initial version for create job
Browse files Browse the repository at this point in the history
  • Loading branch information
andborges committed Apr 17, 2024
1 parent b9a6ac8 commit 40d989f
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 36 deletions.
122 changes: 102 additions & 20 deletions src/app/demo/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,100 @@
"use client";

import { useState } from "react";

import Button from "@/components/Button";
import InputField from "@/components/Input";
import LoadingSpinner from "@/components/Loading";
import {
BuildingOffice2Icon,
EnvelopeIcon,
PhoneIcon,
} from "@heroicons/react/24/outline";
import { useState } from "react";

import { encryptWitness } from "@/utils/cryptography";
import { useChain } from "@/contexts/Chain";

const base64ExampleWitness = "d3RucwIAAAACAAAAAQAAACgAAAAAAAAAIAAAAAEAAPCT9eFDkXC5eUjoMyhdWIGBtkVQuCmgMeFyTmQwBAAAAAIAAACAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
const base64ExampleR1csScript = "cjFjcwEAAAADAAAAAgAAAHgAAAAAAAAAAQAAAAIAAAAAAADwk/XhQ5FwuXlI6DMoXViBgbZFULgpoDHhck5kMAEAAAADAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAAAAPCT9eFDkXC5eUjoMyhdWIGBtkVQuCmgMeFyTmQwAQAAAEAAAAAAAAAAIAAAAAEAAPCT9eFDkXC5eUjoMyhdWIGBtkVQuCmgMeFyTmQwBAAAAAEAAAAAAAAAAgAAAAQAAAAAAAAAAQAAAAMAAAAgAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAMAAAAAAAAA";

export default function DemoPage() {
const [loading, setLoading] = useState(false);
const [form, setForm] = useState({
witness: "",
r1csScript: "",
});
const [logs, setLogs] = useState("");
const [proof, setProof] = useState("");

const { fetchEscrowBalance } = useChain();

const handleChange = (e: any) => {
setForm({
...form,
[e.target.id]: e.target.value,
});
};

const handleSubmit = async (e: any) => {
e.preventDefault();
setLoading(true);

setLogs(`Creating a new job...`);

// const job = await callHub("/jobs", {
// clientId: "123",
// r1csScript: form.r1csScript,
// });
const job = {
id: 1,
encryptKey: "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUExL1ZuQ3VBQjhSeC9sa0JHMDF4RApOUk8rQkF1MVBraGtpOFYxWWYrV3lHajlYU0JzRFhpb3o5MG5jUXNkZnNhUXBuck1qTExIbG9veWpSY1ZTMzNiCk5ycHdld1lNRUI3TEYzVUluOHF0Q1pjTm5RYjU2UjBKZjBFcWhTYjFQWWpEVGxEYS9QMVdkT2xsdi9qS3ZuNm4KYVh5d3FVcVVFZ1lUbVhvcnpwaUtKcy9OTlFsWmwwSmMvdGdhWURXSE96R1hmTk5pdU9lMlM5VUoxUUR0L1YxVApDTXp4MFJsQU15VzBDcURlc1JnRTJpNFhXaWxEczNQUnR4MW1VWnVhVWJUZkxHWDRVbkxLQXZncHd5c05vVGczCjduOUZsVmdCUy9DL2NxdS9kTzkxL0xIWWhVT0s0MUVIZjNTTFIyMFVNaGpmd2RMMHFZVm45Wlh0Mi9uKytBaTEKN3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t",
};

await delay(3000);
setLogs(logs => `${logs}Job ${job.id} created.\nEncrypting witness using Worker public key:\n${Buffer.from(job.encryptKey, "base64").toString("utf-8")}\n`);

const { base64EncryptedWitness, base64EncryptedAesKey, base64AesIv } = encryptWitness(job.encryptKey, form.witness);
setLogs(logs => `${logs}Witness encrypted succesfuly.\nStarting job...`);

// await callHub("/jobs/start", {
// jobId: job.id,
// witness: base64EncryptedWitness,
// aesKey: base64EncryptedAesKey,
// aesIv: base64AesIv,
// });

await delay(3000);
setLogs(logs => `${logs}Done.\nWaiting for proof...`);

await delay(3000);
setProof("0x1234567890");
setLogs(logs => `${logs}Done.`);

fetchEscrowBalance();

setLoading(false);
};

const delay = (delayInms: number) => {
return new Promise(resolve => setTimeout(resolve, delayInms));
};

const callHub = async (url: string, body: any) => {
const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
};

const response = await fetch(
`${process.env.NEXT_PUBLIC_HUB_URL}${url}`,
options,
);

if (!response.ok) {
throw new Error("Failed to fetch data from the server.");
}

const data = await response.json();

return data;
}

return (
<div className="relative isolate bg-gray-900">
<div className="mx-auto grid max-w-7xl grid-cols-1 lg:grid-cols-2">
Expand Down Expand Up @@ -55,32 +138,38 @@ export default function DemoPage() {
/>
</div>
</div>

<form
action="#"
method="POST"
className="px-6 pb-24 pt-20 sm:pb-32 lg:px-8 lg:py-40"
onSubmit={handleSubmit}
>
<div className="mx-auto max-w-xl lg:mr-0 lg:max-w-lg">
<h3 className="text-2xl font-bold tracking-tight text-white pb-6">
Use the SDK to generate a witness and submit here to compute a
proof
</h3>
<div className="grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2">
<InputField label="Witness" id="witness" />
<InputField label="R1CS Script" id="script" />
<InputField label="Witness (Base64 encoded)" id="witness" defaultValue={base64ExampleWitness} onChange={handleChange} />
<InputField label="R1CS Script (Base64 encoded)" id="r1csScript" defaultValue={base64ExampleR1csScript} onChange={handleChange} />
</div>
<div className="mt-8 flex justify-end">
<Button
id="send"
type="button"
type="submit"
label="Compute Proof"
onClick={() => {
console.log("Send message");
}}
/>
</div>
{logs && <div className="mt-3 text-white">
<h3 className="text-2xl font-bold tracking-tight text-white">Logs:</h3>
<pre className="leading-8 text-gray-300">
{logs}
</pre>
</div>}
</div>
</form>

<div className="relative px-6 pb-20 pt-24 sm:pt-32 lg:static lg:px-8 lg:py-40">
<div className="mx-auto max-w-xl lg:mx-0 lg:max-w-lg">
<h3 className="text-2xl font-bold tracking-tight text-white">
Expand All @@ -90,14 +179,7 @@ export default function DemoPage() {
<LoadingSpinner />
) : (
<p className="mt-6 text-lg leading-8 text-gray-300">
{JSON.stringify(
{
proof: "0x1234567890",
result: "true",
},
null,
2,
)}
{proof}
</p>
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type ButtonProps = {
label: string;
type?: "button" | "submit" | "reset";
disabled?: boolean;
onClick: () => void;
onClick?: () => void;
className?: string;
};

Expand Down
28 changes: 20 additions & 8 deletions src/components/WalletConnect.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
"use client";

import { ethers } from "ethers";
import { defineChain } from "thirdweb";
import { ConnectButton } from "thirdweb/react";
import { createWallet, Wallet } from "thirdweb/wallets";

import { useChain } from "@/contexts/Chain";

export default function MetaMaskConnect() {
const { client, setWallet } = useChain();
const wallets = [createWallet("io.metamask")];
const { client, setWallet, escrowBalance } = useChain();

const wallets = [
createWallet("io.metamask"),
createWallet("com.coinbase.wallet"),
createWallet("me.rainbow"),
];

const handleConnect = async (wallet: Wallet) => {
console.log(wallet);
setWallet(wallet);
const account = await wallet?.getAccount();
console.log(account);
console.log(account?.address);
const account = wallet?.getAccount();

try {
const options = {
Expand All @@ -32,6 +37,7 @@ export default function MetaMaskConnect() {
console.log("logged", logged);
} catch (e) {
console.log("error", e);

const options = {
method: "POST",
headers: { "Content-Type": "application/json" },
Expand All @@ -52,17 +58,23 @@ export default function MetaMaskConnect() {
};

return (
<div>
<div className="flex items-center justify-center text-white gap-2">
{escrowBalance != undefined && <div>
Credits: {ethers.utils.formatEther(escrowBalance)}
</div>}

{client && (
<ConnectButton
autoConnect={false}
autoConnect={true}
client={client}
chain={defineChain(2710)}
wallets={wallets}
theme={"dark"}
connectModal={{ size: "wide" }}
onConnect={handleConnect}
/>
)}

</div>
);
}
40 changes: 33 additions & 7 deletions src/contexts/Chain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ import React, {
useMemo,
useEffect,
} from "react";
import { createThirdwebClient, defineChain, getContract } from "thirdweb";
import { createThirdwebClient, defineChain, getContract, readContract } from "thirdweb";
import { useActiveAccount } from "thirdweb/react";
import { Wallet } from "thirdweb/wallets";
import { BigNumber } from "ethers";

// Create the context

const ChainContext = createContext({
client: {} as ReturnType<typeof createThirdwebClient>,
escrowContract: {} as ReturnType<typeof getContract> | undefined,
tokenContract: {} as ReturnType<typeof getContract> | undefined,
setWallet: (wallet: Wallet) => {},
wallet: {} as Wallet | undefined,
escrowBalance: {} as BigNumber | undefined,
fetchEscrowBalance: () => {},
});

// Provider component
Expand All @@ -26,10 +31,27 @@ export function ChainProvider({ children }: { children: React.ReactNode }) {
);

const [wallet, setWallet] = useState<Wallet>();
const [escrowContract, setEscrowContract] =
useState<ReturnType<typeof getContract>>();
const [tokenContract, setTokenContract] =
useState<ReturnType<typeof getContract>>();
const [escrowContract, setEscrowContract] = useState<ReturnType<typeof getContract>>();
const [tokenContract, setTokenContract] = useState<ReturnType<typeof getContract>>();
const [escrowBalance, setEscrowBalance] = useState<BigNumber>();

const activeAccount = useActiveAccount();

const fetchEscrowBalance = () => {
if (activeAccount && escrowContract) {
const fetchBalance = async () => {
const balance = await readContract({
contract: escrowContract,
method: "function balanceOf(address) view returns (uint256)",
params: [activeAccount.address],
});

setEscrowBalance(BigNumber.from(balance));
};

fetchBalance();
}
}

useEffect(() => {
if (client) {
Expand All @@ -49,10 +71,14 @@ export function ChainProvider({ children }: { children: React.ReactNode }) {
}
}, [client]);

useEffect(() => {
fetchEscrowBalance();
}, [activeAccount, escrowContract]);

// Memoize the context value to optimize performance
const value = useMemo(
() => ({ client, escrowContract, tokenContract, wallet, setWallet }),
[client, escrowContract, tokenContract, wallet, setWallet],
() => ({ client, escrowContract, tokenContract, wallet, setWallet, escrowBalance, fetchEscrowBalance}),
[client, escrowContract, tokenContract, wallet, setWallet, escrowBalance, fetchEscrowBalance],
);

return (
Expand Down
37 changes: 37 additions & 0 deletions src/utils/cryptography.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import crypto from "crypto";

export function encryptWitness(base64EnclavePublicKey: string, base64Witness: string) {
const enclavePublicKey = Buffer.from(
base64EnclavePublicKey,
"base64"
).toString("utf-8");

console.log(enclavePublicKey);

const aes_key = crypto.randomBytes(32);
const aes_iv = crypto.randomBytes(16);
const cipher_aes = crypto.createCipheriv("aes-256-cbc", aes_key, aes_iv);

const base64EncryptedWitness = Buffer.concat([
cipher_aes.update(Buffer.from(base64Witness, "utf8")),
cipher_aes.final(),
]).toString("base64");

const base64EncryptedAesKey = crypto
.publicEncrypt(
{
key: enclavePublicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256",
},
aes_key
)
.toString("base64");

return {
base64EncryptedWitness,
base64EncryptedAesKey,
base64AesIv: aes_iv.toString("base64"),
};
}

0 comments on commit 40d989f

Please sign in to comment.