diff --git a/components/Swap/AtomicChat/Actions/LpLock.tsx b/components/Swap/AtomicChat/Actions/LpLock.tsx index 258992d98..bdb5f3ae5 100644 --- a/components/Swap/AtomicChat/Actions/LpLock.tsx +++ b/components/Swap/AtomicChat/Actions/LpLock.tsx @@ -5,14 +5,14 @@ import { useAtomicState } from "../../../../context/atomicContext"; import SubmitButton from "../../../buttons/submitButton"; export const LpLockingAssets: FC = () => { - const { destination_network, commitId, setDestinationDetails, destination_asset, lightClient } = useAtomicState() + const { destination_network, commitId, setDestinationDetails, destination_asset, lightClient, sourceDetails } = useAtomicState() const { getWithdrawalProvider } = useWallet() const destination_provider = destination_network && getWithdrawalProvider(destination_network) const atomicContract = (destination_asset?.contract ? destination_network?.metadata.htlc_token_contract : destination_network?.metadata.htlc_native_contract) as `0x${string}` const getDetails = async ({ provider, network, commitId, asset }: { provider: WalletProvider, network: Network, commitId: string, asset: Token }) => { - if (lightClient) { + if (lightClient && !sourceDetails?.hashlock) { try { const destinationDetails = await lightClient.getHashlock({ network: network, @@ -22,6 +22,7 @@ export const LpLockingAssets: FC = () => { }) if (destinationDetails) { setDestinationDetails({ ...destinationDetails, fetchedByLightClient: true }) + debugger return } } diff --git a/components/Swap/AtomicChat/Resolver.tsx b/components/Swap/AtomicChat/Resolver.tsx index 6d29ef2db..cc779d80c 100644 --- a/components/Swap/AtomicChat/Resolver.tsx +++ b/components/Swap/AtomicChat/Resolver.tsx @@ -1,10 +1,9 @@ import { FC } from "react"; import { UserCommitAction, UserLockAction, UserRefundAction } from "./Actions/UserActions"; -import { useAtomicState } from "../../../context/atomicContext"; +import { CommitStatus, useAtomicState } from "../../../context/atomicContext"; import { LpLockingAssets } from "./Actions/LpLock"; import { RedeemAction } from "./Actions/Redeem"; import ActionStatus from "./Actions/Status/ActionStatus"; -import useWallet from "../../../hooks/useWallet"; import SubmitButton from "../../buttons/submitButton"; import TimelockTimer from "./Timer"; import shortenAddress from "../../utils/ShortenAddress"; @@ -14,14 +13,6 @@ import CheckedIcon from "../../icons/CheckedIcon"; import LockIcon from "../../icons/LockIcon"; import Link from "next/link"; -export enum Progress { - Commit = 'commit', - LpLock = 'lp_lock', - Lock = 'lock', - Redeem = 'redeem', - Refund = 'refund', -} - const RequestStep: FC = () => { const { sourceDetails, commitId, commitTxId, source_network, commitFromApi } = useAtomicState() @@ -44,31 +35,42 @@ const RequestStep: FC = () => { } const SignAndConfirmStep: FC = () => { - const { sourceDetails, destinationDetails, source_network, destination_network, commitFromApi } = useAtomicState() + const { sourceDetails, destinationDetails, source_network, destination_network, commitFromApi, commitStatus } = useAtomicState() const lpLockTx = commitFromApi?.transactions.find(t => t.type === 'lock') const lpRedeemTransaction = commitFromApi?.transactions.find(t => t.type === 'redeem' && t.network === destination_network?.name) - + const addLockSigTx = commitFromApi?.transactions.find(t => t.type === 'addlocksig') const commited = (sourceDetails || lpLockTx) ? true : false; - const assetsLocked = (sourceDetails?.hashlock && destinationDetails?.hashlock) ? true : false; - const loading = sourceDetails && destinationDetails && !(sourceDetails?.hashlock || destinationDetails?.hashlock) - - const { getWithdrawalProvider } = useWallet() - const source_provider = source_network && getWithdrawalProvider(source_network) - const wallet = source_provider?.getConnectedWallet() - - const lp_address = source_network?.metadata.lp_address + const assetsLocked = !!(sourceDetails?.hashlock && destinationDetails?.hashlock) || commitStatus === CommitStatus.AssetsLocked || commitStatus === CommitStatus.RedeemCompleted; + const loading = commitStatus === CommitStatus.UserLocked const title = assetsLocked ? "Signed & Confirmed" : "Sign & Confirm" - const description = (assetsLocked) ?
Solver: {lp_address && shortenAddress(lp_address)} You: {wallet?.address && shortenAddress(wallet?.address)}
: <>Initiates a swap process with the solver + const description = (assetsLocked) + ?
+ { + lpLockTx && destination_network && +
+

Solver:

{shortenAddress(lpLockTx.hash)} +
+ } + { + addLockSigTx && source_network && +
+

You:

{shortenAddress(addLockSigTx.hash)} +
+ } +
+ : <>Initiates a swap process with the solver + + const completed = !!(sourceDetails?.hashlock && destinationDetails?.hashlock) || !!lpRedeemTransaction?.hash || commitStatus === CommitStatus.RedeemCompleted || commitStatus === CommitStatus.AssetsLocked return @@ -76,17 +78,14 @@ const SignAndConfirmStep: FC = () => { } const SolverStatus: FC = () => { - const { sourceDetails, destinationDetails, commitFromApi, destination_network } = useAtomicState() + const { commitId, sourceDetails, destinationDetails, commitFromApi, destination_network, commitStatus } = useAtomicState() const lpLockTx = commitFromApi?.transactions.find(t => t.type === 'lock') - const commited = sourceDetails ? true : false; + const commited = commitId ? true : false; const lpLockDetected = destinationDetails?.hashlock ? true : false; - if (sourceDetails?.hashlock && destinationDetails?.hashlock) - return null - // TODO: maybe we should show the locked amount - if (!commited) + if (sourceDetails?.hashlock && destinationDetails?.hashlock || !commited || !(commitStatus == CommitStatus.LpLockDetected || commitStatus == CommitStatus.Commited)) return null //TODO: add the timer if (lpLockDetected) { @@ -156,15 +155,9 @@ export const ResolveMessages: FC<{ timelock: number | undefined, showTimer: bool } const ResolveAction: FC = () => { - const { sourceDetails, destinationDetails, destination_network, error, setError, isTimelockExpired, commitFromApi } = useAtomicState() - + const { sourceDetails, destination_network, error, setError, commitStatus, commitFromApi } = useAtomicState() const lpRedeemTransaction = commitFromApi?.transactions.find(t => t.type === 'redeem' && t.network === destination_network?.name) - const commited = sourceDetails ? true : false; - const lpLockDetected = destinationDetails?.hashlock ? true : false; - const assetsLocked = sourceDetails?.hashlock && destinationDetails?.hashlock ? true : false; - const redeemCompleted = (destinationDetails?.claimed == 3 ? true : false) || lpRedeemTransaction?.hash; - //TODO: remove lp actions just disable the button if (error) { return
@@ -178,9 +171,8 @@ const ResolveAction: FC = () => { Try again
- } - if (redeemCompleted) { + if (commitStatus === CommitStatus.RedeemCompleted) { return { } /> } - if (isTimelockExpired) { + if (commitStatus === CommitStatus.TimelockExpired) { if (sourceDetails?.claimed == 2) { return { return } } - if (assetsLocked) { + if (commitStatus === CommitStatus.AssetsLocked) { return } - if (lpLockDetected) { + if (commitStatus === CommitStatus.LpLockDetected || commitStatus === CommitStatus.UserLocked) { return } - if (commited) { + if (commitStatus === CommitStatus.Commited) { return } return } export const Actions: FC = () => { - const { destinationDetails, isTimelockExpired, sourceDetails, commitFromApi, destination_network } = useAtomicState() + const { destinationDetails, sourceDetails, commitFromApi, destination_network, commitStatus } = useAtomicState() const lpRedeemTransaction = commitFromApi?.transactions.find(t => t.type === 'redeem' && t.network === destination_network?.name) const allDone = ((sourceDetails?.hashlock && destinationDetails?.claimed == 3) || lpRedeemTransaction?.hash) ? true : false - const showTimer = !allDone && !isTimelockExpired + const showTimer = !allDone && commitStatus !== CommitStatus.TimelockExpired const timelock = sourceDetails?.timelock || sourceDetails?.timelock return
diff --git a/context/atomicContext.tsx b/context/atomicContext.tsx index 7ebb74fbc..c4f9229ff 100644 --- a/context/atomicContext.tsx +++ b/context/atomicContext.tsx @@ -1,4 +1,4 @@ -import { Context, createContext, useContext, useEffect, useState } from 'react' +import { Context, createContext, useContext, useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/router'; import { useSettingsState } from './settings'; import { Commit } from '../Models/PHTLC'; @@ -9,6 +9,17 @@ import { CommitFromApi } from '../lib/layerSwapApiClient'; import { toHex } from 'viem'; import LightClient from '../lib/lightClient'; +export enum CommitStatus { + Commit = 'commit', + Commited = 'commited', + LpLockDetected = 'lpLockDetected', + UserLocked = 'userLocked', + AssetsLocked = 'assetsLocked', + RedeemCompleted = 'redeemCompleted', + TimelockExpired = 'timelockExpired', + Refunded = 'refunded', +} + const AtomicStateContext = createContext(null); type DataContextType = { @@ -23,11 +34,11 @@ type DataContextType = { destinationDetails?: Commit & { fetchedByLightClient?: boolean }, userLocked?: boolean, sourceDetails?: Commit, - isTimelockExpired?: boolean, completedRefundHash?: string, error: string | undefined, commitFromApi?: CommitFromApi, lightClient: LightClient | undefined, + commitStatus: CommitStatus, onCommit: (commitId: string, txId: string) => void; setDestinationDetails: (data: Commit & { fetchedByLightClient?: boolean }) => void; setSourceDetails: (data: Commit) => void; @@ -71,7 +82,9 @@ export function AtomicProvider({ children }) { const fetcher = (args) => fetch(args).then(res => res.json()) const url = process.env.NEXT_PUBLIC_LS_API const parsedCommitId = commitId ? toHex(BigInt(commitId)) : undefined - const { data } = useSWR>((parsedCommitId && commitFromApi?.transactions.length !== 3 && destinationDetails?.claimed !== 3) ? `${url}/api/swap/${parsedCommitId}` : null, fetcher, { refreshInterval: 5000 }) + const { data } = useSWR>((parsedCommitId && commitFromApi?.transactions.length !== 4 && destinationDetails?.claimed !== 3) ? `${url}/api/swap/${parsedCommitId}` : null, fetcher, { refreshInterval: 5000 }) + + const status = useMemo(() => statusResolver({ commitFromApi, sourceDetails, destinationDetails, destination_network, timelockExpired: isTimelockExpired, userLocked }), [commitFromApi, sourceDetails, destinationDetails, destination_network, isTimelockExpired, userLocked]) useEffect(() => { if (data?.data) { @@ -83,12 +96,14 @@ export function AtomicProvider({ children }) { if (destination_network && destination_network.chain_id === '11155111') { (async () => { const lightClient = new LightClient() + console.log('init') await lightClient.initProvider({ network: destination_network }) setLightClient(lightClient) })() } }, [destination_network]) + useEffect(() => { let timer: NodeJS.Timeout; @@ -137,11 +152,11 @@ export function AtomicProvider({ children }) { sourceDetails, destinationDetails, userLocked, - isTimelockExpired, completedRefundHash, error, commitFromApi, lightClient, + commitStatus: status, setDestinationDetails, setSourceDetails, setUserLocked, @@ -153,6 +168,23 @@ export function AtomicProvider({ children }) { ) } +const statusResolver = ({ commitFromApi, sourceDetails, destinationDetails, destination_network, timelockExpired, userLocked }: { commitFromApi: CommitFromApi | undefined, sourceDetails: Commit | undefined, destinationDetails: Commit | undefined, destination_network: Network | undefined, timelockExpired: boolean, userLocked: boolean }) => { + const lpRedeemTransaction = commitFromApi?.transactions.find(t => t.type === 'redeem' && t.network === destination_network?.name) + + const commited = sourceDetails ? true : false; + const lpLockDetected = destinationDetails?.hashlock ? true : false; + const assetsLocked = sourceDetails?.hashlock && destinationDetails?.hashlock ? true : false; + const redeemCompleted = (destinationDetails?.claimed == 3 ? true : false) || lpRedeemTransaction?.hash; + + if (timelockExpired) return CommitStatus.TimelockExpired + else if (redeemCompleted) return CommitStatus.RedeemCompleted + else if (assetsLocked) return CommitStatus.AssetsLocked + else if (userLocked) return CommitStatus.UserLocked + else if (lpLockDetected) return CommitStatus.LpLockDetected + else if (commited) return CommitStatus.Commited + else return CommitStatus.Commit +} + export function useAtomicState() { const data = useContext(AtomicStateContext as Context); diff --git a/lib/layerSwapApiClient.ts b/lib/layerSwapApiClient.ts index ca679cbf7..2dbf11954 100644 --- a/lib/layerSwapApiClient.ts +++ b/lib/layerSwapApiClient.ts @@ -133,7 +133,7 @@ export type CommitFromApi = { receive_amount: number, fee_amount: number, transactions: { - type: 'lock' | 'redeem', + type: 'lock' | 'redeem' | 'addlocksig', hash: string, network: string }[] diff --git a/lib/lightClient/providers/evm/index.ts b/lib/lightClient/providers/evm/index.ts index 4d88db4e9..002c2e93a 100644 --- a/lib/lightClient/providers/evm/index.ts +++ b/lib/lightClient/providers/evm/index.ts @@ -94,9 +94,9 @@ export default class EVMLightClient extends _LightClient { const result = event.data.data const parsedResult: Commit = result ? { ...result, - // secret: Number(hexToBigInt(result.secret._hex)) !== 1 ? result.secret : null, - // amount: formatAmount(Number(hexToBigInt(result.amount._hex)), token.decimals), - // timelock: Number(result.timelock) + secret: Number(hexToBigInt(result.secret._hex)) !== 1 ? result.secret : null, + amount: formatAmount(Number(hexToBigInt(result.amount._hex)), token.decimals), + timelock: Number(result.timelock) } : undefined console.log('Worker event:', event) resolve(parsedResult)