UNPKG

@accret/bridge-sdk

Version:
319 lines 16.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeCrossChainSwap = executeCrossChainSwap; exports.executeSingleChainSwap = executeSingleChainSwap; const ethers_1 = require("ethers"); const buildTransaction_1 = require("../../types/deBridge/buildTransaction"); const constants_1 = require("../../constants"); /** * @description Creates a cross-chain swap order using deBridge API. * @param params - Parameters for creating a cross-chain swap order * @param params.srcChainId - The source chain ID * @param params.srcChainTokenIn - The address of the token being swapped on the source chain * @param params.srcChainTokenInAmount - The amount of the token being swapped on the source chain, in atomic units * @param params.dstChainId - The destination chain ID * @param params.dstChainTokenOut - The address of the token being received on the destination chain * @param params.dstChainTokenOutRecipient - The recipient address for the output token on the destination chain (optional) * @param params.dstChainTokenOutAmount - The amount of the token being received on the destination chain, in atomic units (optional, defaults to "auto") * @returns Promise<deBridgeCrossChainOrderResponse> - The response containing the order details */ async function createCrossChainSwap(params) { try { const queryParams = new URLSearchParams({ srcChainId: params.srcChainId, srcChainTokenIn: params.srcChainTokenIn, srcChainTokenInAmount: params.srcChainTokenInAmount, dstChainId: params.dstChainId, dstChainTokenOut: params.dstChainTokenOut, dstChainTokenOutRecipient: params.dstChainTokenOutRecipient || "", dstChainTokenOutAmount: params.dstChainTokenOutAmount || "auto", senderAddress: params.account || "", srcChainOrderAuthorityAddress: params.srcChainOrderAuthorityAddress || params.account || "", srcChainRefundAddress: params.account || "", dstChainOrderAuthorityAddress: params.dstChainOrderAuthorityAddress || params.dstChainTokenOutRecipient || "", referralCode: params.referralCode?.toString() || "31805", prependOperatingExpenses: "true", }); const response = await fetch(`${constants_1.DEBRIDGE_API}/dln/order/create-tx?${queryParams}`); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to create order: ${response.statusText}. ${errorText}`); } const data = (await response.json()); if (data.tx.data) { data.tx.data = data.tx.data.toString(); } return data; } catch (error) { console.log("Error creating cross-chain swap"); throw error; } } /** * @description Executes a cross-chain token swap using deBridge. * @param params - Swap parameters including tokens, amounts, and chain details * @param params.privateKey - Private key of the wallet initiating the swap * @param params.srcNetwork - Source network chain ID * @param params.srcTokenAddress - Address of the token being swapped on the source chain * @param params.srcTokenDecimals - Decimals of the source token * @param params.amountToSwap - Amount of the source token to swap * @param params.dstNetwork - Destination network chain ID * @param params.dstTokenAddress - Address of the token being received on the destination chain * @param params.dstTokenOutAmount - Amount of the token being received on the destination chain * @param params.recipientAddress - Address to receive the output token (optional, defaults to sender address) * @param params.srcChainOrderAuthorityAddress - Authority address for the source chain order * @param params.dstChainOrderAuthorityAddress - Authority address for the destination chain order * @param params.referralCode - Referral code for the swap (optional) * @param params.enableLogging - Whether to enable logging (default is false) * @returns Promise<CrossChainSwapResult> - Result of the swap operation */ async function executeCrossChainSwap(params) { const log = params.enableLogging ? console.log : () => { }; try { log("Starting cross-chain swap..."); // Initialize provider and wallet log(`Connecting to source chain RPC: ${params.srcChainRpcUrl}`); const provider = new ethers_1.JsonRpcProvider(params.srcChainRpcUrl); const srcChainId = params.srcNetwork; const dstChainId = params.dstNetwork; const wallet = new ethers_1.Wallet(params.privateKey); const signer = wallet.connect(provider); const senderAddress = await signer.getAddress(); log(`Sender address: ${senderAddress}`); // Use sender address as recipient if not specified const recipientAddress = params.recipientAddress || senderAddress; // Convert amount to atomic units const amountInAtomicUnit = ethers_1.ethers.parseUnits(params.amountToSwap, params.srcTokenDecimals); log(`Amount to swap: ${params.amountToSwap} (${amountInAtomicUnit.toString()} atomic units)`); // Prepare order parameters const orderInput = { srcChainId: srcChainId, srcChainTokenIn: params.srcTokenAddress, srcChainTokenInAmount: amountInAtomicUnit.toString(), dstChainId: dstChainId, dstChainTokenOut: params.dstTokenAddress, dstChainTokenOutRecipient: recipientAddress, account: senderAddress, srcChainOrderAuthorityAddress: params.srcChainOrderAuthorityAddress || senderAddress, dstChainOrderAuthorityAddress: params.dstChainOrderAuthorityAddress || recipientAddress, dstChainTokenOutAmount: params.dstChainTokenOutAmount, referralCode: params.referralCode ? parseInt(params.referralCode) : undefined, }; log(" Creating deBridge order..."); const order = (await createCrossChainSwap(orderInput)); if (!order?.tx?.to || !order.tx.data) { throw new Error("Invalid transaction data returned from order creation."); } log(" Order created successfully"); log(` Estimated output: ${(0, ethers_1.formatUnits)(order.estimation.dstChainTokenOut.amount, order.estimation.dstChainTokenOut.decimals)} ${order.estimation.dstChainTokenOut.symbol}`); const transactionRequest = order.tx; const spenderAddress = transactionRequest.to; // Handle token approval log("Checking token approval..."); const tokenContract = new ethers_1.Contract(params.srcTokenAddress, buildTransaction_1.erc20Abi, signer); const requiredAmount = BigInt(order.estimation.srcChainTokenIn.amount); let approvalTxHash; try { const currentAllowance = await tokenContract.allowance(senderAddress, spenderAddress); log(`Current allowance: ${(0, ethers_1.formatUnits)(currentAllowance, params.srcTokenDecimals)}`); if (currentAllowance < requiredAmount) { log("Insufficient allowance, sending approval transaction..."); const approveTx = await tokenContract.approve(spenderAddress, requiredAmount); approvalTxHash = approveTx.hash; log(`Approval tx hash: ${approveTx.hash}`); const receipt = await approveTx.wait(); if (receipt?.status !== 1) { throw new Error(`Approval failed (status=${receipt?.status})`); } log("Approval successful!"); } else { log("Sufficient allowance already granted"); } } catch (err) { throw new Error(`Token approval failed: ${err instanceof Error ? err.message : String(err)}`); } // Execute bridge transaction log(" Executing bridge transaction..."); const txResponse = await signer.sendTransaction(transactionRequest); const bridgeTxHash = txResponse.hash; log(` Bridge tx hash: ${bridgeTxHash}`); log(" Waiting for transaction confirmation..."); const txReceipt = await txResponse.wait(); if (!txReceipt || txReceipt.status !== 1) { throw new Error(`Bridge transaction failed (status=${txReceipt?.status})`); } log(" Cross-chain swap completed successfully!"); log(` Gas used: ${txReceipt.gasUsed.toString()}`); log(` Block number: ${txReceipt.blockNumber}`); return { success: true, bridgeTxHash, approvalTxHash, estimatedOutput: { amount: (0, ethers_1.formatUnits)(order.estimation.dstChainTokenOut.amount, order.estimation.dstChainTokenOut.decimals), symbol: order.estimation.dstChainTokenOut.symbol, decimals: order.estimation.dstChainTokenOut.decimals, }, fees: order.estimation.fees, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); log(` Swap failed: ${errorMessage}`); return { success: false, error: errorMessage, }; } } /** * @description Creates a single-chain swap order using deBridge API. * @param params - Parameters for creating a single-chain swap order * @param params.chainId - The chain ID for the swap * @param params.tokenIn - The address of the token being swapped * @param params.tokenInAmount - The amount of the token being swapped, in atomic units * @param params.tokenOut - The address of the token being received * @param params.tokenOutRecipient - The recipient address for the output token (optional) * @param params.slippage - The slippage tolerance for the swap (optional, default is 0) * @param params.affiliateFeePercent - The affiliate fee percentage (optional, default is 0) * @param params.affiliateFeeRecipient - The recipient address for the affiliate fee (optional) * @returns Promise<deBridgeSingleChainOrderResponse> - The response containing the swap estimation * @throws Error if the API request fails or returns an error */ async function createSingleChainSwap(params) { try { const queryParams = new URLSearchParams({ chainId: params.chainId, tokenIn: params.tokenIn, tokenInAmount: params.tokenInAmount, tokenOut: params.tokenOut, tokenOutRecipient: params.tokenOutRecipient || "", slippage: params.slippage?.toString() || "0", affiliateFeePercent: params.affiliateFeePercent?.toString() || "0", affiliateFeeRecipient: params.affiliateFeeRecipient || "", }); const response = await fetch(`${constants_1.DEBRIDGE_API}/v1.0/chain/transaction?${queryParams}`); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to create order: ${response.statusText}. ${errorText}`); } const data = (await response.json()); return data; } catch (error) { console.log("Error creating cross-chain swap"); throw error; } } /** * @description Executes a single-chain swap using deBridge API. * @param params - Parameters for executing a single-chain swap * @param params.privateKey - Private key of the wallet initiating the swap * @param params.srcChainRpcUrl - RPC URL of the source chain * @param params.network - Chain ID of the source network * @returns Promise<CrossChainSwapResult> - The result of the swap execution */ async function executeSingleChainSwap(params) { const log = params.enableLogging ? console.log : () => { }; try { log("Starting cross-chain swap..."); // Initialize provider and wallet log(`Connecting to source chain RPC: ${params.srcChainRpcUrl}`); const provider = new ethers_1.JsonRpcProvider(params.srcChainRpcUrl); const chainId = params.network; const wallet = new ethers_1.Wallet(params.privateKey); const signer = wallet.connect(provider); const senderAddress = await signer.getAddress(); log(`Sender address: ${senderAddress}`); // Use sender address as recipient if not specified const recipientAddress = params.recipientAddress || senderAddress; // Convert amount to atomic units const amountInAtomicUnit = ethers_1.ethers.parseUnits(params.amountToSwap, params.srcTokenDecimals); log(`Amount to swap: ${params.amountToSwap} (${amountInAtomicUnit.toString()} atomic units)`); // Prepare order parameters const orderInput = { chainId: chainId, tokenIn: params.srcTokenAddress, tokenInAmount: amountInAtomicUnit.toString(), tokenOut: params.dstTokenAddress, tokenOutRecipient: recipientAddress, slippage: params.slippage || 0, affiliateFeePercent: params.affiliateFeePercent || 0, affiliateFeeRecipient: params.dstChainOrderAuthorityAddress || "", }; log(" Creating deBridge order..."); const order = (await createSingleChainSwap(orderInput)); if (!order?.tx?.to || !order.tx.data) { throw new Error("Invalid transaction data returned from order creation."); } log(" Order created successfully"); log(` Estimated output: ${(0, ethers_1.formatUnits)(order.tokenOut.amount, order.tokenOut.decimals)} ${order.tokenOut.symbol}`); const transactionRequest = order.tx; const spenderAddress = transactionRequest.to; // Handle token approval log("Checking token approval..."); const tokenContract = new ethers_1.Contract(params.srcTokenAddress, buildTransaction_1.erc20Abi, signer); const requiredAmount = BigInt(order.tokenIn.amount); let approvalTxHash; try { const currentAllowance = await tokenContract.allowance(senderAddress, spenderAddress); log(`Current allowance: ${(0, ethers_1.formatUnits)(currentAllowance, params.srcTokenDecimals)}`); if (currentAllowance < requiredAmount) { log("Insufficient allowance, sending approval transaction..."); const approveTx = await tokenContract.approve(spenderAddress, requiredAmount); approvalTxHash = approveTx.hash; log(`Approval tx hash: ${approveTx.hash}`); const receipt = await approveTx.wait(); if (receipt?.status !== 1) { throw new Error(`Approval failed (status=${receipt?.status})`); } log("Approval successful!"); } else { log("Sufficient allowance already granted"); } } catch (err) { throw new Error(`Token approval failed: ${err instanceof Error ? err.message : String(err)}`); } // Execute bridge transaction log(" Executing bridge transaction..."); const txResponse = await signer.sendTransaction(transactionRequest); const bridgeTxHash = txResponse.hash; log(` Bridge tx hash: ${bridgeTxHash}`); log(" Waiting for transaction confirmation..."); const txReceipt = await txResponse.wait(); if (!txReceipt || txReceipt.status !== 1) { throw new Error(`Bridge transaction failed (status=${txReceipt?.status})`); } log(" Cross-chain swap completed successfully!"); log(` Gas used: ${txReceipt.gasUsed.toString()}`); log(` Block number: ${txReceipt.blockNumber}`); return { success: true, bridgeTxHash, approvalTxHash, estimatedOutput: { amount: (0, ethers_1.formatUnits)(order.tokenOut.amount, order.tokenOut.decimals), symbol: order.tokenOut.symbol, decimals: order.tokenOut.decimals, }, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); log(` Swap failed: ${errorMessage}`); return { success: false, error: errorMessage, }; } } //# sourceMappingURL=buildTransaction.js.map