@accret/bridge-sdk
Version:
319 lines • 16.5 kB
JavaScript
;
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