UNPKG

@openocean.finance/widget-sdk

Version:

OpenOcean Any-to-Any Cross-Chain-Swap SDK

123 lines 5.55 kB
import { signTypedData } from 'viem/actions'; import { getAction } from 'viem/utils'; import { MaxUint256 } from '../../constants.js'; import { getAllowance } from './getAllowance.js'; import { parseEVMErrors } from './parseEVMErrors.js'; import { getNativePermit } from './permits/getNativePermit.js'; import { setAllowance } from './setAllowance.js'; import { isRelayerStep } from './typeguards.js'; import { waitForTransactionReceipt } from './waitForTransactionReceipt.js'; export const checkAllowance = async ({ client, chain, step, statusManager, executionOptions, allowUserInteraction = false, batchingSupported = false, permit2Supported = false, disableMessageSigning = false, }) => { // Find existing or create new allowance process const allowanceProcess = statusManager.findOrCreateProcess({ step, type: 'TOKEN_ALLOWANCE', chainId: step.action.fromChainId, }); try { // Handle existing pending transaction if (allowanceProcess.txHash && allowanceProcess.status !== 'DONE') { await waitForApprovalTransaction(client, allowanceProcess.txHash, allowanceProcess.type, step, chain, statusManager); return { status: 'DONE' }; } // Start new allowance check statusManager.updateProcess(step, allowanceProcess.type, 'STARTED'); const spenderAddress = permit2Supported ? chain.permit2 : step.estimate.approvalAddress; const fromAmount = BigInt(step.action.fromAmount); const approved = await getAllowance(chain.id, step.action.fromToken.address, client.account.address, spenderAddress); // Return early if already approved if (fromAmount <= approved) { statusManager.updateProcess(step, allowanceProcess.type, 'DONE'); return { status: 'DONE' }; } const isRelayerTransaction = isRelayerStep(step); let nativePermitData; if (isRelayerTransaction) { nativePermitData = step.typedData.find((p) => p.primaryType === 'Permit'); } else { nativePermitData = await getNativePermit(client, chain.id, step.action.fromToken.address, chain.permit2Proxy, fromAmount); } statusManager.updateProcess(step, allowanceProcess.type, 'ACTION_REQUIRED'); if (!allowUserInteraction) { return { status: 'ACTION_REQUIRED' }; } // Check if proxy contract is available and token supports native permits, not available for atomic batch const nativePermitSupported = !!nativePermitData && !!chain.permit2Proxy && !batchingSupported && !disableMessageSigning; if (nativePermitSupported && nativePermitData) { const signature = await getAction(client, signTypedData, 'signTypedData')({ account: client.account, domain: nativePermitData.domain, types: nativePermitData.types, primaryType: 'Permit', message: nativePermitData.message, }); statusManager.updateProcess(step, allowanceProcess.type, 'DONE'); return { status: 'NATIVE_PERMIT', data: { ...nativePermitData, signature, }, }; } // Set new allowance const approveAmount = permit2Supported ? MaxUint256 : fromAmount; const approveTxHash = await setAllowance(client, step.action.fromToken.address, spenderAddress, approveAmount, executionOptions, batchingSupported); if (batchingSupported) { statusManager.updateProcess(step, allowanceProcess.type, 'DONE'); return { status: 'BATCH_APPROVAL', data: { to: step.action.fromToken.address, data: approveTxHash, chainId: step.action.fromToken.chainId, }, }; } await waitForApprovalTransaction(client, approveTxHash, allowanceProcess.type, step, chain, statusManager); return { status: 'DONE' }; } catch (e) { const error = await parseEVMErrors(e, step, allowanceProcess); statusManager.updateProcess(step, allowanceProcess.type, 'FAILED', { error: { message: error.cause.message, code: error.code, }, }); statusManager.updateExecution(step, 'FAILED'); throw error; } }; const waitForApprovalTransaction = async (client, txHash, processType, step, chain, statusManager) => { const baseExplorerUrl = chain.metamask.blockExplorerUrls[0]; const getTxLink = (hash) => `${baseExplorerUrl}tx/${hash}`; statusManager.updateProcess(step, processType, 'PENDING', { txHash, txLink: getTxLink(txHash), }); const transactionReceipt = await waitForTransactionReceipt({ client, chainId: chain.id, txHash, onReplaced(response) { const newHash = response.transaction.hash; statusManager.updateProcess(step, processType, 'PENDING', { txHash: newHash, txLink: getTxLink(newHash), }); }, }); const finalHash = transactionReceipt?.transactionHash || txHash; statusManager.updateProcess(step, processType, 'DONE', { txHash: finalHash, txLink: getTxLink(finalHash), }); }; //# sourceMappingURL=checkAllowance.js.map