@clonegod/ttd-sol-common 2.0.67 → 2.0.69

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.
Files changed (94) hide show
  1. package/dist/appconfig/SolanaQuoteAppConfig.d.ts +9 -0
  2. package/dist/appconfig/SolanaQuoteAppConfig.js +29 -0
  3. package/dist/appconfig/SolanaTradeAppConfig.d.ts +13 -0
  4. package/dist/{config → appconfig}/SolanaTradeAppConfig.js +25 -0
  5. package/dist/appconfig/ensure_core_env.d.ts +1 -0
  6. package/dist/appconfig/ensure_core_env.js +18 -0
  7. package/dist/appconfig/index.d.ts +5 -0
  8. package/dist/appconfig/index.js +21 -0
  9. package/dist/appconfig/sol_dex_env_args.d.ts +5 -0
  10. package/dist/appconfig/sol_dex_env_args.js +29 -0
  11. package/dist/appconfig/sol_env_args.d.ts +17 -0
  12. package/dist/appconfig/sol_env_args.js +37 -0
  13. package/dist/common/get_wallet_token_account.js +13 -16
  14. package/dist/grpc/grpc_provider_registry.d.ts +14 -0
  15. package/dist/grpc/grpc_provider_registry.js +70 -0
  16. package/dist/grpc/index.d.ts +1 -0
  17. package/dist/grpc/index.js +17 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.js +3 -0
  20. package/dist/quote/abstract_dex_quote.d.ts +68 -0
  21. package/dist/quote/abstract_dex_quote.js +208 -0
  22. package/dist/quote/chain_ops.d.ts +18 -0
  23. package/dist/quote/chain_ops.js +66 -0
  24. package/dist/quote/depth/amm_depth_calculator.d.ts +19 -0
  25. package/dist/quote/depth/amm_depth_calculator.js +55 -0
  26. package/dist/quote/depth/clmm_depth_calculator.d.ts +42 -0
  27. package/dist/quote/depth/clmm_depth_calculator.js +173 -0
  28. package/dist/quote/depth/index.d.ts +37 -0
  29. package/dist/quote/depth/index.js +164 -0
  30. package/dist/quote/index.d.ts +9 -0
  31. package/dist/quote/index.js +9 -0
  32. package/dist/quote/pool_event.d.ts +20 -0
  33. package/dist/quote/pool_event.js +22 -0
  34. package/dist/quote/pool_subscription_registry.d.ts +4 -0
  35. package/dist/quote/pool_subscription_registry.js +62 -0
  36. package/dist/quote/quote_amount.d.ts +4 -0
  37. package/dist/quote/quote_amount.js +24 -0
  38. package/dist/quote/quote_trace.d.ts +16 -0
  39. package/dist/quote/quote_trace.js +40 -0
  40. package/dist/quote/tick/clmm_tick_math.d.ts +5 -0
  41. package/dist/quote/tick/clmm_tick_math.js +61 -0
  42. package/dist/quote/tick/index.d.ts +1 -0
  43. package/dist/{config → quote/tick}/index.js +1 -1
  44. package/dist/quote/verify/index.d.ts +1 -0
  45. package/dist/quote/verify/index.js +17 -0
  46. package/dist/quote/verify/quote_price_verify.d.ts +30 -0
  47. package/dist/quote/verify/quote_price_verify.js +247 -0
  48. package/dist/trade/index.d.ts +0 -1
  49. package/dist/trade/index.js +0 -1
  50. package/dist/trade/tx_builder.d.ts +1 -1
  51. package/dist/trade/tx_result_parse.js +1 -0
  52. package/dist/types/index.d.ts +9 -1
  53. package/dist/types/index.js +2 -0
  54. package/dist/utils/index.d.ts +1 -0
  55. package/dist/utils/index.js +17 -0
  56. package/dist/utils/trade_direction.d.ts +14 -0
  57. package/dist/utils/trade_direction.js +23 -0
  58. package/package.json +4 -4
  59. package/src/appconfig/SolanaQuoteAppConfig.ts +55 -0
  60. package/src/appconfig/SolanaTradeAppConfig.ts +117 -0
  61. package/src/appconfig/ensure_core_env.ts +28 -0
  62. package/src/appconfig/index.ts +5 -0
  63. package/src/appconfig/sol_dex_env_args.ts +52 -0
  64. package/src/appconfig/sol_env_args.ts +79 -0
  65. package/src/common/get_wallet_token_account.ts +27 -33
  66. package/src/grpc/grpc_provider_registry.ts +103 -0
  67. package/src/grpc/index.ts +1 -0
  68. package/src/index.ts +3 -0
  69. package/src/quote/abstract_dex_quote.ts +337 -0
  70. package/src/quote/chain_ops.ts +91 -0
  71. package/src/quote/depth/amm_depth_calculator.ts +143 -0
  72. package/src/quote/depth/clmm_depth_calculator.ts +321 -0
  73. package/src/quote/depth/index.ts +272 -0
  74. package/src/quote/index.ts +9 -0
  75. package/src/quote/pool_event.ts +82 -0
  76. package/src/quote/pool_subscription_registry.ts +81 -0
  77. package/src/quote/quote_amount.ts +37 -0
  78. package/src/quote/quote_trace.ts +56 -0
  79. package/src/quote/tick/clmm_tick_math.ts +77 -0
  80. package/src/quote/tick/index.ts +1 -0
  81. package/src/quote/verify/index.ts +1 -0
  82. package/src/quote/verify/quote_price_verify.ts +508 -0
  83. package/src/trade/index.ts +0 -1
  84. package/src/trade/tx_builder.ts +1 -1
  85. package/src/trade/tx_result_parse.ts +1 -0
  86. package/src/types/index.ts +20 -2
  87. package/src/utils/index.ts +1 -0
  88. package/src/utils/trade_direction.ts +68 -0
  89. package/dist/config/SolanaTradeAppConfig.d.ts +0 -10
  90. package/dist/config/index.d.ts +0 -1
  91. package/dist/trade/SolanaTradeAppConfig.d.ts +0 -8
  92. package/dist/trade/SolanaTradeAppConfig.js +0 -26
  93. package/src/config/SolanaTradeAppConfig.ts +0 -70
  94. package/src/config/index.ts +0 -2
@@ -0,0 +1,82 @@
1
+ import { SolanaPoolAccountUpdateEventData } from '../types'
2
+
3
+ /**
4
+ * SolPoolEvent —— 询价基类消费的归一化池事件(对齐 BSC/SUI 的 pool_event 角色,
5
+ * 但建模 **Solana 的账户快照模型**,与 EVM/SUI 的 swap-event 模型有本质差异)。
6
+ *
7
+ * ── 关键差异(设计文档 §2.1)──
8
+ * EVM/SUI:stream 解析 swap/mint/burn 事件 → 推结构化 {type, amount0/1, txIndex},
9
+ * 消费端靠解析事件维护本地 tick。
10
+ * Solana :tickArray/binArray/vault 本身就是独立链上账户。stream-quote 直接订阅这些账户,
11
+ * 账户一变即推**最新账户原始数据**(base64),消费端解码 = 拿到链上真相(天然一致)。
12
+ * → 没有"swap 事件 + amount",事件本身就是新状态快照。
13
+ *
14
+ * 因此 SolPoolEvent 不带 swap/add/remove 分类、不带 amount0/1:
15
+ * - 每个池账户更新都触发 v2 重算(refreshStateFromEvent 解码账户 → 覆盖本地状态)。
16
+ * - 单调水位线用 Solana 账户的 writeVersion(Geyser write_version,全局单调递增),是 txIndex 的天然对等物。
17
+ * stream-quote 已把 write_version 补进推送 wire(step 2)→ 基类启用 (slot, writeVersion) 去重。
18
+ * AMM 聚合快照取 pool+vaultA+vaultB 三账户的 max writeVersion。
19
+ * (writeVersion 缺省时基类回退"无序号无条件推",对齐 SUI 缺 txIndex 行为,防御性兜底。)
20
+ *
21
+ * verify(swap amount 对账)暂缓:SOL 账户快照不含 swap amount,buildSwapVerify 默认返回 null,
22
+ * 待 stream-quote 解码 swap amount 后再接(设计文档 §2.4 / verify 跨源 cacheQuote 仍生效)。
23
+ */
24
+ export interface SolPoolEvent {
25
+ pool_address: string
26
+ dex_id: string
27
+ pool_name: string
28
+ /** 触发事件的 slot(= blockNumber,去重/水位线的"块"维度) */
29
+ blockNumber: number
30
+ /** 账户写版本(= txIndex 的 Solana 对等物,单调递增;wire 暂未携带 → 可空) */
31
+ writeVersion?: number
32
+ /** 导致账户变化的交易哈希(txid 透传,无则 'account') */
33
+ txHash: string
34
+ /** 区块时间(毫秒;缺省 0,stream 暂未必带) */
35
+ blockTime: number
36
+
37
+ // ── 账户原始数据(base64);refreshStateFromEvent 按 DEX layout 解码 ──
38
+ /** 池主账户原始数据(CLMM=pool state / DLMM=lbPair / AMM=pool);子账户独立 push 时为空 */
39
+ poolAccountData: string
40
+ /** AMM vault A 原始数据(reserve;仅 AMM 携带) */
41
+ vaultAAccountData?: string
42
+ /** AMM vault B 原始数据(仅 AMM 携带) */
43
+ vaultBAccountData?: string
44
+
45
+ /**
46
+ * 动态子账户更新(CLMM tickArray / DLMM binArray,方案 A 独立 push)。
47
+ * 存在时本事件是"子账户变更"而非"池主账户变更" → refreshStateFromEvent 按 role 解码更新本地分布。
48
+ */
49
+ subAccount?: {
50
+ role: string // 'tickArray' | 'binArray'
51
+ address: string
52
+ data: string // base64
53
+ }
54
+
55
+ /** 原始事件(需要额外字段时兜底访问,避免反复扩接口) */
56
+ raw: SolanaPoolAccountUpdateEventData
57
+ }
58
+
59
+ /**
60
+ * 把 stream-quote 推送的 SolanaPoolAccountUpdateEventData 归一化为 SolPoolEvent。
61
+ * 收敛 wire → 基类契约的映射,后续 wire 增字段只改这里一处。
62
+ */
63
+ export function toSolPoolEvent(data: SolanaPoolAccountUpdateEventData): SolPoolEvent {
64
+ const d = data.data
65
+ return {
66
+ pool_address: data.pool_address,
67
+ dex_id: data.dex_id,
68
+ pool_name: data.pool_name,
69
+ blockNumber: d.slot,
70
+ // Geyser write_version(全局单调);stream-quote 已补进 wire(step 2)→ (slot, writeVersion) 水位线去重
71
+ writeVersion: d.write_version,
72
+ txHash: d.tx_hash || 'account',
73
+ blockTime: data.event_time || 0,
74
+ poolAccountData: d.pool_account_data,
75
+ vaultAAccountData: d.vaultA_account_data,
76
+ vaultBAccountData: d.vaultB_account_data,
77
+ subAccount: d.sub_account
78
+ ? { role: d.sub_account.role, address: d.sub_account.account, data: d.sub_account.account_data }
79
+ : undefined,
80
+ raw: data,
81
+ }
82
+ }
@@ -0,0 +1,81 @@
1
+ import { AppConfig, HttpUtil, log_info, log_warn, SERVICE_PORT, StandardPoolInfoType } from '@clonegod/ttd-core/dist'
2
+ import { resolveGrpcProvider } from '../grpc/grpc_provider_registry'
3
+
4
+ /**
5
+ * 按需订阅 —— 生产端(询价进程调用)。对齐 BSC/BASE/SUI:询价进程通过 config-center 声明所需池子,
6
+ * config-center 写 `${chain}:pool:subscriptions` Hash + 广播 `:change`,stream-quote 消费后订阅 Helius。
7
+ *
8
+ * Solana 适配(与 BSC 的差异):
9
+ * - **单 Helius provider,且对齐 SUI 由运维在 analyze Config/RPC 页配(type=grpc, endpoint=laserstream URL, auth_token=API key)**。
10
+ * 本 helper **不自动种 provider**;register 用 `resolveGrpcProvider` 解析出 analyze 配的 provider id(无配 fail-loud)。
11
+ * - **base58 地址大小写敏感**:依赖 config-center `lower()` 已改为 0x 感知(非 0x 原样保留),不破坏地址。
12
+ */
13
+
14
+ function configCenterBase(appConfig: AppConfig): string {
15
+ const chain = appConfig.env_args.chain_id // SOLANA
16
+ let host = String(appConfig.env_args.config_center_host || '127.0.0.1').trim()
17
+ // host 可能含端口(127.0.0.1:4000)或不含(127.0.0.1);不含则补 CONFIG_CENTER_HTTP
18
+ if (!host.includes(':')) host = `${host}:${SERVICE_PORT.CONFIG_CENTER_HTTP}`
19
+ return `http://${host}/${chain}/config`
20
+ }
21
+
22
+ /** 注册一批池子订阅(每池 POST config-center /quote/register),provider_ids 用 analyze 配的 grpc provider。 */
23
+ export async function registerPoolSubscriptions(
24
+ appConfig: AppConfig,
25
+ pools: StandardPoolInfoType[],
26
+ quote_app_id: string,
27
+ ): Promise<void> {
28
+ // provider 由运维在 analyze Config/RPC 配(type=grpc);解析其 id 供 register 引用,无配 fail-loud
29
+ const provider = await resolveGrpcProvider(appConfig.arb_cache.redis_cmd, appConfig.env_args.chain_id)
30
+ const provider_ids = [provider.id]
31
+
32
+ const base = configCenterBase(appConfig)
33
+ let ok = 0
34
+ for (const p of pools) {
35
+ try {
36
+ await HttpUtil.post(`${base}/quote/register`, {
37
+ pool_address: p.pool_address,
38
+ provider_ids,
39
+ quote_app_id,
40
+ pair: p.pair,
41
+ dex_id: p.dex_id,
42
+ pool_name: p.pool_name,
43
+ fee_rate: p.fee_rate,
44
+ })
45
+ ok++
46
+ } catch (e: any) {
47
+ log_warn(`[pool/subscriptions] register ${p.pool_address} failed: ${e.message}`)
48
+ }
49
+ }
50
+ log_info(`[pool/subscriptions] registered ${ok}/${pools.length} pools by ${quote_app_id} → provider=${provider.id}`)
51
+ }
52
+
53
+ /** 注销本进程注册的所有池子订阅(按 quote_app_id)。 */
54
+ export async function unregisterPoolSubscriptions(appConfig: AppConfig, quote_app_id: string): Promise<void> {
55
+ try {
56
+ await HttpUtil.post(`${configCenterBase(appConfig)}/quote/unregister`, { quote_app_id })
57
+ log_info(`[pool/subscriptions] unregistered all pools by ${quote_app_id}`)
58
+ } catch (e: any) {
59
+ log_warn(`[pool/subscriptions] unregister failed: ${e.message}`)
60
+ }
61
+ }
62
+
63
+ /**
64
+ * 询价进程启动后调用一次:确保 helius provider + 注册全部池子 + 装退出时自动 unregister。
65
+ * quote_app_id 取 env_args.app_name(每个 DEX 询价进程唯一)。
66
+ */
67
+ export async function attachPoolSubscriptionLifecycle(appConfig: AppConfig, pools: StandardPoolInfoType[]): Promise<void> {
68
+ const quote_app_id = String(appConfig.env_args.app_name || '').toLowerCase() || 'sol-quote'
69
+ await registerPoolSubscriptions(appConfig, pools, quote_app_id)
70
+
71
+ let cleaned = false
72
+ const cleanup = async (sig: string) => {
73
+ if (cleaned) return
74
+ cleaned = true
75
+ log_info(`[pool/subscriptions] ${sig} → unregister ${quote_app_id}`)
76
+ await unregisterPoolSubscriptions(appConfig, quote_app_id)
77
+ process.exit(0)
78
+ }
79
+ process.on('SIGINT', () => void cleanup('SIGINT'))
80
+ process.on('SIGTERM', () => void cleanup('SIGTERM'))
81
+ }
@@ -0,0 +1,37 @@
1
+ import { get_solana_token_price_info, StandardPoolInfoType } from '@clonegod/ttd-core';
2
+ import Decimal from 'decimal.js';
3
+
4
+ /**
5
+ * 解析询价使用的 USD 金额(与 BSC/SUI 同名 helper 对齐)。
6
+ *
7
+ * 优先级:
8
+ * 1. 环境变量 QUOTE_AMOUNT_USD(全局覆盖,方便统一调整)
9
+ * 2. pool 配置里的 quote_amount_usd(每个 pool 可以差异化配置)
10
+ *
11
+ * quote_amount_usd 用于询价时模拟"卖/买多少 USD 价值的 token",应与典型订单量接近,
12
+ * 否则 order_price 与 tx_price 会有明显差距(AMM price impact 非线性)。
13
+ */
14
+ export function getQuoteAmountUsd(poolInfo: StandardPoolInfoType): number {
15
+ const envValue = Number(process.env.QUOTE_AMOUNT_USD);
16
+ if (envValue > 0) {
17
+ return envValue;
18
+ }
19
+ return poolInfo.quote_amount_usd;
20
+ }
21
+
22
+ /**
23
+ * 按 arb_cache 中的当前 USD 价把 quoteAmountUsd 折算成 token 的 UI amount(小数形式)。
24
+ *
25
+ * 各 DEX 询价 compute amountIn 用。价格 miss / 为 0 抛错,由 caller 决定降级。
26
+ */
27
+ export async function usdToTokenUiAmount(
28
+ amountInUsd: number,
29
+ tokenAddress: string,
30
+ ): Promise<Decimal> {
31
+ const priceMap = await get_solana_token_price_info([tokenAddress]);
32
+ const price = priceMap.get(tokenAddress)?.price;
33
+ if (!price || price === '0') {
34
+ throw new Error(`price not available for ${tokenAddress}`);
35
+ }
36
+ return new Decimal(amountInUsd).div(new Decimal(price));
37
+ }
@@ -0,0 +1,56 @@
1
+ import { createLogger } from '@clonegod/ttd-core';
2
+
3
+ const logger = createLogger(__filename);
4
+
5
+ /**
6
+ * QuoteTrace —— 询价链路追踪(镜像 trade 侧 TradeTrace,与 BSC/SUI 同名文件对齐)。
7
+ *
8
+ * 一次询价收集各阶段耗时 + 关键字段,结束一次性输出**一行**结构化日志。
9
+ * 阶段标准:trigger -> compute -> depth -> verify -> publish。
10
+ *
11
+ * 用法:
12
+ * const t = new QuoteTrace('SOL/USDC', '...', slot, 'local:v2');
13
+ * t.mark('compute'); t.set('ask', 1564.6); ...; t.flush();
14
+ */
15
+ export class QuoteTrace {
16
+ private startTime = Date.now();
17
+ private marks: Array<{ name: string; elapsed: number }> = [];
18
+ private data: Record<string, any> = {};
19
+ private error: { stage: string; message: string } | null = null;
20
+
21
+ constructor(
22
+ public readonly poolName: string,
23
+ public readonly poolAddress: string,
24
+ public blockNumber: number = 0,
25
+ public source: string = '',
26
+ ) {}
27
+
28
+ mark(name: string): void {
29
+ this.marks.push({ name, elapsed: Date.now() - this.startTime });
30
+ }
31
+ set(key: string, value: any): void { this.data[key] = value; }
32
+ markError(stage: string, message: string): void { this.error = { stage, message }; }
33
+
34
+ /** trigger(0ms) -> compute(4ms) -> depth(2ms) -> publish(1ms) = 7ms(括号=增量耗时) */
35
+ private buildTimeline(): string {
36
+ if (this.marks.length === 0) return '(no marks)';
37
+ let prev = 0;
38
+ const parts = this.marks.map(m => { const d = m.elapsed - prev; prev = m.elapsed; return `${m.name}(${d}ms)`; });
39
+ return `${parts.join(' -> ')} = ${this.marks[this.marks.length - 1].elapsed}ms`;
40
+ }
41
+
42
+ flush(): void {
43
+ const timeline = this.buildTimeline();
44
+ if (this.error) {
45
+ logger.error(
46
+ `[QUOTE FAILED] ${this.poolName} | stage=${this.error.stage} | source=${this.source} | ${this.error.message}`,
47
+ new Error(this.error.message),
48
+ );
49
+ logger.info(`[QUOTE FAILED detail] ${this.poolName}`, { timeline, error_stage: this.error.stage, source: this.source, ...this.data });
50
+ } else {
51
+ // 成功路径降到 debug:ask/bid/block/txid 已在 on_quote_response 的推送行摘要里,
52
+ // 这里仅保留细粒度 timeline 供调试。失败路径仍 error/info 响亮。
53
+ logger.debug(`[QUOTE OK] ${this.poolName} blk=${this.blockNumber} source=${this.source}`, { timeline, ...this.data });
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * 共享 CLMM TickMath(Solana,Uniswap V3 Q64.64 magic-constant 版)
3
+ *
4
+ * Solana 三个 CLMM(Raydium / Orca / ByReal)的 tick→sqrtPrice 数学**同源 Uniswap V3**:
5
+ * sqrtPriceX64 = sqrt(1.0001)^tick × 2^64,用一组幂次魔数 + 右移 64 位累乘实现。
6
+ *
7
+ * 本实现**逐字移植自 raydium SDK / byreal SDK 的 `SqrtPriceMath.getSqrtPriceX64FromTick`**
8
+ * (node_modules/byreal-clmm-sdk-alpha/.../sqrtPriceMath.js,与 raydium-sdk-v2 的 math.js 同魔数),
9
+ * 仅把 BN 运算改成纯 bigint:
10
+ * - mulRightShift(ratio, mulBy) = (ratio * mulBy) >> 64n
11
+ * (SDK 用 signedRightShift(·,64,256);此处所有值恒正且乘积 < 2^128,等价无符号右移 64)
12
+ * - tick > 0 时取倒数 ratio = MaxUint128 / ratio(SDK 同)。
13
+ *
14
+ * 四源一致性校验结论(逐 tick bigint 比较 -443636/-100000/-1/0/1/100/10000/443636):
15
+ * - **本函数 == raydium SDK == byreal SDK 完全一致**(8/8 tick 全等)。三者都是 X64-native 魔数版。
16
+ * - **orca SDK `PriceMath.tickIndexToSqrtPriceX64` 在末几位有微小偏差**(非 bug):orca 用 **X96 魔数**
17
+ * (2^96-scaled,每步右移 96)算完再 `>> 32` 降到 X64,rounding 累积路径不同 → 低 ~5 位差异。
18
+ * orca whirlpool 链上 sqrtPrice 存的是 u128 X64、链上 swap 走 X64 整数math,故 X64-native 版(本函数/raydium/byreal)
19
+ * 才是与链上一致的形态;orca SDK 的 X96-downshift 只是它的 tick→sqrtPrice 辅助。差异在 tick 粒度上 sub-wei,
20
+ * 对深度档位边界无实质影响 → 三个 CLMM 统一用本函数(符合"共享一份 TickMath"规范)。
21
+ *
22
+ * 纯 bigint、零外部依赖,三个 CLMM 包共享同一份(DepthTick.sqrtPriceX64 的唯一来源)。
23
+ */
24
+
25
+ /** Uniswap V3 tick 边界(与 raydium/orca/byreal SDK 一致)。 */
26
+ export const MIN_TICK = -443636;
27
+ export const MAX_TICK = 443636;
28
+
29
+ /** sqrtPriceX64 边界(getSqrtPriceX64FromTick(MIN_TICK/MAX_TICK),与 SDK 常量一致)。 */
30
+ export const MIN_SQRT_PRICE_X64 = 4295048016n;
31
+ export const MAX_SQRT_PRICE_X64 = 79226673521066979257578248091n;
32
+
33
+ const MaxUint128 = (1n << 128n) - 1n;
34
+
35
+ /** (val * mulBy) >> 64 —— SDK signedRightShift(·, 64, 256) 在恒正、乘积 < 2^128 下的等价。 */
36
+ function mulRightShift(val: bigint, mulBy: bigint): bigint {
37
+ return (val * mulBy) >> 64n;
38
+ }
39
+
40
+ /**
41
+ * tick → sqrtPriceX64(Q64.64)。
42
+ * 与 raydium `SqrtPriceMath.getSqrtPriceX64FromTick` / orca `PriceMath.tickIndexToSqrtPriceX64`
43
+ * / byreal `SqrtPriceMath.getSqrtPriceX64FromTick` bigint 完全一致。
44
+ */
45
+ export function getSqrtPriceX64FromTick(tick: number): bigint {
46
+ if (!Number.isInteger(tick)) {
47
+ throw new Error('tick must be integer');
48
+ }
49
+ if (tick < MIN_TICK || tick > MAX_TICK) {
50
+ throw new Error('tick must be in MIN_TICK and MAX_TICK');
51
+ }
52
+ const tickAbs = tick < 0 ? -tick : tick;
53
+
54
+ let ratio = (tickAbs & 0x1) !== 0 ? 18445821805675395072n : 18446744073709551616n;
55
+ if ((tickAbs & 0x2) !== 0) ratio = mulRightShift(ratio, 18444899583751176192n);
56
+ if ((tickAbs & 0x4) !== 0) ratio = mulRightShift(ratio, 18443055278223355904n);
57
+ if ((tickAbs & 0x8) !== 0) ratio = mulRightShift(ratio, 18439367220385607680n);
58
+ if ((tickAbs & 0x10) !== 0) ratio = mulRightShift(ratio, 18431993317065453568n);
59
+ if ((tickAbs & 0x20) !== 0) ratio = mulRightShift(ratio, 18417254355718170624n);
60
+ if ((tickAbs & 0x40) !== 0) ratio = mulRightShift(ratio, 18387811781193609216n);
61
+ if ((tickAbs & 0x80) !== 0) ratio = mulRightShift(ratio, 18329067761203558400n);
62
+ if ((tickAbs & 0x100) !== 0) ratio = mulRightShift(ratio, 18212142134806163456n);
63
+ if ((tickAbs & 0x200) !== 0) ratio = mulRightShift(ratio, 17980523815641700352n);
64
+ if ((tickAbs & 0x400) !== 0) ratio = mulRightShift(ratio, 17526086738831433728n);
65
+ if ((tickAbs & 0x800) !== 0) ratio = mulRightShift(ratio, 16651378430235570176n);
66
+ if ((tickAbs & 0x1000) !== 0) ratio = mulRightShift(ratio, 15030750278694412288n);
67
+ if ((tickAbs & 0x2000) !== 0) ratio = mulRightShift(ratio, 12247334978884435968n);
68
+ if ((tickAbs & 0x4000) !== 0) ratio = mulRightShift(ratio, 8131365268886854656n);
69
+ if ((tickAbs & 0x8000) !== 0) ratio = mulRightShift(ratio, 3584323654725218816n);
70
+ if ((tickAbs & 0x10000) !== 0) ratio = mulRightShift(ratio, 696457651848324352n);
71
+ if ((tickAbs & 0x20000) !== 0) ratio = mulRightShift(ratio, 26294789957507116n);
72
+ if ((tickAbs & 0x40000) !== 0) ratio = mulRightShift(ratio, 37481735321082n);
73
+
74
+ if (tick > 0) ratio = MaxUint128 / ratio;
75
+
76
+ return ratio;
77
+ }
@@ -0,0 +1 @@
1
+ export * from './clmm_tick_math';
@@ -0,0 +1 @@
1
+ export * from './quote_price_verify';