UNPKG

@devasher/kuru-sdk

Version:

Ethers v6 SDK to interact with Kuru (forked from @kuru-labs/kuru-sdk)

218 lines 10.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParamCreator = void 0; // ============ External Imports ============ const ethers_1 = require("ethers"); const utils_1 = require("../utils"); // ============ Config Imports ============ const Router_json_1 = __importDefault(require("../../abi/Router.json")); const txConfig_1 = __importDefault(require("../utils/txConfig")); class ParamCreator { static async constructDeployMarketTransaction(signer, routerAddress, type, baseAssetAddress, quoteAssetAddress, sizePrecision, pricePrecision, tickSize, minSize, maxSize, takerFeeBps, makerFeeBps, kuruAmmSpread, txOptions) { const address = await signer.getAddress(); const routerInterface = new ethers_1.ethers.Interface(Router_json_1.default.abi); const data = routerInterface.encodeFunctionData('deployProxy', [ type, baseAssetAddress, quoteAssetAddress, sizePrecision, pricePrecision, tickSize, minSize, maxSize, takerFeeBps, makerFeeBps, kuruAmmSpread, ]); return (0, txConfig_1.default)({ from: address, to: routerAddress, signer, data, txOptions, }); } async deployMarket(signer, routerAddress, type, baseAssetAddress, quoteAssetAddress, sizePrecision, pricePrecision, tickSize, minSize, maxSize, takerFeeBps, makerFeeBps, kuruAmmSpread, txOptions) { const router = new ethers_1.ethers.Contract(routerAddress, Router_json_1.default.abi, signer); try { const tx = await ParamCreator.constructDeployMarketTransaction(signer, routerAddress, type, baseAssetAddress, quoteAssetAddress, sizePrecision, pricePrecision, tickSize, minSize, maxSize, takerFeeBps, makerFeeBps, kuruAmmSpread, txOptions); const transaction = await signer.sendTransaction(tx); const receipt = await transaction.wait(1); if (!receipt) { throw new Error('Transaction failed'); } const marketRegisteredLog = receipt.logs.find((log) => { try { const parsedLog = router.interface.parseLog(log); return parsedLog && parsedLog.name === 'MarketRegistered'; } catch (_a) { return false; } }); if (!marketRegisteredLog) { throw new Error('MarketRegistered event not found in transaction receipt'); } const parsedLog = router.interface.parseLog(marketRegisteredLog); if (!parsedLog) { throw new Error('Failed to parse MarketRegistered event'); } return parsedLog.args.market; } catch (e) { console.log({ e }); if (!e.error) { throw e; } throw (0, utils_1.extractErrorMessage)(e); } } calculatePrecisions(quote, base, maxPrice, minSize, tickSizeBps = 10) { let currentPrice = quote / base; // Calculate tick size based on BPS but ensure minimum tick size let tickSize = Math.max(currentPrice * (tickSizeBps / 10000), // BPS-based tick size currentPrice / 1000000, // Minimum tick size (1 millionth of price) 0.00000001); // Convert to fixed notation with max 9 decimals const tickStr = tickSize.toFixed(9); // Convert to string with high precision to detect patterns const priceStr = currentPrice.toFixed(9); // Look for recurring patterns in the decimal part const decimalPart = priceStr.split('.')[1]; if (decimalPart) { // Skip leading zeros before looking for patterns let significantStart = 0; while (significantStart < decimalPart.length && decimalPart[significantStart] === '0') { significantStart++; } // Find recurring pattern in the significant digits const significantPart = decimalPart.slice(significantStart); for (let len = 1; len <= 4; len++) { const pattern = significantPart.slice(0, len); const nextPattern = significantPart.slice(len, len * 2); if (pattern === nextPattern && pattern !== '0') { // Add check to ignore '0' pattern // Found a recurring pattern, limit it to 2 repetitions const limitedDecimal = decimalPart.slice(0, significantStart) + pattern.repeat(2); const newPrice = `${priceStr.split('.')[0]}.${limitedDecimal}`; currentPrice = Number(newPrice); break; } } } if (currentPrice === 0 || !currentPrice) { throw new Error(`Current price is too low: ${currentPrice}`); } // Handle recurring decimals in tick size the same way const tickDecimalPart = tickStr.split('.')[1]; if (tickDecimalPart) { let significantStart = 0; while (significantStart < tickDecimalPart.length && tickDecimalPart[significantStart] === '0') { significantStart++; } const significantPart = tickDecimalPart.slice(significantStart); for (let len = 1; len <= 4; len++) { const pattern = significantPart.slice(0, len); const nextPattern = significantPart.slice(len, len * 2); if (pattern === nextPattern && pattern !== '0') { const limitedDecimal = tickDecimalPart.slice(0, significantStart) + pattern.repeat(2); const newTick = `${tickStr.split('.')[0]}.${limitedDecimal}`; tickSize = Number(newTick); break; } } } // Use the string representation to count decimals const priceDecimals = Math.max(this.countDecimals(Number(priceStr)), ParamCreator.DEFAULT_PRICE_PRECISION_DECIMALS, this.countDecimals(Number(tickStr))); if (priceDecimals > 9) { throw new Error('Price precision exceeds maximum (9 decimals)'); } // Use the fixed notation strings for further calculations const pricePrecision = BigInt(Math.pow(10, priceDecimals)); const tickSizeInPrecision = (0, ethers_1.parseUnits)(tickStr, priceDecimals); // Calculate size precision based on max price * price precision const maxPriceWithPrecision = maxPrice * Math.pow(10, priceDecimals); const sizeDecimalsPower = Math.floor(Math.log10(maxPriceWithPrecision)); const sizeDecimals = Math.max(this.countDecimals(minSize), sizeDecimalsPower); const sizePrecision = BigInt(Math.pow(10, sizeDecimals)); const maxSizeInPrecision = this.getMaxSizeAtPrice((0, ethers_1.parseUnits)(currentPrice.toFixed(priceDecimals), priceDecimals), sizePrecision); const minSizeInPrecision = (0, ethers_1.parseUnits)(minSize.toString(), sizeDecimals); return { pricePrecision: pricePrecision, sizePrecision: sizePrecision, tickSize: BigInt(tickSizeInPrecision), minSize: BigInt(minSizeInPrecision), maxSize: maxSizeInPrecision, }; } getPricePrecision(currentPrice, maxPrice) { const currentDecimals = this.countDecimals(currentPrice); const maxDecimals = this.countDecimals(maxPrice); const neededPrecision = Math.max(currentDecimals, maxDecimals); if (neededPrecision > 8) { return { error: 'Price is greater than 10**9' }; } return { precision: Math.pow(10, neededPrecision) }; } getSizePrecision(maxPriceInPricePrecision) { const numDigits = maxPriceInPricePrecision.toString().length; return { precision: Math.pow(10, numDigits) }; } getMinAndMaxPrice(pricePrecision) { const minPrice = 1 / pricePrecision; const maxPrice = 10 ** 9; return { minPrice, maxPrice }; } getMaxSizeAtPrice(price, sizePrecision) { const UINT32_MAX = BigInt(2) ** BigInt(32) - BigInt(1); const rawMaxSize = (UINT32_MAX * sizePrecision) / price; // Convert to string to count digits const numDigits = rawMaxSize.toString().length; // Calculate nearest power of 10 (rounding down) const maxSize = BigInt(10) ** BigInt(numDigits - 1); return maxSize; } calculateMarketCap(price, base, solPrice) { const marketCap = price * base * solPrice * 2; if (marketCap >= 1000000000) { return `${(marketCap / 1000000000).toFixed(1)}b`; } else if (marketCap >= 1000000) { return `${(marketCap / 1000000).toFixed(1)}m`; } else if (marketCap >= 1000) { return `${(marketCap / 1000).toFixed(1)}k`; } return `${marketCap.toFixed(1)}`; } countDecimals(value) { if (value === 0) return 0; // Convert to string and remove scientific notation let str = value.toString(); if (str.includes('e')) { const [_base, exponent] = str.split('e'); const exp = parseInt(exponent); if (exp < 0) { // For negative exponents (small decimals) return Math.abs(exp); } else { // For positive exponents (large numbers) str = value.toLocaleString('fullwide', { useGrouping: false }); } } // If no decimal point, return 0 if (!str.includes('.')) return 0; // Split on decimal and get length of decimal portion const decimalPart = str.split('.')[1]; return decimalPart ? decimalPart.length : 0; } } exports.ParamCreator = ParamCreator; ParamCreator.DEFAULT_PRICE_PRECISION_DECIMALS = 4; //# sourceMappingURL=market.js.map