@devasher/kuru-sdk
Version:
Ethers v6 SDK to interact with Kuru (forked from @kuru-labs/kuru-sdk)
125 lines • 6.62 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenSwap = void 0;
// ============ External Imports ============
const ethers_1 = require("ethers");
const utils_1 = require("../utils");
const utils_2 = require("../utils");
// ============ Config Imports ============
const IERC20_json_1 = __importDefault(require("../../abi/IERC20.json"));
const Router_json_1 = __importDefault(require("../../abi/Router.json"));
const txConfig_1 = __importDefault(require("../utils/txConfig"));
class TokenSwap {
/**
* @dev Constructs a transaction for token swapping.
* @param signer - The signer instance.
* @param routerAddress - The address of the router contract.
* @param routeOutput - The route output containing path and other swap details.
* @param tokenInAmount - The amount of input tokens.
* @param minTokenOutAmount - The minimum amount of output tokens to receive.
* @param txOptions - Optional transaction parameters.
* @returns A promise that resolves to the transaction request object.
*/
static async constructSwapTransaction(signer, routerAddress, routeOutput, tokenInAmount, minTokenOutAmount, txOptions) {
const address = await signer.getAddress();
const routerInterface = new ethers_1.ethers.Interface(Router_json_1.default.abi);
const data = routerInterface.encodeFunctionData('anyToAnySwap', [
routeOutput.route.path.map((pool) => pool.orderbook),
routeOutput.isBuy,
routeOutput.nativeSend,
routeOutput.route.tokenIn,
routeOutput.route.tokenOut,
tokenInAmount,
minTokenOutAmount,
]);
const value = routeOutput.nativeSend[0] ? tokenInAmount : BigInt(0);
return (0, txConfig_1.default)({
to: routerAddress,
from: address,
data,
value,
txOptions,
signer,
});
}
/**
* @dev Executes a token swap.
* @param providerOrSigner - The ethers.js provider or signer to interact with the blockchain.
* @param routerAddress - The address of the router contract.
* @param routeOutput - The route output containing path and other swap details.
* @param amountIn - The amount of input tokens.
* @param inTokenDecimals - The decimals of the input token.
* @param outTokenDecimals - The decimals of the output token.
* @param slippageTolerance - The maximum acceptable slippage.
* @param approveTokens - Whether to approve token spending before the swap.
* @param approvalCallback - Callback function for approval transaction hash.
* @param txOptions - Optional transaction parameters.
* @param slippageOptions - Optional slippage options.
* @returns A promise that resolves to the transaction receipt.
*/
static async swap(providerOrSigner, routerAddress, routeOutput, amountIn, inTokenDecimals, outTokenDecimals, slippageTolerance, approveTokens, approvalCallback, txOptions, slippageOptions) {
try {
// const router = new ethers.Contract(routerAddress, routerAbi.abi, providerOrSigner);
const tokenContract = new ethers_1.ethers.Contract(routeOutput.route.tokenIn, IERC20_json_1.default.abi, providerOrSigner);
const tokenInAmount = (0, ethers_1.parseUnits)(amountIn.toString(), inTokenDecimals);
slippageTolerance = slippageOptions
? (0, utils_2.calculateDynamicSlippage)(slippageOptions.defaultSlippageBps, amountIn, slippageOptions.priceImpactBps, slippageOptions.ohlcvData)
: slippageTolerance;
const clippedOutput = Number((routeOutput.output * (100 - slippageTolerance)) / 100).toFixed(outTokenDecimals);
const minTokenOutAmount = (0, ethers_1.parseUnits)(clippedOutput.toString(), outTokenDecimals);
if (approveTokens) {
const txHash = await (0, utils_1.approveToken)(tokenContract, routerAddress, tokenInAmount, providerOrSigner);
if (approvalCallback) {
approvalCallback(txHash);
}
}
// Extract signer from contract or use provider/signer directly
let signer;
if ('getAddress' in providerOrSigner) {
signer = providerOrSigner;
}
else {
throw new Error('Provider must have a signer for transaction execution');
}
const tx = await TokenSwap.constructSwapTransaction(signer, routerAddress, routeOutput, tokenInAmount, minTokenOutAmount, txOptions);
console.log(tx);
const transaction = await signer.sendTransaction(tx);
const receipt = await transaction.wait();
if (!receipt) {
throw new Error('Transaction receipt is null');
}
return receipt;
}
catch (e) {
console.error({ e });
if (!e.error) {
throw e;
}
throw (0, utils_1.extractErrorMessage)(e);
}
}
static async estimateGas(providerOrSigner, routerAddress, routeOutput, amountIn, inTokenDecimals, outTokenDecimals, slippageTolerance, approveTokens) {
try {
const tokenContract = new ethers_1.ethers.Contract(routeOutput.route.tokenIn, IERC20_json_1.default.abi, providerOrSigner);
const tokenInAmount = (0, ethers_1.parseUnits)(amountIn.toString(), inTokenDecimals);
if (approveTokens) {
return (0, utils_1.estimateApproveGas)(tokenContract, routerAddress, tokenInAmount);
}
const router = new ethers_1.ethers.Contract(routerAddress, Router_json_1.default.abi, providerOrSigner);
const minTokenOutAmount = (0, ethers_1.parseUnits)(((routeOutput.output * (100 - slippageTolerance)) / 100).toString(), outTokenDecimals);
const gasEstimate = await router.anyToAnySwap.estimateGas(routeOutput.route.path.map((pool) => pool.orderbook), routeOutput.isBuy, routeOutput.nativeSend, routeOutput.route.tokenIn, routeOutput.route.tokenOut, tokenInAmount, minTokenOutAmount);
return gasEstimate;
}
catch (e) {
if (!e.error) {
throw e;
}
throw (0, utils_1.extractErrorMessage)(e);
}
}
}
exports.TokenSwap = TokenSwap;
//# sourceMappingURL=swap.js.map