UNPKG

@lifi/sdk

Version:

LI.FI Any-to-Any Cross-Chain-Swap SDK

235 lines 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkAllowance = void 0; const actions_1 = require("viem/actions"); const utils_1 = require("viem/utils"); const constants_js_1 = require("../../constants.js"); const getActionWithFallback_js_1 = require("./getActionWithFallback.js"); const getAllowance_js_1 = require("./getAllowance.js"); const parseEVMErrors_js_1 = require("./parseEVMErrors.js"); const getNativePermit_js_1 = require("./permits/getNativePermit.js"); const isNativePermitValid_js_1 = require("./permits/isNativePermitValid.js"); const setAllowance_js_1 = require("./setAllowance.js"); const utils_js_1 = require("./utils.js"); const waitForTransactionReceipt_js_1 = require("./waitForTransactionReceipt.js"); const checkAllowance = async ({ checkClient, chain, step, statusManager, executionOptions, allowUserInteraction = false, batchingSupported = false, permit2Supported = false, disableMessageSigning = false, }) => { let sharedProcess; let signedTypedData = []; try { const permitTypedData = step.typedData?.filter((typedData) => typedData.primaryType === 'Permit'); if (!disableMessageSigning && permitTypedData?.length) { sharedProcess = statusManager.findOrCreateProcess({ step, type: 'PERMIT', chainId: step.action.fromChainId, }); signedTypedData = sharedProcess.signedTypedData ?? signedTypedData; for (const typedData of permitTypedData) { const signedTypedDataForChain = signedTypedData.find((signedTypedData) => (0, isNativePermitValid_js_1.isNativePermitValid)(signedTypedData, typedData)); if (signedTypedDataForChain) { continue; } sharedProcess = statusManager.updateProcess(step, sharedProcess.type, 'ACTION_REQUIRED'); if (!allowUserInteraction) { return { status: 'ACTION_REQUIRED' }; } const typedDataChainId = (0, utils_js_1.getDomainChainId)(typedData.domain) || step.action.fromChainId; const permitClient = await checkClient(step, sharedProcess, typedDataChainId); if (!permitClient) { return { status: 'ACTION_REQUIRED' }; } const signature = await (0, utils_1.getAction)(permitClient, actions_1.signTypedData, 'signTypedData')({ account: permitClient.account, domain: typedData.domain, types: typedData.types, primaryType: typedData.primaryType, message: typedData.message, }); const signedPermit = { ...typedData, signature, }; signedTypedData.push(signedPermit); sharedProcess = statusManager.updateProcess(step, sharedProcess.type, 'ACTION_REQUIRED', { signedTypedData, }); } statusManager.updateProcess(step, sharedProcess.type, 'DONE', { signedTypedData, }); const matchingPermit = signedTypedData.find((signedTypedData) => (0, utils_js_1.getDomainChainId)(signedTypedData.domain) === step.action.fromChainId); if (matchingPermit) { return { status: 'NATIVE_PERMIT', data: signedTypedData, }; } } sharedProcess = statusManager.findOrCreateProcess({ step, type: 'TOKEN_ALLOWANCE', chainId: step.action.fromChainId, }); const updatedClient = await checkClient(step, sharedProcess); if (!updatedClient) { return { status: 'ACTION_REQUIRED' }; } if (sharedProcess.txHash && sharedProcess.status !== 'DONE') { await waitForApprovalTransaction(updatedClient, sharedProcess.txHash, sharedProcess.type, step, chain, statusManager); return { status: 'DONE', data: signedTypedData }; } statusManager.updateProcess(step, sharedProcess.type, 'STARTED'); const spenderAddress = permit2Supported ? chain.permit2 : step.estimate.approvalAddress; const fromAmount = BigInt(step.action.fromAmount); const approved = await (0, getAllowance_js_1.getAllowance)(updatedClient, step.action.fromToken.address, updatedClient.account.address, spenderAddress); if (fromAmount <= approved) { statusManager.updateProcess(step, sharedProcess.type, 'DONE'); return { status: 'DONE', data: signedTypedData }; } const isNativePermitAvailable = !!chain.permit2Proxy && !batchingSupported && !disableMessageSigning && !step.estimate.skipPermit; let nativePermitData; if (isNativePermitAvailable) { nativePermitData = await (0, getActionWithFallback_js_1.getActionWithFallback)(updatedClient, getNativePermit_js_1.getNativePermit, 'getNativePermit', { chainId: chain.id, tokenAddress: step.action.fromToken.address, spenderAddress: chain.permit2Proxy, amount: fromAmount, }); } if (isNativePermitAvailable && nativePermitData) { signedTypedData = signedTypedData.length ? signedTypedData : sharedProcess.signedTypedData || []; const signedTypedDataForChain = signedTypedData.find((signedTypedData) => (0, isNativePermitValid_js_1.isNativePermitValid)(signedTypedData, nativePermitData)); if (!signedTypedDataForChain) { statusManager.updateProcess(step, sharedProcess.type, 'ACTION_REQUIRED'); if (!allowUserInteraction) { return { status: 'ACTION_REQUIRED' }; } const signature = await (0, utils_1.getAction)(updatedClient, actions_1.signTypedData, 'signTypedData')({ account: updatedClient.account, domain: nativePermitData.domain, types: nativePermitData.types, primaryType: nativePermitData.primaryType, message: nativePermitData.message, }); const signedPermit = { ...nativePermitData, signature, }; signedTypedData.push(signedPermit); } statusManager.updateProcess(step, sharedProcess.type, 'DONE', { signedTypedData, }); return { status: 'NATIVE_PERMIT', data: signedTypedData, }; } const shouldResetApproval = step.estimate.approvalReset && approved > 0n; const resetApprovalStatus = shouldResetApproval ? 'RESET_REQUIRED' : 'ACTION_REQUIRED'; statusManager.updateProcess(step, sharedProcess.type, resetApprovalStatus, { txHash: undefined, txLink: undefined, }); if (!allowUserInteraction) { return { status: 'ACTION_REQUIRED' }; } let approvalResetTxHash; if (shouldResetApproval) { approvalResetTxHash = await (0, setAllowance_js_1.setAllowance)(updatedClient, step.action.fromToken.address, spenderAddress, 0n, executionOptions, batchingSupported); if (!batchingSupported) { await waitForApprovalTransaction(updatedClient, approvalResetTxHash, sharedProcess.type, step, chain, statusManager); statusManager.updateProcess(step, sharedProcess.type, 'ACTION_REQUIRED', { txHash: undefined, txLink: undefined, }); if (!allowUserInteraction) { return { status: 'ACTION_REQUIRED' }; } } } const approveAmount = permit2Supported ? constants_js_1.MaxUint256 : fromAmount; const approveTxHash = await (0, setAllowance_js_1.setAllowance)(updatedClient, step.action.fromToken.address, spenderAddress, approveAmount, executionOptions, batchingSupported); if (batchingSupported) { statusManager.updateProcess(step, sharedProcess.type, 'DONE'); const calls = []; if (shouldResetApproval && approvalResetTxHash) { calls.push({ to: step.action.fromToken.address, data: approvalResetTxHash, chainId: step.action.fromToken.chainId, }); } calls.push({ to: step.action.fromToken.address, data: approveTxHash, chainId: step.action.fromToken.chainId, }); return { status: 'BATCH_APPROVAL', data: { calls, signedTypedData, }, }; } await waitForApprovalTransaction(updatedClient, approveTxHash, sharedProcess.type, step, chain, statusManager); return { status: 'DONE', data: signedTypedData }; } catch (e) { if (!sharedProcess) { sharedProcess = statusManager.findOrCreateProcess({ step, type: 'TOKEN_ALLOWANCE', chainId: step.action.fromChainId, }); } const error = await (0, parseEVMErrors_js_1.parseEVMErrors)(e, step, sharedProcess); statusManager.updateProcess(step, sharedProcess.type, 'FAILED', { error: { message: error.cause.message, code: error.code, }, }); statusManager.updateExecution(step, 'FAILED'); throw error; } }; exports.checkAllowance = checkAllowance; const waitForApprovalTransaction = async (client, txHash, processType, step, chain, statusManager, approvalReset = false) => { const baseExplorerUrl = chain.metamask.blockExplorerUrls[0]; const getTxLink = (hash) => `${baseExplorerUrl}tx/${hash}`; statusManager.updateProcess(step, processType, 'PENDING', { txHash, txLink: getTxLink(txHash), }); const transactionReceipt = await (0, waitForTransactionReceipt_js_1.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; if (!approvalReset) { statusManager.updateProcess(step, processType, 'DONE', { txHash: finalHash, txLink: getTxLink(finalHash), }); } }; //# sourceMappingURL=checkAllowance.js.map