@devasher/kuru-sdk
Version:
Ethers v6 SDK to interact with Kuru (forked from @kuru-labs/kuru-sdk)
218 lines • 10.3 kB
JavaScript
;
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