@clonegod/ttd-sol-common 2.0.67 → 2.0.68

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 (91) 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/clmm_depth_calculator.d.ts +42 -0
  25. package/dist/quote/depth/clmm_depth_calculator.js +173 -0
  26. package/dist/quote/depth/index.d.ts +20 -0
  27. package/dist/quote/depth/index.js +100 -0
  28. package/dist/quote/index.d.ts +9 -0
  29. package/dist/quote/index.js +9 -0
  30. package/dist/quote/pool_event.d.ts +20 -0
  31. package/dist/quote/pool_event.js +22 -0
  32. package/dist/quote/pool_subscription_registry.d.ts +4 -0
  33. package/dist/quote/pool_subscription_registry.js +62 -0
  34. package/dist/quote/quote_amount.d.ts +4 -0
  35. package/dist/quote/quote_amount.js +24 -0
  36. package/dist/quote/quote_trace.d.ts +16 -0
  37. package/dist/quote/quote_trace.js +40 -0
  38. package/dist/quote/tick/clmm_tick_math.d.ts +5 -0
  39. package/dist/quote/tick/clmm_tick_math.js +61 -0
  40. package/dist/quote/tick/index.d.ts +1 -0
  41. package/dist/{config → quote/tick}/index.js +1 -1
  42. package/dist/quote/verify/index.d.ts +1 -0
  43. package/dist/quote/verify/index.js +17 -0
  44. package/dist/quote/verify/quote_price_verify.d.ts +30 -0
  45. package/dist/quote/verify/quote_price_verify.js +247 -0
  46. package/dist/trade/index.d.ts +0 -1
  47. package/dist/trade/index.js +0 -1
  48. package/dist/trade/tx_builder.d.ts +1 -1
  49. package/dist/trade/tx_result_parse.js +1 -0
  50. package/dist/types/index.d.ts +9 -1
  51. package/dist/types/index.js +2 -0
  52. package/dist/utils/index.d.ts +1 -0
  53. package/dist/utils/index.js +17 -0
  54. package/dist/utils/trade_direction.d.ts +14 -0
  55. package/dist/utils/trade_direction.js +23 -0
  56. package/package.json +4 -4
  57. package/src/appconfig/SolanaQuoteAppConfig.ts +55 -0
  58. package/src/appconfig/SolanaTradeAppConfig.ts +117 -0
  59. package/src/appconfig/ensure_core_env.ts +28 -0
  60. package/src/appconfig/index.ts +5 -0
  61. package/src/appconfig/sol_dex_env_args.ts +52 -0
  62. package/src/appconfig/sol_env_args.ts +79 -0
  63. package/src/common/get_wallet_token_account.ts +27 -33
  64. package/src/grpc/grpc_provider_registry.ts +103 -0
  65. package/src/grpc/index.ts +1 -0
  66. package/src/index.ts +3 -0
  67. package/src/quote/abstract_dex_quote.ts +337 -0
  68. package/src/quote/chain_ops.ts +91 -0
  69. package/src/quote/depth/clmm_depth_calculator.ts +321 -0
  70. package/src/quote/depth/index.ts +167 -0
  71. package/src/quote/index.ts +9 -0
  72. package/src/quote/pool_event.ts +82 -0
  73. package/src/quote/pool_subscription_registry.ts +81 -0
  74. package/src/quote/quote_amount.ts +37 -0
  75. package/src/quote/quote_trace.ts +56 -0
  76. package/src/quote/tick/clmm_tick_math.ts +77 -0
  77. package/src/quote/tick/index.ts +1 -0
  78. package/src/quote/verify/index.ts +1 -0
  79. package/src/quote/verify/quote_price_verify.ts +508 -0
  80. package/src/trade/index.ts +0 -1
  81. package/src/trade/tx_builder.ts +1 -1
  82. package/src/trade/tx_result_parse.ts +1 -0
  83. package/src/types/index.ts +20 -2
  84. package/src/utils/index.ts +1 -0
  85. package/src/utils/trade_direction.ts +68 -0
  86. package/dist/config/SolanaTradeAppConfig.d.ts +0 -10
  87. package/dist/config/index.d.ts +0 -1
  88. package/dist/trade/SolanaTradeAppConfig.d.ts +0 -8
  89. package/dist/trade/SolanaTradeAppConfig.js +0 -26
  90. package/src/config/SolanaTradeAppConfig.ts +0 -70
  91. package/src/config/index.ts +0 -2
@@ -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';