Skip to content
This repository has been archived by the owner on Jan 8, 2025. It is now read-only.

Commit

Permalink
js examples
Browse files Browse the repository at this point in the history
  • Loading branch information
oceans404 committed Mar 27, 2024
1 parent 96623f5 commit 97692e6
Show file tree
Hide file tree
Showing 26 changed files with 1,219 additions and 894 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Download the [Nillion Javascript Client](https://docs.nillion.com/quickstart#dow
Install the Nillion Javascript client as an additional dependency

```bash
yarn add @nillion/nillion-client-js-browser
yarn add {path-to-nillion-js-client-folder}
```

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@
},
"packageManager": "[email protected]",
"devDependencies": {
"@types/react-syntax-highlighter": "^15",
"husky": "^8.0.1",
"lint-staged": "^13.0.3"
},
"dependencies": {
"@nillion/nillion-client-js-browser": "^0.1.18",
"react-syntax-highlighter": "^15.5.0"
}
}
243 changes: 243 additions & 0 deletions packages/nextjs/app/nillion-compute/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
"use client";

import { useEffect, useState } from "react";
import type { NextPage } from "next";
import { useAccount } from "wagmi";
import CodeSnippet from "~~/components/nillion/CodeSnippet";
import { CopyString } from "~~/components/nillion/CopyString";
import { NillionOnboarding } from "~~/components/nillion/NillionOnboarding";
import SecretForm from "~~/components/nillion/SecretForm";
import { Address } from "~~/components/scaffold-eth";
import { compute } from "~~/utils/nillion/compute";
import { getUserKeyFromSnap } from "~~/utils/nillion/getUserKeyFromSnap";
import { storeProgram } from "~~/utils/nillion/storeProgram";
import { storeSecretsInteger } from "~~/utils/nillion/storeSecretsInteger";

interface StringObject {
[key: string]: string | null;
}

const Home: NextPage = () => {
const { address: connectedAddress } = useAccount();
const [connectedToSnap, setConnectedToSnap] = useState<boolean>(false);
const [userKey, setUserKey] = useState<string | null>(null);
const [userId, setUserId] = useState<string | null>(null);
const [nillion, setNillion] = useState<any>(null);
const [nillionClient, setNillionClient] = useState<any>(null);

const [programName] = useState<string>("addition_simple");
const [programId, setProgramId] = useState<string | null>(null);
const [computeResult, setComputeResult] = useState<string | null>(null);

const [storedSecretsNameToStoreId, setStoredSecretsNameToStoreId] = useState<StringObject>({
my_int1: null,
my_int2: null,
});
const [parties] = useState<string[]>(["Party1"]);

// connect to snap
async function handleConnectToSnap() {
const snapResponse = await getUserKeyFromSnap();
setUserKey(snapResponse?.user_key || null);
setConnectedToSnap(snapResponse?.connectedToSnap || false);
}

// store program in the Nillion network and set the resulting program id
async function handleStoreProgram() {
await storeProgram(nillionClient, programName).then(setProgramId);
}

// reset nillion values
const resetNillion = () => {
setConnectedToSnap(false);
setUserKey(null);
setUserId(null);
setNillion(null);
setNillionClient(null);
};

useEffect(() => {
// when wallet is disconnected, reset nillion
if (!connectedAddress) {
resetNillion();
}
}, [connectedAddress]);

// Initialize nillionClient for use on page
useEffect(() => {
if (userKey) {
const getNillionClientLibrary = async () => {
const nillionClientUtil = await import("~~/utils/nillion/nillionClient");
const libraries = await nillionClientUtil.getNillionClient(userKey);
setNillion(libraries.nillion);
setNillionClient(libraries.nillionClient);
return libraries.nillionClient;
};
getNillionClientLibrary().then(nillionClient => {
const user_id = nillionClient.user_id();
setUserId(user_id);
});
}
}, [userKey]);

// handle form submit to store secrets with bindings
async function handleSecretFormSubmit(
secretName: string,
secretValue: string,
// permissionedUserIdForSecret?: string | null,
) {
if (programId) {
const partyName = parties[0];
await storeSecretsInteger(nillion, nillionClient, secretValue, secretName, programId, partyName).then(
async (store_id: string) => {
console.log("Secret stored at store_id:", store_id);
setStoredSecretsNameToStoreId(prevSecrets => ({
...prevSecrets,
[secretName]: store_id,
}));
},
);
}
}

// compute on secrets
async function handleCompute() {
if (programId) {
await compute(nillion, nillionClient, Object.values(storedSecretsNameToStoreId), programId).then(result =>
setComputeResult(result),
);
}
}

return (
<>
<div className="flex items-center flex-col pt-10">
<div className="px-5 flex flex-col">
<h1 className="text-xl">
<span className="block text-4xl font-bold">Build a Blind Computation App with Nillion</span>
{!connectedAddress && <p>Connect your MetaMask Flask wallet</p>}
{connectedAddress && connectedToSnap && !userKey && (
<a target="_blank" href="https://nillion-snap-site.vercel.app/" rel="noopener noreferrer">
<button className="btn btn-sm btn-primary mt-4">
No Nillion User Key - Generate and store user key here
</button>
</a>
)}
</h1>

{connectedAddress && (
<div className="flex justify-center items-center space-x-2">
<p className="my-2 font-medium">Connected Wallet Address:</p>
<Address address={connectedAddress} />
</div>
)}

{connectedAddress && !connectedToSnap && (
<button className="btn btn-sm btn-primary mt-4" onClick={handleConnectToSnap}>
Connect to Snap with your Nillion User Key
</button>
)}

{connectedToSnap && (
<div>
{userKey && (
<div>
<div className="flex justify-center items-center space-x-2">
<p className="my-2 font-medium">
🤫 Nillion User Key from{" "}
<a target="_blank" href="https://nillion-snap-site.vercel.app/" rel="noopener noreferrer">
MetaMask Flask
</a>
:
</p>

<CopyString str={userKey} />
</div>

{userId && (
<div className="flex justify-center items-center space-x-2">
<p className="my-2 font-medium">Connected as Nillion User ID:</p>
<CopyString str={userId} />
</div>
)}
</div>
)}
</div>
)}
</div>

<div className="flex-grow bg-base-300 w-full mt-16 px-8 py-12">
<div className="flex justify-center items-center gap-12 flex-col sm:flex-row">
{!connectedToSnap ? (
<NillionOnboarding />
) : (
<div>
<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center max-w-m rounded-3xl my-2">
<h1 className="text-xl">Step 1: Store a Nada program</h1>
{!programId ? (
<button className="btn btn-sm btn-primary mt-4" onClick={handleStoreProgram}>
Store {programName} program
</button>
) : (
<div>
{programName} program stored <br />
<span className="flex">
<CopyString str={programId} start={5} end={programName.length + 5} textBefore="program_id: " />
</span>
</div>
)}

<CodeSnippet program_name={programName} />
</div>

<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center w-full rounded-3xl my-2 justify-between">
<h1 className="text-xl">
Step 2: Store secret integers with program bindings to the {programName} program
</h1>

<div className="flex flex-row w-full justify-between items-center my-10 mx-10">
{Object.keys(storedSecretsNameToStoreId).map(key => (
<div className="flex-1 px-2" key={key}>
{!!storedSecretsNameToStoreId[key] ? (
<p>
✅ Stored SecretInteger {key} <br />{" "}
<CopyString str={storedSecretsNameToStoreId[key] || ""} textBefore={`store_id: `} full />
</p>
) : (
<SecretForm
secretName={key}
onSubmit={handleSecretFormSubmit}
isDisabled={!programId}
secretType="number"
/>
)}
</div>
))}
</div>
</div>

<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center w-full rounded-3xl my-2 justify-between">
<h1 className="text-xl">
Step 3: Perform blind computation with stored secrets in the {programName} program
</h1>
{!computeResult && (
<button
className="btn btn-sm btn-primary mt-4"
onClick={handleCompute}
disabled={Object.values(storedSecretsNameToStoreId).every(v => !v)}
>
Compute on {programName}
</button>
)}
{computeResult && <p>✅ Compute result: {computeResult}</p>}
</div>
</div>
)}
</div>
</div>
</div>
</>
);
};

export default Home;
Loading

0 comments on commit 97692e6

Please sign in to comment.