diff --git a/apps/frontend/next-app/.env.example b/apps/frontend/next-app/.env.example new file mode 100644 index 0000000..2592cc7 --- /dev/null +++ b/apps/frontend/next-app/.env.example @@ -0,0 +1 @@ +NEXT_PUBLIC_WALLECT_CONNECT_PROJECT_ID = YOUR_PROJECT_ID \ No newline at end of file diff --git a/apps/frontend/next-app/app/GraphqlClient.ts b/apps/frontend/next-app/app/GraphqlClient.ts new file mode 100644 index 0000000..63f1d56 --- /dev/null +++ b/apps/frontend/next-app/app/GraphqlClient.ts @@ -0,0 +1,30 @@ +"use client" +import { useMemo } from 'react'; +import { + UrqlProvider, + ssrExchange, + cacheExchange, + fetchExchange, + createClient, +} from '@urql/next'; + +// YOUR API URL +const API_BASE_URL = 'http://localhost:8080/graphql' + +export default function GraphQLClient({ children }: React.PropsWithChildren) { + const [client, ssr] = useMemo(() => { + const ssr = ssrExchange({ + isClient: typeof window !== 'undefined', + }); + const client = createClient({ + url: API_BASE_URL, + exchanges: [cacheExchange, ssr, fetchExchange], + suspense: true, + }); + + return [client, ssr]; + }, []); + + return {client, ssr} +} + diff --git a/apps/frontend/next-app/app/cartesi/GraphQL.tsx b/apps/frontend/next-app/app/cartesi/GraphQL.tsx index ac73bc6..89079fb 100644 --- a/apps/frontend/next-app/app/cartesi/GraphQL.tsx +++ b/apps/frontend/next-app/app/cartesi/GraphQL.tsx @@ -15,7 +15,8 @@ import { useSetChain } from "@web3-onboard/react"; import React, { useMemo } from "react"; import { Client, createClient, Provider } from "urql"; - +import { Chain } from "viem"; +// import { Chain } from "@rainbow-me/rainbowkit"; import configFile from "./config.json"; const config: any = configFile; diff --git a/apps/frontend/next-app/app/cartesi/Input.tsx b/apps/frontend/next-app/app/cartesi/Input.tsx index fe65236..1bf971a 100644 --- a/apps/frontend/next-app/app/cartesi/Input.tsx +++ b/apps/frontend/next-app/app/cartesi/Input.tsx @@ -40,7 +40,7 @@ export const Input: React.FC = (propos) => { const addInput = async (str: string) => { if (rollups) { try { - let payload = ethers.utils.toUtf8Bytes(str); + let payload = ethers.toUtf8Bytes(str); if (hexInput) { payload = ethers.utils.arrayify(str); } @@ -54,7 +54,7 @@ export const Input: React.FC = (propos) => { const depositErc20ToPortal = async (token: string,amount: number) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes(`Deposited (${amount}) of ERC20 (${token}).`); + const data = ethers.toUtf8Bytes(`Deposited (${amount}) of ERC20 (${token}).`); //const data = `Deposited ${args.amount} tokens (${args.token}) for DAppERC20Portal(${portalAddress}) (signer: ${address})`; const signer = provider.getSigner(); const signerAddress = await signer.getAddress() @@ -64,9 +64,9 @@ export const Input: React.FC = (propos) => { // query current allowance const currentAllowance = await tokenContract.allowance(signerAddress, erc20PortalAddress); - if (ethers.utils.parseEther(`${amount}`) > currentAllowance) { + if (ethers.parseEther(`${amount}`) > currentAllowance) { // Allow portal to withdraw `amount` tokens from signer - const tx = await tokenContract.approve(erc20PortalAddress, ethers.utils.parseEther(`${amount}`)); + const tx = await tokenContract.approve(erc20PortalAddress, ethers.parseEther(`${amount}`)); const receipt = await tx.wait(1); const event = (await tokenContract.queryFilter(tokenContract.filters.Approval(), receipt.blockHash)).pop(); if (!event) { @@ -84,8 +84,8 @@ export const Input: React.FC = (propos) => { const depositEtherToPortal = async (amount: number) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes(`Deposited (${amount}) ether.`); - const txOverrides = {value: ethers.utils.parseEther(`${amount}`)} + const data = ethers.toUtf8Bytes(`Deposited (${amount}) ether.`); + const txOverrides = {value: ethers.parseEther(`${amount}`)} // const tx = await ... rollups.etherPortalContract.depositEther(propos.dappAddress,data,txOverrides); @@ -98,7 +98,7 @@ export const Input: React.FC = (propos) => { const transferNftToPortal = async (contractAddress: string,nftid: number) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes(`Deposited (${nftid}) of ERC721 (${contractAddress}).`); + const data = ethers.toUtf8Bytes(`Deposited (${nftid}) of ERC721 (${contractAddress}).`); //const data = `Deposited ${args.amount} tokens (${args.token}) for DAppERC20Portal(${portalAddress}) (signer: ${address})`; const signer = provider.getSigner(); const signerAddress = await signer.getAddress() @@ -130,7 +130,7 @@ export const Input: React.FC = (propos) => { const transferErc1155SingleToPortal = async (contractAddress: string, id: number, amount: number) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes(`Deposited (${amount}) tokens from id (${id}) of ERC1155 (${contractAddress}).`); + const data = ethers.toUtf8Bytes(`Deposited (${amount}) tokens from id (${id}) of ERC1155 (${contractAddress}).`); //const data = `Deposited ${args.amount} tokens (${args.token}) for DAppERC20Portal(${portalAddress}) (signer: ${address})`; const signer = provider.getSigner(); const signerAddress = await signer.getAddress() diff --git a/apps/frontend/next-app/app/cartesi/Inspect.tsx b/apps/frontend/next-app/app/cartesi/Inspect.tsx index a2e0b82..c2b0236 100644 --- a/apps/frontend/next-app/app/cartesi/Inspect.tsx +++ b/apps/frontend/next-app/app/cartesi/Inspect.tsx @@ -13,31 +13,34 @@ import React, { useState } from "react"; import { useSetChain } from "@web3-onboard/react"; import { ethers } from "ethers"; -// import { useRollups } from "./useRollups"; - -import configFile from "../config.json"; +import { useRollups } from "./useRollups"; +import { useAccount } from "wagmi"; +import configFile from "../cartesi/config.json"; +import { DAPP_ADDRESS } from "../utils/constants"; +import { toHex } from "viem"; const config: any = configFile; export const Inspect: React.FC = () => { - // const rollups = useRollups(); - const [{ connectedChain }] = useSetChain(); + const rollups = useRollups(DAPP_ADDRESS); + const { chain } = useAccount(); + const inspectCall = async (str: string) => { let payload = str; if (hexData) { const uint8array = ethers.utils.arrayify(str); payload = new TextDecoder().decode(uint8array); } - if (!connectedChain){ + if (!chain){ return; } let apiURL= "" - if(config[connectedChain.id]?.inspectAPIURL) { - apiURL = `${config[connectedChain.id].inspectAPIURL}/inspect`; + if(config[toHex(chain.id)]?.inspectAPIURL) { + apiURL = `${config[toHex(chain.id)].inspectAPIURL}/inspect`; } else { - console.error(`No inspect interface defined for chain ${connectedChain.id}`); + console.error(`No inspect interface defined for chain ${toHex(chain.id)}`); return; } @@ -90,7 +93,7 @@ export const Inspect: React.FC = () => { {metadata.metadata ? metadata.metadata.active_epoch_index : ""} {metadata.metadata ? metadata.metadata.current_input_index : ""} {metadata.status} - {metadata.exception_payload ? ethers.utils.toUtf8String(metadata.exception_payload): ""} + {metadata.exception_payload ? ethers.toUtf8String(metadata.exception_payload): ""} @@ -104,7 +107,7 @@ export const Inspect: React.FC = () => { )} {reports?.map((n: any) => ( - {ethers.utils.toUtf8String(n.payload)} + {ethers.toUtf8String(n.payload)} ))} diff --git a/apps/frontend/next-app/app/cartesi/Notices copy.tsx b/apps/frontend/next-app/app/cartesi/Notices copy.tsx new file mode 100644 index 0000000..1124892 --- /dev/null +++ b/apps/frontend/next-app/app/cartesi/Notices copy.tsx @@ -0,0 +1,109 @@ +"use client" +// Copyright 2022 Cartesi Pte. Ltd. + +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the license at http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import { ethers } from "ethers"; +import React, {useEffect} from "react"; + +import { useNoticesQuery } from "../cartesi/generated/graphql"; + +type Notice = { + id: string; + index: number; + input: any, //{index: number; epoch: {index: number; } + payload: string; +}; + +export const Notices: React.FC = () => { + const [result,reexecuteQuery] = useNoticesQuery(); + const { data, fetching, error } = result; + + useEffect(() => { + reexecuteQuery({ requestPolicy: 'network-only' }); + }, [reexecuteQuery]); + + if (fetching) return

Loading...

; + if (error) return

Oh no... {error.message}

; + + if (!data || !data.notices) return

No notices

; + + const notices: Notice[] = data.notices.edges.map((node: any) => { + const n = node.node; + let inputPayload = n?.input.payload; + if (inputPayload) { + try { + inputPayload = ethers.toUtf8String(inputPayload); + } catch (e) { + inputPayload = inputPayload + " (hex)"; + } + } else { + inputPayload = "(empty)"; + } + let payload = n?.payload; + if (payload) { + try { + payload = ethers.toUtf8String(payload); + } catch (e) { + payload = payload + " (hex)"; + } + } else { + payload = "(empty)"; + } + return { + id: `${n?.id}`, + index: parseInt(n?.index), + payload: `${payload}`, + input: n ? {index:n.input.index,payload: inputPayload} : {}, + }; + }).sort((b: any, a: any) => { + if (a.input.index === b.input.index) { + return b.index - a.index; + } else { + return b.input.index - a.input.index; + } + }); + + // const forceUpdate = useForceUpdate(); + return ( +
+ + + + + + + {/* */} + + + + + {notices.length === 0 && ( + + + + )} + {notices.map((n: any) => ( + + + + {/* */} + + + ))} + +
Input IndexNotice IndexInput PayloadPayload
no notices
{n.input.index}{n.index}{n.input.payload}{n.payload}
+ +
+ ); +}; diff --git a/apps/frontend/next-app/app/cartesi/Notices.tsx b/apps/frontend/next-app/app/cartesi/Notices.tsx index 5301463..1124892 100644 --- a/apps/frontend/next-app/app/cartesi/Notices.tsx +++ b/apps/frontend/next-app/app/cartesi/Notices.tsx @@ -12,7 +12,8 @@ // under the License. import { ethers } from "ethers"; -import React from "react"; +import React, {useEffect} from "react"; + import { useNoticesQuery } from "../cartesi/generated/graphql"; type Notice = { @@ -26,6 +27,10 @@ export const Notices: React.FC = () => { const [result,reexecuteQuery] = useNoticesQuery(); const { data, fetching, error } = result; + useEffect(() => { + reexecuteQuery({ requestPolicy: 'network-only' }); + }, [reexecuteQuery]); + if (fetching) return

Loading...

; if (error) return

Oh no... {error.message}

; @@ -36,7 +41,7 @@ export const Notices: React.FC = () => { let inputPayload = n?.input.payload; if (inputPayload) { try { - inputPayload = ethers.utils.toUtf8String(inputPayload); + inputPayload = ethers.toUtf8String(inputPayload); } catch (e) { inputPayload = inputPayload + " (hex)"; } @@ -46,7 +51,7 @@ export const Notices: React.FC = () => { let payload = n?.payload; if (payload) { try { - payload = ethers.utils.toUtf8String(payload); + payload = ethers.toUtf8String(payload); } catch (e) { payload = payload + " (hex)"; } @@ -70,22 +75,22 @@ export const Notices: React.FC = () => { // const forceUpdate = useForceUpdate(); return (
- - +
- - - + + + {/* */} - + {notices.length === 0 && ( - + )} {notices.map((n: any) => ( diff --git a/apps/frontend/next-app/app/cartesi/Reports copy.tsx b/apps/frontend/next-app/app/cartesi/Reports copy.tsx new file mode 100644 index 0000000..b17bdbf --- /dev/null +++ b/apps/frontend/next-app/app/cartesi/Reports copy.tsx @@ -0,0 +1,121 @@ +"use client" + +// Copyright 2022 Cartesi Pte. Ltd. + +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the license at http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +import { ethers } from "ethers"; +import React, { useEffect } from "react"; +import { useReportsQuery } from "../cartesi/generated/graphql"; +import { + Table, + Thead, + Tbody, + Tfoot, + Tr, + Th, + Td, + TableCaption, + TableContainer, + Button + } from '@chakra-ui/react' + +type Report = { + id: string; + index: number; + input: any, //{index: number; epoch: {index: number; } + payload: string; +}; + +export const Reports: React.FC = () => { + + const [result,reexecuteQuery] = useReportsQuery(); + const { data, fetching, error } = result; + + useEffect(() => { + reexecuteQuery({ requestPolicy: 'network-only' }); + }, [reexecuteQuery]); + + if (fetching) return

Loading...

; + if (error) return

Oh no... {error.message}

; + + if (!data || !data.reports) return

No reports

; + + + const reports: Report[] = data.reports.edges.map((node: any) => { + const n = node.node; + let inputPayload = n?.input.payload; + if (inputPayload) { + try { + inputPayload = ethers.toUtf8String(inputPayload); + } catch (e) { + inputPayload = inputPayload + " (hex)"; + } + } else { + inputPayload = "(empty)"; + } + let payload = n?.payload; + if (payload) { + try { + payload = ethers.toUtf8String(payload); + } catch (e) { + payload = payload + " (hex)"; + } + } else { + payload = "(empty)"; + } + return { + id: `${n?.id}`, + index: parseInt(n?.index), + payload: `${payload}`, + input: n ? {index:n.input.index,payload: inputPayload} : {}, + }; + }).sort((b: any, a: any) => { + if (a.input.index === b.input.index) { + return b.index - a.index; + } else { + return b.input.index - a.input.index; + } + }); + + // const forceUpdate = useForceUpdate(); + return ( +
+
Input IndexNotice Index
Input IndexNotice IndexInput PayloadPayloadPayload
no noticesno notices
+ + + {/* + */} + {/* */} + + + + + {reports.length === 0 && ( + + + + )} + {reports.map((n: any) => ( + + {/* + */} + {/* */} + + + ))} + +
Input IndexNotice IndexInput PayloadReports +
-
{n.input.index}{n.index}{n.input.payload}{n.payload}
+ +
+ ); +}; diff --git a/apps/frontend/next-app/app/cartesi/Reports.tsx b/apps/frontend/next-app/app/cartesi/Reports.tsx index fc7f7d9..b17bdbf 100644 --- a/apps/frontend/next-app/app/cartesi/Reports.tsx +++ b/apps/frontend/next-app/app/cartesi/Reports.tsx @@ -1,3 +1,5 @@ +"use client" + // Copyright 2022 Cartesi Pte. Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -10,7 +12,7 @@ // License for the specific language governing permissions and limitations // under the License. import { ethers } from "ethers"; -import React from "react"; +import React, { useEffect } from "react"; import { useReportsQuery } from "../cartesi/generated/graphql"; import { Table, @@ -33,20 +35,26 @@ type Report = { }; export const Reports: React.FC = () => { + const [result,reexecuteQuery] = useReportsQuery(); const { data, fetching, error } = result; + useEffect(() => { + reexecuteQuery({ requestPolicy: 'network-only' }); + }, [reexecuteQuery]); + if (fetching) return

Loading...

; if (error) return

Oh no... {error.message}

; if (!data || !data.reports) return

No reports

; + const reports: Report[] = data.reports.edges.map((node: any) => { const n = node.node; let inputPayload = n?.input.payload; if (inputPayload) { try { - inputPayload = ethers.utils.toUtf8String(inputPayload); + inputPayload = ethers.toUtf8String(inputPayload); } catch (e) { inputPayload = inputPayload + " (hex)"; } @@ -56,7 +64,7 @@ export const Reports: React.FC = () => { let payload = n?.payload; if (payload) { try { - payload = ethers.utils.toUtf8String(payload); + payload = ethers.toUtf8String(payload); } catch (e) { payload = payload + " (hex)"; } @@ -86,8 +94,8 @@ export const Reports: React.FC = () => { {/* Input Index Notice Index */} {/* Input Payload */} - Reports + Reports diff --git a/apps/frontend/next-app/app/cartesi/Vouchers.tsx b/apps/frontend/next-app/app/cartesi/Vouchers.tsx index ba57563..af0b12d 100644 --- a/apps/frontend/next-app/app/cartesi/Vouchers.tsx +++ b/apps/frontend/next-app/app/cartesi/Vouchers.tsx @@ -1,3 +1,4 @@ +"use client" // Copyright 2022 Cartesi Pte. Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -10,7 +11,7 @@ // License for the specific language governing permissions and limitations // under the License. -import { BigNumber, ethers } from "ethers"; +import { ethers } from "ethers"; import React, { useEffect } from "react"; import { useVouchersQuery, useVoucherQuery } from "./generated/graphql"; import { useRollups } from "./useRollups"; @@ -18,15 +19,13 @@ import { Table, Thead, Tbody, - Tfoot, Tr, Th, Td, - TableCaption, - TableContainer, Button, Text } from '@chakra-ui/react' + import { useEthersSigner } from "../utils/useEtherSigner"; type Voucher = { id: string; @@ -51,7 +50,9 @@ export const Vouchers: React.FC = (propos) => { const [voucherToExecute, setVoucherToExecute] = React.useState(); const { data, fetching, error } = result; const rollups = useRollups(propos.dappAddress); - + const signer = useEthersSigner() + const provider = signer?.provider + const getProof = async (voucher: Voucher) => { setVoucherToFetch([voucher.index,voucher.input.index]); reexecuteVoucherQuery({ requestPolicy: 'network-only' }); @@ -63,8 +64,9 @@ export const Vouchers: React.FC = (propos) => { const newVoucherToExecute = {...voucher}; try { const tx = await rollups.dappContract.executeVoucher( voucher.destination,voucher.payload,voucher.proof); - const receipt = await tx.wait(); - newVoucherToExecute.msg = `voucher executed! (tx="${tx.hash}")`; + const trans = await signer?.sendTransaction(tx) + const receipt = await trans?.wait(1); + newVoucherToExecute.msg = `voucher executed! (tx="${receipt?.hash}")`; if (receipt.events) { newVoucherToExecute.msg = `${newVoucherToExecute.msg} - resulting events: ${JSON.stringify(receipt.events)}`; newVoucherToExecute.executed = await rollups.dappContract.wasVoucherExecuted(BigNumber.from(voucher.input.index),BigNumber.from(voucher.index)); @@ -101,7 +103,7 @@ export const Vouchers: React.FC = (propos) => { let inputPayload = n?.input.payload; if (inputPayload) { try { - inputPayload = ethers.utils.toUtf8String(inputPayload); + inputPayload = ethers.toUtf8String(inputPayload); } catch (e) { inputPayload = inputPayload + " (hex)"; } @@ -109,15 +111,15 @@ export const Vouchers: React.FC = (propos) => { inputPayload = "(empty)"; } if (payload) { - const decoder = new ethers.utils.AbiCoder(); + const decoder = new ethers.AbiCoder(); const selector = decoder.decode(["bytes4"], payload)[0]; - payload = ethers.utils.hexDataSlice(payload,4); + payload = ethers.dataSlice(payload,4); try { switch(selector) { case '0xa9059cbb': { // erc20 transfer; const decode = decoder.decode(["address","uint256"], payload); - payload = `Erc20 Transfer - Amount: ${ethers.utils.formatEther(decode[1])} - Address: ${decode[0]}`; + payload = `Erc20 Transfer - Amount: ${ethers.formatEther(decode[1])} - Address: ${decode[0]}`; break; } case '0x42842e0e': { @@ -129,7 +131,7 @@ export const Vouchers: React.FC = (propos) => { case '0x522f6815': { //ether transfer; const decode2 = decoder.decode(["address", "uint256"], payload) - payload = `Ether Transfer - Amount: ${ethers.utils.formatEther(decode2[1])} (Native eth) - Address: ${decode2[0]}`; + payload = `Ether Transfer - Amount: ${ethers.formatEther(decode2[1])} (Native eth) - Address: ${decode2[0]}`; break; } case '0xf242432a': { diff --git a/apps/frontend/next-app/app/cartesi/config.json b/apps/frontend/next-app/app/cartesi/config.json index 98277d2..59ca1c2 100644 --- a/apps/frontend/next-app/app/cartesi/config.json +++ b/apps/frontend/next-app/app/cartesi/config.json @@ -16,7 +16,7 @@ "0xaa36a7":{ "token": "SepETH", "label": "Sepolia Test Network", - "rpcUrl": "https://eth-goerli.g.alchemy.com/v2/demo", + "rpcUrl": "https://eth-sepolia.g.alchemy.com/v2/demo", "graphqlAPIURL" : "http://localhost:8080", "inspectAPIURL":"http://localhost:8080", "DAppRelayAddress":"0xF5DE34d6BbC0446E2a45719E718efEbaaE179daE", @@ -27,10 +27,10 @@ "Erc1155SinglePortalAddress":"0x7CFB0193Ca87eB6e48056885E026552c3A941FC4", "Erc1155BatchPortalAddress":"0xedB53860A6B52bbb7561Ad596416ee9965B055Aa" }, - "0x1a4":{ - "token": "GOP", - "label": "Optimism Goerli Test Network", - "rpcUrl": "https://opt-goerli.g.alchemy.com/v2/demo", + "0xaa37dc":{ + "token": "OPSep", + "label": "Optimism Sepolia Test Network", + "rpcUrl": "https://sepolia.optimism.io", "graphqlAPIURL" : "http://localhost:8080", "inspectAPIURL":"http://localhost:8080", "DAppRelayAddress":"0xF5DE34d6BbC0446E2a45719E718efEbaaE179daE", @@ -41,10 +41,24 @@ "Erc1155SinglePortalAddress":"0x7CFB0193Ca87eB6e48056885E026552c3A941FC4", "Erc1155BatchPortalAddress":"0xedB53860A6B52bbb7561Ad596416ee9965B055Aa" }, - "0x66eed":{ - "token": "GAGO", - "label": "Arbitrum Goerli Test Network", - "rpcUrl": "https://goerli-rollup.arbitrum.io/rpc", + "0x66eee":{ + "token": "AGOSep", + "label": "Arbitrum Sepolia Test Network", + "rpcUrl": "https://sepolia-rollup.arbitrum.io/rpc", + "graphqlAPIURL" : "http://localhost:8080", + "inspectAPIURL":"http://localhost:8080", + "DAppRelayAddress":"0xF5DE34d6BbC0446E2a45719E718efEbaaE179daE", + "InputBoxAddress":"0x59b22D57D4f067708AB0c00552767405926dc768", + "EtherPortalAddress":"0xFfdbe43d4c855BF7e0f105c400A50857f53AB044", + "Erc20PortalAddress":"0x9C21AEb2093C32DDbC53eEF24B873BDCd1aDa1DB", + "Erc721PortalAddress":"0x237F8DD094C0e47f4236f12b4Fa01d6Dae89fb87", + "Erc1155SinglePortalAddress":"0x7CFB0193Ca87eB6e48056885E026552c3A941FC4", + "Erc1155BatchPortalAddress":"0xedB53860A6B52bbb7561Ad596416ee9965B055Aa" + }, + "0x14a34":{ + "token": "BASESep", + "label": "Base Sepolia", + "rpcUrl": "https://sepolia.base.org", "graphqlAPIURL" : "http://localhost:8080", "inspectAPIURL":"http://localhost:8080", "DAppRelayAddress":"0xF5DE34d6BbC0446E2a45719E718efEbaaE179daE", @@ -96,5 +110,19 @@ "Erc721PortalAddress":"0x237F8DD094C0e47f4236f12b4Fa01d6Dae89fb87", "Erc1155SinglePortalAddress":"0x7CFB0193Ca87eB6e48056885E026552c3A941FC4", "Erc1155BatchPortalAddress":"0xedB53860A6B52bbb7561Ad596416ee9965B055Aa" + }, + "0x2105":{ + "token": "BASE", + "label": "Base Mainnet", + "rpcUrl": "https://mainnet.base.org", + "graphqlAPIURL" : "http://localhost:8080", + "inspectAPIURL":"http://localhost:8080", + "DAppRelayAddress":"0xF5DE34d6BbC0446E2a45719E718efEbaaE179daE", + "InputBoxAddress":"0x59b22D57D4f067708AB0c00552767405926dc768", + "EtherPortalAddress":"0xFfdbe43d4c855BF7e0f105c400A50857f53AB044", + "Erc20PortalAddress":"0x9C21AEb2093C32DDbC53eEF24B873BDCd1aDa1DB", + "Erc721PortalAddress":"0x237F8DD094C0e47f4236f12b4Fa01d6Dae89fb87", + "Erc1155SinglePortalAddress":"0x7CFB0193Ca87eB6e48056885E026552c3A941FC4", + "Erc1155BatchPortalAddress":"0xedB53860A6B52bbb7561Ad596416ee9965B055Aa" } } \ No newline at end of file diff --git a/apps/frontend/next-app/app/cartesi/useRollups.tsx b/apps/frontend/next-app/app/cartesi/useRollups.tsx index d0c930b..7cda067 100644 --- a/apps/frontend/next-app/app/cartesi/useRollups.tsx +++ b/apps/frontend/next-app/app/cartesi/useRollups.tsx @@ -1,3 +1,5 @@ +"use client" + // Copyright 2022 Cartesi Pte. Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -13,6 +15,9 @@ import { useEffect, useState } from "react"; import { ethers } from "ethers"; import { useSetChain, useWallets } from "@web3-onboard/react"; +import { useAccount, Config } from 'wagmi'; +import { Chain, toHex } from "viem"; +import { useEthersSigner } from "../utils/useEtherSigner"; import { CartesiDApp, @@ -32,8 +37,6 @@ import { ERC1155BatchPortal, ERC1155BatchPortal__factory } from "../cartesi/generated/rollups"; -import { ConnectedChain } from "@web3-onboard/core"; - import configFile from "./config.json"; import { JsonRpcSigner } from "@ethersproject/providers"; @@ -42,7 +45,7 @@ const config: any = configFile; export interface RollupsContracts { dappContract: CartesiDApp; - signer: JsonRpcSigner; + signer: any; relayContract: DAppAddressRelay; inputContract: InputBox; etherPortalContract: EtherPortal; @@ -54,70 +57,66 @@ export interface RollupsContracts { export const useRollups = (dAddress: string): RollupsContracts | undefined => { const [contracts, setContracts] = useState(); - const [{ connectedChain }] = useSetChain(); - const [connectedWallet] = useWallets(); const [dappAddress] = useState(dAddress); + const { address, chain } = useAccount(); + const signer = useEthersSigner(); + useEffect(() => { const connect = async ( - chain: ConnectedChain + chain: Chain ): Promise => { - const provider = new ethers.providers.Web3Provider( - connectedWallet.provider - ); - const signer = provider.getSigner(); - let dappRelayAddress = ""; - if(config[chain.id]?.DAppRelayAddress) { - dappRelayAddress = config[chain.id].DAppRelayAddress; + if(config[toHex(toHex(chain.id))]?.DAppRelayAddress) { + dappRelayAddress = config[toHex(chain.id)].DAppRelayAddress; } else { - console.error(`No dapp relay address address defined for chain ${chain.id}`); + console.error(`No dapp relay address address defined for chain ${toHex(chain.id)}`); } let inputBoxAddress = ""; - if(config[chain.id]?.InputBoxAddress) { - inputBoxAddress = config[chain.id].InputBoxAddress; + if(config[toHex(chain.id)]?.InputBoxAddress) { + inputBoxAddress = config[toHex(chain.id)].InputBoxAddress; } else { - console.error(`No input box address address defined for chain ${chain.id}`); + console.error(`No input box address address defined for chain ${toHex(chain.id)}`); } let etherPortalAddress = ""; - if(config[chain.id]?.EtherPortalAddress) { - etherPortalAddress = config[chain.id].EtherPortalAddress; + if(config[toHex(chain.id)]?.EtherPortalAddress) { + etherPortalAddress = config[toHex(chain.id)].EtherPortalAddress; } else { - console.error(`No ether portal address address defined for chain ${chain.id}`); + console.error(`No ether portal address address defined for chain ${toHex(chain.id)}`); } let erc20PortalAddress = ""; - if(config[chain.id]?.Erc20PortalAddress) { - erc20PortalAddress = config[chain.id].Erc20PortalAddress; + if(config[toHex(chain.id)]?.Erc20PortalAddress) { + erc20PortalAddress = config[toHex(chain.id)].Erc20PortalAddress; } else { - console.error(`No erc20 portal address address defined for chain ${chain.id}`); - alert(`No erc20 portal address defined for chain ${chain.id}`); + console.error(`No erc20 portal address address defined for chain ${toHex(chain.id)}`); + alert(`No erc20 portal address defined for chain ${toHex(chain.id)}`); } let erc721PortalAddress = ""; - if(config[chain.id]?.Erc721PortalAddress) { - erc721PortalAddress = config[chain.id].Erc721PortalAddress; + if(config[toHex(chain.id)]?.Erc721PortalAddress) { + erc721PortalAddress = config[toHex(chain.id)].Erc721PortalAddress; } else { - console.error(`No erc721 portal address address defined for chain ${chain.id}`); - alert(`No erc721 portal address defined for chain ${chain.id}`); + console.error(`No erc721 portal address address defined for chain ${toHex(chain.id)}`); + alert(`No erc721 portal address defined for chain ${toHex(chain.id)}`); } let erc1155SinglePortalAddress = ""; - if(config[chain.id]?.Erc1155SinglePortalAddress) { - erc1155SinglePortalAddress = config[chain.id].Erc1155SinglePortalAddress; + if(config[toHex(chain.id)]?.Erc1155SinglePortalAddress) { + erc1155SinglePortalAddress = config[toHex(chain.id)].Erc1155SinglePortalAddress; } else { - console.error(`No erc1155 single portal address address defined for chain ${chain.id}`); - alert(`No erc1155 single portal address defined for chain ${chain.id}`); + console.error(`No erc1155 single portal address address defined for chain ${toHex(chain.id)}`); + alert(`No erc1155 single portal address defined for chain ${toHex(chain.id)}`); } let erc1155BatchPortalAddress = ""; - if(config[chain.id]?.Erc1155BatchPortalAddress) { - erc1155BatchPortalAddress = config[chain.id].Erc1155BatchPortalAddress; + if(config[toHex(chain.id)]?.Erc1155BatchPortalAddress) { + erc1155BatchPortalAddress = config[toHex(chain.id)].Erc1155BatchPortalAddress; } else { - console.error(`No erc1155 batch portal address address defined for chain ${chain.id}`); - alert(`No erc1155 batch portal address defined for chain ${chain.id}`); + console.error(`No erc1155 batch portal address address defined for chain ${toHex(chain.id)}`); + alert(`No erc1155 batch portal address defined for chain ${toHex(chain.id)}`); } // dapp contract const dappContract = CartesiDApp__factory.connect(dappAddress, signer); @@ -151,11 +150,11 @@ export const useRollups = (dAddress: string): RollupsContracts | undefined => { erc1155BatchPortalContract, }; }; - if (connectedWallet?.provider && connectedChain) { - connect(connectedChain).then((contracts) => { + if (address && chain) { + connect(chain).then((contracts) => { setContracts(contracts); }); } - }, [connectedWallet, connectedChain, dappAddress]); + }, [address, chain, dappAddress, signer]); return contracts; }; diff --git a/apps/frontend/next-app/app/component/Balance.tsx b/apps/frontend/next-app/app/component/Balance.tsx index bd9777c..839f2b7 100644 --- a/apps/frontend/next-app/app/component/Balance.tsx +++ b/apps/frontend/next-app/app/component/Balance.tsx @@ -12,12 +12,12 @@ import React, { useState } from "react"; import { useSetChain } from "@web3-onboard/react"; -import { ethers } from "ethers"; +import { ethers, parseEther } from "ethers"; // import { useRollups } from "./useRollups"; - +import { useAccount } from "wagmi"; import configFile from "./../cartesi/config.json"; -import { parseEther } from "ethers/lib/utils"; //import "./App.css" + import { Table, Thead, @@ -33,6 +33,8 @@ import { Box, Spacer } from '@chakra-ui/react' +import { useRollups } from "../cartesi/useRollups"; +import { toHex } from "viem"; const config: any = configFile; interface Report { @@ -40,24 +42,25 @@ interface Report { } export const Balance: React.FC = () => { - // const rollups = useRollups(); - const [{ connectedChain }] = useSetChain(); + const { chain } = useAccount(); + + // const rollups = useRollups("DApp Address"); const inspectCall = async (str: string) => { let payload = str; if (hexData) { - const uint8array = ethers.utils.arrayify(payload); + const uint8array = ethers.getBytes(payload); payload = new TextDecoder().decode(uint8array); } - if (!connectedChain){ + if (!chain){ return; } let apiURL= "" - if(config[connectedChain.id]?.inspectAPIURL) { - apiURL = `${config[connectedChain.id].inspectAPIURL}/inspect`; + if(config[toHex(chain.id)]?.inspectAPIURL) { + apiURL = `${config[toHex(chain.id)].inspectAPIURL}/inspect`; } else { - console.error(`No inspect interface defined for chain ${connectedChain.id}`); + console.error(`No inspect interface defined for chain ${toHex(chain.id)}`); return; } @@ -77,7 +80,7 @@ export const Balance: React.FC = () => { // Decode payload from each report const decode = data.reports.map((report: Report) => { - return ethers.utils.toUtf8String(report.payload); + return ethers.toUtf8String(report.payload); }); console.log("Decoded Reports:", decode); const reportData = JSON.parse(decode) @@ -95,15 +98,15 @@ export const Balance: React.FC = () => { const [postData, setPostData] = useState(false); return ( - + - - - + + + @@ -115,7 +118,7 @@ export const Balance: React.FC = () => { { {decodedReports && decodedReports.ether && ( - )} + )} { decodedReports && decodedReports.erc20 && ( }
EtherERC-20ERC-721EtherERC-20ERC-721
{ethers.utils.formatEther(decodedReports.ether)}{ethers.formatEther(decodedReports.ether)}
📍 {String(decodedReports.erc20).split(",")[0]}
@@ -129,7 +132,7 @@ export const Balance: React.FC = () => {
- +
diff --git a/apps/frontend/next-app/app/component/Button.tsx b/apps/frontend/next-app/app/component/Button.tsx deleted file mode 100644 index 187adc1..0000000 --- a/apps/frontend/next-app/app/component/Button.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { useState } from "react" - -interface ButtonProps extends React.ButtonHTMLAttributes { - -} - -export function Button(props: ButtonProps) { - const [disabled, setDisabled] = useState(false) - async function onClick(e: React.MouseEvent) { - try { - setDisabled(true) - if (props.onClick) { - await props.onClick(e) - } - } catch (e) { - console.error(e) - } finally { - setDisabled(false) - } - } - - return -} \ No newline at end of file diff --git a/apps/frontend/next-app/app/component/CustomButton.tsx b/apps/frontend/next-app/app/component/CustomButton.tsx new file mode 100644 index 0000000..2021de2 --- /dev/null +++ b/apps/frontend/next-app/app/component/CustomButton.tsx @@ -0,0 +1,107 @@ +import { ConnectButton } from '@rainbow-me/rainbowkit'; +import { FC } from 'react'; +import Image from 'next/image'; + +const CustomButton: FC = () => { + return ( +
+ + {({ + account, + chain, + openAccountModal, + openChainModal, + openConnectModal, + mounted, + }) => { + return ( +
+ {(() => { + if (!mounted || !account || !chain) { + return ( + + ); + } + + if (chain.unsupported) { + return ( + + ); + } + + return ( +
+ + + +
+ ); + })()} +
+ ); + }} +
+
+ ); +} + +export default CustomButton; diff --git a/apps/frontend/next-app/app/component/FooterItems.tsx b/apps/frontend/next-app/app/component/FooterItems.tsx new file mode 100644 index 0000000..71bf721 --- /dev/null +++ b/apps/frontend/next-app/app/component/FooterItems.tsx @@ -0,0 +1,59 @@ +import Link from "next/link" + +type FooterProps = { + title: string, + content?: string, + contentItems?: string[] +} + +const footerItems : FooterProps[] = [ + { + title: "Supported Templates", + contentItems: [ + "Reactjs & Nextjs", + "Cartesify Reactjs & Nextjs", + // "Javascript & Typescript" + ] + }, + // { + // title: "How to Use", + // contentItems: [ + // "Documentation", + // ] + // }, + { + title: "Follow Us", + contentItems: [ + "Twitter", + "Linkedln", + "Github" + ] + }, + + { + title: "Contribute", + contentItems: [ + "Github", + "Documentation" + ] + }, +] + + +const FooterItems: React.FC = () => { + return( +
+ {footerItems.map((item: FooterProps, index: any)=> + (
+

{item.title}

+
    +
  • + {item.contentItems?.map((item, index)=> (

    {item}

    ))} +
  • +
+
))} +
+ ) +} + +export default FooterItems \ No newline at end of file diff --git a/apps/frontend/next-app/app/component/Header.tsx b/apps/frontend/next-app/app/component/Header.tsx index 3cf070d..d7cc51e 100644 --- a/apps/frontend/next-app/app/component/Header.tsx +++ b/apps/frontend/next-app/app/component/Header.tsx @@ -3,10 +3,10 @@ import { useState } from "react"; import { ConnectButton } from "@rainbow-me/rainbowkit"; import Link from "next/link"; import Image from "next/image"; -import cartesi from "../../public/images/cartesikit-logo.png"; +import devkit from "../../public/images/devkit-logo.png"; import {FaBars} from 'react-icons/fa' import { IoCloseSharp } from "react-icons/io5"; -import { Network } from "./Network"; +import CustomButton from "./CustomButton"; const Header: React.FC = () => { const [isMenuOpen, setIsMenuOpen] = useState(false); @@ -16,22 +16,19 @@ const Header: React.FC = () => { }; return ( -
+

- logo + logo

- -

Greetings

- - -

Wallet

+ +

Wallet

- +
@@ -45,22 +42,17 @@ const Header: React.FC = () => { {isMenuOpen && (
{isMenuOpen && -
+
+ logo
}
- -
-

Greetings

- CartesiKit -
- - -

Wallet

+ +

Wallet

- +
diff --git a/apps/frontend/next-app/app/component/Network.tsx b/apps/frontend/next-app/app/component/Network.tsx deleted file mode 100644 index ef04585..0000000 --- a/apps/frontend/next-app/app/component/Network.tsx +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2022 Cartesi Pte. Ltd. - -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the license at http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -import { FC } from "react"; -import { useConnectWallet, useSetChain } from "@web3-onboard/react"; -import configFile from "../cartesi/config.json"; -import {Button, Select, Box, Badge, Spacer, Heading, Text, Stack } from "@chakra-ui/react" - -const config: any = configFile; - -export const Network: FC = () => { - const [{ wallet, connecting }, connect, disconnect] = useConnectWallet(); - const [{ chains, connectedChain, settingChain }, setChain] = useSetChain(); - - return ( - - {!wallet && - - - Welcome to CartesiKit Template! 💰 - - Assets are paramount for the functioning of dApps on-chain. This web interface will guide you on how to deposit and withdraw assets from a Cartesi rollups dApp. Play around and you'll learn a few tricks on how to build wallets for dApp chains. 🚀 - - - - - } - {wallet && ( - - {/* */} - {settingChain ? ( - Switching chain... - ) : ( - - )} - - - - - - )} - - ); -}; diff --git a/apps/frontend/next-app/app/component/Transfers.tsx b/apps/frontend/next-app/app/component/Transfers.tsx index c796e26..ffb2c92 100644 --- a/apps/frontend/next-app/app/component/Transfers.tsx +++ b/apps/frontend/next-app/app/component/Transfers.tsx @@ -1,3 +1,4 @@ +"use client" // Copyright 2022 Cartesi Pte. Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -11,25 +12,16 @@ // under the License. import React, { useState } from "react"; -import { ethers } from "ethers"; +import { ethers, parseEther, Provider } from "ethers"; import { useRollups } from "../cartesi/useRollups"; -import { useWallets } from "@web3-onboard/react"; import { IERC1155__factory, IERC20__factory, IERC721__factory, } from "../cartesi/generated/rollups"; -import { Tabs, TabList, TabPanels, TabPanel, Tab } from "@chakra-ui/react"; -import { Divider } from "@chakra-ui/react"; +import { Tabs, TabList, TabPanels, TabPanel, Tab, Card, CardBody } from "@chakra-ui/react"; import { useToast } from "@chakra-ui/react"; -import { Button, ButtonGroup, Box } from "@chakra-ui/react"; -import { - NumberInput, - NumberInputField, - NumberInputStepper, - NumberIncrementStepper, - NumberDecrementStepper, -} from "@chakra-ui/react"; +import { Button, Box } from "@chakra-ui/react"; import { Input, Stack, Flex } from "@chakra-ui/react"; import { Accordion, @@ -42,16 +34,25 @@ import { Text } from "@chakra-ui/react"; import { Vouchers } from "./../cartesi/Vouchers"; import { Notices } from "./../cartesi/Notices"; import { Reports } from "./../cartesi/Reports"; - +import { useEthersSigner } from "../utils/useEtherSigner"; +import toast from "react-hot-toast"; interface IInputPropos { dappAddress: string; } export const Transfers: React.FC = (propos) => { const rollups = useRollups(propos.dappAddress); - const [connectedWallet] = useWallets(); - const provider = new ethers.providers.Web3Provider(connectedWallet.provider); - const toast = useToast(); + const signer = useEthersSigner() + const provider = signer?.provider + + const [input, setInput] = useState(""); + const [dappRelayedAddress, setDappRelayedAddress] = useState(false) + const [erc20Amount, setErc20Amount] = useState(0); + const [erc20Token, setErc20Token] = useState(""); + const [erc721Id, setErc721Id] = useState(0); + const [erc721, setErc721] = useState(""); + const [etherAmount, setEtherAmount] = useState(0); + const [loadEther, setLoadEther] = useState(false) const sendAddress = async (str: string) => { if (rollups) { @@ -67,34 +68,35 @@ export const Transfers: React.FC = (propos) => { const depositErc20ToPortal = async (token: string, amount: number) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes( + const data = ethers.toUtf8Bytes( `Deposited (${amount}) of ERC20 (${token}).` ); //const data = `Deposited ${args.amount} tokens (${args.token}) for DAppERC20Portal(${portalAddress}) (signer: ${address})`; - const signer = provider.getSigner(); + // const signer = provider.getSigner(); const signerAddress = await signer.getAddress(); const erc20PortalAddress = rollups.erc20PortalContract.address; const tokenContract = signer ? IERC20__factory.connect(token, signer) - : IERC20__factory.connect(token, provider); + : IERC20__factory.connect(token, signer); // query current allowance const currentAllowance = await tokenContract.allowance( signerAddress, erc20PortalAddress ); - if (ethers.utils.parseEther(`${amount}`) > currentAllowance) { + if (parseEther(`${amount}`) > currentAllowance) { // Allow portal to withdraw `amount` tokens from signer const tx = await tokenContract.approve( erc20PortalAddress, - ethers.utils.parseEther(`${amount}`) + parseEther(`${amount}`) ); - const receipt = await tx.wait(1); + const trans = await signer.sendTransaction(tx) + const receipt = await trans.wait(); const event = ( await tokenContract.queryFilter( tokenContract.filters.Approval(), - receipt.blockHash + receipt?.hash ) ).pop(); if (!event) { @@ -107,7 +109,7 @@ export const Transfers: React.FC = (propos) => { await rollups.erc20PortalContract.depositERC20Tokens( token, propos.dappAddress, - ethers.utils.parseEther(`${amount}`), + ethers.parseEther(`${amount}`), data ); } @@ -119,26 +121,41 @@ export const Transfers: React.FC = (propos) => { const depositEtherToPortal = async (amount: number) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes(`Deposited (${amount}) ether.`); - const txOverrides = { value: ethers.utils.parseEther(`${amount}`) }; + setLoadEther(true) + const data = ethers.toUtf8Bytes(`Deposited (${amount}) ether.`); + const txOverrides = { value: parseEther(`${amount}`) }; console.log("Ether to deposit: ", txOverrides); // const tx = await ... - rollups.etherPortalContract.depositEther( + const trans = await rollups.etherPortalContract.depositEther( propos.dappAddress, data, txOverrides ); + const tx = await signer.sendTransaction(trans) + setLoadEther(false) + console.log(tx.hash) + toast(tx.hash, { + position: 'bottom-right', + }) + return tx.hash } - } catch (e) { + } catch (e: any) { + setLoadEther(false) console.log(`${e}`); + toast.error(e.message, { + position: 'bottom-right', + style: { + paddingRight: '40px', + }, + }) } }; const withdrawEther = async (amount: number) => { try { if (rollups && provider) { - let ether_amount = ethers.utils.parseEther(String(amount)).toString(); + let ether_amount = parseEther(String(amount)).toString(); console.log("ether after parsing: ", ether_amount); const input_obj = { method: "ether_withdraw", @@ -147,7 +164,7 @@ export const Transfers: React.FC = (propos) => { }, }; const data = JSON.stringify(input_obj); - let payload = ethers.utils.toUtf8Bytes(data); + let payload = ethers.toUtf8Bytes(data); await rollups.inputContract.addInput(propos.dappAddress, payload); } } catch (e) { @@ -158,7 +175,7 @@ export const Transfers: React.FC = (propos) => { const withdrawErc20 = async (amount: number, address: String) => { try { if (rollups && provider) { - let erc20_amount = ethers.utils.parseEther(String(amount)).toString(); + let erc20_amount = parseEther(String(amount)).toString(); console.log("erc20 after parsing: ", erc20_amount); const input_obj = { method: "erc20_withdraw", @@ -168,7 +185,7 @@ export const Transfers: React.FC = (propos) => { }, }; const data = JSON.stringify(input_obj); - let payload = ethers.utils.toUtf8Bytes(data); + let payload = ethers.toUtf8Bytes(data); await rollups.inputContract.addInput(propos.dappAddress, payload); } } catch (e) { @@ -189,7 +206,7 @@ export const Transfers: React.FC = (propos) => { }, }; const data = JSON.stringify(input_obj); - let payload = ethers.utils.toUtf8Bytes(data); + let payload = ethers.toUtf8Bytes(data); await rollups.inputContract.addInput(propos.dappAddress, payload); } } catch (e) { @@ -203,29 +220,30 @@ export const Transfers: React.FC = (propos) => { ) => { try { if (rollups && provider) { - const data = ethers.utils.toUtf8Bytes( + const data = ethers.toUtf8Bytes( `Deposited (${nftid}) of ERC721 (${contractAddress}).` ); //const data = `Deposited ${args.amount} tokens (${args.token}) for DAppERC20Portal(${portalAddress}) (signer: ${address})`; const signer = provider.getSigner(); - const signerAddress = await signer.getAddress(); + const signerAddress = await (await signer).getAddress(); const erc721PortalAddress = rollups.erc721PortalContract.address; const tokenContract = signer - ? IERC721__factory.connect(contractAddress, signer) - : IERC721__factory.connect(contractAddress, provider); + ? IERC721__factory.connect(contractAddress, await signer) + : IERC721__factory.connect(contractAddress, signer); // query current approval const currentApproval = await tokenContract.getApproved(nftid); if (currentApproval !== erc721PortalAddress) { // Allow portal to withdraw `amount` tokens from signer const tx = await tokenContract.approve(erc721PortalAddress, nftid); - const receipt = await tx.wait(1); + const trans = await (await signer).sendTransaction(tx) + const receipt = await trans.wait(1); const event = ( await tokenContract.queryFilter( tokenContract.filters.Approval(), - receipt.blockHash + receipt?.hash ) ).pop(); if (!event) { @@ -249,52 +267,56 @@ export const Transfers: React.FC = (propos) => { } }; - const [input, setInput] = useState(""); - const [dappRelayedAddress, setDappRelayedAddress] = useState(false) - const [hexInput, setHexInput] = useState(false); - const [erc20Amount, setErc20Amount] = useState(0); - const [erc20Token, setErc20Token] = useState(""); - const [erc721Id, setErc721Id] = useState(0); - const [erc721, setErc721] = useState(""); - const [etherAmount, setEtherAmount] = useState(0); - return ( + - - 🚀 Transfer - 🎟️ Vouchers - 🔔 Activity + + 🚀 Transfer + 🎟️ Vouchers + 🔔 Activity - + Cartesi dApps recieve asset deposits via Portal smart contracts on the base layer. -
- - +
+ +

- + Ether

+ - setEtherAmount(Number(value))} + borderWidth="0.1px" + borderColor="slategrey" + color="slategrey" + type="number" + variant="outline" + placeholder="Enter amount" + onChange={(e) => setEtherAmount(Number(e.target.value))} value={etherAmount} - > - - - - - - + />
); }; diff --git a/apps/frontend/next-app/app/component/footer.tsx b/apps/frontend/next-app/app/component/footer.tsx index fb9ad3d..5c5c765 100644 --- a/apps/frontend/next-app/app/component/footer.tsx +++ b/apps/frontend/next-app/app/component/footer.tsx @@ -1,13 +1,20 @@ import Link from "next/link" +import FooterItems from "./FooterItems" +import devkit from "../../public/images/devkit-logo.png"; +import Image from "next/image"; const Footer: React.FC = () => { return( -
- This template was built with 💟 for the Cartesi community by: - - gconnect - - +
+
+ logo + This template was built with 💟 for the Cartesi community by: + + Africinnovate Team + + +
+
) } diff --git a/apps/frontend/next-app/app/globals.css b/apps/frontend/next-app/app/globals.css index 875c01e..ae1606d 100644 --- a/apps/frontend/next-app/app/globals.css +++ b/apps/frontend/next-app/app/globals.css @@ -17,13 +17,14 @@ } body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( + color: white; + /* background-color: #05051F; */ + /* background: linear-gradient( to bottom, transparent, rgb(var(--background-end-rgb)) ) - rgb(var(--background-start-rgb)); + rgb(var(--background-start-rgb)); */ } @layer utilities { diff --git a/apps/frontend/next-app/app/greetings/page.tsx b/apps/frontend/next-app/app/greetings/page.tsx new file mode 100644 index 0000000..0d5e7df --- /dev/null +++ b/apps/frontend/next-app/app/greetings/page.tsx @@ -0,0 +1,71 @@ +'use client' +import {useState, useEffect } from 'react' +import { useAccount } from 'wagmi' +import { useEthersSigner } from '../utils/useEtherSigner' +import { BASE_URL, DAPP_ADDRESS } from '@/app/utils/constants' +import { Box } from '@chakra-ui/react' +import { useRollups } from '../cartesi/useRollups' +import toast from 'react-hot-toast' + +export default function Greetings() { + const [result, setResult] = useState("") + // const [signer, setSigner] = useState(undefined) + const [loading, setLoading] = useState(false) + const [greeting, setGreeting] = useState('') + const [loadGreeting, setLoadGreeting] = useState(false) + const rollups = useRollups(DAPP_ADDRESS); + const { isConnected } = useAccount(); + const signer = useEthersSigner() + const provider = signer?.provider + + const handleMessageChange = (e: React.ChangeEvent) =>{ + console.log(e.target.value) + setGreeting(e.target.value) +} + const jsonPayload = JSON.stringify({ + method: 'sendgreeting', + data: greeting, + }) + + const sendGreeting = async () => { + if(!isConnected) return toast("Please connect your wallet") + if (rollups) { + try { + const trans = await rollups.inputContract.addInput(JSON.stringify(jsonPayload), DAPP_ADDRESS); + const tx = await signer?.sendTransaction(trans) + const receipt = await tx?.wait() + console.log("receipt", receipt?.hash) + return receipt?.hash + } catch (e) { + console.log(`${e}`); + } + } + }; + + + const getGreeting = async () => { + if(!isConnected) return toast("Please connect your wallet") + console.log("Hello world") + } + + + + return ( +
+

Welcome! Say Hello 👋

+ + + + + +

+ {greeting && greeting} +

+

{`Result: ${result}`}

+
+ ); +} diff --git a/apps/frontend/next-app/app/layout copy.tsx b/apps/frontend/next-app/app/layout copy.tsx new file mode 100644 index 0000000..198ba72 --- /dev/null +++ b/apps/frontend/next-app/app/layout copy.tsx @@ -0,0 +1,73 @@ +"use client" +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; +import '@rainbow-me/rainbowkit/styles.css'; +import Header from "./component/Header"; +import { GraphQLProvider } from "./cartesi/GraphQL"; +import { useState } from "react"; +import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client' +import { Toaster } from 'react-hot-toast' +import { ChakraProviders } from './chakraProvider' +import { + ChakraBaseProvider, + extendBaseTheme, + theme as chakraTheme, +} from '@chakra-ui/react' + +const inter = Inter({ subsets: ["latin"] }); + +// export const metadata: Metadata = { +// title: "Create Next App", +// description: "Generated by create next app", +// }; + +import configFile from "./cartesi/config.json"; + +const config: any = configFile; + +import injectedModule from "@web3-onboard/injected-wallets"; +import { init } from "@web3-onboard/react"; + +const injected: any = injectedModule(); +init({ + wallets: [injected], + chains: Object.entries(config).map(([k, v]: [string, any], i) => ({id: k, token: v.token, label: v.label, rpcUrl: v.rpcUrl})), + appMetadata: { + name: "Cartesi Rollups Test DApp", + icon: "", + description: "Demo app for Cartesi Rollups", + recommendedInjectedWallets: [ + { name: "MetaMask", url: "https://metamask.io" }, + ], + }, +}); + +//Setup GraphQL Apollo client +// const URL_QUERY_GRAPHQL = 'http://localhost:8080/graphql' +const URL_QUERY_GRAPHQL = 'http://localhost:8080/host-runner' + +const client = new ApolloClient({ + uri: URL_QUERY_GRAPHQL, + cache: new InMemoryCache(), +}) + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>){ + return ( + + + + + {/*
*/} + {children} + + + + + + ); +} diff --git a/apps/frontend/next-app/app/layout.tsx b/apps/frontend/next-app/app/layout.tsx index 198ba72..b9b6172 100644 --- a/apps/frontend/next-app/app/layout.tsx +++ b/apps/frontend/next-app/app/layout.tsx @@ -2,72 +2,74 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; +import { useMemo, createContext, useContext, useState } from 'react'; import '@rainbow-me/rainbowkit/styles.css'; +import { Providers } from './utils/providers'; import Header from "./component/Header"; -import { GraphQLProvider } from "./cartesi/GraphQL"; -import { useState } from "react"; +import Footer from "./component/Footer"; +import { ChakraProvider } from "@chakra-ui/react"; +// import { Provider as URQLProvider } from "urql"; import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client' import { Toaster } from 'react-hot-toast' -import { ChakraProviders } from './chakraProvider' import { - ChakraBaseProvider, - extendBaseTheme, - theme as chakraTheme, -} from '@chakra-ui/react' - + UrqlProvider, + ssrExchange, + cacheExchange, + fetchExchange, + createClient, +} from '@urql/next'; +import GraphQLClient from "./GraphqlClient"; const inter = Inter({ subsets: ["latin"] }); // export const metadata: Metadata = { // title: "Create Next App", // description: "Generated by create next app", // }; - -import configFile from "./cartesi/config.json"; - -const config: any = configFile; - -import injectedModule from "@web3-onboard/injected-wallets"; -import { init } from "@web3-onboard/react"; - -const injected: any = injectedModule(); -init({ - wallets: [injected], - chains: Object.entries(config).map(([k, v]: [string, any], i) => ({id: k, token: v.token, label: v.label, rpcUrl: v.rpcUrl})), - appMetadata: { - name: "Cartesi Rollups Test DApp", - icon: "", - description: "Demo app for Cartesi Rollups", - recommendedInjectedWallets: [ - { name: "MetaMask", url: "https://metamask.io" }, - ], - }, -}); +const API_BASE_URL = 'http://localhost:8080/graphql' //Setup GraphQL Apollo client // const URL_QUERY_GRAPHQL = 'http://localhost:8080/graphql' -const URL_QUERY_GRAPHQL = 'http://localhost:8080/host-runner' +// const URL_QUERY_GRAPHQL = 'http://localhost:8080/host-runner' -const client = new ApolloClient({ - uri: URL_QUERY_GRAPHQL, - cache: new InMemoryCache(), -}) +// const client = new ApolloClient({ +// uri: URL_QUERY_GRAPHQL, +// cache: new InMemoryCache(), +// }) export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; -}>){ +}>) { + + const [client, ssr] = useMemo(() => { + const ssr = ssrExchange({ + isClient: typeof window !== 'undefined', + }); + const client = createClient({ + url: API_BASE_URL, + exchanges: [cacheExchange, ssr, fetchExchange], + suspense: true, + }); + + return [client, ssr]; + }, []); + return ( - - - - {/*
*/} - {children} - - - - + + + + +
+ { children } +