From 0b71ce6ce9fb5470d93194bfda06b3cab0e15525 Mon Sep 17 00:00:00 2001 From: Ali Mahdiyar Date: Thu, 23 Nov 2023 23:54:47 +0330 Subject: [PATCH 1/2] refactor: taco react and nextjs example --- examples/taco/nextjs/package.json | 1 + examples/taco/nextjs/src/app/layout.tsx | 1 + examples/taco/nextjs/src/app/page.tsx | 136 ++++++++++++---------- examples/taco/nextjs/src/hooks/useTaco.ts | 62 ++++++++++ examples/taco/nextjs/styles/global.css | 7 ++ examples/taco/react/package.json | 1 + examples/taco/react/src/App.tsx | 133 +++++++++++---------- examples/taco/react/src/hooks/useTaco.ts | 62 ++++++++++ examples/taco/react/src/index.css | 7 ++ examples/taco/react/src/index.tsx | 1 + pnpm-lock.yaml | 6 + 11 files changed, 290 insertions(+), 127 deletions(-) create mode 100644 examples/taco/nextjs/src/hooks/useTaco.ts create mode 100644 examples/taco/nextjs/styles/global.css create mode 100644 examples/taco/react/src/hooks/useTaco.ts create mode 100644 examples/taco/react/src/index.css diff --git a/examples/taco/nextjs/package.json b/examples/taco/nextjs/package.json index 2b4dfb69a..bb2601d8b 100644 --- a/examples/taco/nextjs/package.json +++ b/examples/taco/nextjs/package.json @@ -10,6 +10,7 @@ "type-check": "tsc -p tsconfig.build.json" }, "dependencies": { + "@nucypher/shared": "workspace:*", "@nucypher/taco": "workspace:*", "@types/node": "20.6.3", "@types/react": "18.2.37", diff --git a/examples/taco/nextjs/src/app/layout.tsx b/examples/taco/nextjs/src/app/layout.tsx index 215ca6cb7..a048075ad 100644 --- a/examples/taco/nextjs/src/app/layout.tsx +++ b/examples/taco/nextjs/src/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; +import '../../styles/global.css' const inter = Inter({ subsets: ['latin'] }); diff --git a/examples/taco/nextjs/src/app/page.tsx b/examples/taco/nextjs/src/app/page.tsx index 7a77c9c95..a9530033a 100644 --- a/examples/taco/nextjs/src/app/page.tsx +++ b/examples/taco/nextjs/src/app/page.tsx @@ -1,36 +1,34 @@ 'use client'; -import { - conditions, - decrypt, - domains, - encrypt, - fromBytes, - getPorterUri, - initialize, -} from '@nucypher/taco'; -import { ethers } from 'ethers'; -import { hexlify } from "ethers/lib/utils"; -import { useEffect, useState } from 'react'; +import {fromHexString} from "@nucypher/shared"; +import {conditions, domains, fromBytes, toHexString} from '@nucypher/taco'; +import {ethers} from 'ethers'; +import {hexlify} from 'ethers/lib/utils'; +import {useEffect, useState} from 'react'; + +import useTaco from '../hooks/useTaco'; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any declare const window: any; -const message = 'this is a secret'; +const ritualId = 5; // Replace with your own ritual ID +const domain = domains.TESTNET; function App() { - const [isInit, setIsInit] = useState(false); const [provider, setProvider] = useState< ethers.providers.Web3Provider | undefined >(); + const [message, setMessage] = useState('this is a secret') + const [encrypting, setEncrypting] = useState(false) + const [encryptedText, setEncryptedText] = useState( + '', + ); + const [decrypting, setDecrypting] = useState(false) const [decryptedMessage, setDecryptedMessage] = useState( '', ); - const initNucypher = async () => { - await initialize(); - setIsInit(true); - }; - const loadWeb3Provider = async () => { if (!window.ethereum) { console.error('You need to connect to your wallet first'); @@ -52,64 +50,74 @@ function App() { }; useEffect(() => { - initNucypher(); loadWeb3Provider(); }, []); + const { isInit, encryptDataToBytes, decryptDataFromBytes } = useTaco({ + domain, + provider, + ritualId, + }); + if (!isInit || !provider) { return
Loading...
; } - const runExample = async () => { - if (!window.ethereum) { - console.error('You need to connect to your wallet first'); - } - - await initialize(); + const encryptMessage = async () => { + if(!provider) return; + setEncrypting(true) + try { + const signer = provider.getSigner(); + const hasPositiveBalance = new conditions.RpcCondition({ + chain: 80001, + method: 'eth_getBalance', + parameters: [':userAddress', 'latest'], + returnValueTest: { + comparator: '>', + value: 0, + }, + }); - const ritualId = 5; // Replace with your own ritual ID - const domain = domains.TESTNET; + console.log('Encrypting message...'); + const encryptedBytes = await encryptDataToBytes( + message, + hasPositiveBalance, + signer, + ); + if (encryptedBytes) { + setEncryptedText(toHexString(encryptedBytes)) + } + } catch (e) { + console.log(e) + } + setEncrypting(false) + } - const provider = new ethers.providers.Web3Provider(window.ethereum!, 'any'); - await provider.send('eth_requestAccounts', []); - const signer = provider.getSigner(); - - console.log('Encrypting message...'); - const hasPositiveBalance = new conditions.RpcCondition({ - chain: 80001, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>', - value: 0, - }, - }); - const messageKit = await encrypt( - provider, - domain, - message, - hasPositiveBalance, - ritualId, - signer, - ); - - console.log('Decrypting message...'); - const decryptedMessage = await decrypt( - provider, - domain, - messageKit, - getPorterUri(domain), - signer, - ); - - setDecryptedMessage(fromBytes(decryptedMessage)); + const decryptMessage = async () => { + if(!encryptedText || !provider) return + try { + setDecrypting(true) + const signer = provider.getSigner(); + + console.log('Decrypting message...'); + const decryptedMessage = await decryptDataFromBytes( + fromHexString(encryptedText), + signer, + ); + if (decryptedMessage) { + setDecryptedMessage(fromBytes(decryptedMessage)); + } + } catch (e) { + console.log(e) + } + setDecrypting(false) }; return (
-

Secret message: {message}

- {decryptedMessage &&

Decrypted message: {decryptedMessage}

} - +

Secret message: setMessage(e.target.value)} onClick={encryptMessage}/> {encrypting && 'Encrypting...'}

+

Encrypted message: setEncryptedText(e.target.value)} /> {decrypting && 'Decrypting...'}

+ {decryptedMessage &&

Decrypted message: {decryptedMessage}

}
); } diff --git a/examples/taco/nextjs/src/hooks/useTaco.ts b/examples/taco/nextjs/src/hooks/useTaco.ts new file mode 100644 index 000000000..082ff1b23 --- /dev/null +++ b/examples/taco/nextjs/src/hooks/useTaco.ts @@ -0,0 +1,62 @@ +import { + decrypt, + Domain, + encrypt, + getPorterUri, + initialize, + ThresholdMessageKit, +} from '@nucypher/taco'; +import { Condition } from '@nucypher/taco/src/conditions'; +import { ethers } from 'ethers'; +import { useCallback, useEffect, useState } from 'react'; + +export default function useTaco({ + ritualId, + domain, + provider, +}: { + ritualId: number; + domain: Domain; + provider: ethers.providers.Provider | undefined; +}) { + const [isInit, setIsInit] = useState(false); + + useEffect(() => { + initialize().then(() => setIsInit(true)); + }, []); + + const decryptDataFromBytes = useCallback( + async (encryptedBytes: Uint8Array, signer?: ethers.Signer) => { + if (!isInit || !provider) return; + const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); + return decrypt(provider, domain, messageKit, getPorterUri(domain), signer); + }, + [isInit, provider, domain], + ); + + const encryptDataToBytes = useCallback( + async ( + message: string, + condition: Condition, + encryptorSigner: ethers.Signer, + ) => { + if (!isInit || !provider) return; + const messageKit = await encrypt( + provider, + domain, + message, + condition, + ritualId, + encryptorSigner, + ); + return messageKit.toBytes(); + }, + [isInit, provider, domain, ritualId], + ); + + return { + isInit, + decryptDataFromBytes, + encryptDataToBytes, + }; +} diff --git a/examples/taco/nextjs/styles/global.css b/examples/taco/nextjs/styles/global.css new file mode 100644 index 000000000..8439a5936 --- /dev/null +++ b/examples/taco/nextjs/styles/global.css @@ -0,0 +1,7 @@ +input { + font-size: 20px; +} + +button { + font-size: 15px; +} diff --git a/examples/taco/react/package.json b/examples/taco/react/package.json index 01c0406fd..f291ff05d 100644 --- a/examples/taco/react/package.json +++ b/examples/taco/react/package.json @@ -23,6 +23,7 @@ ] }, "dependencies": { + "@nucypher/shared": "workspace:*", "@nucypher/taco": "workspace:*", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/taco/react/src/App.tsx b/examples/taco/react/src/App.tsx index c12d28c09..9820d7d65 100644 --- a/examples/taco/react/src/App.tsx +++ b/examples/taco/react/src/App.tsx @@ -1,35 +1,31 @@ -import { - conditions, - decrypt, - domains, - encrypt, - fromBytes, - getPorterUri, - initialize, -} from '@nucypher/taco'; -import { ethers } from 'ethers'; -import { hexlify } from "ethers/lib/utils"; -import { useEffect, useState } from 'react'; +import {fromHexString} from "@nucypher/shared"; +import {conditions, domains, fromBytes, toHexString} from '@nucypher/taco'; +import {ethers} from 'ethers'; +import {hexlify} from 'ethers/lib/utils'; +import {useEffect, useState} from 'react'; + +import useTaco from './hooks/useTaco'; // eslint-disable-next-line @typescript-eslint/no-explicit-any declare const window: any; -const message = 'this is a secret'; +const ritualId = 5; // Replace with your own ritual ID +const domain = domains.TESTNET; function App() { - const [isInit, setIsInit] = useState(false); const [provider, setProvider] = useState< ethers.providers.Web3Provider | undefined >(); + const [message, setMessage] = useState('this is a secret') + const [encrypting, setEncrypting] = useState(false) + const [encryptedText, setEncryptedText] = useState( + '', + ); + const [decrypting, setDecrypting] = useState(false) const [decryptedMessage, setDecryptedMessage] = useState( '', ); - const initNucypher = async () => { - await initialize(); - setIsInit(true); - }; - const loadWeb3Provider = async () => { if (!window.ethereum) { console.error('You need to connect to your wallet first'); @@ -51,63 +47,74 @@ function App() { }; useEffect(() => { - initNucypher(); loadWeb3Provider(); }, []); + const { isInit, encryptDataToBytes, decryptDataFromBytes } = useTaco({ + domain, + provider, + ritualId, + }); + if (!isInit || !provider) { return
Loading...
; } - const runExample = async () => { - if (!window.ethereum) { - console.error('You need to connect to your wallet first'); - } + const encryptMessage = async () => { + if(!provider) return; + setEncrypting(true) + try { + const signer = provider.getSigner(); + const hasPositiveBalance = new conditions.RpcCondition({ + chain: 80001, + method: 'eth_getBalance', + parameters: [':userAddress', 'latest'], + returnValueTest: { + comparator: '>', + value: 0, + }, + }); - await initialize(); - const ritualId = 5; // Replace with your own ritual ID - const domain = domains.TESTNET; + console.log('Encrypting message...'); + const encryptedBytes = await encryptDataToBytes( + message, + hasPositiveBalance, + signer, + ); + if (encryptedBytes) { + setEncryptedText(toHexString(encryptedBytes)) + } + } catch (e) { + console.log(e) + } + setEncrypting(false) + } - const provider = new ethers.providers.Web3Provider(window.ethereum!, 'any'); - await provider.send('eth_requestAccounts', []); - const signer = provider.getSigner(); - - console.log('Encrypting message...'); - const hasPositiveBalance = new conditions.RpcCondition({ - chain: 80001, - method: 'eth_getBalance', - parameters: [':userAddress', 'latest'], - returnValueTest: { - comparator: '>', - value: 0, - }, - }); - const messageKit = await encrypt( - provider, - domain, - message, - hasPositiveBalance, - ritualId, - signer, - ); - - console.log('Decrypting message...'); - const decryptedMessage = await decrypt( - provider, - domain, - messageKit, - getPorterUri(domain), - signer, - ); - - setDecryptedMessage(fromBytes(decryptedMessage)); + const decryptMessage = async () => { + if(!encryptedText || !provider) return + try { + setDecrypting(true) + const signer = provider.getSigner(); + + console.log('Decrypting message...'); + const decryptedMessage = await decryptDataFromBytes( + fromHexString(encryptedText), + signer, + ); + if (decryptedMessage) { + setDecryptedMessage(fromBytes(decryptedMessage)); + } + } catch (e) { + console.log(e) + } + setDecrypting(false) }; return (
-

Secret message: {message}

- {decryptedMessage &&

Decrypted message: {decryptedMessage}

} - +

Secret message: setMessage(e.target.value)} onClick={encryptMessage}/> {encrypting && 'Encrypting...'}

+

Encrypted message: setEncryptedText(e.target.value)} /> {decrypting && 'Decrypting...'}

+ {decryptedMessage &&

Decrypted message: {decryptedMessage}

}
); } diff --git a/examples/taco/react/src/hooks/useTaco.ts b/examples/taco/react/src/hooks/useTaco.ts new file mode 100644 index 000000000..082ff1b23 --- /dev/null +++ b/examples/taco/react/src/hooks/useTaco.ts @@ -0,0 +1,62 @@ +import { + decrypt, + Domain, + encrypt, + getPorterUri, + initialize, + ThresholdMessageKit, +} from '@nucypher/taco'; +import { Condition } from '@nucypher/taco/src/conditions'; +import { ethers } from 'ethers'; +import { useCallback, useEffect, useState } from 'react'; + +export default function useTaco({ + ritualId, + domain, + provider, +}: { + ritualId: number; + domain: Domain; + provider: ethers.providers.Provider | undefined; +}) { + const [isInit, setIsInit] = useState(false); + + useEffect(() => { + initialize().then(() => setIsInit(true)); + }, []); + + const decryptDataFromBytes = useCallback( + async (encryptedBytes: Uint8Array, signer?: ethers.Signer) => { + if (!isInit || !provider) return; + const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); + return decrypt(provider, domain, messageKit, getPorterUri(domain), signer); + }, + [isInit, provider, domain], + ); + + const encryptDataToBytes = useCallback( + async ( + message: string, + condition: Condition, + encryptorSigner: ethers.Signer, + ) => { + if (!isInit || !provider) return; + const messageKit = await encrypt( + provider, + domain, + message, + condition, + ritualId, + encryptorSigner, + ); + return messageKit.toBytes(); + }, + [isInit, provider, domain, ritualId], + ); + + return { + isInit, + decryptDataFromBytes, + encryptDataToBytes, + }; +} diff --git a/examples/taco/react/src/index.css b/examples/taco/react/src/index.css new file mode 100644 index 000000000..8439a5936 --- /dev/null +++ b/examples/taco/react/src/index.css @@ -0,0 +1,7 @@ +input { + font-size: 20px; +} + +button { + font-size: 15px; +} diff --git a/examples/taco/react/src/index.tsx b/examples/taco/react/src/index.tsx index cd808f32c..253d3f9b3 100644 --- a/examples/taco/react/src/index.tsx +++ b/examples/taco/react/src/index.tsx @@ -1,6 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; +import './index.css' import App from './App'; const root = ReactDOM.createRoot( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea4f9a006..35d518e6c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -355,6 +355,9 @@ importers: examples/taco/nextjs: dependencies: + '@nucypher/shared': + specifier: workspace:* + version: link:../../../packages/shared '@nucypher/taco': specifier: workspace:* version: link:../../../packages/taco @@ -403,6 +406,9 @@ importers: examples/taco/react: dependencies: + '@nucypher/shared': + specifier: workspace:* + version: link:../../../packages/shared '@nucypher/taco': specifier: workspace:* version: link:../../../packages/taco From 413f1b57152b9648e25644695af9f8c612000480 Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Fri, 24 Nov 2023 10:59:32 +0100 Subject: [PATCH 2/2] chore(linter): fix linter --- examples/taco/nextjs/src/hooks/useTaco.ts | 12 +++++++++--- examples/taco/react/src/hooks/useTaco.ts | 8 +++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/taco/nextjs/src/hooks/useTaco.ts b/examples/taco/nextjs/src/hooks/useTaco.ts index 082ff1b23..be78a7bb5 100644 --- a/examples/taco/nextjs/src/hooks/useTaco.ts +++ b/examples/taco/nextjs/src/hooks/useTaco.ts @@ -1,4 +1,5 @@ import { + conditions, decrypt, Domain, encrypt, @@ -6,7 +7,6 @@ import { initialize, ThresholdMessageKit, } from '@nucypher/taco'; -import { Condition } from '@nucypher/taco/src/conditions'; import { ethers } from 'ethers'; import { useCallback, useEffect, useState } from 'react'; @@ -29,7 +29,13 @@ export default function useTaco({ async (encryptedBytes: Uint8Array, signer?: ethers.Signer) => { if (!isInit || !provider) return; const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); - return decrypt(provider, domain, messageKit, getPorterUri(domain), signer); + return decrypt( + provider, + domain, + messageKit, + getPorterUri(domain), + signer, + ); }, [isInit, provider, domain], ); @@ -37,7 +43,7 @@ export default function useTaco({ const encryptDataToBytes = useCallback( async ( message: string, - condition: Condition, + condition: conditions.Condition, encryptorSigner: ethers.Signer, ) => { if (!isInit || !provider) return; diff --git a/examples/taco/react/src/hooks/useTaco.ts b/examples/taco/react/src/hooks/useTaco.ts index 082ff1b23..ed7732eb6 100644 --- a/examples/taco/react/src/hooks/useTaco.ts +++ b/examples/taco/react/src/hooks/useTaco.ts @@ -29,7 +29,13 @@ export default function useTaco({ async (encryptedBytes: Uint8Array, signer?: ethers.Signer) => { if (!isInit || !provider) return; const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); - return decrypt(provider, domain, messageKit, getPorterUri(domain), signer); + return decrypt( + provider, + domain, + messageKit, + getPorterUri(domain), + signer, + ); }, [isInit, provider, domain], );