Skip to content

Commit

Permalink
retrieve secret integer with updated api
Browse files Browse the repository at this point in the history
  • Loading branch information
oceans404 committed Apr 1, 2024
1 parent 4908073 commit a13f19e
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 46 deletions.
4 changes: 4 additions & 0 deletions packages/nextjs/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
# More info: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
NEXT_PUBLIC_ALCHEMY_API_KEY=
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=

# An example Nillion user key and corresponding user id pair
NEXT_PUBLIC_NILLION_EXAMPLE_USER_KEY_1=2nKjvzkL4uXC4tEZWNobyrt26U93SnouPnbF2iJodktqr92V1wjE2BEECFj99MZQ2RujKXHwazfkyQXuW1eUiyFp
NEXT_PUBLIC_NILLION_EXAMPLE_USER_ID_1=2HmFxRPFvefm5gr5T8rjuV9WynR26GF3NxVBkwM4mxxdPsnQx9TnTwRkGF2mCWK2koDabF2kbMumHPLkDf9ePMyT
37 changes: 30 additions & 7 deletions packages/nextjs/app/nillion-compute/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Address } from "~~/components/scaffold-eth";
import { compute } from "~~/utils/nillion/compute";
import { getUserKeyFromSnap } from "~~/utils/nillion/getUserKeyFromSnap";
import { retrieveSecretCommand } from "~~/utils/nillion/retrieveSecretCommand";
import { retrieveSecretInteger } from "~~/utils/nillion/retrieveSecretInteger";
import { storeProgram } from "~~/utils/nillion/storeProgram";
import { storeSecretsInteger } from "~~/utils/nillion/storeSecretsInteger";

Expand Down Expand Up @@ -50,6 +51,13 @@ const Home: NextPage = () => {
await storeProgram(nillionClient, programName).then(setProgramId);
}

async function handleRetrieveInt(secret_name: string, store_id: string | null) {
if (store_id) {
const value = await retrieveSecretInteger(nillionClient, store_id, secret_name);
alert(`${secret_name} is ${value}`);
}
}

// reset nillion values
const resetNillion = () => {
setConnectedToSnap(false);
Expand Down Expand Up @@ -87,7 +95,10 @@ const Home: NextPage = () => {
async function handleSecretFormSubmit(
secretName: string,
secretValue: string,
// permissionedUserIdForSecret?: string | null,
permissionedUserIdForRetrieveSecret: string | null,
permissionedUserIdForUpdateSecret: string | null,
permissionedUserIdForDeleteSecret: string | null,
permissionedUserIdForComputeSecret: string | null,
) {
if (programId) {
const partyName = parties[0];
Expand All @@ -97,6 +108,10 @@ const Home: NextPage = () => {
[{ name: secretName, value: secretValue }],
programId,
partyName,
permissionedUserIdForRetrieveSecret ? [permissionedUserIdForRetrieveSecret] : [],
permissionedUserIdForUpdateSecret ? [permissionedUserIdForUpdateSecret] : [],
permissionedUserIdForDeleteSecret ? [permissionedUserIdForDeleteSecret] : [],
permissionedUserIdForComputeSecret ? [permissionedUserIdForComputeSecret] : [],
).then(async (store_id: string) => {
console.log("Secret stored at store_id:", store_id);
setStoredSecretsNameToStoreId(prevSecrets => ({
Expand Down Expand Up @@ -206,12 +221,20 @@ const Home: NextPage = () => {
{Object.keys(storedSecretsNameToStoreId).map(key => (
<div className="flex-1 px-2" key={key}>
{!!storedSecretsNameToStoreId[key] && userKey ? (
<RetrieveSecretCommand
secretType="SecretInteger"
userKey={userKey}
storeId={storedSecretsNameToStoreId[key]}
secretName={key}
/>
<>
<RetrieveSecretCommand
secretType="SecretInteger"
userKey={userKey}
storeId={storedSecretsNameToStoreId[key]}
secretName={key}
/>
<button
className="btn btn-sm btn-primary mt-4"
onClick={() => handleRetrieveInt(key, storedSecretsNameToStoreId[key])}
>
👀 Retrieve SecretInteger
</button>
</>
) : (
<SecretForm
secretName={key}
Expand Down
37 changes: 24 additions & 13 deletions packages/nextjs/app/nillion-hello-world-complete/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,29 @@ const Home: NextPage = () => {

// ✅ #3 DONE: complete this asynchronous function to process the submission of a form used for storing secrets
// Once this is done, the form will be hooked up to store your secret blob
async function handleSecretFormSubmit(secretName: string, secretValue: string) {
async function handleSecretFormSubmit(
secretName: string,
secretValue: string,
permissionedUserIdForRetrieveSecret: string | null,
permissionedUserIdForUpdateSecret: string | null,
permissionedUserIdForDeleteSecret: string | null,
) {
// call storeSecretsBlob, then handle the promise that resolves with a store_id
await storeSecretsBlob(nillion, nillionClient, [{ name: secretName, value: secretValue }]).then(
(store_id: string) => {
// inside of the "then" method, console log the store_id
console.log("Secret stored at store_id:", store_id);
// update state: set storedSecretName
setStoredSecretName(secretName);
// update state: set storeId
setStoreId(store_id);
},
);
await storeSecretsBlob(
nillion,
nillionClient,
[{ name: secretName, value: secretValue }],
permissionedUserIdForRetrieveSecret ? [permissionedUserIdForRetrieveSecret] : [],
permissionedUserIdForUpdateSecret ? [permissionedUserIdForUpdateSecret] : [],
permissionedUserIdForDeleteSecret ? [permissionedUserIdForDeleteSecret] : [],
).then((store_id: string) => {
// inside of the "then" method, console log the store_id
console.log("Secret stored at store_id:", store_id);
// update state: set storedSecretName
setStoredSecretName(secretName);
// update state: set storeId
setStoreId(store_id);
});
}

// ✅ #4 DONE: complete this asynchronous function to retrieve and read the value of a secret blob
Expand Down Expand Up @@ -221,15 +232,15 @@ const Home: NextPage = () => {
{/* Retrieve secret blob */}

<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center w-full rounded-3xl my-2 justify-between mx-5">
<h1 className="text-xl">Retrieve SecretBlob from Nillion</h1>
<h1 className="text-xl">Retrieve and decode SecretBlob from Nillion</h1>
<div className="flex flex-row w-full justify-between items-center my-10 mx-10">
<div className="flex-1 px-2" key={storedSecretName}>
<button
className="btn btn-sm btn-primary mt-4"
onClick={() => handleRetrieveSecretBlob(storeId || "", storedSecretName)}
disabled={!storeId}
>
Retrieve {storedSecretName}
Retrieve and decode {storedSecretName}
</button>

{retrievedValue && <p>✅ Retrieved value: {retrievedValue}</p>}
Expand Down
12 changes: 9 additions & 3 deletions packages/nextjs/app/nillion-hello-world/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,13 @@ const Home: NextPage = () => {

// 🎯 TODO #3 complete this asynchronous function to process the submission of a form used for storing secrets
// Once this is done, the form will be hooked up to store your secret blob
async function handleSecretFormSubmit(secretName: string, secretValue: string) {
async function handleSecretFormSubmit(
secretName: string,
secretValue: string,
permissionedUserIdForRetrieveSecret: string | null,
permissionedUserIdForUpdateSecret: string | null,
permissionedUserIdForDeleteSecret: string | null,
) {
// call storeSecretsBlob, then handle the promise that resolves with a store_id
// inside of the "then" method, console log the store_id
// update state: set storedSecretName
Expand Down Expand Up @@ -212,15 +218,15 @@ const Home: NextPage = () => {
{/* Retrieve secret blob */}

<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center w-full rounded-3xl my-2 justify-between mx-5">
<h1 className="text-xl">Retrieve SecretBlob from Nillion</h1>
<h1 className="text-xl">Retrieve and decode SecretBlob from Nillion</h1>
<div className="flex flex-row w-full justify-between items-center my-10 mx-10">
<div className="flex-1 px-2" key={storedSecretName}>
<button
className="btn btn-sm btn-primary mt-4"
onClick={() => handleRetrieveSecretBlob(storeId || "", storedSecretName)}
disabled={!storeId}
>
Retrieve {storedSecretName}
Retrieve and decode {storedSecretName}
</button>

{retrievedValue && <p>✅ Retrieved value: {retrievedValue}</p>}
Expand Down
6 changes: 5 additions & 1 deletion packages/nextjs/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ export const Footer = () => {
>
Fork Scaffold-Nillion
</a>

<a href="https://nillion-snap-site.vercel.app/" target="_blank" rel="noreferrer" className="link ml-5">
Generate Nillion User Key
</a>
</div>
<span>·</span>
<span></span>
</div>
</ul>
</div>
Expand Down
95 changes: 84 additions & 11 deletions packages/nextjs/components/nillion/SecretForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import React, { useState } from "react";

interface SecretFormProps {
onSubmit: (secretName: string, secret: string, permissionedUserIdForSecret: string | null) => void;
onSubmit: (
secretName: string,
secret: string,
permissionedUserIdForRetrieveSecret: string | null,
permissionedUserIdForUpdateSecret: string | null,
permissionedUserIdForDeleteSecret: string | null,
permissionedUserIdForComputeSecret: string | null,
) => void;
secretName: string;
isDisabled?: boolean;
isLoading?: boolean;
Expand All @@ -15,15 +22,28 @@ const SecretForm: React.FC<SecretFormProps> = ({
isLoading = false,
secretType, // Destructure this prop
}) => {
const [permissionedUserIdForSecret, setPermissionedUserIdForSecret] = useState("");
const [secret, setSecret] = useState("");
const [loading, setLoading] = useState(isLoading);
const [permissionedUserIdForRetrieveSecret, setPermissionedUserIdForRetrieveSecret] = useState("");
const [permissionedUserIdForUpdateSecret, setPermissionedUserIdForUpdateSecret] = useState("");
const [permissionedUserIdForDeleteSecret, setPermissionedUserIdForDeleteSecret] = useState("");
const [permissionedUserIdForComputeSecret, setPermissionedUserIdForComputeSecret] = useState("");

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
onSubmit(secretName, secret, permissionedUserIdForSecret);
setPermissionedUserIdForSecret("");
onSubmit(
secretName,
secret,
permissionedUserIdForRetrieveSecret,
permissionedUserIdForUpdateSecret,
permissionedUserIdForDeleteSecret,
permissionedUserIdForComputeSecret,
);
setPermissionedUserIdForRetrieveSecret("");
setPermissionedUserIdForUpdateSecret("");
setPermissionedUserIdForDeleteSecret("");
setPermissionedUserIdForComputeSecret("");
setSecret("");
};

Expand All @@ -48,21 +68,74 @@ const SecretForm: React.FC<SecretFormProps> = ({
}`}
/>
</div>
{/* <div className="mt-4">
<label htmlFor="permissionedUserIdForSecret" className="block text-sm font-medium text-gray-700">
Optional: set user id to grant compute permissions to another user

{/* can only compute on secret integers - don't show for SecretBlobs */}
{secretType === "number" && (
<div className="mt-4">
<label htmlFor="permissionedUserIdForComputeSecret" className="block text-sm font-medium text-gray-700">
Optional: Set a user id to grant compute permissions to another user
</label>
<input
type="text"
id="permissionedUserIdForComputeSecret"
value={permissionedUserIdForComputeSecret}
onChange={e => setPermissionedUserIdForComputeSecret(e.target.value)}
disabled={isDisabled}
className={`mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm ${
isDisabled ? "cursor-not-allowed bg-gray-100" : "bg-white"
}`}
/>
</div>
)}

<div className="mt-4">
<label htmlFor="permissionedUserIdForRetrieveSecret" className="block text-sm font-medium text-gray-700">
Optional: Set a user id to grant retrieve permissions to another user
</label>
<input
type="text"
id="permissionedUserIdForRetrieveSecret"
value={permissionedUserIdForRetrieveSecret}
onChange={e => setPermissionedUserIdForRetrieveSecret(e.target.value)}
disabled={isDisabled}
className={`mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm ${
isDisabled ? "cursor-not-allowed bg-gray-100" : "bg-white"
}`}
/>
</div>

<div className="mt-4">
<label htmlFor="permissionedUserIdForUpdateSecret" className="block text-sm font-medium text-gray-700">
Optional: Set a user id to grant update permissions to another user
</label>
<input
type="text"
id="permissionedUserIdForSecret"
value={permissionedUserIdForSecret}
onChange={e => setPermissionedUserIdForSecret(e.target.value)}
id="permissionedUserIdForUpdateSecret"
value={permissionedUserIdForUpdateSecret}
onChange={e => setPermissionedUserIdForUpdateSecret(e.target.value)}
disabled={isDisabled}
className={`mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm ${
isDisabled ? "cursor-not-allowed bg-gray-100" : "bg-white"
}`}
/>
</div> */}
</div>

<div className="mt-4">
<label htmlFor="permissionedUserIdForDeleteSecret" className="block text-sm font-medium text-gray-700">
Optional: Set a user id to grant delete permissions to another user
</label>
<input
type="text"
id="permissionedUserIdForDeleteSecret"
value={permissionedUserIdForDeleteSecret}
onChange={e => setPermissionedUserIdForDeleteSecret(e.target.value)}
disabled={isDisabled}
className={`mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm ${
isDisabled ? "cursor-not-allowed bg-gray-100" : "bg-white"
}`}
/>
</div>

<button
type="submit"
disabled={isDisabled}
Expand Down
6 changes: 3 additions & 3 deletions packages/nextjs/utils/nillion/compute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export async function compute(
program_bindings.add_input_party(partyName, party_id);
program_bindings.add_output_party(partyName, party_id);

console.log(program_bindings);
console.log(party_id);
console.log(store_ids);
console.log("program_bindings", program_bindings);
console.log("party_id", party_id);
console.log("store_ids", store_ids);

// create a compute time secrets object
const compute_time_secrets = new nillion.Secrets();
Expand Down
4 changes: 1 addition & 3 deletions packages/nextjs/utils/nillion/retrieveSecretInteger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ export async function retrieveSecretInteger(
): Promise<string> {
try {
const retrieved = await nillionClient.retrieve_secret(nillionConfig.cluster_id, store_id, secret_name);
console.log(retrieved);
// TODO - needs decode bigint function
return "";
return retrieved.to_integer();
} catch (error: any) {
return error;
}
Expand Down
39 changes: 36 additions & 3 deletions packages/nextjs/utils/nillion/storeSecretsBlob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ interface JsInput {
value: string;
}

export async function storeSecretsBlob(nillion: any, nillionClient: any, secretsToStore: JsInput[]): Promise<string> {
export async function storeSecretsBlob(
nillion: any,
nillionClient: any,
secretsToStore: JsInput[],
usersWithRetrievePermissions: string[] = [],
usersWithUpdatePermissions: string[] = [],
usersWithDeletePermissions: string[] = [],
): Promise<string> {
try {
// create secrets object
const secrets = new nillion.Secrets();
Expand All @@ -22,8 +29,34 @@ export async function storeSecretsBlob(nillion: any, nillionClient: any, secrets
secrets.insert(secret.name, newSecret);
}

// store secrets
const store_id = await nillionClient.store_secrets(nillionConfig.cluster_id, secrets);
// you cannot compute with SecretBlobs, so they don't need bindings to any programs
const empty_blob_bindings = null;

// get user id for user storing the secret
const user_id = await nillionClient.user_id();

// create a permissions object, give the storer default perissions
const permissions = nillion.Permissions.default_for_user(user_id);

// add retrieve permissions to the permissions object
permissions.add_retrieve_permissions(usersWithRetrievePermissions);
console.log("user ids given retrieve permissions:", usersWithRetrievePermissions);

// add update permissions to the permissions object
permissions.add_update_permissions(usersWithUpdatePermissions);
console.log("user ids given update permissions:", usersWithUpdatePermissions);

// add delete permissions to the permissions object
permissions.add_delete_permissions(usersWithDeletePermissions);
console.log("user ids given delete permissions:", usersWithDeletePermissions);

// store secrets with permissions
const store_id = await nillionClient.store_secrets(
nillionConfig.cluster_id,
secrets,
empty_blob_bindings,
permissions,
);
return store_id;
} catch (error) {
console.log(error);
Expand Down
Loading

0 comments on commit a13f19e

Please sign in to comment.