import { BigNumber } from "bignumber.js"; import { isSwapOperationPending } from "./"; import { getMultipleStatus } from "./getStatus"; import type { TokenAccount, Account, SwapOperation, Operation } from "@ledgerhq/types-live"; import type { SwapStatus, SwapStatusRequest, UpdateAccountSwapStatus } from "./types"; import { log } from "@ledgerhq/logs"; const PROVIDERS_REQUIRING_OPERATION_ID = ["thorswap", "lifi", "nearintents", "swapsxyz"]; const maybeGetUpdatedSwapHistory = async ( swapHistory: SwapOperation[] | null | undefined, operations: Operation[] | null | undefined, ): Promise => { const pendingSwapIds: SwapStatusRequest[] = []; const atomicSwapIds: SwapStatus[] = []; let accountNeedsUpdating = false; let consolidatedSwapHistory: SwapOperation[] = []; if (swapHistory) { for (const swap of swapHistory) { const { provider, swapId, status, operationId } = swap; const updatedSwap: SwapOperation = { ...swap }; if (isSwapOperationPending(status)) { // if swapId is in operationId, then we can get the status from the operation // it means DEX swap like Uniswap if (operationId && swapId && operationId.includes(swapId)) { const operation = operations?.find(o => o.id.includes(operationId)); if (operation) { let newStatus; if (operation.blockHeight) { newStatus = operation.hasFailed ? "refunded" : "finished"; } else { newStatus = "pending"; } if (newStatus !== swap.status) { accountNeedsUpdating = true; updatedSwap.status = newStatus; atomicSwapIds.push({ provider, swapId, status: newStatus }); } } } else { // Collect all others swaps that need status update via getMultipleStatus const requiresOperationId = PROVIDERS_REQUIRING_OPERATION_ID.includes(provider); const relatedTransactionId = requiresOperationId ? operations?.find(op => op.id.includes(operationId))?.hash : undefined; pendingSwapIds.push({ provider, swapId, transactionId: relatedTransactionId, ...(requiresOperationId && { operationId }), }); } } } if (pendingSwapIds.length || atomicSwapIds.length) { const uniquePendingSwapIdsMap = new Map(); for (const item of pendingSwapIds) { if (item.provider === "uniswap") { continue; } const existingItem = uniquePendingSwapIdsMap.get(item.swapId); if (!existingItem) { uniquePendingSwapIdsMap.set(item.swapId, item); } else if (item.transactionId && !existingItem.transactionId) { uniquePendingSwapIdsMap.set(item.swapId, item); } } const uniquePendingSwapIds = Array.from(uniquePendingSwapIdsMap.values()); if (uniquePendingSwapIds.length !== pendingSwapIds.length) { log( "error", "swap: duplicate ids inside app.json, number", pendingSwapIds.length - uniquePendingSwapIds.length, ); } const newStatusList = pendingSwapIds.length ? await getMultipleStatus(uniquePendingSwapIds) : []; newStatusList.push(...atomicSwapIds); consolidatedSwapHistory = swapHistory.map((swap: SwapOperation) => { const newStatus = newStatusList.find(s => s.swapId === swap.swapId); if (newStatus) { const statusChanged = newStatus.status !== swap.status; const hasValidFinalAmount = newStatus.finalAmount != null && newStatus.finalAmount !== ""; const finalAmountChanged = hasValidFinalAmount && newStatus.finalAmount !== swap.finalAmount?.toString(); if (statusChanged || finalAmountChanged) { accountNeedsUpdating = true; return { ...swap, status: newStatus.status, ...(hasValidFinalAmount && { finalAmount: new BigNumber(newStatus.finalAmount!), }), }; } } return swap; }); } if (accountNeedsUpdating) { return consolidatedSwapHistory; } } }; const updateAccountSwapStatus: UpdateAccountSwapStatus = async (account: Account) => { const swapHistoryUpdated = await maybeGetUpdatedSwapHistory( account.swapHistory, account.operations, ); let subAccountSwapHistoryUpdated = false; let subAccounts: TokenAccount[] = []; if (account.type === "Account" && account.subAccounts?.length) { subAccounts = await Promise.all( account.subAccounts.map(async (subAccount: TokenAccount): Promise => { const updatedSwapHistory = await maybeGetUpdatedSwapHistory( subAccount.swapHistory, subAccount.operations, ); //As soon as we get one update, we will need to update the parent account if (updatedSwapHistory) subAccountSwapHistoryUpdated = true; return { ...subAccount, swapHistory: updatedSwapHistory || subAccount.swapHistory, }; }), ); } if (swapHistoryUpdated || subAccountSwapHistoryUpdated) { return { ...account, swapHistory: swapHistoryUpdated || account.swapHistory, subAccounts, }; } }; export default updateAccountSwapStatus;