Skip to content

Commit

Permalink
loading states fixes, implement commit status resolver and store in a…
Browse files Browse the repository at this point in the history
…tomicContext
  • Loading branch information
arentant committed Dec 25, 2024
1 parent 78888a3 commit b781265
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 53 deletions.
5 changes: 3 additions & 2 deletions components/Swap/AtomicChat/Actions/LpLock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -22,6 +22,7 @@ export const LpLockingAssets: FC = () => {
})
if (destinationDetails) {
setDestinationDetails({ ...destinationDetails, fetchedByLightClient: true })
debugger
return
}
}
Expand Down
78 changes: 35 additions & 43 deletions components/Swap/AtomicChat/Resolver.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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()

Expand All @@ -44,49 +35,57 @@ 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) ? <div><span>Solver:</span> <span>{lp_address && shortenAddress(lp_address)}</span> <span>You:</span> <span>{wallet?.address && shortenAddress(wallet?.address)}</span></div> : <>Initiates a swap process with the solver</>
const description = (assetsLocked)
? <div className="inline-flex gap-3">
{
lpLockTx && destination_network &&
<div className="inline-flex gap-1">
<p>Solver:</p> <Link className="underline hover:no-underline" target="_blank" href={destination_network?.transaction_explorer_template.replace('{0}', lpLockTx?.hash)}>{shortenAddress(lpLockTx.hash)}</Link>
</div>
}
{
addLockSigTx && source_network &&
<div className="inline-flex gap-1">
<p>You:</p> <Link className="underline hover:no-underline" target="_blank" href={source_network?.transaction_explorer_template.replace('{0}', addLockSigTx?.hash)}>{shortenAddress(addLockSigTx.hash)}</Link>
</div>
}
</div>
: <>Initiates a swap process with the solver</>

const completed = !!(sourceDetails?.hashlock && destinationDetails?.hashlock) || !!lpRedeemTransaction?.hash || commitStatus === CommitStatus.RedeemCompleted || commitStatus === CommitStatus.AssetsLocked

return <Step
step={2}
title={title}
description={description}
active={commited}
completed={!!assetsLocked}
completed={completed}
loading={loading}
>
<SolverStatus />
</Step>
}

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) {
Expand Down Expand Up @@ -156,15 +155,9 @@ export const ResolveMessages: FC<{ timelock: number | undefined, showTimer: bool
</div>
}
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 <div className="w-full flex flex-col gap-4">
Expand All @@ -178,9 +171,8 @@ const ResolveAction: FC = () => {
Try again
</SubmitButton>
</div>

}
if (redeemCompleted) {
if (commitStatus === CommitStatus.RedeemCompleted) {
return <ActionStatus
status="success"
title={
Expand All @@ -196,7 +188,7 @@ const ResolveAction: FC = () => {
}
/>
}
if (isTimelockExpired) {
if (commitStatus === CommitStatus.TimelockExpired) {
if (sourceDetails?.claimed == 2) {
return <ActionStatus
status="success"
Expand All @@ -207,25 +199,25 @@ const ResolveAction: FC = () => {
return <UserRefundAction />
}
}
if (assetsLocked) {
if (commitStatus === CommitStatus.AssetsLocked) {
return <RedeemAction />
}
if (lpLockDetected) {
if (commitStatus === CommitStatus.LpLockDetected || commitStatus === CommitStatus.UserLocked) {
return <UserLockAction />
}
if (commited) {
if (commitStatus === CommitStatus.Commited) {
return <LpLockingAssets />
}
return <UserCommitAction />
}

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 <div className="space-y-4">
Expand Down
40 changes: 36 additions & 4 deletions context/atomicContext.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<DataContextType | null>(null);

type DataContextType = {
Expand All @@ -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;
Expand Down Expand Up @@ -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<ApiResponse<CommitFromApi>>((parsedCommitId && commitFromApi?.transactions.length !== 3 && destinationDetails?.claimed !== 3) ? `${url}/api/swap/${parsedCommitId}` : null, fetcher, { refreshInterval: 5000 })
const { data } = useSWR<ApiResponse<CommitFromApi>>((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) {
Expand All @@ -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;

Expand Down Expand Up @@ -137,11 +152,11 @@ export function AtomicProvider({ children }) {
sourceDetails,
destinationDetails,
userLocked,
isTimelockExpired,
completedRefundHash,
error,
commitFromApi,
lightClient,
commitStatus: status,
setDestinationDetails,
setSourceDetails,
setUserLocked,
Expand All @@ -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<DataContextType>(AtomicStateContext as Context<DataContextType>);

Expand Down
2 changes: 1 addition & 1 deletion lib/layerSwapApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}[]
Expand Down
6 changes: 3 additions & 3 deletions lib/lightClient/providers/evm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit b781265

Please sign in to comment.