diff --git a/src/components/Claim/Link/Initial.view.tsx b/src/components/Claim/Link/Initial.view.tsx
index 0701a3fb4..2930ffd60 100644
--- a/src/components/Claim/Link/Initial.view.tsx
+++ b/src/components/Claim/Link/Initial.view.tsx
@@ -20,7 +20,12 @@ import { Popover } from '@headlessui/react'
import { useAuth } from '@/context/authContext'
import { ActionType, estimatePoints } from '@/components/utils/utils'
import { CrispButton } from '@/components/CrispChat'
-import { MAX_CASHOUT_LIMIT, MIN_CASHOUT_LIMIT, optimismChainId, usdcAddressOptimism } from '@/components/Offramp/Offramp.consts'
+import {
+ MAX_CASHOUT_LIMIT,
+ MIN_CASHOUT_LIMIT,
+ optimismChainId,
+ usdcAddressOptimism,
+} from '@/components/Offramp/Offramp.consts'
export const InitialClaimLinkView = ({
onNext,
@@ -296,6 +301,7 @@ export const InitialClaimLinkView = ({
Number(claimLinkData.tokenAmount) * Math.pow(10, claimLinkData.tokenDecimals)
).toString()
+ // TODO: this is duplicate with src/utils/fetchRouteRaw
const route = await getSquidRouteRaw({
squidRouterUrl: 'https://apiplus.squidrouter.com/v2/route',
fromChain: claimLinkData.chainId.toString(),
@@ -634,8 +640,9 @@ export const InitialClaimLinkView = ({
<>
{errorState.errorMessage === 'No route found for the given token pair.' && (
<>
-
- {' '}
+ {' '}
{
@@ -654,14 +661,16 @@ export const InitialClaimLinkView = ({
{errorState.errorMessage === 'offramp_lt_minimum' && (
<>
>
)}
{errorState.errorMessage === 'offramp_mt_maximum' && (
<>
>
)}
diff --git a/src/components/Offramp/Confirm.view.tsx b/src/components/Offramp/Confirm.view.tsx
index 6fd502b5b..f52215859 100644
--- a/src/components/Offramp/Confirm.view.tsx
+++ b/src/components/Offramp/Confirm.view.tsx
@@ -93,7 +93,7 @@ export const OfframpConfirmView = ({
//////////////////////
// functions for cashout offramps
// TODO: they need to be refactored to a separate file
-
+ // TODO: this function is a clusterfuck
const fetchNecessaryDetails = useCallback(async () => {
if (!user || !selectedChainID || !selectedTokenAddress) {
throw new Error('Missing user or token information')
@@ -137,7 +137,8 @@ export const OfframpConfirmView = ({
}
}, [user, selectedChainID, selectedTokenAddress, offrampForm])
- const handleConfirm = async () => {
+ // For cashout offramps
+ const handleCashoutConfirm = async () => {
setLoadingState('Loading')
setErrorState({ showError: false, errorMessage: '' })
@@ -145,7 +146,6 @@ export const OfframpConfirmView = ({
if (!preparedCreateLinkWrapperResponse) return
// Fetch all necessary details before creating the link
- // (and make sure we have all the data we need)
const {
crossChainDetails,
peanutAccount,
@@ -154,26 +154,10 @@ export const OfframpConfirmView = ({
allLiquidationAddresses,
} = await fetchNecessaryDetails()
- const link = await createLinkWrapper(preparedCreateLinkWrapperResponse)
- setCreatedLink(link)
- console.log(`created claimlink: ${link}`)
-
- // Save link temporarily in localStorage with TEMP tag
- const tempKey = `TEMP_CASHOUT_LINK_${Date.now()}`
- localStorage.setItem(
- tempKey,
- JSON.stringify({
- link,
- createdAt: Date.now(),
- })
- )
- console.log(`Temporarily saved link in localStorage with key: ${tempKey}`)
-
- const claimLinkData = await getLinkDetails({ link: link })
-
// Process link details and determine if cross-chain transfer is needed
+ // TODO: type safety
const { tokenName, chainName, xchainNeeded, liquidationAddress } = await processLinkDetails(
- claimLinkData,
+ preparedCreateLinkWrapperResponse.linkDetails,
crossChainDetails as CrossChainDetails[],
allLiquidationAddresses,
bridgeCustomerId,
@@ -189,12 +173,38 @@ export const OfframpConfirmView = ({
const chainId = utils.getChainIdFromBridgeChainName(chainName) ?? ''
const tokenAddress = utils.getTokenAddressFromBridgeTokenName(chainId ?? '10', tokenName) ?? ''
+ // Now that we have all the necessary information, create the link
+ const link = await createLinkWrapper(preparedCreateLinkWrapperResponse)
+ setCreatedLink(link)
+ console.log(`created claimlink: ${link}`)
+
+ // Save link temporarily in localStorage with TEMP tag
+ const tempKey = `TEMP_CASHOUT_LINK_${Date.now()}`
+ localStorage.setItem(
+ tempKey,
+ JSON.stringify({
+ link,
+ createdAt: Date.now(),
+ })
+ )
+ console.log(`Temporarily saved link in localStorage with key: ${tempKey}`)
+
+ const claimLinkData = await getLinkDetails({ link: link })
+
+ const srcChainId = claimLinkData.chainId
+ const destChainId = chainId
+ const isSameChain = srcChainId === destChainId
const { sourceTxHash, destinationTxHash } = await claimAndProcessLink(
xchainNeeded,
liquidationAddress.address,
claimLinkData,
chainId,
- tokenAddress
+ tokenAddress,
+ isSameChain
+ )
+
+ console.log(
+ `finalized claimAndProcessLink, sourceTxHash: ${sourceTxHash}, destinationTxHash: ${destinationTxHash}`
)
localStorage.removeItem(tempKey)
@@ -215,7 +225,6 @@ export const OfframpConfirmView = ({
console.log('Transaction hash:', destinationTxHash)
onNext()
- setLoadingState('Idle')
} catch (error) {
handleError(error)
} finally {
@@ -277,13 +286,13 @@ export const OfframpConfirmView = ({
}
const route = await utils.fetchRouteRaw(
- claimLinkData.tokenAddress,
- claimLinkData.chainId.toString(),
+ claimLinkData.tokenAddress!,
+ claimLinkData.chainId!.toString(),
usdcAddressOptimism,
optimismChainId,
- claimLinkData.tokenDecimals,
- claimLinkData.tokenAmount,
- claimLinkData.senderAddress
+ claimLinkData.tokenDecimals!,
+ claimLinkData.tokenAmount!,
+ claimLinkData.senderAddress ?? '0x9647BB6a598c2675310c512e0566B60a5aEE6261'
)
if (route === undefined) {
@@ -301,8 +310,9 @@ export const OfframpConfirmView = ({
address: string,
claimLinkData: any, // TODO: fix type
chainId: string,
- tokenAddress: string
- ) => {
+ tokenAddress: string,
+ isSameChain?: boolean // e.g. for opt ETH -> opt USDC
+ ): Promise<{ sourceTxHash: string; destinationTxHash: string }> => {
if (xchainNeeded) {
const sourceTxHash = await claimLinkXchain({
address,
@@ -310,34 +320,48 @@ export const OfframpConfirmView = ({
destinationChainId: chainId,
destinationToken: tokenAddress,
})
+ setLoadingState('Executing transaction') // claimLinkXchain sets loading state to idle after it finishes. pls no.
- // Wait for the destination transaction
- const destinationTxHash = await new Promise((resolve) => {
- let retryCount = 0
- let intervalId = setInterval(async () => {
- if (retryCount >= 10) {
- clearInterval(intervalId)
- resolve(sourceTxHash)
- return
- }
+ if (isSameChain) {
+ return {
+ sourceTxHash,
+ destinationTxHash: sourceTxHash,
+ }
+ }
+
+ const maxAttempts = 15
+ let attempts = 0
+
+ while (attempts < maxAttempts) {
+ try {
const status = await checkTransactionStatus(sourceTxHash)
if (status.squidTransactionStatus === 'success') {
- clearInterval(intervalId)
- resolve(status.toChain.transactionId)
+ return {
+ sourceTxHash,
+ destinationTxHash: status.toChain.transactionId,
+ }
}
- retryCount++
- }, 1000)
- })
+ } catch (error) {
+ console.warn('Error checking transaction status:', error)
+ }
+
+ attempts++
+ if (attempts < maxAttempts) {
+ await new Promise((resolve) => setTimeout(resolve, 2000))
+ }
+ }
+ console.warn('Transaction status check timed out. Using sourceTxHash as destinationTxHash.')
return {
sourceTxHash,
- destinationTxHash: destinationTxHash,
+ destinationTxHash: sourceTxHash,
}
} else {
const txHash = await claimLink({
address,
link: claimLinkData.link,
})
+ setLoadingState('Executing transaction') // claimLink
return { sourceTxHash: txHash, destinationTxHash: txHash }
}
}
@@ -383,7 +407,7 @@ export const OfframpConfirmView = ({
}
const handleError = (error: unknown) => {
- console.error('Error in handleConfirm:', error)
+ console.error('Error in handleCashoutConfirm:', error)
setErrorState({
showError: true,
errorMessage:
@@ -428,9 +452,8 @@ export const OfframpConfirmView = ({
}
//////////////////////
- // functions for claim link offramps
+ // functions for claim link offramps (not self-cashout)
// TODO: they need to be refactored to a separate file
-
const handleSubmitTransfer = async () => {
if (claimLinkData && tokenPrice && estimatedPoints && attachment && recipientType) {
try {
@@ -743,7 +766,7 @@ export const OfframpConfirmView = ({
onClick={() => {
switch (offrampType) {
case OfframpType.CASHOUT: {
- handleConfirm()
+ handleCashoutConfirm()
break
}
case OfframpType.CLAIM: {
diff --git a/src/components/utils/utils.ts b/src/components/utils/utils.ts
index 0935ba66b..d119c811f 100644
--- a/src/components/utils/utils.ts
+++ b/src/components/utils/utils.ts
@@ -76,7 +76,7 @@ export async function checkTransactionStatus(txHash: string): Promise {
try {
const _tokenAmount = BigInt(Math.floor(Number(tokenAmount) * Math.pow(10, tokenDecimals))).toString()
@@ -537,12 +539,11 @@ export const fetchRouteRaw = async (
fromChain: fromChain,
fromToken: fromToken.toLowerCase(),
fromAmount: _tokenAmount,
+ fromAddress: fromAddress ?? '0x9647BB6a598c2675310c512e0566B60a5aEE6261', // placeholder address just to get a route sample
+ toAddress: '0x04B5f21facD2ef7c7dbdEe7EbCFBC68616adC45C', // placeholder address just to get a route sample
toChain: toChain,
toToken: toToken,
slippage: 1,
- fromAddress: senderAddress,
-
- toAddress: '0x04B5f21facD2ef7c7dbdEe7EbCFBC68616adC45C',
})
return route
} catch (error) {