otomato-sdk 2.0.435 → 2.0.436

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- export const SDK_VERSION = '2.0.435';
1
+ export const SDK_VERSION = '2.0.436';
2
2
  export function compareVersions(v1, v2) {
3
3
  // Split the version strings into parts
4
4
  const v1Parts = v1.split('.').map(Number);
@@ -494,3 +494,297 @@ export const callWithRetry = async (callback, maxRetries = 3, retryDelayMs = 100
494
494
  }
495
495
  }
496
496
  };
497
+ const ERC20_ABI = [
498
+ 'function decimals() external view returns (uint8)',
499
+ 'function symbol() external view returns (string)',
500
+ 'function name() external view returns (string)',
501
+ ];
502
+ /**
503
+ * Fetches token information from an ERC20 contract.
504
+ * Generic function that works with any ERC20-compliant token.
505
+ */
506
+ export async function getTokenInfo(tokenAddress, provider) {
507
+ const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
508
+ try {
509
+ const [symbol, decimals, name] = await Promise.all([
510
+ tokenContract.symbol(),
511
+ tokenContract.decimals(),
512
+ tokenContract.name(),
513
+ ]);
514
+ return {
515
+ symbol: String(symbol),
516
+ decimals: Number(decimals),
517
+ name: String(name),
518
+ address: tokenAddress,
519
+ };
520
+ }
521
+ catch (error) {
522
+ throw new Error(`Failed to fetch token info for ${tokenAddress}: ${error.message}`);
523
+ }
524
+ }
525
+ /**
526
+ * Fetches token info with fallback values if contract call fails.
527
+ */
528
+ export async function getTokenInfoWithFallback(tokenAddress, provider) {
529
+ try {
530
+ return await getTokenInfo(tokenAddress, provider);
531
+ }
532
+ catch (error) {
533
+ const truncatedAddress = `${tokenAddress.slice(0, 6)}...${tokenAddress.slice(-4)}`;
534
+ return {
535
+ symbol: truncatedAddress,
536
+ decimals: 18,
537
+ name: '',
538
+ address: tokenAddress,
539
+ };
540
+ }
541
+ }
542
+ /**
543
+ * Fetches multiple token info objects in parallel.
544
+ */
545
+ export async function getMultipleTokenInfo(tokenAddresses, provider) {
546
+ return Promise.all(tokenAddresses.map(address => getTokenInfoWithFallback(address, provider)));
547
+ }
548
+ /**
549
+ * Known stablecoin symbols for token classification.
550
+ */
551
+ export const KNOWN_STABLE_SYMBOLS = new Set([
552
+ 'USDT', 'USDC', 'DAI', 'BUSD', 'TUSD',
553
+ 'USDP', 'GUSD', 'LUSD', 'USDD', 'FRAX',
554
+ 'USDC.E', 'USDC.N', 'USDC.B',
555
+ 'FDUSD', 'PYUSD', 'XAUT',
556
+ 'SUSD', 'MUSD', 'HUSD',
557
+ 'USDN', 'USDX', 'USDJ',
558
+ 'WUSDT', 'WUSDC', 'WDAI',
559
+ 'USDB', 'USDE', 'USDL',
560
+ 'USDbC', 'USDT0',
561
+ ]);
562
+ /**
563
+ * Gas asset symbols by chain ID.
564
+ */
565
+ export const GAS_ASSET_SYMBOLS = {
566
+ [CHAINS.BASE]: 'WETH',
567
+ [CHAINS.BINANCE]: 'WBNB',
568
+ [CHAINS.ETHEREUM]: 'WETH',
569
+ [CHAINS.POLYGON]: 'WMATIC',
570
+ [CHAINS.ARBITRUM]: 'WETH',
571
+ [CHAINS.AVALANCHE]: 'WAVAX',
572
+ [CHAINS.OPTIMISM]: 'WETH',
573
+ [CHAINS.HYPER_EVM]: 'WHYPE',
574
+ };
575
+ /**
576
+ * Check if a symbol is a known stablecoin.
577
+ */
578
+ export function isStableCoin(symbol) {
579
+ if (!symbol || typeof symbol !== 'string') {
580
+ return false;
581
+ }
582
+ const upperSymbol = symbol.toUpperCase();
583
+ return upperSymbol.includes('USD') || KNOWN_STABLE_SYMBOLS.has(upperSymbol);
584
+ }
585
+ /**
586
+ * Check if a symbol is a gas asset for the given chain.
587
+ */
588
+ export function isGasAsset(symbol, chainId) {
589
+ if (!symbol || typeof symbol !== 'string') {
590
+ return false;
591
+ }
592
+ const upperSymbol = symbol.toUpperCase();
593
+ const gasAsset = GAS_ASSET_SYMBOLS[chainId];
594
+ return gasAsset?.toUpperCase() === upperSymbol;
595
+ }
596
+ /**
597
+ * Get the gas asset symbol for a given chain.
598
+ */
599
+ export function getGasAssetSymbol(chainId) {
600
+ return GAS_ASSET_SYMBOLS[chainId] || null;
601
+ }
602
+ /**
603
+ * Converts a Uniswap V3-style tick to a human-readable price.
604
+ * Price formula: price = 1.0001^tick * (10^(decimals1 - decimals0))
605
+ */
606
+ export function tickToPrice(tick, decimals0, decimals1) {
607
+ const tickMathBase = 1.0001;
608
+ const powResult = Math.pow(tickMathBase, tick);
609
+ const decimalsAdjustment = Math.pow(10, decimals0 - decimals1);
610
+ const price = powResult * decimalsAdjustment;
611
+ if (!isFinite(price) || isNaN(price)) {
612
+ throw new Error(`Invalid price calculation: tick=${tick}, decimals0=${decimals0}, decimals1=${decimals1}`);
613
+ }
614
+ return price;
615
+ }
616
+ /**
617
+ * Converts a price to the nearest tick.
618
+ */
619
+ export function priceToTick(price, decimals0, decimals1) {
620
+ const decimalsAdjustment = Math.pow(10, decimals0 - decimals1);
621
+ const adjustedPrice = price / decimalsAdjustment;
622
+ const tick = Math.log(adjustedPrice) / Math.log(1.0001);
623
+ return Math.round(tick);
624
+ }
625
+ /**
626
+ * Calculates price from sqrtPriceX96 (used in Uniswap V3 slot0).
627
+ */
628
+ export function calculatePriceFromSqrtPriceX96(sqrtPriceX96, decimals0, decimals1) {
629
+ const sqrtPrice = Number(sqrtPriceX96) / Math.pow(2, 96);
630
+ const price = Math.pow(sqrtPrice, 2);
631
+ const decimalsAdjustment = Math.pow(10, decimals0 - decimals1);
632
+ return price * decimalsAdjustment;
633
+ }
634
+ /**
635
+ * Inverts a price (converts from token1/token0 to token0/token1).
636
+ */
637
+ export function invertPrice(price) {
638
+ if (price === 0) {
639
+ throw new Error('Cannot invert zero price');
640
+ }
641
+ return 1 / price;
642
+ }
643
+ /**
644
+ * Format a price number to avoid scientific notation and round appropriately.
645
+ */
646
+ export function formatPrice(price, isStableQuoted = false) {
647
+ if (price === null || price === undefined || isNaN(price) || !isFinite(price)) {
648
+ return null;
649
+ }
650
+ const decimals = isStableQuoted ? 2 : 6;
651
+ const rounded = Number(price.toFixed(decimals));
652
+ return rounded.toString();
653
+ }
654
+ /**
655
+ * Format two prices based on the difference between them.
656
+ */
657
+ export function formatPriceRange(price1, price2) {
658
+ if (price1 === null || price1 === undefined || isNaN(price1) || !isFinite(price1) ||
659
+ price2 === null || price2 === undefined || isNaN(price2) || !isFinite(price2)) {
660
+ return {
661
+ price1: price1 !== null && price1 !== undefined ? formatPrice(price1, false) : null,
662
+ price2: price2 !== null && price2 !== undefined ? formatPrice(price2, false) : null,
663
+ };
664
+ }
665
+ const diff = Math.abs(price1 - price2);
666
+ let decimalPlaces;
667
+ if (diff < 0.0001) {
668
+ decimalPlaces = 5;
669
+ }
670
+ else if (diff < 0.001) {
671
+ decimalPlaces = 4;
672
+ }
673
+ else if (diff < 0.01) {
674
+ decimalPlaces = 4;
675
+ }
676
+ else if (diff < 0.1) {
677
+ decimalPlaces = 3;
678
+ }
679
+ else if (diff < 1) {
680
+ decimalPlaces = 2;
681
+ }
682
+ else if (diff < 10) {
683
+ decimalPlaces = 1;
684
+ }
685
+ else {
686
+ decimalPlaces = 0;
687
+ }
688
+ const formatted1 = price1.toFixed(decimalPlaces);
689
+ const formatted2 = price2.toFixed(decimalPlaces);
690
+ return {
691
+ price1: formatted1,
692
+ price2: formatted2,
693
+ };
694
+ }
695
+ /**
696
+ * Format a price with a specific number of decimal places.
697
+ */
698
+ export function formatPriceWithDecimals(price, decimals) {
699
+ if (price === null || price === undefined || isNaN(price) || !isFinite(price)) {
700
+ return null;
701
+ }
702
+ return price.toFixed(decimals);
703
+ }
704
+ /**
705
+ * Rearrange token pair so stablecoin or gas asset is the quote token.
706
+ */
707
+ export function rearrangeTokenPair(token1, token2, chainId) {
708
+ const symbol1 = typeof token1 === 'string' ? token1 : token1?.symbol;
709
+ const symbol2 = typeof token2 === 'string' ? token2 : token2?.symbol;
710
+ if (!symbol1 || !symbol2) {
711
+ throw new Error('Both tokens must have valid symbols');
712
+ }
713
+ const isToken1Stable = isStableCoin(symbol1);
714
+ const isToken2Stable = isStableCoin(symbol2);
715
+ if (isToken1Stable && !isToken2Stable) {
716
+ return {
717
+ base: typeof token2 === 'string' ? { symbol: symbol2 } : token2,
718
+ quote: typeof token1 === 'string' ? { symbol: symbol1 } : token1,
719
+ baseSymbol: symbol2,
720
+ quoteSymbol: symbol1,
721
+ };
722
+ }
723
+ if (!isToken1Stable && isToken2Stable) {
724
+ return {
725
+ base: typeof token1 === 'string' ? { symbol: symbol1 } : token1,
726
+ quote: typeof token2 === 'string' ? { symbol: symbol2 } : token2,
727
+ baseSymbol: symbol1,
728
+ quoteSymbol: symbol2,
729
+ };
730
+ }
731
+ if (!isToken1Stable && !isToken2Stable && chainId) {
732
+ const chainIdNum = Number(chainId);
733
+ const isToken1Gas = isGasAsset(symbol1, chainIdNum);
734
+ const isToken2Gas = isGasAsset(symbol2, chainIdNum);
735
+ if (isToken1Gas && !isToken2Gas) {
736
+ return {
737
+ base: typeof token2 === 'string' ? { symbol: symbol2 } : token2,
738
+ quote: typeof token1 === 'string' ? { symbol: symbol1 } : token1,
739
+ baseSymbol: symbol2,
740
+ quoteSymbol: symbol1,
741
+ };
742
+ }
743
+ if (!isToken1Gas && isToken2Gas) {
744
+ return {
745
+ base: typeof token1 === 'string' ? { symbol: symbol1 } : token1,
746
+ quote: typeof token2 === 'string' ? { symbol: symbol2 } : token2,
747
+ baseSymbol: symbol1,
748
+ quoteSymbol: symbol2,
749
+ };
750
+ }
751
+ }
752
+ return {
753
+ base: typeof token1 === 'string' ? { symbol: symbol1 } : token1,
754
+ quote: typeof token2 === 'string' ? { symbol: symbol2 } : token2,
755
+ baseSymbol: symbol1,
756
+ quoteSymbol: symbol2,
757
+ };
758
+ }
759
+ /**
760
+ * Get a formatted pair label from two token symbols.
761
+ */
762
+ export function getPairLabel(baseSymbol, quoteSymbol) {
763
+ return `${baseSymbol}/${quoteSymbol}`;
764
+ }
765
+ /**
766
+ * Check if a current tick is within the specified range.
767
+ */
768
+ export function isTickInRange(currentTick, tickLower, tickUpper) {
769
+ console.log('[nauht] - check currentTickdasdas', currentTick);
770
+ console.log('[nauht] - check tickLower', tickLower);
771
+ console.log('[nauht] - check tickUpper', tickUpper);
772
+ if (currentTick === null || currentTick === undefined) {
773
+ return false;
774
+ }
775
+ return currentTick >= tickLower && currentTick <= tickUpper;
776
+ }
777
+ /**
778
+ * Calculate the percentage of the range that the current tick occupies.
779
+ */
780
+ export function calculateRangePercentage(currentTick, tickLower, tickUpper) {
781
+ if (currentTick === null || currentTick === undefined) {
782
+ return null;
783
+ }
784
+ const range = tickUpper - tickLower;
785
+ if (range === 0) {
786
+ return 0.5;
787
+ }
788
+ const position = currentTick - tickLower;
789
+ return position / range;
790
+ }
@@ -1,2 +1,2 @@
1
- export declare const SDK_VERSION = "2.0.435";
1
+ export declare const SDK_VERSION = "2.0.436";
2
2
  export declare function compareVersions(v1: string, v2: string): number;
@@ -131,3 +131,101 @@ export declare const findNewElements: (oldArray: string[], newArray: string[]) =
131
131
  export declare const createEthersContract: (chainId: number, contractAddress: string, abi: any[], rpcUrl?: string) => ethers.Contract;
132
132
  export declare const jsonStringifyCircularObject: (obj: any) => Promise<void>;
133
133
  export declare const callWithRetry: (callback: () => Promise<any>, maxRetries?: number, retryDelayMs?: number) => Promise<any>;
134
+ export interface TokenInfo {
135
+ symbol: string;
136
+ decimals: number;
137
+ name: string;
138
+ address: string;
139
+ }
140
+ /**
141
+ * Fetches token information from an ERC20 contract.
142
+ * Generic function that works with any ERC20-compliant token.
143
+ */
144
+ export declare function getTokenInfo(tokenAddress: string, provider: ethers.Provider): Promise<TokenInfo>;
145
+ /**
146
+ * Fetches token info with fallback values if contract call fails.
147
+ */
148
+ export declare function getTokenInfoWithFallback(tokenAddress: string, provider: ethers.Provider): Promise<TokenInfo>;
149
+ /**
150
+ * Fetches multiple token info objects in parallel.
151
+ */
152
+ export declare function getMultipleTokenInfo(tokenAddresses: string[], provider: ethers.Provider): Promise<TokenInfo[]>;
153
+ /**
154
+ * Known stablecoin symbols for token classification.
155
+ */
156
+ export declare const KNOWN_STABLE_SYMBOLS: Set<string>;
157
+ /**
158
+ * Gas asset symbols by chain ID.
159
+ */
160
+ export declare const GAS_ASSET_SYMBOLS: Record<number, string>;
161
+ /**
162
+ * Check if a symbol is a known stablecoin.
163
+ */
164
+ export declare function isStableCoin(symbol: string | null | undefined): boolean;
165
+ /**
166
+ * Check if a symbol is a gas asset for the given chain.
167
+ */
168
+ export declare function isGasAsset(symbol: string | null | undefined, chainId: number): boolean;
169
+ /**
170
+ * Get the gas asset symbol for a given chain.
171
+ */
172
+ export declare function getGasAssetSymbol(chainId: number): string | null;
173
+ /**
174
+ * Converts a Uniswap V3-style tick to a human-readable price.
175
+ * Price formula: price = 1.0001^tick * (10^(decimals1 - decimals0))
176
+ */
177
+ export declare function tickToPrice(tick: number, decimals0: number, decimals1: number): number;
178
+ /**
179
+ * Converts a price to the nearest tick.
180
+ */
181
+ export declare function priceToTick(price: number, decimals0: number, decimals1: number): number;
182
+ /**
183
+ * Calculates price from sqrtPriceX96 (used in Uniswap V3 slot0).
184
+ */
185
+ export declare function calculatePriceFromSqrtPriceX96(sqrtPriceX96: bigint | string, decimals0: number, decimals1: number): number;
186
+ /**
187
+ * Inverts a price (converts from token1/token0 to token0/token1).
188
+ */
189
+ export declare function invertPrice(price: number): number;
190
+ /**
191
+ * Format a price number to avoid scientific notation and round appropriately.
192
+ */
193
+ export declare function formatPrice(price: number | null | undefined, isStableQuoted?: boolean): string | null;
194
+ /**
195
+ * Format two prices based on the difference between them.
196
+ */
197
+ export declare function formatPriceRange(price1: number | null | undefined, price2: number | null | undefined): {
198
+ price1: string | null;
199
+ price2: string | null;
200
+ };
201
+ /**
202
+ * Format a price with a specific number of decimal places.
203
+ */
204
+ export declare function formatPriceWithDecimals(price: number | null | undefined, decimals: number): string | null;
205
+ export interface TokenPairInfo {
206
+ symbol: string;
207
+ address?: string;
208
+ decimals?: number;
209
+ }
210
+ export interface RearrangedPair {
211
+ base: TokenPairInfo;
212
+ quote: TokenPairInfo;
213
+ baseSymbol: string;
214
+ quoteSymbol: string;
215
+ }
216
+ /**
217
+ * Rearrange token pair so stablecoin or gas asset is the quote token.
218
+ */
219
+ export declare function rearrangeTokenPair(token1: string | TokenPairInfo, token2: string | TokenPairInfo, chainId?: number | null): RearrangedPair;
220
+ /**
221
+ * Get a formatted pair label from two token symbols.
222
+ */
223
+ export declare function getPairLabel(baseSymbol: string, quoteSymbol: string): string;
224
+ /**
225
+ * Check if a current tick is within the specified range.
226
+ */
227
+ export declare function isTickInRange(currentTick: number | null, tickLower: number, tickUpper: number): boolean;
228
+ /**
229
+ * Calculate the percentage of the range that the current tick occupies.
230
+ */
231
+ export declare function calculateRangePercentage(currentTick: number | null, tickLower: number, tickUpper: number): number | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "otomato-sdk",
3
- "version": "2.0.435",
3
+ "version": "2.0.436",
4
4
  "description": "An SDK for building and managing automations on Otomato",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/types/src/index.d.ts",