UNPKG

@tristeroresearch/mach-sdk

Version:

A TypeScript SDK for integrating with Mach's API.

67 lines (66 loc) 3.35 kB
import { signApprovalTransaction } from '../helpers/index.js'; import { attemptToLoadPrivateKeyFromEnv, createWalletClients } from '../utils/index.js'; import { readContract } from 'viem/actions'; import { abi } from '../index.js'; import { FunctionName, SpecialAddress } from '../enums/index.js'; import { MAX_UINT256 } from '../constants/index.js'; import { ErrorMessage } from '../errors/constants.js'; import { encodeFunctionData, parseUnits } from 'viem'; /** * A helper function to ensure a token is approved for transfer by checking allowance and sending an approval transaction if necessary. * @param quote - The quote to approve the token for * @param key - The private key of the account to sign the transaction * @returns The hash of the approval transaction * @description This helper function ensures a token is approved for transfer by checking allowance and sending an approval transaction if necessary. */ export const approveToken = async (quote, privateKey, gasData) => { try { //Throws an error if the private key is not found in the environment if (!privateKey) privateKey = attemptToLoadPrivateKeyFromEnv(privateKey); // Create wallet clients const clients = await createWalletClients(quote.src_chain, privateKey); const publicClient = clients.publicClient; const walletClient = clients.walletClient; const address = walletClient.account.address; // Add a check to ensure the address is not zero if (address === SpecialAddress.Zero) throw new Error(ErrorMessage.WalletAddressZero); // Get decimals of token const decimals = await readContract(publicClient, { address: quote.src_asset_address, abi: abi.erc20, functionName: FunctionName.Decimals, }); // Check existing allowance const allowance = await readContract(publicClient, { address: quote.src_asset_address, abi: abi.erc20, functionName: FunctionName.Allowance, args: [address, quote.order_data.contract_address], }); // If allowance is already sufficient, skip approval // Return a string-typed 0 hash if allowance is sufficient if (allowance >= parseUnits(quote.src_amount, Number(decimals))) return '0x0'; // Prepare the approval transaction data (approve maximum amount) // TODO: Support approving less than maxUint256 const approvalTxData = encodeFunctionData({ abi: abi.erc20, functionName: FunctionName.Approve, args: [quote.order_data.contract_address, MAX_UINT256], }); // Sign the approval transaction const approvalSignedHash = await signApprovalTransaction(approvalTxData, quote.src_chain, quote.src_asset_address, privateKey, gasData); // Send the approval transaction const approvalTx = { serializedTransaction: approvalSignedHash }; const approvalHash = await publicClient.sendRawTransaction(approvalTx); // Wait for the transaction to be mined await publicClient.waitForTransactionReceipt({ hash: approvalHash }); return approvalHash; } catch (error) { console.error('Error during token approval:', error); throw error; } };