diff --git a/.env.example b/.env.example index 33bc1b4..b8d1c76 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,5 @@ VITE_REOWN_PROJECT_ID=YOUR_PROJECT_ID VITE_ETHEREUM_MAINNET_RPC=YOUR_MAINNET_RPC_URL -VITE_ETHREUM_SEPOLIA_RPC=YOUR_SEPOLIA_RPC_URL \ No newline at end of file +VITE_ETHEREUM_SEPOLIA_RPC=YOUR_SEPOLIA_RPC_URL +VITE_IPFS_UPLOAD_URL=YOUR_IPFS_UPLOAD_URL +VITE_IPFS_GATEWAY_URL=YOUR_IPFS_GATEWAY_URL \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4abe73e..af20c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ dist-ssr # Environment variables .env + +# Yarn +.yarn/install-state.gz \ No newline at end of file diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz deleted file mode 100644 index e7a62aa..0000000 Binary files a/.yarn/install-state.gz and /dev/null differ diff --git a/README.md b/README.md index 6843fd9..7586678 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ # Escrow V1 UI -Local development: +For local development: + +1. Install dependencies: + +```bash +yarn install +``` + +2. Generate hooks using `wagmi/cli`: + +```bash +yarn generate +``` + +3. Run: ```bash -yarn install && yarn dev -``` \ No newline at end of file +yarn dev +``` diff --git a/package.json b/package.json index fb806ef..e814234 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,11 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "generate": "wagmi generate" }, "dependencies": { - "@kleros/ui-components-library": "^3.3.4", + "@kleros/ui-components-library": "^3.4.5", "@reown/appkit": "^1.7.6", "@reown/appkit-adapter-wagmi": "^1.7.6", "@tanstack/react-query": "^5.76.1", @@ -26,6 +27,7 @@ "@types/react": "^18.2.55", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.4.1", + "@wagmi/cli": "^2.3.1", "eslint": "^9.25.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", diff --git a/src/App.tsx b/src/App.tsx index 29450c4..11b4385 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,8 @@ import { BrowserRouter, Routes, Route } from "react-router"; import { Providers } from "./providers"; import Layout from "layout/Layout"; -import Home from "components/Home/Home"; +import Home from "pages/Home/Home"; +import Transaction from "pages/Transaction/Transaction"; function App() { return ( @@ -10,6 +11,10 @@ function App() { }> } /> + } + /> diff --git a/src/assets/doc.svg b/src/assets/doc.svg new file mode 100644 index 0000000..ba8258a --- /dev/null +++ b/src/assets/doc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/etherscan.svg b/src/assets/etherscan.svg new file mode 100644 index 0000000..37ec3d2 --- /dev/null +++ b/src/assets/etherscan.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/components/common/IconButton.ts b/src/components/Common/Buttons/IconButton.ts similarity index 100% rename from src/components/common/IconButton.ts rename to src/components/Common/Buttons/IconButton.ts diff --git a/src/components/Common/Skeleton/BaseSkeleton.ts b/src/components/Common/Skeleton/BaseSkeleton.ts new file mode 100644 index 0000000..fafd25b --- /dev/null +++ b/src/components/Common/Skeleton/BaseSkeleton.ts @@ -0,0 +1,6 @@ +import styled from "styled-components"; + +export const BaseSkeleton = styled.div` + animation: ${({ theme }) => theme.animations.loading}; + background-color: ${({ theme }) => theme.colors.tintPurple}; +`; diff --git a/src/components/Footer/KlerosLinks/KlerosLinks.tsx b/src/components/Footer/KlerosLinks/KlerosLinks.tsx index f8c7804..0c28508 100644 --- a/src/components/Footer/KlerosLinks/KlerosLinks.tsx +++ b/src/components/Footer/KlerosLinks/KlerosLinks.tsx @@ -1,4 +1,4 @@ -import { IconButton } from "components/common/IconButton"; +import { IconButton } from "components/Common/Buttons/IconButton"; import styled from "styled-components"; import Discord from "assets/discord.svg?react"; import Blog from "assets/blog.svg?react"; diff --git a/src/components/Header/ConnectWallet/ConnectButton/ConnectButton.tsx b/src/components/Header/ConnectWallet/ConnectButton/ConnectButton.tsx index be740e1..08d6536 100644 --- a/src/components/Header/ConnectWallet/ConnectButton/ConnectButton.tsx +++ b/src/components/Header/ConnectWallet/ConnectButton/ConnectButton.tsx @@ -10,7 +10,7 @@ export default function ConnectButton() { isDisabled={isOpen} small text={"Connect Wallet"} - onClick={async () => open({ view: "Connect" })} + onPress={async () => open({ view: "Connect" })} /> ); } diff --git a/src/components/Header/ConnectWallet/ConnectedMenu/ConnectedMenu.tsx b/src/components/Header/ConnectWallet/ConnectedMenu/ConnectedMenu.tsx index 0dad184..7ecc9cd 100644 --- a/src/components/Header/ConnectWallet/ConnectedMenu/ConnectedMenu.tsx +++ b/src/components/Header/ConnectWallet/ConnectedMenu/ConnectedMenu.tsx @@ -1,6 +1,7 @@ import { Button, Tag } from "@kleros/ui-components-library"; import { useState, useRef, useEffect } from "react"; import styled from "styled-components"; +import { addressToShortString } from "utils/common"; import { useAccount, useDisconnect } from "wagmi"; const Container = styled.div` @@ -10,6 +11,9 @@ const Container = styled.div` const CustomTag = styled(Tag)` font-weight: bold; background-color: transparent; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; &:hover { opacity: 0.8; @@ -66,9 +70,7 @@ export default function ConnectedMenu() { setIsMenuOpen(!isMenuOpen)} /> {isMenuOpen && ( diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 65d050d..44febdd 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -3,6 +3,7 @@ import KlerosEscrowLogo from "assets/kleros.svg?react"; import ConnectWallet from "./ConnectWallet/ConnectWallet"; import ToggleTheme from "./ToggleTheme/ToggleTheme"; import Tutorial from "./Tutorial/Tutorial"; +import { Link } from "react-router"; const Container = styled.header` display: flex; @@ -17,6 +18,12 @@ const Container = styled.header` : theme.colors.primaryPurple}; padding: 8px 16px; justify-content: space-between; + + @media (max-width: ${({ theme }) => theme.breakpoints.xs}) { + height: 120px; + flex-direction: column; + align-items: center; + } `; const EscrowLogo = styled(KlerosEscrowLogo)` @@ -33,7 +40,9 @@ const OptionsContainer = styled.div` export default function Header() { return ( - + + + diff --git a/src/components/Header/ToggleTheme/ToggleTheme.tsx b/src/components/Header/ToggleTheme/ToggleTheme.tsx index 0306d40..bb2471a 100644 --- a/src/components/Header/ToggleTheme/ToggleTheme.tsx +++ b/src/components/Header/ToggleTheme/ToggleTheme.tsx @@ -1,6 +1,6 @@ import Moon from "assets/moon.svg?react"; import Sun from "assets/sun.svg?react"; -import { IconButton } from "components/common/IconButton"; +import { IconButton } from "components/Common/Buttons/IconButton"; import { useThemeContext } from "context/theme/useThemeContext"; export default function ToggleTheme() { diff --git a/src/components/Header/Tutorial/Tutorial.tsx b/src/components/Header/Tutorial/Tutorial.tsx index 544bcde..14291a6 100644 --- a/src/components/Header/Tutorial/Tutorial.tsx +++ b/src/components/Header/Tutorial/Tutorial.tsx @@ -1,4 +1,4 @@ -import { IconButton } from "components/common/IconButton"; +import { IconButton } from "components/Common/Buttons/IconButton"; import InfoCircleFull from "assets/info-circle-full.svg?react"; export default function Tutorial() { diff --git a/src/components/Home/Home.tsx b/src/components/Home/Home.tsx deleted file mode 100644 index 43f7945..0000000 --- a/src/components/Home/Home.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { useTransactions } from "hooks/useTransactions"; - -export default function Home() { - const { data: transactions } = useTransactions(); - console.log("## transactions: ", transactions); - return
Hello World
; -} diff --git a/src/components/Transactions/DisplayTransactions/DisplayTransactions.tsx b/src/components/Transactions/DisplayTransactions/DisplayTransactions.tsx new file mode 100644 index 0000000..b9b82e4 --- /dev/null +++ b/src/components/Transactions/DisplayTransactions/DisplayTransactions.tsx @@ -0,0 +1,72 @@ +import { useTransactions } from "hooks/useTransactions"; +import TransactionCard from "../TransactionCard/TransactionCard"; +import styled from "styled-components"; +import { BaseSkeleton } from "components/Common/Skeleton/BaseSkeleton"; +import { useMemo, useState } from "react"; +import { Searchbar } from "@kleros/ui-components-library"; + +const Container = styled.div` + display: flex; + flex-direction: column; + gap: 16px; + width: 80%; +`; + +const StyledSearchbar = styled(Searchbar)` + width: 100%; +`; + +const CardContainer = styled.div` + display: grid; + grid-template-columns: repeat( + auto-fill, + minmax(min(100%, max(312px, (100% - 16px * 2)/3)), 1fr) + ); + align-items: center; + gap: 16px; +`; + +const SkeletonCard = styled(BaseSkeleton)` + border-radius: ${({ theme }) => theme.radius.base}; + height: 200px; +`; + +export default function DisplayTransactions() { + const { data: transactions, isFetching } = useTransactions(); + const [search, setSearch] = useState(""); + + //Allow users to filter transactions by title or address + const filteredTransactions = useMemo(() => { + if (!search) return transactions; + + const searchLower = search.toLowerCase(); + return transactions.filter( + (transaction) => + transaction.metaEvidence.title.toLowerCase().includes(searchLower) || + transaction.metaEvidence.sender.toLowerCase().includes(searchLower) || + transaction.metaEvidence.receiver.toLowerCase().includes(searchLower) + ); + }, [transactions, search]); + + return ( + + setSearch(value)} + /> + + + {isFetching + ? [...Array(9)].map((_, i) => ) + : filteredTransactions.map((transaction) => ( + + ))} + + + ); +} diff --git a/src/components/Transactions/TransactionCard/TransactionCard.tsx b/src/components/Transactions/TransactionCard/TransactionCard.tsx new file mode 100644 index 0000000..cb2009b --- /dev/null +++ b/src/components/Transactions/TransactionCard/TransactionCard.tsx @@ -0,0 +1,102 @@ +import { Card, Tag } from "@kleros/ui-components-library"; +import { type TransactionMini } from "model/Transaction"; +import { Link } from "react-router"; +import styled from "styled-components"; +import { addressToShortString } from "utils/common"; +import { TransactionStatusTag } from "components/Transactions/TransactionStatusTag/TransactionStatusTag"; + +const StyledCard = styled(Card)` + display: flex; + flex-direction: column; + height: 200px; + overflow: hidden; + + p { + font-size: 14px; + } + + @media (max-width: ${({ theme }) => theme.breakpoints.xs}) { + height: 280px; +`; + +const CardEdge = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + background-color: ${({ theme }) => theme.colors.tintPurple}; + padding: 8px; + height: 40px; + + @media (max-width: ${({ theme }) => theme.breakpoints.xs}) { + height: 80px; + flex-direction: column; + gap: 8px; + align-items: center; + } +`; + +const CardBody = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + padding: 8px; + flex: 1; +`; + +const Title = styled.p` + font-weight: bold; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +`; + +const Description = styled.p` + display: -webkit-box; + text-overflow: ellipsis; + overflow: hidden; + word-break: break-all; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; +`; + +const AmountTag = styled(Tag)` + pointer-events: none; + text-transform: capitalize; + font-weight: bold; +`; + +interface Props { + transaction: TransactionMini; +} + +export default function TransactionCard({ transaction }: Props) { + return ( + + + + + + + + {transaction.metaEvidence.title} + {transaction.metaEvidence.description} + + + +

{transaction.createdAt}

+
+
+ + ); +} diff --git a/src/components/Transactions/TransactionDetails/Agreement/Agreement.tsx b/src/components/Transactions/TransactionDetails/Agreement/Agreement.tsx new file mode 100644 index 0000000..991d013 --- /dev/null +++ b/src/components/Transactions/TransactionDetails/Agreement/Agreement.tsx @@ -0,0 +1,56 @@ +import styled from "styled-components"; +import { getIpfsUrl } from "utils/ipfs"; +import DocIcon from "assets/doc.svg?react"; + +const Title = styled.h1` + font-size: 1.5em; + font-weight: bold; + word-break: break-all; +`; + +const Description = styled.p` + word-break: break-all; + white-space: pre-wrap; +`; + +const StyledA = styled.a` + display: flex; + align-items: center; + gap: 4px; + + p { + font-size: 14px; + color: ${({ theme }) => theme.colors.primaryBlue}; + } +`; + +interface Props { + title: string; + description: string; + agreementDocURI?: string; +} + +export default function Agreement({ + title, + description, + agreementDocURI, +}: Props) { + return ( + <> + {title} + + {description} + + {agreementDocURI && ( + + +

Contract details

+
+ )} + + ); +} diff --git a/src/components/Transactions/TransactionDetails/Header/Header.tsx b/src/components/Transactions/TransactionDetails/Header/Header.tsx new file mode 100644 index 0000000..1721f3c --- /dev/null +++ b/src/components/Transactions/TransactionDetails/Header/Header.tsx @@ -0,0 +1,57 @@ +import styled from "styled-components"; +import { TransactionStatusTag } from "components/Transactions/TransactionStatusTag/TransactionStatusTag"; +import EtherscanIcon from "assets/etherscan.svg?react"; + +const HeaderContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + + @media (max-width: ${({ theme }) => theme.breakpoints.xs}) { + flex-direction: column; + gap: 8px; + } +`; + +const HeaderLeft = styled.div` + display: flex; + align-items: center; + gap: 8px; +`; + +const BlockExplorerLink = styled.a` + &:hover { + opacity: 0.8; + } +`; + +interface Props { + status: string; + blockExplorerLink: string; + createdAt: string; +} + +export default function Header({ + status, + blockExplorerLink, + createdAt, +}: Props) { + return ( + + + + + + + + + +

{createdAt}

+
+ ); +} diff --git a/src/components/Transactions/TransactionDetails/Summary/Summary.tsx b/src/components/Transactions/TransactionDetails/Summary/Summary.tsx new file mode 100644 index 0000000..4a680bd --- /dev/null +++ b/src/components/Transactions/TransactionDetails/Summary/Summary.tsx @@ -0,0 +1,67 @@ +import styled from "styled-components"; +import { DisplaySmall } from "@kleros/ui-components-library"; +import { addressToShortString } from "utils/common"; + +const Container = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 8px; + + @media (max-width: ${({ theme }) => theme.breakpoints.sm}) { + justify-content: center; + } +`; + +const StyledDisplaySmall = styled(DisplaySmall)` + overflow: hidden; + white-space: nowrap; + height: fit-content; + + label { + font-weight: bold; + } +`; + +interface Props { + originalAmount: string; + escrowAmount: string; + ticker: string; + sender: string; + receiver: string; +} + +export default function Summary({ + originalAmount, + escrowAmount, + ticker, + sender, + receiver, +}: Props) { + return ( + + <>} + /> + + <>} + /> + + <>} + /> + <>} + /> + + ); +} diff --git a/src/components/Transactions/TransactionDetails/TransactionDetails.tsx b/src/components/Transactions/TransactionDetails/TransactionDetails.tsx new file mode 100644 index 0000000..41ef263 --- /dev/null +++ b/src/components/Transactions/TransactionDetails/TransactionDetails.tsx @@ -0,0 +1,154 @@ +import styled from "styled-components"; +import { + AlertMessage, + Box, + CustomTimeline, +} from "@kleros/ui-components-library"; +import Agreement from "./Agreement/Agreement"; +import { useTransactionDetails } from "hooks/useTransactionDetails"; +import { BaseSkeleton } from "components/Common/Skeleton/BaseSkeleton"; +import Header from "./Header/Header"; +import { useMemo } from "react"; +import Summary from "./Summary/Summary"; +import { getIpfsUrl } from "utils/ipfs"; + +const StyledSkeleton = styled(BaseSkeleton)` + height: 100%; + width: 80%; + border-radius: ${({ theme }) => theme.radius.boxDefault}; + background-color: ${({ theme }) => theme.colors.mediumBlue}; +`; + +const StyledBox = styled(Box)` + display: flex; + flex-direction: column; + width: 80%; + height: fit-content; + gap: 16px; + padding: 8px 16px; + align-self: center; +`; + +const StyledHr = styled.hr` + border: 1px solid ${({ theme }) => theme.colors.primaryBlue}; +`; + +const StyledA = styled.a` + font-size: 12px; + color: ${({ theme }) => theme.colors.secondaryText}; + + &:hover { + text-decoration: underline; + } +`; + +type TimelineItems = React.ComponentProps["items"]; +const StyledTimeline = styled(CustomTimeline)` + align-self: center; +`; + +const TimelinePartyContainer = styled.div` + display: flex; + align-items: center; + gap: 4px; +`; + +const StyledSpan = styled.span` + color: ${({ theme }) => theme.colors.secondaryText}; +`; + +interface Props { + id: bigint; + contractAddress: `0x${string}`; +} + +export default function TransactionDetails({ id, contractAddress }: Props) { + const { data: transaction, isFetching } = useTransactionDetails({ + id: id, + contractAddress, + }); + + //This can be simplified if the CustomTimeline component is updated and no longer expects a tuple + const timelineItems = useMemo(() => { + if (!transaction) { + return [ + { + title: "No timeline available", + subtitle: "", + party: "", + }, + ]; + } + + const items = transaction.timeline.map((event) => ({ + title: event.title, + subtitle: event.date, + party: ( + + + View transaction + + + {event.evidenceURI && ( + <> + | + + View evidence + + + )} + + ), + })); + + return [...items] as TimelineItems; + }, [transaction]); + + if (isFetching) { + return ; + } + + if (!transaction) { + return ( + + ); + } + + return ( + +
+ + + + + + + + + + + + ); +} diff --git a/src/components/Transactions/TransactionStatusTag/TransactionStatusTag.ts b/src/components/Transactions/TransactionStatusTag/TransactionStatusTag.ts new file mode 100644 index 0000000..aba440a --- /dev/null +++ b/src/components/Transactions/TransactionStatusTag/TransactionStatusTag.ts @@ -0,0 +1,26 @@ +import { Tag } from "@kleros/ui-components-library"; +import styled from "styled-components"; + +interface Props { + status: string; + customWidth?: string; +} + +export const TransactionStatusTag = styled(Tag)` + --status-color: ${({ theme, status }) => + status === "Completed" + ? theme.colors.success + : status === "Disputed" + ? theme.colors.error + : theme.colors.warning}; + + width: ${({ customWidth = "fit-content" }) => customWidth}; + + pointer-events: none; + border-color: var(--status-color); + + p { + font-weight: bold; + color: var(--status-color); + } +`; diff --git a/src/config/contracts/events.ts b/src/config/contracts/events.ts new file mode 100644 index 0000000..7b04b52 --- /dev/null +++ b/src/config/contracts/events.ts @@ -0,0 +1,45 @@ +import { parseAbiItem, type GetLogsReturnType } from "viem"; + +export const metaEvidenceEvent = parseAbiItem( + "event MetaEvidence(uint indexed _metaEvidenceID, string _evidence)" +); +export type MetaEvidenceLogs = GetLogsReturnType; + +export const paymentEvent = parseAbiItem( + "event Payment(uint indexed _transactionID, uint _amount, address _party)" +); +export type PaymentLogs = GetLogsReturnType; + +export const hasToPayFeeEvent = parseAbiItem( + "event HasToPayFee(uint indexed _transactionID, uint8 _party)" +); +export type HasToPayFeeLogs = GetLogsReturnType; + +export const disputeEvent = parseAbiItem( + "event Dispute(address indexed _arbitrator, uint indexed _disputeID, uint _metaEvidenceID, uint _evidenceGroupID)" +); +export type DisputeLogs = GetLogsReturnType; + +export const appealDecisionEvent = parseAbiItem( + "event AppealDecision(uint indexed _disputeID, address indexed _arbitrable)" +); +export type AppealDecisionLogs = GetLogsReturnType; + +export const evidenceEvent = parseAbiItem( + "event Evidence(address indexed _arbitrator, uint indexed _evidenceGroupID, address indexed _party, string _evidence)" +); +export type EvidenceLogs = GetLogsReturnType; + +export const rulingEvent = parseAbiItem( + "event Ruling(address indexed _arbitrator, uint indexed _disputeID, uint _ruling)" +); +export type RulingLogs = GetLogsReturnType; + +export type ContractEventLogs = + | MetaEvidenceLogs + | PaymentLogs + | HasToPayFeeLogs + | DisputeLogs + | AppealDecisionLogs + | EvidenceLogs + | RulingLogs; diff --git a/src/config/contracts/generated.ts b/src/config/contracts/generated.ts new file mode 100644 index 0000000..f6119a2 --- /dev/null +++ b/src/config/contracts/generated.ts @@ -0,0 +1,1276 @@ +import { + createUseReadContract, + createUseWriteContract, + createUseSimulateContract, + createUseWatchContractEvent, +} from 'wagmi/codegen' + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MultipleArbitrableTokenTransaction +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const multipleArbitrableTokenTransactionAbi = [ + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'arbitratorExtraData', + outputs: [{ name: '', type: 'bytes' }], + stateMutability: 'view', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [{ name: '', type: 'uint256' }], + name: 'disputeIDtoTransactionID', + outputs: [{ name: '', type: 'uint256' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_disputeID', type: 'uint256' }, + { name: '_ruling', type: 'uint256' }, + ], + name: 'rule', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'timeOutByReceiver', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'arbitrator', + outputs: [{ name: '', type: 'address' }], + stateMutability: 'view', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'payArbitrationFeeByReceiver', + outputs: [], + stateMutability: 'payable', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'payArbitrationFeeBySender', + outputs: [], + stateMutability: 'payable', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'appeal', + outputs: [], + stateMutability: 'payable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [{ name: '', type: 'uint256' }], + name: 'transactions', + outputs: [ + { name: 'sender', type: 'address' }, + { name: 'receiver', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'token', type: 'address' }, + { name: 'timeoutPayment', type: 'uint256' }, + { name: 'disputeId', type: 'uint256' }, + { name: 'senderFee', type: 'uint256' }, + { name: 'receiverFee', type: 'uint256' }, + { name: 'lastInteraction', type: 'uint256' }, + { name: 'status', type: 'uint8' }, + ], + stateMutability: 'view', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'getCountTransactions', + outputs: [{ name: 'countTransactions', type: 'uint256' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_transactionID', type: 'uint256' }, + { name: '_evidence', type: 'string' }, + ], + name: 'submitEvidence', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'feeTimeout', + outputs: [{ name: '', type: 'uint256' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_amount', type: 'uint256' }, + { name: '_token', type: 'address' }, + { name: '_timeoutPayment', type: 'uint256' }, + { name: '_receiver', type: 'address' }, + { name: '_metaEvidence', type: 'string' }, + ], + name: 'createTransaction', + outputs: [{ name: 'transactionIndex', type: 'uint256' }], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'executeTransaction', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_transactionID', type: 'uint256' }, + { name: '_amount', type: 'uint256' }, + ], + name: 'pay', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'timeOutBySender', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [{ name: '_address', type: 'address' }], + name: 'getTransactionIDsByAddress', + outputs: [{ name: 'transactionIDs', type: 'uint256[]' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_transactionID', type: 'uint256' }, + { name: '_amountReimbursed', type: 'uint256' }, + ], + name: 'reimburse', + outputs: [], + stateMutability: 'nonpayable', + }, + { + payable: false, + type: 'constructor', + inputs: [ + { name: '_arbitrator', type: 'address' }, + { name: '_arbitratorExtraData', type: 'bytes' }, + { name: '_feeTimeout', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_transactionID', type: 'uint256', indexed: true }, + { name: '_amount', type: 'uint256', indexed: false }, + { name: '_party', type: 'address', indexed: false }, + ], + name: 'Payment', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_transactionID', type: 'uint256', indexed: true }, + { name: '_party', type: 'uint8', indexed: false }, + ], + name: 'HasToPayFee', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_arbitrator', type: 'address', indexed: true }, + { name: '_disputeID', type: 'uint256', indexed: true }, + { name: '_ruling', type: 'uint256', indexed: false }, + ], + name: 'Ruling', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_transactionID', type: 'uint256', indexed: false }, + { name: '_sender', type: 'address', indexed: true }, + { name: '_receiver', type: 'address', indexed: true }, + { name: '_token', type: 'address', indexed: false }, + { name: '_amount', type: 'uint256', indexed: false }, + ], + name: 'TransactionCreated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_metaEvidenceID', type: 'uint256', indexed: true }, + { name: '_evidence', type: 'string', indexed: false }, + ], + name: 'MetaEvidence', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_arbitrator', type: 'address', indexed: true }, + { name: '_disputeID', type: 'uint256', indexed: true }, + { name: '_metaEvidenceID', type: 'uint256', indexed: false }, + { name: '_evidenceGroupID', type: 'uint256', indexed: false }, + ], + name: 'Dispute', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_arbitrator', type: 'address', indexed: true }, + { name: '_evidenceGroupID', type: 'uint256', indexed: true }, + { name: '_party', type: 'address', indexed: true }, + { name: '_evidence', type: 'string', indexed: false }, + ], + name: 'Evidence', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MultipleArbitrableTransaction +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const multipleArbitrableTransactionAbi = [ + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'arbitratorExtraData', + outputs: [{ name: '', type: 'bytes' }], + stateMutability: 'view', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [{ name: '', type: 'uint256' }], + name: 'disputeIDtoTransactionID', + outputs: [{ name: '', type: 'uint256' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_disputeID', type: 'uint256' }, + { name: '_ruling', type: 'uint256' }, + ], + name: 'rule', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'timeOutByReceiver', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'arbitrator', + outputs: [{ name: '', type: 'address' }], + stateMutability: 'view', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'payArbitrationFeeByReceiver', + outputs: [], + stateMutability: 'payable', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'payArbitrationFeeBySender', + outputs: [], + stateMutability: 'payable', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'appeal', + outputs: [], + stateMutability: 'payable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [{ name: '', type: 'uint256' }], + name: 'transactions', + outputs: [ + { name: 'sender', type: 'address' }, + { name: 'receiver', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'timeoutPayment', type: 'uint256' }, + { name: 'disputeId', type: 'uint256' }, + { name: 'senderFee', type: 'uint256' }, + { name: 'receiverFee', type: 'uint256' }, + { name: 'lastInteraction', type: 'uint256' }, + { name: 'status', type: 'uint8' }, + ], + stateMutability: 'view', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'getCountTransactions', + outputs: [{ name: 'countTransactions', type: 'uint256' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_transactionID', type: 'uint256' }, + { name: '_evidence', type: 'string' }, + ], + name: 'submitEvidence', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [], + name: 'feeTimeout', + outputs: [{ name: '', type: 'uint256' }], + stateMutability: 'view', + }, + { + constant: false, + payable: true, + type: 'function', + inputs: [ + { name: '_timeoutPayment', type: 'uint256' }, + { name: '_receiver', type: 'address' }, + { name: '_metaEvidence', type: 'string' }, + ], + name: 'createTransaction', + outputs: [{ name: 'transactionID', type: 'uint256' }], + stateMutability: 'payable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'executeTransaction', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_transactionID', type: 'uint256' }, + { name: '_amount', type: 'uint256' }, + ], + name: 'pay', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [{ name: '_transactionID', type: 'uint256' }], + name: 'timeOutBySender', + outputs: [], + stateMutability: 'nonpayable', + }, + { + constant: true, + payable: false, + type: 'function', + inputs: [{ name: '_address', type: 'address' }], + name: 'getTransactionIDsByAddress', + outputs: [{ name: 'transactionIDs', type: 'uint256[]' }], + stateMutability: 'view', + }, + { + constant: false, + payable: false, + type: 'function', + inputs: [ + { name: '_transactionID', type: 'uint256' }, + { name: '_amountReimbursed', type: 'uint256' }, + ], + name: 'reimburse', + outputs: [], + stateMutability: 'nonpayable', + }, + { + payable: false, + type: 'constructor', + inputs: [ + { name: '_arbitrator', type: 'address' }, + { name: '_arbitratorExtraData', type: 'bytes' }, + { name: '_feeTimeout', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_transactionID', type: 'uint256', indexed: true }, + { name: '_amount', type: 'uint256', indexed: false }, + { name: '_party', type: 'address', indexed: false }, + ], + name: 'Payment', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_transactionID', type: 'uint256', indexed: true }, + { name: '_party', type: 'uint8', indexed: false }, + ], + name: 'HasToPayFee', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_arbitrator', type: 'address', indexed: true }, + { name: '_disputeID', type: 'uint256', indexed: true }, + { name: '_ruling', type: 'uint256', indexed: false }, + ], + name: 'Ruling', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_transactionID', type: 'uint256', indexed: false }, + { name: '_sender', type: 'address', indexed: true }, + { name: '_receiver', type: 'address', indexed: true }, + { name: '_amount', type: 'uint256', indexed: false }, + ], + name: 'TransactionCreated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_metaEvidenceID', type: 'uint256', indexed: true }, + { name: '_evidence', type: 'string', indexed: false }, + ], + name: 'MetaEvidence', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_arbitrator', type: 'address', indexed: true }, + { name: '_disputeID', type: 'uint256', indexed: true }, + { name: '_metaEvidenceID', type: 'uint256', indexed: false }, + { name: '_evidenceGroupID', type: 'uint256', indexed: false }, + ], + name: 'Dispute', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: '_arbitrator', type: 'address', indexed: true }, + { name: '_evidenceGroupID', type: 'uint256', indexed: true }, + { name: '_party', type: 'address', indexed: true }, + { name: '_evidence', type: 'string', indexed: false }, + ], + name: 'Evidence', + }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// React +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ + */ +export const useReadMultipleArbitrableTokenTransaction = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"arbitratorExtraData"` + */ +export const useReadMultipleArbitrableTokenTransactionArbitratorExtraData = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'arbitratorExtraData', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"disputeIDtoTransactionID"` + */ +export const useReadMultipleArbitrableTokenTransactionDisputeIDtoTransactionId = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'disputeIDtoTransactionID', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"arbitrator"` + */ +export const useReadMultipleArbitrableTokenTransactionArbitrator = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'arbitrator', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"transactions"` + */ +export const useReadMultipleArbitrableTokenTransactionTransactions = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'transactions', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"getCountTransactions"` + */ +export const useReadMultipleArbitrableTokenTransactionGetCountTransactions = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'getCountTransactions', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"feeTimeout"` + */ +export const useReadMultipleArbitrableTokenTransactionFeeTimeout = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'feeTimeout', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"getTransactionIDsByAddress"` + */ +export const useReadMultipleArbitrableTokenTransactionGetTransactionIDsByAddress = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'getTransactionIDsByAddress', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ + */ +export const useWriteMultipleArbitrableTokenTransaction = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"rule"` + */ +export const useWriteMultipleArbitrableTokenTransactionRule = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'rule', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"timeOutByReceiver"` + */ +export const useWriteMultipleArbitrableTokenTransactionTimeOutByReceiver = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'timeOutByReceiver', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"payArbitrationFeeByReceiver"` + */ +export const useWriteMultipleArbitrableTokenTransactionPayArbitrationFeeByReceiver = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'payArbitrationFeeByReceiver', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"payArbitrationFeeBySender"` + */ +export const useWriteMultipleArbitrableTokenTransactionPayArbitrationFeeBySender = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'payArbitrationFeeBySender', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"appeal"` + */ +export const useWriteMultipleArbitrableTokenTransactionAppeal = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'appeal', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"submitEvidence"` + */ +export const useWriteMultipleArbitrableTokenTransactionSubmitEvidence = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'submitEvidence', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"createTransaction"` + */ +export const useWriteMultipleArbitrableTokenTransactionCreateTransaction = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'createTransaction', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"executeTransaction"` + */ +export const useWriteMultipleArbitrableTokenTransactionExecuteTransaction = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'executeTransaction', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"pay"` + */ +export const useWriteMultipleArbitrableTokenTransactionPay = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'pay', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"timeOutBySender"` + */ +export const useWriteMultipleArbitrableTokenTransactionTimeOutBySender = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'timeOutBySender', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"reimburse"` + */ +export const useWriteMultipleArbitrableTokenTransactionReimburse = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'reimburse', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ + */ +export const useSimulateMultipleArbitrableTokenTransaction = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"rule"` + */ +export const useSimulateMultipleArbitrableTokenTransactionRule = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'rule', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"timeOutByReceiver"` + */ +export const useSimulateMultipleArbitrableTokenTransactionTimeOutByReceiver = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'timeOutByReceiver', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"payArbitrationFeeByReceiver"` + */ +export const useSimulateMultipleArbitrableTokenTransactionPayArbitrationFeeByReceiver = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'payArbitrationFeeByReceiver', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"payArbitrationFeeBySender"` + */ +export const useSimulateMultipleArbitrableTokenTransactionPayArbitrationFeeBySender = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'payArbitrationFeeBySender', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"appeal"` + */ +export const useSimulateMultipleArbitrableTokenTransactionAppeal = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'appeal', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"submitEvidence"` + */ +export const useSimulateMultipleArbitrableTokenTransactionSubmitEvidence = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'submitEvidence', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"createTransaction"` + */ +export const useSimulateMultipleArbitrableTokenTransactionCreateTransaction = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'createTransaction', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"executeTransaction"` + */ +export const useSimulateMultipleArbitrableTokenTransactionExecuteTransaction = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'executeTransaction', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"pay"` + */ +export const useSimulateMultipleArbitrableTokenTransactionPay = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'pay', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"timeOutBySender"` + */ +export const useSimulateMultipleArbitrableTokenTransactionTimeOutBySender = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'timeOutBySender', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `functionName` set to `"reimburse"` + */ +export const useSimulateMultipleArbitrableTokenTransactionReimburse = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTokenTransactionAbi, + functionName: 'reimburse', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ + */ +export const useWatchMultipleArbitrableTokenTransactionEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"Payment"` + */ +export const useWatchMultipleArbitrableTokenTransactionPaymentEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'Payment', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"HasToPayFee"` + */ +export const useWatchMultipleArbitrableTokenTransactionHasToPayFeeEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'HasToPayFee', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"Ruling"` + */ +export const useWatchMultipleArbitrableTokenTransactionRulingEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'Ruling', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"TransactionCreated"` + */ +export const useWatchMultipleArbitrableTokenTransactionTransactionCreatedEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'TransactionCreated', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"MetaEvidence"` + */ +export const useWatchMultipleArbitrableTokenTransactionMetaEvidenceEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'MetaEvidence', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"Dispute"` + */ +export const useWatchMultipleArbitrableTokenTransactionDisputeEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'Dispute', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTokenTransactionAbi}__ and `eventName` set to `"Evidence"` + */ +export const useWatchMultipleArbitrableTokenTransactionEvidenceEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTokenTransactionAbi, + eventName: 'Evidence', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ + */ +export const useReadMultipleArbitrableTransaction = + /*#__PURE__*/ createUseReadContract({ abi: multipleArbitrableTransactionAbi }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"arbitratorExtraData"` + */ +export const useReadMultipleArbitrableTransactionArbitratorExtraData = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'arbitratorExtraData', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"disputeIDtoTransactionID"` + */ +export const useReadMultipleArbitrableTransactionDisputeIDtoTransactionId = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'disputeIDtoTransactionID', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"arbitrator"` + */ +export const useReadMultipleArbitrableTransactionArbitrator = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'arbitrator', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"transactions"` + */ +export const useReadMultipleArbitrableTransactionTransactions = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'transactions', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"getCountTransactions"` + */ +export const useReadMultipleArbitrableTransactionGetCountTransactions = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'getCountTransactions', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"feeTimeout"` + */ +export const useReadMultipleArbitrableTransactionFeeTimeout = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'feeTimeout', + }) + +/** + * Wraps __{@link useReadContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"getTransactionIDsByAddress"` + */ +export const useReadMultipleArbitrableTransactionGetTransactionIDsByAddress = + /*#__PURE__*/ createUseReadContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'getTransactionIDsByAddress', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ + */ +export const useWriteMultipleArbitrableTransaction = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"rule"` + */ +export const useWriteMultipleArbitrableTransactionRule = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'rule', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"timeOutByReceiver"` + */ +export const useWriteMultipleArbitrableTransactionTimeOutByReceiver = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'timeOutByReceiver', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"payArbitrationFeeByReceiver"` + */ +export const useWriteMultipleArbitrableTransactionPayArbitrationFeeByReceiver = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'payArbitrationFeeByReceiver', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"payArbitrationFeeBySender"` + */ +export const useWriteMultipleArbitrableTransactionPayArbitrationFeeBySender = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'payArbitrationFeeBySender', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"appeal"` + */ +export const useWriteMultipleArbitrableTransactionAppeal = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'appeal', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"submitEvidence"` + */ +export const useWriteMultipleArbitrableTransactionSubmitEvidence = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'submitEvidence', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"createTransaction"` + */ +export const useWriteMultipleArbitrableTransactionCreateTransaction = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'createTransaction', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"executeTransaction"` + */ +export const useWriteMultipleArbitrableTransactionExecuteTransaction = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'executeTransaction', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"pay"` + */ +export const useWriteMultipleArbitrableTransactionPay = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'pay', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"timeOutBySender"` + */ +export const useWriteMultipleArbitrableTransactionTimeOutBySender = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'timeOutBySender', + }) + +/** + * Wraps __{@link useWriteContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"reimburse"` + */ +export const useWriteMultipleArbitrableTransactionReimburse = + /*#__PURE__*/ createUseWriteContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'reimburse', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ + */ +export const useSimulateMultipleArbitrableTransaction = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"rule"` + */ +export const useSimulateMultipleArbitrableTransactionRule = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'rule', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"timeOutByReceiver"` + */ +export const useSimulateMultipleArbitrableTransactionTimeOutByReceiver = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'timeOutByReceiver', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"payArbitrationFeeByReceiver"` + */ +export const useSimulateMultipleArbitrableTransactionPayArbitrationFeeByReceiver = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'payArbitrationFeeByReceiver', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"payArbitrationFeeBySender"` + */ +export const useSimulateMultipleArbitrableTransactionPayArbitrationFeeBySender = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'payArbitrationFeeBySender', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"appeal"` + */ +export const useSimulateMultipleArbitrableTransactionAppeal = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'appeal', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"submitEvidence"` + */ +export const useSimulateMultipleArbitrableTransactionSubmitEvidence = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'submitEvidence', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"createTransaction"` + */ +export const useSimulateMultipleArbitrableTransactionCreateTransaction = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'createTransaction', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"executeTransaction"` + */ +export const useSimulateMultipleArbitrableTransactionExecuteTransaction = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'executeTransaction', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"pay"` + */ +export const useSimulateMultipleArbitrableTransactionPay = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'pay', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"timeOutBySender"` + */ +export const useSimulateMultipleArbitrableTransactionTimeOutBySender = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'timeOutBySender', + }) + +/** + * Wraps __{@link useSimulateContract}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `functionName` set to `"reimburse"` + */ +export const useSimulateMultipleArbitrableTransactionReimburse = + /*#__PURE__*/ createUseSimulateContract({ + abi: multipleArbitrableTransactionAbi, + functionName: 'reimburse', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ + */ +export const useWatchMultipleArbitrableTransactionEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"Payment"` + */ +export const useWatchMultipleArbitrableTransactionPaymentEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'Payment', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"HasToPayFee"` + */ +export const useWatchMultipleArbitrableTransactionHasToPayFeeEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'HasToPayFee', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"Ruling"` + */ +export const useWatchMultipleArbitrableTransactionRulingEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'Ruling', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"TransactionCreated"` + */ +export const useWatchMultipleArbitrableTransactionTransactionCreatedEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'TransactionCreated', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"MetaEvidence"` + */ +export const useWatchMultipleArbitrableTransactionMetaEvidenceEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'MetaEvidence', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"Dispute"` + */ +export const useWatchMultipleArbitrableTransactionDisputeEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'Dispute', + }) + +/** + * Wraps __{@link useWatchContractEvent}__ with `abi` set to __{@link multipleArbitrableTransactionAbi}__ and `eventName` set to `"Evidence"` + */ +export const useWatchMultipleArbitrableTransactionEvidenceEvent = + /*#__PURE__*/ createUseWatchContractEvent({ + abi: multipleArbitrableTransactionAbi, + eventName: 'Evidence', + }) diff --git a/src/config/ipfs.ts b/src/config/ipfs.ts new file mode 100644 index 0000000..f01f2f3 --- /dev/null +++ b/src/config/ipfs.ts @@ -0,0 +1,7 @@ +if (!import.meta.env.VITE_IPFS_UPLOAD_URL) { + throw new Error("No VITE_IPFS_UPLOAD_URL environment variable"); +} + +export const IPFS_UPLOAD_URL = import.meta.env.VITE_IPFS_UPLOAD_URL; +export const IPFS_GATEWAY_URL = + import.meta.env.VITE_IPFS_GATEWAY_URL || "https://ipfs.io"; diff --git a/src/config/queryKeys.ts b/src/config/queryKeys.ts new file mode 100644 index 0000000..be8cf01 --- /dev/null +++ b/src/config/queryKeys.ts @@ -0,0 +1,4 @@ +export const QUERY_KEYS = { + transactionList: "transactionList", + transactionDetails: "transactionDetails", +}; diff --git a/src/global.css b/src/global.css index 59410e7..3ab8923 100644 --- a/src/global.css +++ b/src/global.css @@ -3,3 +3,29 @@ body { min-height: 100vh; margin: 0; } + +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background-color: var(--klerosUIComponentsPrimaryBlue); + border-radius: 10px; + transition: opacity 0.15s, background-color 0.15s, border-color 0.15s, + width 0.15s; +} +::-webkit-scrollbar-thumb:hover { + background-color: var(--klerosUIComponentsSecondaryBlue); +} +::-webkit-scrollbar-thumb:active { + background-color: var(--klerosUIComponentsPrimaryBlue); +} + +/* For Firefox */ +* { + scrollbar-width: thin; + scrollbar-color: var(--color-klerosUIComponentsPrimaryBlue) transparent; +} diff --git a/src/hooks/useTransactionDetails.ts b/src/hooks/useTransactionDetails.ts new file mode 100644 index 0000000..f013f9b --- /dev/null +++ b/src/hooks/useTransactionDetails.ts @@ -0,0 +1,298 @@ +import { useAccount, useClient } from "wagmi"; +import { useQuery } from "@tanstack/react-query"; +import { getLogs, readContract } from "viem/actions"; +import { formatUnits, type Client } from "viem"; +import { ipfsFetch } from "utils/ipfs"; +import type { MetaEvidence } from "model/MetaEvidence"; +import { TransactionStatus, type Transaction } from "model/Transaction"; +import { mapTransactionStatus } from "utils/transaction"; +import { QUERY_KEYS } from "config/queryKeys"; +import { + addressToAbi, + fetchBlockTimestamps, + getBlockExplorerLink, +} from "utils/common"; +import { formatTimelineEvents } from "utils/transaction"; +import { + appealDecisionEvent, + disputeEvent, + evidenceEvent, + hasToPayFeeEvent, + metaEvidenceEvent, + paymentEvent, + rulingEvent, + type ContractEventLogs, + type EvidenceLogs, + type MetaEvidenceLogs, +} from "config/contracts/events"; +import type { Evidence } from "model/Evidence"; +import type { TimelineEvent } from "model/TimelineEvent"; + +async function fetchDetails( + client: Client, + contractAddress: `0x${string}`, + id: bigint +) { + return await readContract(client, { + abi: addressToAbi(contractAddress), + address: contractAddress, + functionName: "transactions" as const, + args: [id], + }); +} + +async function fetchArbitrator(client: Client, contractAddress: `0x${string}`) { + return await readContract(client, { + abi: addressToAbi(contractAddress), + address: contractAddress, + functionName: "arbitrator" as const, + }); +} + +async function fetchTimelineEvents( + client: Client, + contractAddress: `0x${string}`, + arbitratorAddress: `0x${string}`, + id: bigint, + disputeId: bigint +) { + const [ + metaEvidenceLogs, + paymentLogs, + hasToPayFeeLogs, + disputeLogs, + appealDecisionLogs, + evidenceLogs, + rulingLogs, + ] = await Promise.all([ + await getLogs(client, { + address: contractAddress, + event: metaEvidenceEvent, + args: { _metaEvidenceID: id }, + fromBlock: 0n, + toBlock: "latest", + }), + await getLogs(client, { + address: contractAddress, + event: paymentEvent, + args: { _transactionID: id }, + fromBlock: 0n, + toBlock: "latest", + }), + await getLogs(client, { + address: contractAddress, + event: hasToPayFeeEvent, + args: { _transactionID: id }, + fromBlock: 0n, + toBlock: "latest", + }), + await getLogs(client, { + address: contractAddress, + event: disputeEvent, + args: { _disputeID: disputeId, _arbitrator: arbitratorAddress }, + fromBlock: 0n, + toBlock: "latest", + }), + await getLogs(client, { + address: contractAddress, + event: appealDecisionEvent, + args: { _disputeID: disputeId, _arbitrable: contractAddress }, + fromBlock: 0n, + toBlock: "latest", + }), + await getLogs(client, { + address: contractAddress, + event: evidenceEvent, + args: { + _arbitrator: arbitratorAddress, + _evidenceGroupID: id, + }, + fromBlock: 0n, + toBlock: "latest", + }), + await getLogs(client, { + address: contractAddress, + event: rulingEvent, + args: { _disputeID: disputeId, _arbitrator: arbitratorAddress }, + fromBlock: 0n, + toBlock: "latest", + }), + ]); + + const ordered = [ + ...metaEvidenceLogs, + ...paymentLogs, + ...hasToPayFeeLogs, + ...disputeLogs, + ...appealDecisionLogs, + ...evidenceLogs, + ...rulingLogs, + ].sort((a, b) => Number(a.blockNumber) - Number(b.blockNumber)); + + return ordered; +} + +async function fetchMetaEvidenceContent(log: MetaEvidenceLogs[0]) { + try { + if (!log.args._evidence) return null; + const content = await ipfsFetch(log.args._evidence); + return content as MetaEvidence; + } catch (error) { + console.error( + `Failed to fetch IPFS content for txID ${log.args._metaEvidenceID}: ${error}` + ); + return null; + } +} + +async function fetchEvidenceContent(logs: EvidenceLogs) { + return await Promise.all( + logs.map(async (log) => { + try { + if (!log.args._evidence) return null; + const content = (await ipfsFetch(log.args._evidence)) as Evidence; + + //Old UI allowed evidence to be text (e.g. links). This will no longer be the case, only PDFs. + //However, to still display evidence such as this that was uploaded in the old UI, we can check if we downloaded an actual file by checking the fileURI. + //If we didn't, just use the log URI, and the user will have access to the text evidence uploaded, in JSON format. + if (!content.fileURI) { + content.fileURI = log.args._evidence; + } + + return content; + } catch (error) { + console.error( + `Failed to fetch IPFS content for evidence ${log.args._evidence}: ${error}` + ); + return null; + } + }) + ); +} + +function mapToTransaction( + id: bigint, + disputeId: bigint, + blockTimestamp: bigint, + contractAddress: `0x${string}`, + metaEvidence: MetaEvidence, + status: number, + lastInteraction: number, + amountInEscrow: string, + blockExplorerLink: string, + timelineEvents: TimelineEvent[] +): Transaction { + return { + id: id, + disputeId: disputeId, + createdAt: new Date( + parseInt(blockTimestamp.toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + arbitrableAddress: contractAddress, + metaEvidence: metaEvidence, + status: mapTransactionStatus(TransactionStatus[status], amountInEscrow), + lastInteraction: Number(lastInteraction), + amountInEscrow: amountInEscrow, + blockExplorerLink: blockExplorerLink, + timeline: timelineEvents, + }; +} + +interface Props { + id: bigint; + contractAddress: `0x${string}`; +} + +/** + * NOTE: This hook intentionally does not use wagmi generated hooks because: + * 1. It would require determining which generated hooks to use based on the contract address. + * 2. It batches information fetching for better performance. + * 3. It needs to fetch and process multiple types of data (transaction details, event logs, IPFS content). + * Using generated hooks would make the code more complex and not as performant. + */ +export function useTransactionDetails({ id, contractAddress }: Props) { + const client = useClient(); + const { chainId } = useAccount(); + + return useQuery({ + queryKey: [QUERY_KEYS.transactionDetails, id.toString(), contractAddress], + queryFn: async () => { + if (!client) return undefined; + + const [details, arbitratorAddress] = await Promise.all([ + fetchDetails(client, contractAddress, id), + fetchArbitrator(client, contractAddress), + ]); + + const disputeId = details[details.length - 5]; + + const timelineEventsLogs = await fetchTimelineEvents( + client, + contractAddress, + arbitratorAddress, + id, + disputeId as bigint + ); + + //MetaEvidence event is emmitted when the transaction is created, and since we need it to download the meta evidence from IPFS, + //we can use it for the Transaction Creation timeline event + const metaEvidenceLog = timelineEventsLogs[0] as MetaEvidenceLogs[0]; + const evidenceLogs = timelineEventsLogs.filter( + (log) => log.eventName === evidenceEvent.name + ); + + const [metaEvidence, evidenceContent, blockTimestamps] = + await Promise.all([ + fetchMetaEvidenceContent(metaEvidenceLog), + fetchEvidenceContent(evidenceLogs), + fetchBlockTimestamps( + client, + timelineEventsLogs.map((log) => log.blockNumber) + ), + ]); + + if (!metaEvidence) return undefined; + + const amountInEscrow = formatUnits( + details[2], + (metaEvidence.token?.decimals as number) ?? 18 + ); + + const blockExplorerLink = getBlockExplorerLink( + metaEvidenceLog.transactionHash, + chainId ?? 1 + ); + + const timelineEvents = formatTimelineEvents( + timelineEventsLogs as ContractEventLogs, + evidenceLogs, + evidenceContent as Evidence[], + blockTimestamps, + metaEvidence.receiver, + metaEvidence.sender, + metaEvidence.token?.ticker ?? "ETH", + (metaEvidence.token?.decimals as number) ?? 18, + chainId ?? 1 + ); + + return mapToTransaction( + id, + disputeId as bigint, + blockTimestamps[0], //we can rely on the order of Promise.all, so we can use the first timestamp for the createdAt date + contractAddress, + metaEvidence, + details[details.length - 1] as number, // status + details[details.length - 2] as number, //last interaction + amountInEscrow, + blockExplorerLink, + timelineEvents + ); + }, + enabled: typeof id === "bigint" && !!contractAddress, + refetchOnWindowFocus: false, + }); +} diff --git a/src/hooks/useTransactions.ts b/src/hooks/useTransactions.ts index 566acfc..daa99fc 100644 --- a/src/hooks/useTransactions.ts +++ b/src/hooks/useTransactions.ts @@ -3,94 +3,241 @@ import { MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS, } from "config/contracts/addresses"; import { wagmiConfig } from "config/reown"; -import { useAccount } from "wagmi"; +import { useAccount, useClient } from "wagmi"; import { multicall } from "wagmi/actions"; import { useQuery } from "@tanstack/react-query"; import { MULTIPLE_ARBITRABLE_TRANSACTION_ABI } from "config/contracts/abi/multipleArbitrableTransaction"; import { MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI } from "config/contracts/abi/mutlipleArbitrableTokenTransaction"; +import { getLogs } from "viem/actions"; +import { fetchBlockTimestamps } from "utils/common"; +import { type Client } from "viem"; +import { useMemo } from "react"; +import { ipfsFetch } from "utils/ipfs"; +import type { MetaEvidence } from "model/MetaEvidence"; +import { TransactionStatus, type TransactionMini } from "model/Transaction"; +import { mapTransactionStatus } from "utils/transaction"; +import { QUERY_KEYS } from "config/queryKeys"; +import { + metaEvidenceEvent, + type MetaEvidenceLogs, +} from "config/contracts/events"; + +//Batch fetch all tx IDs for the connected wallet, from all contracts +async function fetchTxIDsByContract( + contractAddresses: `0x${string}`[], + address: `0x${string}` +) { + return await multicall(wagmiConfig, { + contracts: [ + { + abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, + address: contractAddresses[0], + functionName: "getTransactionIDsByAddress", + args: [address], + }, + { + abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, + address: contractAddresses[1], + functionName: "getTransactionIDsByAddress", + args: [address], + }, + { + abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, + address: contractAddresses[2], + functionName: "getTransactionIDsByAddress", + args: [address], + }, + { + abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, + address: contractAddresses[3], + functionName: "getTransactionIDsByAddress", + args: [address], + }, + ], + }); +} + +//Batch fetch details for the txIDs, for a given contract +async function fetchContractTxDetails( + contractAddress: `0x${string}`, + abi: + | typeof MULTIPLE_ARBITRABLE_TRANSACTION_ABI + | typeof MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, + txIDs: readonly bigint[] +) { + return await multicall(wagmiConfig, { + contracts: txIDs.map((txID) => ({ + abi, + address: contractAddress, + functionName: "transactions" as const, + args: [txID], + })), + }); +} + +//Batch fetch meta evidence logs for the txIDs, for a given contract +async function fetchContractMetaEvidenceLogs( + contractAddress: `0x${string}`, + client: Client, + txIDs: readonly bigint[] +) { + return await getLogs(client, { + address: contractAddress, + event: metaEvidenceEvent, + args: { _metaEvidenceID: [...txIDs] }, + fromBlock: 0n, + toBlock: "latest", + }); +} + +//Fetch from IPFS the JSON content for each log in the array +async function fetchLogsContentFromIPFS(logs: MetaEvidenceLogs) { + return await Promise.all( + logs.map(async (log) => { + try { + if (!log.args._evidence) return null; + const content = await ipfsFetch(log.args._evidence); + return content as MetaEvidence; + } catch (error) { + console.error( + `Failed to fetch IPFS content for txID ${log.args._metaEvidenceID}: ${error}` + ); + return null; + } + }) + ); +} + +function mapToTransactionMini( + txID: bigint, + blockTimestamp: bigint, + contractAddress: `0x${string}`, + metaEvidence: MetaEvidence, + userParty: string, + status: number, + txAmountInEscrow: string, + lastInteraction: number +): TransactionMini { + return { + id: txID, + createdAt: new Date( + parseInt(blockTimestamp.toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + arbitrableAddress: contractAddress, + metaEvidence: metaEvidence, + userPartyLabel: userParty, + otherPartyAddress: + userParty === "sender" ? metaEvidence.receiver : metaEvidence.sender, + status: mapTransactionStatus(TransactionStatus[status], txAmountInEscrow), + lastInteraction: Number(lastInteraction), + }; +} +/** + * NOTE: This hook intentionally does not use wagmi generated hooks because: + * 1. It needs to handle 4 different contracts, with 2 different ABIs. + * 2. It batches information fetching using multicall for better performance. + * 3. It needs to fetch and process multiple types of data (transactions, logs, IPFS content). + * Using generated hooks would make the code more complex and not as performant. + */ export function useTransactions() { const { address, chain } = useAccount(); + const client = useClient(); - return useQuery({ - queryKey: ["transactions", address, chain?.id], + const contractAddresses = useMemo(() => { + if (!chain) return []; + + return [ + MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS[chain.id] + .BLOCKCHAIN_NON_TECHNICAL, + MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS[chain.id].GENERAL_COURT, + MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ADDRESS[chain.id] + .BLOCKCHAIN_NON_TECHNICAL, + MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ADDRESS[chain.id].GENERAL_COURT, + ]; + }, [chain]); + + return useQuery({ + queryKey: [QUERY_KEYS.transactionList, address, chain?.id], queryFn: async () => { - if (!chain || !address) return []; - - const allTxIDs = await multicall(wagmiConfig, { - contracts: [ - { - abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS[chain.id] - .BLOCKCHAIN_NON_TECHNICAL, - functionName: "getTransactionIDsByAddress", - args: [address], - }, - { - abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS[chain.id].GENERAL_COURT, - functionName: "getTransactionIDsByAddress", - args: [address], - }, - { - abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ADDRESS[chain.id] - .BLOCKCHAIN_NON_TECHNICAL, - functionName: "getTransactionIDsByAddress", - args: [address], - }, - { - abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ADDRESS[chain.id] - .GENERAL_COURT, - functionName: "getTransactionIDsByAddress", - args: [address], - }, - ], - }); - - const txDetails = await multicall(wagmiConfig, { - contracts: [ - ...(allTxIDs[0].result ?? []).map((txID: bigint) => ({ - abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS[chain.id] - .BLOCKCHAIN_NON_TECHNICAL, - functionName: "transactions", - args: [txID], - })), - ...(allTxIDs[1].result ?? []).map((txID: bigint) => ({ - abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS[chain.id].GENERAL_COURT, - functionName: "transactions", - args: [txID], - })), - ...(allTxIDs[2].result ?? []).map((txID: bigint) => ({ - abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ADDRESS[chain.id] - .BLOCKCHAIN_NON_TECHNICAL, - functionName: "transactions", - args: [txID], - })), - ...(allTxIDs[3].result ?? []).map((txID: bigint) => ({ - abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, - address: - MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ADDRESS[chain.id] - .GENERAL_COURT, - functionName: "transactions", - args: [txID], - })), - ], - }); - - return txDetails; + if (!chain || !address || !client) return []; + + //First get all txIDs, from the respective contracts + const txIDsByContract = await fetchTxIDsByContract( + contractAddresses, + address + ); + + const txsByContract = await Promise.all( + //Then, for each contract + contractAddresses.map(async (contractAddress, contractIndex) => { + //Get the respective txIDs + const txIDs = txIDsByContract[contractIndex]?.result ?? []; + if (!txIDs.length) return []; + + //Batch fetch details for the txIDs + const txDetails = await fetchContractTxDetails( + contractAddress, + contractIndex < 2 + ? MULTIPLE_ARBITRABLE_TRANSACTION_ABI + : MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, + txIDs + ); + + //Batch fetch meta evidence logs for the txIDs + const metaEvidenceLogs = await fetchContractMetaEvidenceLogs( + contractAddress, + client, + txIDs + ); + + //Batch fetch from IPFS the JSON content for each log + const metaEvidenceContent = + await fetchLogsContentFromIPFS(metaEvidenceLogs); + + //Batch fetch the timestamps for the block numbers + const blockTimestamps = await fetchBlockTimestamps( + client, + metaEvidenceLogs.map((log) => log.blockNumber) + ); + + //Map the results to a TransactionMini object + const txs = txDetails + .map((tx, index) => { + //Get the corresponding meta evidence content - we can rely on the order of Promise.all + const metaEvidence = metaEvidenceContent[index]; + + //Shouldn't happen, but if we did not get the details or the meta evidence, skip for now + if (tx.status !== "success" || !metaEvidence) return null; + + //Note we can rely on the order of batch fetches + return mapToTransactionMini( + txIDs[index], + blockTimestamps[index], + contractAddress, + metaEvidence, + metaEvidence?.aliases[address], + tx.result[tx.result.length - 1] as number, //status + tx.result[2].toString(), //amount in escrow + tx.result[tx.result.length - 2] as number //last interaction + ); + }) + .filter((tx) => tx !== null); //remove nulls as we don't have the needed information to display + + return txs; + }) + ); + + //Return a single array of all transactions + return txsByContract + .flat() + .sort((a, b) => b.lastInteraction - a.lastInteraction); }, enabled: !!chain && !!address, + initialData: [], }); } diff --git a/src/layout/Layout.tsx b/src/layout/Layout.tsx index 15de6b4..c695910 100644 --- a/src/layout/Layout.tsx +++ b/src/layout/Layout.tsx @@ -6,7 +6,6 @@ import { Outlet } from "react-router"; const Container = styled.div` display: flex; flex-direction: column; - justify-content: space-between; height: 100vh; width: 100%; `; diff --git a/src/model/Evidence.ts b/src/model/Evidence.ts new file mode 100644 index 0000000..2cde9f4 --- /dev/null +++ b/src/model/Evidence.ts @@ -0,0 +1,5 @@ +export interface Evidence { + name: string; + fileURI: string; + description: string; +} diff --git a/src/model/MetaEvidence.ts b/src/model/MetaEvidence.ts new file mode 100644 index 0000000..58b722c --- /dev/null +++ b/src/model/MetaEvidence.ts @@ -0,0 +1,41 @@ +interface Token { + address: string | null; + decimals: number | string; + name: string; + symbolURI: string; + ticker: string; +} + +interface RulingOptions { + descriptions: string[]; + titles: string[]; + type: "single-select" | "multiple-select0" | "uint" | "int" | "string"; +} + +interface ExtraData { + Address?: string; + Blockchain?: string; + "Cryptoasset Description"?: string; + "Due Date (Local Time)"?: string; + "Contract Information"?: string; +} + +export interface MetaEvidence { + aliases: Record; + amount: string; + arbitrableAddress: string; + category: string; + description: string; + evidenceDisplayInterfaceURI: string; + extraData: ExtraData; + invoice: boolean; + question: string; + receiver: string; + rulingOptions: RulingOptions; + sender: string; + subCategory: string; + timeout: number; + token?: Token; + title: string; + fileURI?: string; +} diff --git a/src/model/TimelineEvent.ts b/src/model/TimelineEvent.ts new file mode 100644 index 0000000..cadfa24 --- /dev/null +++ b/src/model/TimelineEvent.ts @@ -0,0 +1,6 @@ +export interface TimelineEvent { + title: string; + date: string; + txURL: string; + evidenceURI?: string; +} diff --git a/src/model/Transaction.ts b/src/model/Transaction.ts new file mode 100644 index 0000000..9c7dc5b --- /dev/null +++ b/src/model/Transaction.ts @@ -0,0 +1,39 @@ +import type { MetaEvidence } from "./MetaEvidence"; +import type { TimelineEvent } from "./TimelineEvent"; + +export enum TransactionStatus { + NoDispute, + WaitingSender, + WaitingReceiver, + DisputeCreated, + Resolved, +} + +export enum DisputeRuling { + "Jurors refused to arbitrate", + "Jurors ruled in favor of the sender", + "Jurors ruled in favor of the receiver", +} + +interface BaseTransaction { + id: bigint; + createdAt: string; + lastInteraction: number; + arbitrableAddress: string; + metaEvidence: MetaEvidence; + status: string; +} + +//Used for cards +export interface TransactionMini extends BaseTransaction { + userPartyLabel: string; + otherPartyAddress: string; +} + +//Used for detailed view +export interface Transaction extends BaseTransaction { + amountInEscrow: string; + disputeId: bigint; + blockExplorerLink: string; + timeline: TimelineEvent[]; +} diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx new file mode 100644 index 0000000..9a60db1 --- /dev/null +++ b/src/pages/Home/Home.tsx @@ -0,0 +1,33 @@ +import styled from "styled-components"; +import { AlertMessage } from "@kleros/ui-components-library"; +import { useAccount } from "wagmi"; +import DisplayTransactions from "components/Transactions/DisplayTransactions/DisplayTransactions"; + +const Container = styled.div` + display: flex; + flex-direction: column; + height: 100%; + gap: 16px; + align-items: center; + overflow-y: auto; + padding: 8px 16px; +`; + +export default function Home() { + const { isConnected } = useAccount(); + + return ( + + {!isConnected ? ( + + ) : ( + + )} + + ); +} diff --git a/src/pages/Transaction/Transaction.tsx b/src/pages/Transaction/Transaction.tsx new file mode 100644 index 0000000..525887d --- /dev/null +++ b/src/pages/Transaction/Transaction.tsx @@ -0,0 +1,31 @@ +import { useParams } from "react-router"; +import { type Transaction } from "model/Transaction"; +import TransactionDetails from "components/Transactions/TransactionDetails/TransactionDetails"; +import styled from "styled-components"; + +const Container = styled.div` + display: flex; + flex-direction: column; + height: 100%; + gap: 16px; + align-items: center; + overflow-y: auto; + padding: 8px 0; +`; + +//NOTE: If in dev and using the Sepolia network, you will see "Transaction not found" when trying to access this page directly (eg. pasting an url into the browser). +//This is expected behavior, as the viem client defaults to mainnet and the contracts are deployed on Sepolia for testing, so the transaction will be undefined. +//Using mainnet, in prod or dev, accessing this page directly will work. +export default function Transaction() { + const { id, contractAddress } = useParams(); + const transactionId = BigInt(id ?? "0"); + + return ( + + + + ); +} diff --git a/src/theme/theme.ts b/src/theme/theme.ts index 1993290..7214599 100644 --- a/src/theme/theme.ts +++ b/src/theme/theme.ts @@ -39,8 +39,11 @@ export const theme: KlerosTheme = { }, radius: { base: "var(--klerosUIComponentsBaseRadius)", + boxDefault: "18px", }, breakpoints: { + xs: "430px", + sm: "593px", lg: "var(--breakpoint-lg)", }, animations: { diff --git a/src/theme/types.ts b/src/theme/types.ts index 572f10e..d24d70f 100644 --- a/src/theme/types.ts +++ b/src/theme/types.ts @@ -36,8 +36,11 @@ export interface KlerosTheme { }; radius: { base: string; + boxDefault: string; }; breakpoints: { + xs: string; + sm: string; lg: string; }; animations: { diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 0000000..2994a71 --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1,44 @@ +import { MULTIPLE_ARBITRABLE_TRANSACTION_ABI } from "config/contracts/abi/multipleArbitrableTransaction"; +import { MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI } from "config/contracts/abi/mutlipleArbitrableTokenTransaction"; +import { MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS } from "config/contracts/addresses"; +import type { Client } from "viem"; +import { getBlock } from "viem/actions"; + +export function addressToShortString(address: string) { + return `${address.slice(0, 6)}...${address.slice(-4)}`; +} + +export function getBlockExplorerLink(txHash: string, chainId: number) { + switch (chainId) { + case 1: + return `https://etherscan.io/tx/${txHash}`; + case 11155111: + return `https://sepolia.etherscan.io/tx/${txHash}`; + default: + return `https://etherscan.io/tx/${txHash}`; + } +} + +const HELPER_ADDRESSES = Object.values( + MULTIPLE_ARBITRABLE_TRANSACTION_ADDRESS +).flatMap(Object.values); + +export function addressToAbi(address: `0x${string}`) { + const exists = HELPER_ADDRESSES.includes(address); + return exists + ? MULTIPLE_ARBITRABLE_TRANSACTION_ABI + : MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI; +} + +//Fetch the timestamps for the block numbers, so we can display the transaction date +export async function fetchBlockTimestamps( + client: Client, + blockNumbers: bigint[] +) { + return await Promise.all( + blockNumbers.map(async (blockNumber) => { + const block = await getBlock(client, { blockNumber }); + return block.timestamp; + }) + ); +} diff --git a/src/utils/ipfs.ts b/src/utils/ipfs.ts new file mode 100644 index 0000000..5d9b6b2 --- /dev/null +++ b/src/utils/ipfs.ts @@ -0,0 +1,50 @@ +import { IPFS_UPLOAD_URL, IPFS_GATEWAY_URL } from "config/ipfs"; + +export async function ipfsPost( + fileName: string, + data: string | Blob +): Promise { + const payload = new FormData(); + payload.append("file", new Blob([data]), fileName); + + const url = `${IPFS_UPLOAD_URL}?operation=evidence&pinToGraph=false`; + + const response = await fetch(url, { + method: "POST", + body: payload, + }); + + if (!response.ok) { + throw new Error(`IPFS post failed with status ${response.status}`); + } + + const result = await response.json(); + return result.cids[0]; +} + +export async function ipfsFetch(uri: string): Promise { + try { + const formattedUri = getIpfsUrl(uri); + const response = await fetch(formattedUri); + + if (!response.ok) { + throw new Error(`IPFS fetch failed with status ${response.status}`); + } + return await response.json(); + } catch (err) { + console.error(`Failed to fetch IPFS content for uri ${uri}: ${err}`); + throw err; + } +} + +export const getIpfsUrl = (url: string) => { + const formatedIPFSPath = getFormattedPath(url); + return `${IPFS_GATEWAY_URL}${formatedIPFSPath}`; +}; + +const getFormattedPath = (url: string) => { + if (url.startsWith("/ipfs/")) return url; + else if (url.startsWith("ipfs/")) return "/" + url; + else if (url.startsWith("ipfs://")) return url.replace("ipfs://", "/ipfs/"); + return url; +}; diff --git a/src/utils/transaction.ts b/src/utils/transaction.ts new file mode 100644 index 0000000..08707f6 --- /dev/null +++ b/src/utils/transaction.ts @@ -0,0 +1,154 @@ +import { + metaEvidenceEvent, + paymentEvent, + hasToPayFeeEvent, + rulingEvent, + disputeEvent, + appealDecisionEvent, + evidenceEvent, + type ContractEventLogs, + type EvidenceLogs, +} from "config/contracts/events"; +import { formatUnits } from "viem"; +import { addressToShortString, getBlockExplorerLink } from "./common"; +import { DisputeRuling } from "model/Transaction"; +import type { Evidence } from "model/Evidence"; + +export const mapTransactionStatus = ( + backendStatus: string, + amountInEscrow?: string +): "Pending" | "Completed" | "Disputed" | "Unknown" => { + switch (backendStatus) { + case "Resolved": + return "Completed"; + case "DisputeCreated": + return "Disputed"; + case "WaitingSender": + case "WaitingReceiver": + return "Pending"; + case "NoDispute": + //Check if the transaction has been paid (amount in escrow is 0) + return amountInEscrow === "0" ? "Completed" : "Pending"; + default: + return "Unknown"; + } +}; + +export function formatTimelineEvents( + timelineEvents: ContractEventLogs, + evidenceLogs: EvidenceLogs, + evidenceContent: Evidence[], + blockTimestamps: bigint[], + receiver: string, + sender: string, + ticker: string, + decimals: number, + chainId: number +) { + return timelineEvents.map((event, index) => { + switch (event.eventName) { + case metaEvidenceEvent.name: + return { + title: "Escrow created", + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + }; + case paymentEvent.name: + return { + title: `${formatUnits( + event.args._amount as bigint, + decimals + )} ${ticker} paid by ${addressToShortString( + event.args._party as string + )}`, + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + }; + case hasToPayFeeEvent.name: + return { + title: `${ + event.args._party === 0 + ? addressToShortString(sender) + : addressToShortString(receiver) + } has to pay fee`, + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + }; + case disputeEvent.name: + return { + title: `Dispute created`, + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + }; + case appealDecisionEvent.name: + return { + title: "Appealed", + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + }; + case evidenceEvent.name: { + const evidenceIndex = evidenceLogs.findIndex( + (log) => log.transactionHash === event.transactionHash + ); + const evidence = evidenceContent[evidenceIndex]; + + return { + title: `${addressToShortString( + event.args._party as string + )} submitted "${evidence.name}" as evidence`, + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + evidenceURI: evidence.fileURI, + }; + } + case rulingEvent.name: + return { + title: `${DisputeRuling[Number(event.args._ruling)]}`, + date: new Date( + parseInt(blockTimestamps[index].toString()) * 1000 + ).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }), + txURL: getBlockExplorerLink(event.transactionHash, chainId), + }; + } + }); +} diff --git a/tsconfig.app.json b/tsconfig.app.json index d4e49cb..90af897 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -31,7 +31,10 @@ "context/*": ["./src/context/*"], "hooks/*": ["./src/hooks/*"], "layout/*": ["./src/layout/*"], - "theme/*": ["./src/theme/*"] + "model/*": ["./src/model/*"], + "pages/*": ["./src/pages/*"], + "theme/*": ["./src/theme/*"], + "utils/*": ["./src/utils/*"] } }, "include": ["src"] diff --git a/vite.config.ts b/vite.config.ts index cf98dbf..5047a29 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,13 +7,16 @@ export default defineConfig({ plugins: [react(), svgr()], resolve: { alias: { + assets: "/src/assets", components: "/src/components", + config: "/src/config", context: "/src/context", hooks: "/src/hooks", - theme: "/src/theme", - assets: "/src/assets", - config: "/src/config", layout: "/src/layout", + model: "/src/model", + pages: "/src/pages", + theme: "/src/theme", + utils: "/src/utils", }, }, }); diff --git a/wagmi.config.ts b/wagmi.config.ts new file mode 100644 index 0000000..c9b792d --- /dev/null +++ b/wagmi.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from "@wagmi/cli"; +import { react } from "@wagmi/cli/plugins"; +import { MULTIPLE_ARBITRABLE_TRANSACTION_ABI } from "./src/config/contracts/abi/multipleArbitrableTransaction"; +import { MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI } from "./src/config/contracts/abi/mutlipleArbitrableTokenTransaction"; + +export default defineConfig({ + out: "src/config/contracts/generated.ts", + contracts: [ + { + name: "MultipleArbitrableTransaction", + abi: MULTIPLE_ARBITRABLE_TRANSACTION_ABI, + }, + { + name: "MultipleArbitrableTokenTransaction", + abi: MULTIPLE_ARBITRABLE_TOKEN_TRANSACTION_ABI, + }, + ], + plugins: [react()], +}); diff --git a/yarn.lock b/yarn.lock index 238aa6e..358bbab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,7 +5,7 @@ __metadata: version: 8 cacheKey: 10c0 -"@adraffy/ens-normalize@npm:^1.10.1": +"@adraffy/ens-normalize@npm:^1.10.1, @adraffy/ens-normalize@npm:^1.11.0": version: 1.11.0 resolution: "@adraffy/ens-normalize@npm:1.11.0" checksum: 10c0/5111d0f1a273468cb5661ed3cf46ee58de8f32f84e2ebc2365652e66c1ead82649df94c736804e2b9cfa831d30ef24e1cc3575d970dbda583416d3a98d8870a6 @@ -277,6 +277,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/aix-ppc64@npm:0.25.5" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/android-arm64@npm:0.25.4" @@ -284,6 +291,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm64@npm:0.25.5" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/android-arm@npm:0.25.4" @@ -291,6 +305,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm@npm:0.25.5" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/android-x64@npm:0.25.4" @@ -298,6 +319,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-x64@npm:0.25.5" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/darwin-arm64@npm:0.25.4" @@ -305,6 +333,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-arm64@npm:0.25.5" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/darwin-x64@npm:0.25.4" @@ -312,6 +347,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-x64@npm:0.25.5" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/freebsd-arm64@npm:0.25.4" @@ -319,6 +361,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-arm64@npm:0.25.5" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/freebsd-x64@npm:0.25.4" @@ -326,6 +375,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-x64@npm:0.25.5" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-arm64@npm:0.25.4" @@ -333,6 +389,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm64@npm:0.25.5" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-arm@npm:0.25.4" @@ -340,6 +403,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm@npm:0.25.5" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-ia32@npm:0.25.4" @@ -347,6 +417,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ia32@npm:0.25.5" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-loong64@npm:0.25.4" @@ -354,6 +431,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-loong64@npm:0.25.5" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-mips64el@npm:0.25.4" @@ -361,6 +445,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-mips64el@npm:0.25.5" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-ppc64@npm:0.25.4" @@ -368,6 +459,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ppc64@npm:0.25.5" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-riscv64@npm:0.25.4" @@ -375,6 +473,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-riscv64@npm:0.25.5" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-s390x@npm:0.25.4" @@ -382,6 +487,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-s390x@npm:0.25.5" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/linux-x64@npm:0.25.4" @@ -389,6 +501,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-x64@npm:0.25.5" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/netbsd-arm64@npm:0.25.4" @@ -396,6 +515,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-arm64@npm:0.25.5" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/netbsd-x64@npm:0.25.4" @@ -403,6 +529,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-x64@npm:0.25.5" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/openbsd-arm64@npm:0.25.4" @@ -410,6 +543,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-arm64@npm:0.25.5" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/openbsd-x64@npm:0.25.4" @@ -417,6 +557,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-x64@npm:0.25.5" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/sunos-x64@npm:0.25.4" @@ -424,6 +571,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/sunos-x64@npm:0.25.5" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/win32-arm64@npm:0.25.4" @@ -431,6 +585,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-arm64@npm:0.25.5" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/win32-ia32@npm:0.25.4" @@ -438,6 +599,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-ia32@npm:0.25.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.25.4": version: 0.25.4 resolution: "@esbuild/win32-x64@npm:0.25.4" @@ -445,6 +613,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-x64@npm:0.25.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.7.0": version: 4.7.0 resolution: "@eslint-community/eslint-utils@npm:4.7.0" @@ -771,13 +946,14 @@ __metadata: languageName: node linkType: hard -"@kleros/ui-components-library@npm:^3.3.4": - version: 3.3.4 - resolution: "@kleros/ui-components-library@npm:3.3.4" +"@kleros/ui-components-library@npm:^3.4.5": + version: 3.4.5 + resolution: "@kleros/ui-components-library@npm:3.4.5" dependencies: "@internationalized/date": "npm:^3.7.0" bignumber.js: "npm:^9.1.2" clsx: "npm:^2.1.1" + lodash: "npm:^4.17.21" react: "npm:^18.0.0" react-aria-components: "npm:^1.7.1" react-dom: "npm:^18.0.0" @@ -793,7 +969,7 @@ __metadata: react-dom: ^18.0.0 react-is: ^18.0.0 tailwindcss: ^4.0.11 - checksum: 10c0/197890940992336aa2260716a1d2884dc85c5f86492ae90cd75a9dab51810a3598d70ada990cd743e6839a8ae4b9dfa893f35a64147990f2f2428308f561a177 + checksum: 10c0/ef3d0851dabe2454444cfe5ea43bb74db65a0257321165e41c3b26128bf99ef43d44baf67735246237b9345aee280431d3d88f5088d5cf0103edce47e03fe9ff languageName: node linkType: hard @@ -1037,7 +1213,7 @@ __metadata: languageName: node linkType: hard -"@noble/ciphers@npm:^1.0.0": +"@noble/ciphers@npm:^1.0.0, @noble/ciphers@npm:^1.3.0": version: 1.3.0 resolution: "@noble/ciphers@npm:1.3.0" checksum: 10c0/3ba6da645ce45e2f35e3b2e5c87ceba86b21dfa62b9466ede9edfb397f8116dae284f06652c0cd81d99445a2262b606632e868103d54ecc99fd946ae1af8cd37 @@ -1080,6 +1256,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.9.2, @noble/curves@npm:^1.9.1": + version: 1.9.2 + resolution: "@noble/curves@npm:1.9.2" + dependencies: + "@noble/hashes": "npm:1.8.0" + checksum: 10c0/21d049ae4558beedbf5da0004407b72db84360fa29d64822d82dc9e80251e1ecb46023590cc4b20e70eed697d1b87279b4911dc39f8694c51c874289cfc8e9a7 + languageName: node + linkType: hard + "@noble/curves@npm:^1.6.0, @noble/curves@npm:~1.9.0": version: 1.9.1 resolution: "@noble/curves@npm:1.9.1" @@ -1117,7 +1302,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:~1.8.0": +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": version: 1.8.0 resolution: "@noble/hashes@npm:1.8.0" checksum: 10c0/06a0b52c81a6fa7f04d67762e08b2c476a00285858150caeaaff4037356dd5e119f45b2a530f638b77a5eeca013168ec1b655db41bae3236cb2e9d511484fc77 @@ -3353,7 +3538,7 @@ __metadata: languageName: node linkType: hard -"@scure/bip32@npm:^1.5.0": +"@scure/bip32@npm:1.7.0, @scure/bip32@npm:^1.5.0, @scure/bip32@npm:^1.7.0": version: 1.7.0 resolution: "@scure/bip32@npm:1.7.0" dependencies: @@ -3384,7 +3569,7 @@ __metadata: languageName: node linkType: hard -"@scure/bip39@npm:^1.4.0": +"@scure/bip39@npm:1.6.0, @scure/bip39@npm:^1.4.0, @scure/bip39@npm:^1.6.0": version: 1.6.0 resolution: "@scure/bip39@npm:1.6.0" dependencies: @@ -3793,6 +3978,39 @@ __metadata: languageName: node linkType: hard +"@wagmi/cli@npm:^2.3.1": + version: 2.3.1 + resolution: "@wagmi/cli@npm:2.3.1" + dependencies: + abitype: "npm:^1.0.4" + bundle-require: "npm:^5.1.0" + cac: "npm:^6.7.14" + change-case: "npm:^5.4.4" + chokidar: "npm:4.0.1" + dedent: "npm:^0.7.0" + dotenv: "npm:^16.3.1" + dotenv-expand: "npm:^10.0.0" + esbuild: "npm:~0.25.4" + escalade: "npm:3.2.0" + fdir: "npm:^6.1.1" + nanospinner: "npm:1.2.2" + pathe: "npm:^1.1.2" + picocolors: "npm:^1.0.0" + picomatch: "npm:^3.0.0" + prettier: "npm:^3.0.3" + viem: "npm:2.x" + zod: "npm:^3.22.2" + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + bin: + wagmi: dist/esm/cli.js + checksum: 10c0/9b838d9807efab26db5689575477923c6ddf63397269fd84ab4966d87aebc796d32920df77f27556a973ec73d973b9bcf1958d59c4559cdb794c65ec96186cca + languageName: node + linkType: hard + "@wagmi/connectors@npm:5.8.3, @wagmi/connectors@npm:>=5.7.11": version: 5.8.3 resolution: "@wagmi/connectors@npm:5.8.3" @@ -4233,7 +4451,7 @@ __metadata: languageName: node linkType: hard -"abitype@npm:1.0.8, abitype@npm:^1.0.6": +"abitype@npm:1.0.8, abitype@npm:^1.0.4, abitype@npm:^1.0.6, abitype@npm:^1.0.8": version: 1.0.8 resolution: "abitype@npm:1.0.8" peerDependencies: @@ -4486,6 +4704,24 @@ __metadata: languageName: node linkType: hard +"bundle-require@npm:^5.1.0": + version: 5.1.0 + resolution: "bundle-require@npm:5.1.0" + dependencies: + load-tsconfig: "npm:^0.2.3" + peerDependencies: + esbuild: ">=0.18" + checksum: 10c0/8bff9df68eb686f05af952003c78e70ffed2817968f92aebb2af620cc0b7428c8154df761d28f1b38508532204278950624ef86ce63644013dc57660a9d1810f + languageName: node + linkType: hard + +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 + languageName: node + linkType: hard + "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -4607,6 +4843,22 @@ __metadata: languageName: node linkType: hard +"change-case@npm:^5.4.4": + version: 5.4.4 + resolution: "change-case@npm:5.4.4" + checksum: 10c0/2a9c2b9c9ad6ab2491105aaf506db1a9acaf543a18967798dcce20926c6a173aa63266cb6189f3086e3c14bf7ae1f8ea4f96ecc466fcd582310efa00372f3734 + languageName: node + linkType: hard + +"chokidar@npm:4.0.1": + version: 4.0.1 + resolution: "chokidar@npm:4.0.1" + dependencies: + readdirp: "npm:^4.0.1" + checksum: 10c0/4bb7a3adc304059810bb6c420c43261a15bb44f610d77c35547addc84faa0374265c3adc67f25d06f363d9a4571962b02679268c40de07676d260de1986efea9 + languageName: node + linkType: hard + "chokidar@npm:^4.0.3": version: 4.0.3 resolution: "chokidar@npm:4.0.3" @@ -4863,6 +5115,13 @@ __metadata: languageName: node linkType: hard +"dedent@npm:^0.7.0": + version: 0.7.0 + resolution: "dedent@npm:0.7.0" + checksum: 10c0/7c3aa00ddfe3e5fcd477958e156156a5137e3bb6ff1493ca05edff4decf29a90a057974cc77e75951f8eb801c1816cb45aea1f52d628cdd000b82b36ab839d1b + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -4928,6 +5187,20 @@ __metadata: languageName: node linkType: hard +"dotenv-expand@npm:^10.0.0": + version: 10.0.0 + resolution: "dotenv-expand@npm:10.0.0" + checksum: 10c0/298f5018e29cfdcb0b5f463ba8e8627749103fbcf6cf81c561119115754ed582deee37b49dfc7253028aaba875ab7aea5fa90e5dac88e511d009ab0e6677924e + languageName: node + linkType: hard + +"dotenv@npm:^16.3.1": + version: 16.5.0 + resolution: "dotenv@npm:16.5.0" + checksum: 10c0/5bc94c919fbd955bf0ba44d33922a1e93d1078e64a1db5c30faeded1d996e7a83c55332cb8ea4fae5a9ca4d0be44cbceb95c5811e70f9f095298df09d1997dd9 + languageName: node + linkType: hard + "dunder-proto@npm:^1.0.1": version: 1.0.1 resolution: "dunder-proto@npm:1.0.1" @@ -5187,7 +5460,93 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.2.0": +"esbuild@npm:~0.25.4": + version: 0.25.5 + resolution: "esbuild@npm:0.25.5" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.5" + "@esbuild/android-arm": "npm:0.25.5" + "@esbuild/android-arm64": "npm:0.25.5" + "@esbuild/android-x64": "npm:0.25.5" + "@esbuild/darwin-arm64": "npm:0.25.5" + "@esbuild/darwin-x64": "npm:0.25.5" + "@esbuild/freebsd-arm64": "npm:0.25.5" + "@esbuild/freebsd-x64": "npm:0.25.5" + "@esbuild/linux-arm": "npm:0.25.5" + "@esbuild/linux-arm64": "npm:0.25.5" + "@esbuild/linux-ia32": "npm:0.25.5" + "@esbuild/linux-loong64": "npm:0.25.5" + "@esbuild/linux-mips64el": "npm:0.25.5" + "@esbuild/linux-ppc64": "npm:0.25.5" + "@esbuild/linux-riscv64": "npm:0.25.5" + "@esbuild/linux-s390x": "npm:0.25.5" + "@esbuild/linux-x64": "npm:0.25.5" + "@esbuild/netbsd-arm64": "npm:0.25.5" + "@esbuild/netbsd-x64": "npm:0.25.5" + "@esbuild/openbsd-arm64": "npm:0.25.5" + "@esbuild/openbsd-x64": "npm:0.25.5" + "@esbuild/sunos-x64": "npm:0.25.5" + "@esbuild/win32-arm64": "npm:0.25.5" + "@esbuild/win32-ia32": "npm:0.25.5" + "@esbuild/win32-x64": "npm:0.25.5" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/aba8cbc11927fa77562722ed5e95541ce2853f67ad7bdc40382b558abc2e0ec57d92ffb820f082ba2047b4ef9f3bc3da068cdebe30dfd3850cfa3827a78d604e + languageName: node + linkType: hard + +"escalade@npm:3.2.0, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 @@ -5206,13 +5565,14 @@ __metadata: resolution: "escrow-v1-ui@workspace:." dependencies: "@eslint/js": "npm:^9.25.0" - "@kleros/ui-components-library": "npm:^3.3.4" + "@kleros/ui-components-library": "npm:^3.4.5" "@reown/appkit": "npm:^1.7.6" "@reown/appkit-adapter-wagmi": "npm:^1.7.6" "@tanstack/react-query": "npm:^5.76.1" "@types/react": "npm:^18.2.55" "@types/react-dom": "npm:^18.2.18" "@vitejs/plugin-react": "npm:^4.4.1" + "@wagmi/cli": "npm:^2.3.1" eslint: "npm:^9.25.0" eslint-plugin-react-hooks: "npm:^5.2.0" eslint-plugin-react-refresh: "npm:^0.4.19" @@ -5531,6 +5891,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.1.1": + version: 6.4.6 + resolution: "fdir@npm:6.4.6" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/45b559cff889934ebb8bc498351e5acba40750ada7e7d6bde197768d2fa67c149be8ae7f8ff34d03f4e1eb20f2764116e56440aaa2f6689e9a4aa7ef06acafe9 + languageName: node + linkType: hard + "fdir@npm:^6.4.4": version: 6.4.4 resolution: "fdir@npm:6.4.4" @@ -6273,6 +6645,13 @@ __metadata: languageName: node linkType: hard +"load-tsconfig@npm:^0.2.3": + version: 0.2.5 + resolution: "load-tsconfig@npm:0.2.5" + checksum: 10c0/bf2823dd26389d3497b6567f07435c5a7a58d9df82e879b0b3892f87d8db26900f84c85bc329ef41c0540c0d6a448d1c23ddc64a80f3ff6838b940f3915a3fcb + languageName: node + linkType: hard + "locate-path@npm:^5.0.0": version: 5.0.0 resolution: "locate-path@npm:5.0.0" @@ -6319,6 +6698,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c + languageName: node + linkType: hard + "loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -6543,6 +6929,15 @@ __metadata: languageName: node linkType: hard +"nanospinner@npm:1.2.2": + version: 1.2.2 + resolution: "nanospinner@npm:1.2.2" + dependencies: + picocolors: "npm:^1.1.1" + checksum: 10c0/07264f63816a8ec24d84ffe216a605cf11dffd8b098d4c5e6790437304b47e10ce4fc341de8dbcfc1b59aa42107f9949c89bcc201239eb61a80e14b6b1a20c90 + languageName: node + linkType: hard + "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -6759,6 +7154,27 @@ __metadata: languageName: node linkType: hard +"ox@npm:0.8.1": + version: 0.8.1 + resolution: "ox@npm:0.8.1" + dependencies: + "@adraffy/ens-normalize": "npm:^1.11.0" + "@noble/ciphers": "npm:^1.3.0" + "@noble/curves": "npm:^1.9.1" + "@noble/hashes": "npm:^1.8.0" + "@scure/bip32": "npm:^1.7.0" + "@scure/bip39": "npm:^1.6.0" + abitype: "npm:^1.0.8" + eventemitter3: "npm:5.0.1" + peerDependencies: + typescript: ">=5.4.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/3d04df384a35c94b21a29d867ee3735acf9a975d46ffb0a26cc438b92f1e4952b2b3cddb74b4213e88d2988e82687db9b85c1018c5d4b24737b1c3d7cb7c809e + languageName: node + linkType: hard + "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -6868,7 +7284,14 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.1.1": +"pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 + languageName: node + linkType: hard + +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 @@ -6882,6 +7305,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^3.0.0": + version: 3.0.1 + resolution: "picomatch@npm:3.0.1" + checksum: 10c0/70ec738569f1864658378b7abdab8939d15dae0718c1df994eae3346fd33daf6a3c1ff4e0c1a0cd1e2c0319130985b63a2cff34d192f2f2acbb78aca76111736 + languageName: node + linkType: hard + "picomatch@npm:^4.0.2": version: 4.0.2 resolution: "picomatch@npm:4.0.2" @@ -7005,6 +7435,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.0.3": + version: 3.5.3 + resolution: "prettier@npm:3.5.3" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/3880cb90b9dc0635819ab52ff571518c35bd7f15a6e80a2054c05dbc8a3aa6e74f135519e91197de63705bcb38388ded7e7230e2178432a1468005406238b877 + languageName: node + linkType: hard + "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -8290,6 +8729,27 @@ __metadata: languageName: node linkType: hard +"viem@npm:2.x": + version: 2.31.2 + resolution: "viem@npm:2.31.2" + dependencies: + "@noble/curves": "npm:1.9.2" + "@noble/hashes": "npm:1.8.0" + "@scure/bip32": "npm:1.7.0" + "@scure/bip39": "npm:1.6.0" + abitype: "npm:1.0.8" + isows: "npm:1.0.7" + ox: "npm:0.8.1" + ws: "npm:8.18.2" + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/02a0df1f9d3f789ac8b3e95cb717ca16eb81e62493f6fc5e5d7c0fe8d68f6a7889d3f8295deca96d5daa570317ece9716b4a717f9cf2c36629b6662fd03591cd + languageName: node + linkType: hard + "viem@npm:>=2.23.11, viem@npm:>=2.29.0, viem@npm:^2.1.1, viem@npm:^2.30.0": version: 2.30.0 resolution: "viem@npm:2.30.0" @@ -8550,6 +9010,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.18.2": + version: 8.18.2 + resolution: "ws@npm:8.18.2" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/4b50f67931b8c6943c893f59c524f0e4905bbd183016cfb0f2b8653aa7f28dad4e456b9d99d285bbb67cca4fedd9ce90dfdfaa82b898a11414ebd66ee99141e4 + languageName: node + linkType: hard + "ws@npm:^7.5.1": version: 7.5.10 resolution: "ws@npm:7.5.10" @@ -8665,6 +9140,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.22.2": + version: 3.25.64 + resolution: "zod@npm:3.25.64" + checksum: 10c0/00d76093a999e377e4ffd037fa7185e861c35917e8c4272f514115c206a0654995168f57fb71708b11e0a9243206d988b7f63b543404e1796402e50d346a6bd7 + languageName: node + linkType: hard + "zustand@npm:5.0.0": version: 5.0.0 resolution: "zustand@npm:5.0.0"