@lifi/sdk
Version:
LI.FI Any-to-Any Cross-Chain-Swap SDK
235 lines • 11.1 kB
JavaScript
"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