diff --git a/frontend/src/components/atoms/etherscanLink.tsx b/frontend/src/components/atoms/etherscanLink.tsx new file mode 100644 index 0000000..9e1aa27 --- /dev/null +++ b/frontend/src/components/atoms/etherscanLink.tsx @@ -0,0 +1,15 @@ +import { Link } from "react-daisyui"; +import { shortTransaction } from "utils/shortTransaction"; + +export const EtherScanLink = ({ hash }: { hash: `0x${string}` }) => { + return ( + + {shortTransaction(hash)} + + ); +}; diff --git a/frontend/src/components/homePage/events/event.tsx b/frontend/src/components/homePage/events/event.tsx index 109cc25..daaa112 100644 --- a/frontend/src/components/homePage/events/event.tsx +++ b/frontend/src/components/homePage/events/event.tsx @@ -3,6 +3,11 @@ import { Event, EventType, Payload } from "types/events"; import { Card } from "react-daisyui"; import { motion } from "framer-motion"; +import { EtherScanLink } from "components/atoms/etherscanLink"; +import { GLMAmountStat } from "components/atoms/GLMAmount"; +import { formatBalance } from "utils/formatBalance"; +import { parseEther } from "viem"; +import dayjs from "dayjs"; const variants = { visible: { opacity: 1, transition: { duration: 1 } }, hidden: { opacity: 0, transition: { duration: 1 } }, @@ -42,6 +47,44 @@ const AllocationReleasedEvent = (event: { ); }; +const DepositCreatedEvent = (event: { + kind: Event.DEPOSIT_CREATED; + payload: Payload[Event.DEPOSIT_CREATED]; +}) => { + return ( + + + Deposit Created +
+
+
TX Hash:
+ + +
+
+
Amount:
+ {" "} +
+
+
Fee:
+ {" "} +
+
+
Valid to:
+ {dayjs(event.payload.validityTimestamp).format("YYYY-MM-DD HH:mm")} +
+
+
+
+ ); +}; + export const EventCard = (event: EventType) => { return ( @@ -51,6 +94,8 @@ export const EventCard = (event: EventType) => { return ; case Event.ALLOCATION_RELEASED: return ; + case Event.DEPOSIT_CREATED: + return ; } })()} diff --git a/frontend/src/components/homePage/events/events.tsx b/frontend/src/components/homePage/events/events.tsx index 578218e..2e1d1bd 100644 --- a/frontend/src/components/homePage/events/events.tsx +++ b/frontend/src/components/homePage/events/events.tsx @@ -3,7 +3,8 @@ import { EventType } from "types/events"; import { useAllocationEvents } from "hooks/events/useAllocationEvents"; import { EventCard } from "./event"; import { uniqBy } from "ramda"; -import { use } from "i18next"; +import { useDepositEvents } from "hooks/events/useDepositEvents"; +import { merge } from "rxjs"; export const Events = () => { const [events, setEvents] = useState< @@ -13,10 +14,10 @@ export const Events = () => { })[] >([]); const { events$: allocationEvents$ } = useAllocationEvents(); + const { events$: depositEvents$ } = useDepositEvents(); useEffect(() => { - const sub = allocationEvents$.subscribe((event) => { - console; + const sub = merge(allocationEvents$, depositEvents$).subscribe((event) => { setEvents((prevEvents) => { return uniqBy( (e) => { diff --git a/frontend/src/components/homePage/modals/createDepositForm.tsx b/frontend/src/components/homePage/modals/createDepositForm.tsx deleted file mode 100644 index 95be1de..0000000 --- a/frontend/src/components/homePage/modals/createDepositForm.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import dayjs from "dayjs"; -import { AnimatePresence, motion } from "framer-motion"; -import { useCreateDeposit } from "hooks/depositContract/useDeposit"; -import { useSaveDeposit } from "hooks/useSaveDeposit"; - -import { useEffect, useState } from "react"; -import { Button, Card, Input, Loading } from "react-daisyui"; -import { useAccount, useWaitForTransactionReceipt } from "wagmi"; -import { GLMAmountInput } from "./molecules/glmAmountInput/glmAmountInput"; - -export const CreateDepositForm = () => { - const { - data, - createDeposit, - setFee, - error: errorPrepareDeposit, - setAmount, - isPending, - setValidToTimestamp, - } = useCreateDeposit(); - - const { - isSuccess: isSuccessTransaction, - isError: isErrorTransaction, - isLoading: isLoadingTransaction, - } = useWaitForTransactionReceipt({ - hash: data, - }); - - const [nonce, setNonce] = useState(0); - const [depositId, setDepositId] = useState(""); - const { - saveDeposit, - isSuccess: isSuccessSaveDeposit, - isError: isErrorSaveDeposit, - } = useSaveDeposit(); - const { address } = useAccount(); - if (!address) { - throw new Error("Address not found"); - } - - const [isProcessing, setIsProcessing] = useState(false); - - useEffect(() => { - console.log("da", data); - }, [data]); - - useEffect(() => { - console.log("isSuccessTransaction", isSuccessTransaction); - console.log("isErrorTransaction", isErrorTransaction); - if (isSuccessTransaction) { - setTimeout(() => { - saveDeposit({ - nonce, - id: depositId, - funder: address, - }); - }, 1000); - } - }, [isSuccessTransaction, isErrorTransaction, nonce]); - - useEffect(() => { - if (isPending) { - setIsProcessing(true); - } - - if (isErrorSaveDeposit || isSuccessSaveDeposit) { - setIsProcessing(false); - } - }, [isPending, isErrorSaveDeposit, isSuccessSaveDeposit]); - - return ( - <> -
- In order to pay for the service deposit in GLMs is needed. We - intentionally render here form with fee and valid to timestamp for idea - presentation purposes (try to set fee smaller than 10% of amount) In - real world scenario both fee and valid to timestamp should be calculated - by the backend. -
-
-
- - - { - setValidToTimestamp(dayjs(e.target.value).unix()); - }} - style={{ - color: "gray", - }} - /> -
-
- - ); -}; diff --git a/frontend/src/components/homePage/modals/deposit/createDeposit.tsx b/frontend/src/components/homePage/modals/deposit/createDeposit.tsx index 1a0a20d..58a3659 100644 --- a/frontend/src/components/homePage/modals/deposit/createDeposit.tsx +++ b/frontend/src/components/homePage/modals/deposit/createDeposit.tsx @@ -10,12 +10,13 @@ const log = debug("CreateDeposit"); export const CreateDeposit = () => { const { - data, createDeposit, setFee, - error: errorPrepareDeposit, setAmount, isPending, + isSuccess, + isError, + isLoading, validToTimestamp, setValidToTimestamp, depositId, @@ -23,25 +24,15 @@ export const CreateDeposit = () => { errorContext, } = useCreateDeposit(); - const { - isSuccess: isSuccessTransaction, - isError: isErrorTransaction, - isLoading: isLoadingTransaction, - isPending: isPendingTransaction, - } = useWaitForTransactionReceipt({ - hash: data, - }); - const { saveDeposit } = useSaveDeposit(); const { address } = useAccount(); + if (!address) { throw new Error("Address not found"); } - const [isProcessing, setIsProcessing] = useState(false); - useEffect(() => { - if (isSuccessTransaction) { + if (isSuccess) { setTimeout(() => { log("saving deposit", depositId); log("nonce", nonce); @@ -54,14 +45,14 @@ export const CreateDeposit = () => { }); }, 1000); } - }, [isSuccessTransaction, isErrorTransaction, nonce, depositId]); + }, [isSuccess, isError, nonce, depositId]); return ( { + if (isSuccess && data) { + console.log("emit", data); + emit({ + txHash: data, + amount: amount, + fee: fee, + validityTimestamp: validToTimestamp, + }); + } + }, [isSuccess, data]); + const { data: contractSimulationData, error: simulationError } = useSimulateContract({ address: config.depositContractAddress[chainId], @@ -70,11 +93,13 @@ export function useCreateDeposit() { }; }, data, - isError, - isSuccess, + error, setFee, isPending, + isSuccess, + isError, + isLoading, isIdle, setValidToTimestamp, validToTimestamp, diff --git a/frontend/src/hooks/events/useCreateAllocationEvents.tsx b/frontend/src/hooks/events/useCreateAllocationEvents.tsx index 20618d8..c1fc8df 100644 --- a/frontend/src/hooks/events/useCreateAllocationEvents.tsx +++ b/frontend/src/hooks/events/useCreateAllocationEvents.tsx @@ -1,7 +1,7 @@ -import { useSyncExternalEvents } from "./useSyncExternalEvent"; import { Event } from "types/events"; +import { useEvents } from "./useEvents"; export const useCreateAllocationEvents = () => { - return useSyncExternalEvents({ + return useEvents({ eventKind: Event.ALLOCATION_CREATED, key: "allocationCreatedEvents", }); diff --git a/frontend/src/hooks/events/useDepositCreatedEvents.tsx b/frontend/src/hooks/events/useDepositCreatedEvents.tsx new file mode 100644 index 0000000..1ed7222 --- /dev/null +++ b/frontend/src/hooks/events/useDepositCreatedEvents.tsx @@ -0,0 +1,8 @@ +import { Event } from "types/events"; +import { useEvents } from "./useEvents"; +export const useDepositCreatedEvents = () => { + return useEvents({ + eventKind: Event.DEPOSIT_CREATED, + key: "depositCreatedEvents", + }); +}; diff --git a/frontend/src/hooks/events/useDepositEvents.tsx b/frontend/src/hooks/events/useDepositEvents.tsx new file mode 100644 index 0000000..060b2b9 --- /dev/null +++ b/frontend/src/hooks/events/useDepositEvents.tsx @@ -0,0 +1,12 @@ +import { merge } from "rxjs"; +import { useDepositReleasedEvents } from "./useDepositReleasedEvents"; +import { useDepositCreatedEvents } from "./useDepositCreatedEvents"; + +export const useDepositEvents = () => { + const { events$: depositCreatedEvents$ } = useDepositCreatedEvents(); + const { events$: depositReleasedEvents$ } = useDepositReleasedEvents(); + + return { + events$: merge(depositReleasedEvents$, depositCreatedEvents$), + }; +}; diff --git a/frontend/src/hooks/events/useDepositReleasedEvents.ts b/frontend/src/hooks/events/useDepositReleasedEvents.ts new file mode 100644 index 0000000..575cf55 --- /dev/null +++ b/frontend/src/hooks/events/useDepositReleasedEvents.ts @@ -0,0 +1,8 @@ +import { Event } from "types/events"; +import { useEvents } from "./useEvents"; +export const useDepositReleasedEvents = () => { + return useEvents({ + eventKind: Event.DEPOSIT_CREATED, + key: "allocationCreatedEvents", + }); +}; diff --git a/frontend/src/hooks/events/useSyncExternalEvent.ts b/frontend/src/hooks/events/useEvents.ts similarity index 65% rename from frontend/src/hooks/events/useSyncExternalEvent.ts rename to frontend/src/hooks/events/useEvents.ts index 345328b..8fdf37f 100644 --- a/frontend/src/hooks/events/useSyncExternalEvent.ts +++ b/frontend/src/hooks/events/useEvents.ts @@ -5,7 +5,47 @@ import useLocalStorageState from "use-local-storage-state"; const getId = (e: any) => e.id; -export const useSyncExternalEvents = ({ +// const subject = new Subject(); + +// const initialState: Task[] = []; + +// let state = initialState; + +// export const eventStore = { +// init: (state) => { +// subject.next(state); +// }, +// subscribe: (setState: any) => { +// subject.subscribe(setState); +// }, +// addTask: (content: string) => { +// const task = { +// content, +// id: uid(), +// isDone: false, +// }; +// state = [...state, task]; +// subject.next(state); +// }, +// removeTask: (id: string) => { +// const tasks = state.filter((task) => task.id !== id); +// state = tasks; +// subject.next(state); +// }, +// completeTask: (id: string) => { +// const tasks = state.map((task) => { +// if (task.id === id) { +// task.isDone = !task.isDone; +// } +// return task; +// }); +// state = tasks; +// subject.next(state); +// }, +// initialState, +// }; + +export const useEvents = ({ key, eventKind, }: { diff --git a/frontend/src/hooks/events/useReleaseAllocationEvents.tsx b/frontend/src/hooks/events/useReleaseAllocationEvents.tsx index 1e7c553..7ae5410 100644 --- a/frontend/src/hooks/events/useReleaseAllocationEvents.tsx +++ b/frontend/src/hooks/events/useReleaseAllocationEvents.tsx @@ -1,9 +1,8 @@ -import { useSyncExternalEvents } from "./useSyncExternalEvent"; - import { Event } from "types/events"; +import { useEvents } from "./useEvents"; export const useReleaseAllocationEvents = () => { - return useSyncExternalEvents({ + return useEvents({ eventKind: Event.ALLOCATION_RELEASED, key: "allocationReleasedEvents", }); diff --git a/frontend/src/hooks/useWatchContractEvents.ts b/frontend/src/hooks/useWatchContractEvents.ts new file mode 100644 index 0000000..5fb4bf1 --- /dev/null +++ b/frontend/src/hooks/useWatchContractEvents.ts @@ -0,0 +1,58 @@ +import { useEvents } from "hooks/events/useEvents"; + +import { Event } from "types/events"; +import { useWatchContractEvent } from "wagmi/dist/types/hooks/useWatchContractEvent"; + +export const useContractEvent = ({ + address, + abi, + //blockchain event name + eventName, + storageKey, + // internal event kind + eventKind, +}: { + address: `0x${string}`; + abi: any; + eventName: string; + storageKey: string; + eventKind: Event; +}) => { + const { emit, events$ } = useEvents({ + eventKind, + key: storageKey, + }); + + useWatchContractEvent({ + address, + abi, + eventName, + onLogs: (logs: any[]) => { + logs.forEach((log) => { + console.log("log", log); + emit(log); + }); + }, + }); +}; +// import { config } from "config"; +// import { holesky } from "viem/chains"; +// import { useWatchContractEvent } from "wagmi"; +// import { abi } from "./abi"; +// import { useCallback } from "react"; +// export const useWatchDepositPayments = () => { +// const onLogs = useCallback((logs: any) => { +// console.log("Deposit", logs); +// }, []); + +// useWatchContractEvent({ +// address: config.depositContractAddress[holesky.id], +// abi: abi, +// eventName: "DepositFeeTransfer", +// // args: { +// // owner: address, +// // spender: requestor?.wallet, +// // }, +// onLogs: onLogs, +// }); +// }; diff --git a/frontend/src/types/events.ts b/frontend/src/types/events.ts index 18c1ba7..bd3022c 100644 --- a/frontend/src/types/events.ts +++ b/frontend/src/types/events.ts @@ -16,7 +16,7 @@ export enum Event { export type Payload = { [Event.DEPOSIT_CREATED]: { - transactionHash: string; + txHash: `0x${string}`; amount: number; fee: number; validityTimestamp: number;