From 4c1693834fb00deca343fd92b4cccfa552e1feda Mon Sep 17 00:00:00 2001 From: oceans404 Date: Tue, 26 Mar 2024 23:27:37 -0700 Subject: [PATCH] add instructions --- .../app/nillion-hello-world/page-complete.tsx | 222 ++++++++++++++++++ .../nextjs/app/nillion-hello-world/page.tsx | 110 +++++---- 2 files changed, 291 insertions(+), 41 deletions(-) create mode 100644 packages/nextjs/app/nillion-hello-world/page-complete.tsx diff --git a/packages/nextjs/app/nillion-hello-world/page-complete.tsx b/packages/nextjs/app/nillion-hello-world/page-complete.tsx new file mode 100644 index 0000000..3e411a2 --- /dev/null +++ b/packages/nextjs/app/nillion-hello-world/page-complete.tsx @@ -0,0 +1,222 @@ +"use client"; + +import { useEffect, useState } from "react"; +import type { NextPage } from "next"; +import { useAccount } from "wagmi"; +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 { getUserKeyFromSnap } from "~~/utils/nillion/getUserKeyFromSnap"; +import { retrieveSecretBlob } from "~~/utils/nillion/retrieveSecretBlob"; +import { storeSecretsBlob } from "~~/utils/nillion/storeSecretsBlob"; + +const Home: NextPage = () => { + const { address: connectedAddress } = useAccount(); + const [connectedToSnap, setConnectedToSnap] = useState(false); + const [userKey, setUserKey] = useState(null); + const [userId, setUserId] = useState(null); + const [nillion, setNillion] = useState(null); + const [nillionClient, setNillionClient] = useState(null); + const [storedSecretName, setStoredSecretName] = useState("my_blob"); + const [storeId, setStoreId] = useState(null); + const [retrievedValue, setRetrievedValue] = useState(null); + + // ✅ DONE: complete this function to connect to the MetaMask Snap + async function handleConnectToSnap() { + // call getUserKeyFromSnap + const snapResponse = await getUserKeyFromSnap(); + // update state: set userKey with the response from getUserKeyFromSnap + setUserKey(snapResponse?.user_key || null); + // update state: set connectedToSnap based on the response from getUserKeyFromSnap + setConnectedToSnap(snapResponse?.connectedToSnap || false); + } + + // ✅ DONE: complete this useEffect hook to set up Nillion once a userKey exists + useEffect(() => { + // conditional execution: Check if userKey exists before implementing logic + if (userKey) { + // create an asynchronous getNillionClientLibrary function + const getNillionClientLibrary = async () => { + // dynamically import the nillionClient module using await import("~~/utils/nillion/nillionClient") + const nillionClientUtil = await import("~~/utils/nillion/nillionClient"); + + // asyncronously call the getNillionClient function from the imported nillionClient module with the userKey + const libraries = await nillionClientUtil.getNillionClient(userKey); + // update state: set nillion + setNillion(libraries.nillion); + // update state: set nillionClient + setNillionClient(libraries.nillionClient); + + // return nillionClient + return libraries.nillionClient; + }; + + // call getNillionClientLibrary, then use the returned nillionClient + getNillionClientLibrary().then(nillionClient => { + // get the user_id from the instance of nillionClient + const user_id = nillionClient.user_id(); + // update state: set user_id + setUserId(user_id); + }); + } + }, [userKey]); + + // ✅ DONE: complete this asynchronous function to process the submission of a form used for storing secrets + async function handleSecretFormSubmit(secretName: string, secretValue: string) { + // call storeSecretsBlob, then handle the promise that resolves with a store_id + await storeSecretsBlob(nillion, nillionClient, secretValue, secretName).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); + }); + } + + // ✅ DONE: complete this asynchronous function to retrieve and read the value of a secret blob + async function handleRetrieveSecretBlob(store_id: string, secret_name: string) { + // call retrieveSecretBlob then handle the promise that resolves with the retrieved value + // update state: set retrievedValue + await retrieveSecretBlob(nillion, nillionClient, store_id, secret_name).then(setRetrievedValue); + } + + // reset nillion values + const resetNillion = () => { + setConnectedToSnap(false); + setUserKey(null); + setUserId(null); + setNillion(null); + setNillionClient(null); + }; + + // reset store blob form to store a new secret + const resetForm = () => { + setStoreId(null); + setRetrievedValue(null); + }; + + useEffect(() => { + // when wallet is disconnected, reset nillion + if (!connectedAddress) { + resetNillion(); + } + }, [connectedAddress]); + + return ( + <> +
+
+

+ Store and Retrieve "Hello World" with Nillion + {!connectedAddress &&

Connect your MetaMask Flask wallet

} + {connectedAddress && connectedToSnap && !userKey && ( + + + + )} +

+ + {connectedAddress && ( +
+

Connected Wallet Address:

+
+
+ )} + + {connectedAddress && !connectedToSnap && ( + + )} + + {connectedToSnap && ( +
+ {userKey && ( +
+
+

+ 🤫 Nillion User Key from{" "} + + MetaMask Flask + + : +

+ + +
+ + {userId && ( +
+

Connected as Nillion User ID:

+ +
+ )} +
+ )} +
+ )} +
+ +
+
+ {!connectedToSnap ? ( + + ) : ( +
+ {/* Store secret blob */} +
+

Store "Hello World" as a SecretBlob in Nillion

+
+
+ {!!storeId ? ( +

+ ✅ Stored SecretBlob {storedSecretName}
{" "} + + +

+ ) : ( + + )} +
+
+
+ + {/* Retrieve secret blob */} + +
+

Retrieve SecretBlob from Nillion

+
+
+ + + {retrievedValue &&

✅ Retrieved value: {retrievedValue}

} +
+
+
+
+ )} +
+
+
+ + ); +}; + +export default Home; diff --git a/packages/nextjs/app/nillion-hello-world/page.tsx b/packages/nextjs/app/nillion-hello-world/page.tsx index 8c42171..ec72e46 100644 --- a/packages/nextjs/app/nillion-hello-world/page.tsx +++ b/packages/nextjs/app/nillion-hello-world/page.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ "use client"; import { useEffect, useState } from "react"; @@ -11,6 +12,28 @@ import { getUserKeyFromSnap } from "~~/utils/nillion/getUserKeyFromSnap"; import { retrieveSecretBlob } from "~~/utils/nillion/retrieveSecretBlob"; import { storeSecretsBlob } from "~~/utils/nillion/storeSecretsBlob"; +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +/* eslint-disable @typescript-eslint/no-unused-vars */ + const Home: NextPage = () => { const { address: connectedAddress } = useAccount(); const [connectedToSnap, setConnectedToSnap] = useState(false); @@ -25,11 +48,47 @@ const Home: NextPage = () => { // 🎯 TODO complete this function to connect to the MetaMask Snap async function handleConnectToSnap() { // call getUserKeyFromSnap - const snapResponse = await getUserKeyFromSnap(); // update state: set userKey with the response from getUserKeyFromSnap - setUserKey(snapResponse?.user_key || null); // update state: set connectedToSnap based on the response from getUserKeyFromSnap - setConnectedToSnap(snapResponse?.connectedToSnap || false); + } + + // 🎯 TODO complete this useEffect hook to set up Nillion once a userKey exists + useEffect(() => { + // conditional execution: Check if userKey exists before implementing logic + if (userKey) { + // create an asynchronous getNillionClientLibrary function + const getNillionClientLibrary = async () => { + // dynamically import the nillionClient module using await import("~~/utils/nillion/nillionClient") + const nillionClientUtil = await import("~~/utils/nillion/nillionClient"); + + // asyncronously call the getNillionClient function from the imported nillionClient module with the userKey + + // update state: set nillion + // update state: set nillionClient + + // return nillionClient + }; + + // call getNillionClientLibrary, then use the returned nillionClient + getNillionClientLibrary().then(nillionClient => { + // get the user_id from the instance of nillionClient + // update state: set user_id + }); + } + }, [userKey]); + + // 🎯 TODO complete this asynchronous function to process the submission of a form used for storing secrets + async function handleSecretFormSubmit(secretName: string, secretValue: string) { + // 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 + // update state: set storeId + } + + // 🎯 TODO complete this asynchronous function to retrieve and read the value of a secret blob + async function handleRetrieveSecretBlob(store_id: string, secret_name: string) { + // call retrieveSecretBlob then handle the promise that resolves with the retrieved value + // update state: set retrievedValue } // reset nillion values @@ -54,50 +113,19 @@ const Home: NextPage = () => { } }, [connectedAddress]); - // TODO if userKey - // 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]); - - // TODO - // handle form submit to store secrets - async function handleSecretFormSubmit( - secretName: string, - secretValue: string, - // permissionedUserIdForSecret?: string | null, - ) { - await storeSecretsBlob(nillion, nillionClient, secretValue, secretName).then((store_id: string) => { - console.log("Secret stored at store_id:", store_id); - setStoredSecretName(secretName); - setStoreId(store_id); - }); - } - - // TODO - // handle retrieve secret blob - async function handleRetrieveSecretBlob(store_id: string, secret_name: string) { - await retrieveSecretBlob(nillion, nillionClient, store_id, secret_name).then(setRetrievedValue); - } - return ( <>

Store and Retrieve "Hello World" with Nillion + +

+ Complete the "🎯 TODOs " within the code of this page to hook up this page to store and retrieve + SecretBlob secrets in Nillion. Need a hint on how to get something working? Take a look at + `nillion-hello-world/page-complete.tsx` +

+ {!connectedAddress &&

Connect your MetaMask Flask wallet

} {connectedAddress && connectedToSnap && !userKey && (