From dff4d2f767acc39206a94050218e6cdf77abf7c8 Mon Sep 17 00:00:00 2001 From: Pedro Luis Frias Favero Date: Thu, 27 Jun 2024 13:36:23 +0200 Subject: [PATCH] integrating web3 wallet --- lotto-ui/ui/layouts/web3.tsx | 295 ++++++++++++++++++++++++++ lotto-ui/ui/pages/admin/index.tsx | 6 +- lotto-ui/ui/pages/dashboard/index.tsx | 5 +- lotto-ui/ui/pages/index.tsx | 254 ---------------------- 4 files changed, 301 insertions(+), 259 deletions(-) create mode 100644 lotto-ui/ui/layouts/web3.tsx diff --git a/lotto-ui/ui/layouts/web3.tsx b/lotto-ui/ui/layouts/web3.tsx new file mode 100644 index 0000000..405ad0d --- /dev/null +++ b/lotto-ui/ui/layouts/web3.tsx @@ -0,0 +1,295 @@ +import { Link } from "@nextui-org/link"; + +import { Head } from "./head"; + +import { Navbar } from "@/components/navbar"; + +import GradientBG from "@/components/GradientBG"; + +import { Field, PublicKey } from 'o1js'; +import { useEffect, useState } from 'react'; +import styles from '../styles/Home.module.css'; +import '../pages/reactCOIServiceWorker'; +import ZkappWorkerClient from '../pages/zkappWorkerClient'; + +let transactionFee = 0.1; +const ZKAPP_ADDRESS = 'B62qpXPvmKDf4SaFJynPsT6DyvuxMS9H1pT4TGonDT26m599m7dS9gP'; + + +export default function Web3Layout({ + children, +}: { + children: React.ReactNode; +}) { + + + const [state, setState] = useState({ + zkappWorkerClient: null as null | ZkappWorkerClient, + hasWallet: null as null | boolean, + hasBeenSetup: false, + accountExists: false, + currentNum: null as null | Field, + publicKey: null as null | PublicKey, + zkappPublicKey: null as null | PublicKey, + creatingTransaction: false, + }); + + const [displayText, setDisplayText] = useState(''); + const [transactionlink, setTransactionLink] = useState(''); + + useEffect(() => { + async function timeout(seconds: number): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, seconds * 1000); + }); + } + + (async () => { + if (!state.hasBeenSetup) { + setDisplayText('Loading web worker...'); + console.log('Loading web worker...'); + const zkappWorkerClient = new ZkappWorkerClient(); + await timeout(5); + + setDisplayText('Done loading web worker'); + console.log('Done loading web worker'); + + await zkappWorkerClient.setActiveInstanceToDevnet(); + + const mina = (window as any).mina; + + if (mina == null) { + setState({ ...state, hasWallet: false }); + return; + } + + const publicKeyBase58: string = (await mina.requestAccounts())[0]; + const publicKey = PublicKey.fromBase58(publicKeyBase58); + + console.log(`Using key:${publicKey.toBase58()}`); + setDisplayText(`Using key:${publicKey.toBase58()}`); + + setDisplayText('Checking if fee payer account exists...'); + console.log('Checking if fee payer account exists...'); + + const res = await zkappWorkerClient.fetchAccount({ + publicKey: publicKey!, + }); + const accountExists = res.error == null; + + await zkappWorkerClient.loadContract(); + + console.log('Compiling zkApp...'); + setDisplayText('Compiling zkApp...'); + await zkappWorkerClient.compileContract(); + console.log('zkApp compiled'); + setDisplayText('zkApp compiled...'); + + const zkappPublicKey = PublicKey.fromBase58(ZKAPP_ADDRESS); + + await zkappWorkerClient.initZkappInstance(zkappPublicKey); + + console.log('Getting zkApp state...'); + setDisplayText('Getting zkApp state...'); + await zkappWorkerClient.fetchAccount({ publicKey: zkappPublicKey }); + const currentNum = await zkappWorkerClient.getNum(); + console.log(`Current state in zkApp: ${currentNum.toString()}`); + setDisplayText(''); + + setState({ + ...state, + zkappWorkerClient, + hasWallet: true, + hasBeenSetup: true, + publicKey, + zkappPublicKey, + accountExists, + currentNum, + }); + } + })(); + }, []); + + // ------------------------------------------------------- + // Wait for account to exist, if it didn't + + useEffect(() => { + (async () => { + if (state.hasBeenSetup && !state.accountExists) { + for (;;) { + setDisplayText('Checking if fee payer account exists...'); + console.log('Checking if fee payer account exists...'); + const res = await state.zkappWorkerClient!.fetchAccount({ + publicKey: state.publicKey!, + }); + const accountExists = res.error == null; + if (accountExists) { + break; + } + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + setState({ ...state, accountExists: true }); + } + })(); + }, [state.hasBeenSetup]); + + + // ------------------------------------------------------- + // Send a transaction + + const onSendTransaction = async () => { + setState({ ...state, creatingTransaction: true }); + + setDisplayText('Creating a transaction...'); + console.log('Creating a transaction...'); + + await state.zkappWorkerClient!.fetchAccount({ + publicKey: state.publicKey!, + }); + + await state.zkappWorkerClient!.createUpdateTransaction(); + + setDisplayText('Creating proof...'); + console.log('Creating proof...'); + await state.zkappWorkerClient!.proveUpdateTransaction(); + + console.log('Requesting send transaction...'); + setDisplayText('Requesting send transaction...'); + const transactionJSON = await state.zkappWorkerClient!.getTransactionJSON(); + + setDisplayText('Getting transaction JSON...'); + console.log('Getting transaction JSON...'); + const { hash } = await (window as any).mina.sendTransaction({ + transaction: transactionJSON, + feePayer: { + fee: transactionFee, + memo: '', + }, + }); + + const transactionLink = `https://minascan.io/devnet/tx/${hash}`; + console.log(`View transaction at ${transactionLink}`); + + setTransactionLink(transactionLink); + setDisplayText(transactionLink); + + setState({ ...state, creatingTransaction: false }); + }; + + // ------------------------------------------------------- + // Refresh the current state + + const onRefreshCurrentNum = async () => { + console.log('Getting zkApp state...'); + setDisplayText('Getting zkApp state...'); + + await state.zkappWorkerClient!.fetchAccount({ + publicKey: state.zkappPublicKey!, + }); + const currentNum = await state.zkappWorkerClient!.getNum(); + setState({ ...state, currentNum }); + console.log(`Current state in zkApp: ${currentNum.toString()}`); + setDisplayText(''); + }; + + // ------------------------------------------------------- + // Create UI elements + + let hasWallet; + if (state.hasWallet != null && !state.hasWallet) { + const auroLink = 'https://www.aurowallet.com/'; + const auroLinkElem = ( + + Install Auro wallet here + + ); + hasWallet =
Could not find a wallet. {auroLinkElem}
; + } + + const stepDisplay = transactionlink ? ( + + View transaction + + ) : ( + displayText + ); + + let setup = ( +
+ {stepDisplay} + {hasWallet} +
+ ); + + let accountDoesNotExist; + if (state.hasBeenSetup && !state.accountExists) { + const faucetLink = + 'https://faucet.minaprotocol.com/?address=' + state.publicKey!.toBase58(); + accountDoesNotExist = ( +
+ Account does not exist. + + Visit the faucet to fund this fee payer account + +
+ ); + } + + let mainContent; + if (state.hasBeenSetup && state.accountExists) { + mainContent = ( +
+
+ Current state in zkApp: {state.currentNum!.toString()}{' '} +
+ + +
+ ); + } + + + + return ( + +
+ + +
+ {setup} + {accountDoesNotExist} + {children} +
+
+ + Powered by +

Mina

+ +
+
+
+ ); +} diff --git a/lotto-ui/ui/pages/admin/index.tsx b/lotto-ui/ui/pages/admin/index.tsx index ebf6f5a..245a143 100644 --- a/lotto-ui/ui/pages/admin/index.tsx +++ b/lotto-ui/ui/pages/admin/index.tsx @@ -1,8 +1,8 @@ -import DefaultLayout from "@/layouts/default"; import { title } from "@/components/primitives"; import React from "react"; import { Card, CardHeader, Spacer, Input, Button } from "@nextui-org/react"; import dynamic from "next/dynamic"; +import Web3Layout from "@/layouts/web3"; // Cargar Countdown dinámicamente para evitar errores de hidratación const Countdown = dynamic(() => import("../../components/Countdown"), { ssr: false }); @@ -20,7 +20,7 @@ const getNextMonday = (): string => { export default function AdminPage() { const targetDate = getNextMonday(); return ( - +

Admin dashboard

@@ -109,6 +109,6 @@ export default function AdminPage() { End Game Week -
+ ); } diff --git a/lotto-ui/ui/pages/dashboard/index.tsx b/lotto-ui/ui/pages/dashboard/index.tsx index fabbe0c..83f41a8 100644 --- a/lotto-ui/ui/pages/dashboard/index.tsx +++ b/lotto-ui/ui/pages/dashboard/index.tsx @@ -3,6 +3,7 @@ import { title } from "@/components/primitives"; import React from "react"; import { Card, CardHeader, Spacer, Input, Button, Divider } from "@nextui-org/react"; import dynamic from "next/dynamic"; +import Web3Layout from "@/layouts/web3"; // Cargar Countdown dinámicamente para evitar errores de hidratación const Countdown = dynamic(() => import("../../components/Countdown"), { ssr: false }); @@ -19,7 +20,7 @@ const getNextMonday = (): string => { export default function DashboardPage() { const targetDate = getNextMonday(); return ( - +

Dashboard

@@ -128,6 +129,6 @@ export default function DashboardPage() { Claim -
+ ); } diff --git a/lotto-ui/ui/pages/index.tsx b/lotto-ui/ui/pages/index.tsx index 0e5f0e0..db20dd4 100644 --- a/lotto-ui/ui/pages/index.tsx +++ b/lotto-ui/ui/pages/index.tsx @@ -6,264 +6,10 @@ import { title } from "@/components/primitives"; import { GithubIcon } from "@/components/icons"; import DefaultLayout from "@/layouts/default"; -import { Field, PublicKey } from 'o1js'; -import { useEffect, useState } from 'react'; -import styles from '../styles/Home.module.css'; -import './reactCOIServiceWorker'; -import ZkappWorkerClient from './zkappWorkerClient'; -let transactionFee = 0.1; -const ZKAPP_ADDRESS = 'B62qpXPvmKDf4SaFJynPsT6DyvuxMS9H1pT4TGonDT26m599m7dS9gP'; export default function IndexPage() { - const [state, setState] = useState({ - zkappWorkerClient: null as null | ZkappWorkerClient, - hasWallet: null as null | boolean, - hasBeenSetup: false, - accountExists: false, - currentNum: null as null | Field, - publicKey: null as null | PublicKey, - zkappPublicKey: null as null | PublicKey, - creatingTransaction: false, - }); - - const [displayText, setDisplayText] = useState(''); - const [transactionlink, setTransactionLink] = useState(''); - - useEffect(() => { - async function timeout(seconds: number): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, seconds * 1000); - }); - } - - (async () => { - if (!state.hasBeenSetup) { - setDisplayText('Loading web worker...'); - console.log('Loading web worker...'); - const zkappWorkerClient = new ZkappWorkerClient(); - await timeout(5); - - setDisplayText('Done loading web worker'); - console.log('Done loading web worker'); - - await zkappWorkerClient.setActiveInstanceToDevnet(); - - const mina = (window as any).mina; - - if (mina == null) { - setState({ ...state, hasWallet: false }); - return; - } - - const publicKeyBase58: string = (await mina.requestAccounts())[0]; - const publicKey = PublicKey.fromBase58(publicKeyBase58); - - console.log(`Using key:${publicKey.toBase58()}`); - setDisplayText(`Using key:${publicKey.toBase58()}`); - - setDisplayText('Checking if fee payer account exists...'); - console.log('Checking if fee payer account exists...'); - - const res = await zkappWorkerClient.fetchAccount({ - publicKey: publicKey!, - }); - const accountExists = res.error == null; - - await zkappWorkerClient.loadContract(); - - console.log('Compiling zkApp...'); - setDisplayText('Compiling zkApp...'); - await zkappWorkerClient.compileContract(); - console.log('zkApp compiled'); - setDisplayText('zkApp compiled...'); - - const zkappPublicKey = PublicKey.fromBase58(ZKAPP_ADDRESS); - - await zkappWorkerClient.initZkappInstance(zkappPublicKey); - - console.log('Getting zkApp state...'); - setDisplayText('Getting zkApp state...'); - await zkappWorkerClient.fetchAccount({ publicKey: zkappPublicKey }); - const currentNum = await zkappWorkerClient.getNum(); - console.log(`Current state in zkApp: ${currentNum.toString()}`); - setDisplayText(''); - - setState({ - ...state, - zkappWorkerClient, - hasWallet: true, - hasBeenSetup: true, - publicKey, - zkappPublicKey, - accountExists, - currentNum, - }); - } - })(); - }, []); - - // ------------------------------------------------------- - // Wait for account to exist, if it didn't - - useEffect(() => { - (async () => { - if (state.hasBeenSetup && !state.accountExists) { - for (;;) { - setDisplayText('Checking if fee payer account exists...'); - console.log('Checking if fee payer account exists...'); - const res = await state.zkappWorkerClient!.fetchAccount({ - publicKey: state.publicKey!, - }); - const accountExists = res.error == null; - if (accountExists) { - break; - } - await new Promise((resolve) => setTimeout(resolve, 5000)); - } - setState({ ...state, accountExists: true }); - } - })(); - }, [state.hasBeenSetup]); - - - // ------------------------------------------------------- - // Send a transaction - - const onSendTransaction = async () => { - setState({ ...state, creatingTransaction: true }); - - setDisplayText('Creating a transaction...'); - console.log('Creating a transaction...'); - - await state.zkappWorkerClient!.fetchAccount({ - publicKey: state.publicKey!, - }); - - await state.zkappWorkerClient!.createUpdateTransaction(); - - setDisplayText('Creating proof...'); - console.log('Creating proof...'); - await state.zkappWorkerClient!.proveUpdateTransaction(); - - console.log('Requesting send transaction...'); - setDisplayText('Requesting send transaction...'); - const transactionJSON = await state.zkappWorkerClient!.getTransactionJSON(); - - setDisplayText('Getting transaction JSON...'); - console.log('Getting transaction JSON...'); - const { hash } = await (window as any).mina.sendTransaction({ - transaction: transactionJSON, - feePayer: { - fee: transactionFee, - memo: '', - }, - }); - - const transactionLink = `https://minascan.io/devnet/tx/${hash}`; - console.log(`View transaction at ${transactionLink}`); - - setTransactionLink(transactionLink); - setDisplayText(transactionLink); - - setState({ ...state, creatingTransaction: false }); - }; - - // ------------------------------------------------------- - // Refresh the current state - - const onRefreshCurrentNum = async () => { - console.log('Getting zkApp state...'); - setDisplayText('Getting zkApp state...'); - - await state.zkappWorkerClient!.fetchAccount({ - publicKey: state.zkappPublicKey!, - }); - const currentNum = await state.zkappWorkerClient!.getNum(); - setState({ ...state, currentNum }); - console.log(`Current state in zkApp: ${currentNum.toString()}`); - setDisplayText(''); - }; - - // ------------------------------------------------------- - // Create UI elements - - let hasWallet; - if (state.hasWallet != null && !state.hasWallet) { - const auroLink = 'https://www.aurowallet.com/'; - const auroLinkElem = ( - - Install Auro wallet here - - ); - hasWallet =
Could not find a wallet. {auroLinkElem}
; - } - - const stepDisplay = transactionlink ? ( - - View transaction - - ) : ( - displayText - ); - - let setup = ( -
- {stepDisplay} - {hasWallet} -
- ); - - let accountDoesNotExist; - if (state.hasBeenSetup && !state.accountExists) { - const faucetLink = - 'https://faucet.minaprotocol.com/?address=' + state.publicKey!.toBase58(); - accountDoesNotExist = ( - - ); - } - - let mainContent; - if (state.hasBeenSetup && state.accountExists) { - mainContent = ( -
-
- Current state in zkApp: {state.currentNum!.toString()}{' '} -
- - -
- ); - } - - - - - return (