UNPKG

@swapper-finance/sdk

Version:
150 lines (132 loc) 4.91 kB
import { BigNumber, ethers } from "ethers"; import { logger } from "./logger"; /** * Calculate the gas cashback from a transaction - how much USDC was saved from the estimated cost * @param receipt The transaction receipt * @param estimatedGasCost The estimated gas cost from the route * @param tokenDecimals The decimals of the cash token * @param smartWalletAddress The user's smart wallet address * @param knownAddresses The address not to be included in the cashback calculation * @returns Information about the gas cashback amount */ interface GasCashbackResult { estimatedGasCost: BigNumber; actualGasCost: BigNumber; cashbackAmount: BigNumber; } export const calculateGasCashback = async ( receipt: ethers.providers.TransactionReceipt, estimatedGasCost: BigNumber, tokenAddress: `0x${string}`, tokenDecimals: number = 6, smartWalletAddress: string, knownAddresses?: string[], ): Promise<GasCashbackResult> => { try { // Normalize addresses const normalizedSmartWallet = smartWalletAddress.toLowerCase(); const normalizedKnownAddresses = knownAddresses?.map((address) => address.toLowerCase()) || []; // Find all USDC transfers FROM the smart wallet const walletTransfers = receipt.logs.filter((log) => { try { // Filter for ERC20 Transfer events const topics = log.topics || []; // Check if this is a Transfer event const isTransferEvent = topics[0] === ethers.utils.id("Transfer(address,address,uint256)"); // Check if transfer is for USDC token const isUsdcToken = log.address.toLowerCase() === tokenAddress.toLowerCase(); // Check if sender is the smart wallet (topic[1] contains the sender address) let isFromSmartWallet = false; if (topics.length >= 2 && topics[1]) { // Decode the sender address from the event (first topic after event signature) const sender = ethers.utils .getAddress("0x" + topics[1].substring(26)) .toLowerCase(); isFromSmartWallet = sender === normalizedSmartWallet; } // Check if recipient is NOT the swap target let isNotToSwapTarget = true; if ( normalizedKnownAddresses.length > 0 && topics.length >= 3 && topics[2] ) { // Decode the recipient address from the event const recipient = ethers.utils .getAddress("0x" + topics[2].substring(26)) .toLowerCase(); isNotToSwapTarget = !normalizedKnownAddresses.includes(recipient); } return ( isTransferEvent && isUsdcToken && isFromSmartWallet && isNotToSwapTarget ); } catch (e) { console.error("Error parsing transfer event:", e); return false; } }); // Get the total USDC spent on gas (all transfers from smart wallet excluding to swap target) let actualGasCost = BigNumber.from(0); if (walletTransfers.length > 0) { // Sum all USDC transfers from the wallet actualGasCost = walletTransfers.reduce((total, transferLog) => { try { const transferData = ethers.utils.defaultAbiCoder.decode( ["uint256"], transferLog.data, ); return total.add(transferData[0]); } catch (e) { console.error("Error decoding transfer amount:", e); return total; } }, BigNumber.from(0)); } // Calculate the cashback amount (how much USDC was saved) const cashbackAmount = estimatedGasCost.sub(actualGasCost); // Format for logging const formattedEstimate = ethers.utils.formatUnits( estimatedGasCost, tokenDecimals, ); const formattedActual = ethers.utils.formatUnits( actualGasCost, tokenDecimals, ); const formattedCashback = ethers.utils.formatUnits( cashbackAmount.lt(0) ? BigNumber.from(0) : cashbackAmount, tokenDecimals, ); // Log the results logger.log(`Gas cost estimate: ${formattedEstimate} USDC`); logger.log(`Actual gas cost: ${formattedActual} USDC`); logger.log(`Gas cashback: ${formattedCashback} USDC`); if (walletTransfers.length === 0) { logger.warn( `No USDC transfers from smart wallet (${normalizedSmartWallet}) found in transaction`, ); } else { logger.log( `Found ${walletTransfers.length} USDC transfers from smart wallet for gas payments`, ); } return { estimatedGasCost, actualGasCost, cashbackAmount: cashbackAmount.lt(0) ? BigNumber.from(0) : cashbackAmount, }; } catch (error) { console.error("Failed to calculate gas cashback:", error); return { estimatedGasCost, actualGasCost: BigNumber.from(0), cashbackAmount: BigNumber.from(0), }; } };