imm-cli 0.1.0

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 (227) hide show
  1. package/README.md +315 -0
  2. package/dist/cli.d.ts +7 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +112 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/config.d.ts +3 -0
  7. package/dist/commands/config.d.ts.map +1 -0
  8. package/dist/commands/config.js +251 -0
  9. package/dist/commands/config.js.map +1 -0
  10. package/dist/commands/immbook.d.ts +16 -0
  11. package/dist/commands/immbook.d.ts.map +1 -0
  12. package/dist/commands/immbook.js +795 -0
  13. package/dist/commands/immbook.js.map +1 -0
  14. package/dist/commands/jaine.d.ts +3 -0
  15. package/dist/commands/jaine.d.ts.map +1 -0
  16. package/dist/commands/jaine.js +1397 -0
  17. package/dist/commands/jaine.js.map +1 -0
  18. package/dist/commands/send.d.ts +3 -0
  19. package/dist/commands/send.d.ts.map +1 -0
  20. package/dist/commands/send.js +229 -0
  21. package/dist/commands/send.js.map +1 -0
  22. package/dist/commands/setup.d.ts +3 -0
  23. package/dist/commands/setup.d.ts.map +1 -0
  24. package/dist/commands/setup.js +83 -0
  25. package/dist/commands/setup.js.map +1 -0
  26. package/dist/commands/slop-app.d.ts +9 -0
  27. package/dist/commands/slop-app.d.ts.map +1 -0
  28. package/dist/commands/slop-app.js +793 -0
  29. package/dist/commands/slop-app.js.map +1 -0
  30. package/dist/commands/slop.d.ts +3 -0
  31. package/dist/commands/slop.d.ts.map +1 -0
  32. package/dist/commands/slop.js +1053 -0
  33. package/dist/commands/slop.js.map +1 -0
  34. package/dist/commands/wallet.d.ts +3 -0
  35. package/dist/commands/wallet.d.ts.map +1 -0
  36. package/dist/commands/wallet.js +298 -0
  37. package/dist/commands/wallet.js.map +1 -0
  38. package/dist/config/paths.d.ts +6 -0
  39. package/dist/config/paths.d.ts.map +1 -0
  40. package/dist/config/paths.js +24 -0
  41. package/dist/config/paths.js.map +1 -0
  42. package/dist/config/store.d.ts +44 -0
  43. package/dist/config/store.d.ts.map +1 -0
  44. package/dist/config/store.js +109 -0
  45. package/dist/config/store.js.map +1 -0
  46. package/dist/constants/chain.d.ts +56 -0
  47. package/dist/constants/chain.d.ts.map +1 -0
  48. package/dist/constants/chain.js +50 -0
  49. package/dist/constants/chain.js.map +1 -0
  50. package/dist/errors.d.ts +86 -0
  51. package/dist/errors.d.ts.map +1 -0
  52. package/dist/errors.js +100 -0
  53. package/dist/errors.js.map +1 -0
  54. package/dist/immbook/api.d.ts +38 -0
  55. package/dist/immbook/api.d.ts.map +1 -0
  56. package/dist/immbook/api.js +86 -0
  57. package/dist/immbook/api.js.map +1 -0
  58. package/dist/immbook/auth.d.ts +31 -0
  59. package/dist/immbook/auth.d.ts.map +1 -0
  60. package/dist/immbook/auth.js +93 -0
  61. package/dist/immbook/auth.js.map +1 -0
  62. package/dist/immbook/comments.d.ts +26 -0
  63. package/dist/immbook/comments.d.ts.map +1 -0
  64. package/dist/immbook/comments.js +20 -0
  65. package/dist/immbook/comments.js.map +1 -0
  66. package/dist/immbook/follows.d.ts +19 -0
  67. package/dist/immbook/follows.d.ts.map +1 -0
  68. package/dist/immbook/follows.js +21 -0
  69. package/dist/immbook/follows.js.map +1 -0
  70. package/dist/immbook/jwtCache.d.ts +15 -0
  71. package/dist/immbook/jwtCache.d.ts.map +1 -0
  72. package/dist/immbook/jwtCache.js +63 -0
  73. package/dist/immbook/jwtCache.js.map +1 -0
  74. package/dist/immbook/points.d.ts +35 -0
  75. package/dist/immbook/points.d.ts.map +1 -0
  76. package/dist/immbook/points.js +20 -0
  77. package/dist/immbook/points.js.map +1 -0
  78. package/dist/immbook/posts.d.ts +46 -0
  79. package/dist/immbook/posts.d.ts.map +1 -0
  80. package/dist/immbook/posts.js +43 -0
  81. package/dist/immbook/posts.js.map +1 -0
  82. package/dist/immbook/profile.d.ts +29 -0
  83. package/dist/immbook/profile.d.ts.map +1 -0
  84. package/dist/immbook/profile.js +14 -0
  85. package/dist/immbook/profile.js.map +1 -0
  86. package/dist/immbook/submolts.d.ts +22 -0
  87. package/dist/immbook/submolts.d.ts.map +1 -0
  88. package/dist/immbook/submolts.js +24 -0
  89. package/dist/immbook/submolts.js.map +1 -0
  90. package/dist/immbook/tradeProof.d.ts +21 -0
  91. package/dist/immbook/tradeProof.d.ts.map +1 -0
  92. package/dist/immbook/tradeProof.js +14 -0
  93. package/dist/immbook/tradeProof.js.map +1 -0
  94. package/dist/immbook/votes.d.ts +17 -0
  95. package/dist/immbook/votes.d.ts.map +1 -0
  96. package/dist/immbook/votes.js +20 -0
  97. package/dist/immbook/votes.js.map +1 -0
  98. package/dist/intents/store.d.ts +22 -0
  99. package/dist/intents/store.d.ts.map +1 -0
  100. package/dist/intents/store.js +76 -0
  101. package/dist/intents/store.js.map +1 -0
  102. package/dist/intents/types.d.ts +21 -0
  103. package/dist/intents/types.d.ts.map +1 -0
  104. package/dist/intents/types.js +2 -0
  105. package/dist/intents/types.js.map +1 -0
  106. package/dist/jaine/abi/erc20.d.ts +90 -0
  107. package/dist/jaine/abi/erc20.d.ts.map +1 -0
  108. package/dist/jaine/abi/erc20.js +65 -0
  109. package/dist/jaine/abi/erc20.js.map +1 -0
  110. package/dist/jaine/abi/factory.d.ts +38 -0
  111. package/dist/jaine/abi/factory.d.ts.map +1 -0
  112. package/dist/jaine/abi/factory.js +26 -0
  113. package/dist/jaine/abi/factory.js.map +1 -0
  114. package/dist/jaine/abi/index.d.ts +11 -0
  115. package/dist/jaine/abi/index.d.ts.map +1 -0
  116. package/dist/jaine/abi/index.js +11 -0
  117. package/dist/jaine/abi/index.js.map +1 -0
  118. package/dist/jaine/abi/nftManager.d.ts +282 -0
  119. package/dist/jaine/abi/nftManager.d.ts.map +1 -0
  120. package/dist/jaine/abi/nftManager.js +182 -0
  121. package/dist/jaine/abi/nftManager.js.map +1 -0
  122. package/dist/jaine/abi/pool.d.ts +77 -0
  123. package/dist/jaine/abi/pool.d.ts.map +1 -0
  124. package/dist/jaine/abi/pool.js +56 -0
  125. package/dist/jaine/abi/pool.js.map +1 -0
  126. package/dist/jaine/abi/quoter.d.ts +84 -0
  127. package/dist/jaine/abi/quoter.d.ts.map +1 -0
  128. package/dist/jaine/abi/quoter.js +53 -0
  129. package/dist/jaine/abi/quoter.js.map +1 -0
  130. package/dist/jaine/abi/router.d.ts +135 -0
  131. package/dist/jaine/abi/router.d.ts.map +1 -0
  132. package/dist/jaine/abi/router.js +88 -0
  133. package/dist/jaine/abi/router.js.map +1 -0
  134. package/dist/jaine/abi/w0g.d.ts +41 -0
  135. package/dist/jaine/abi/w0g.d.ts.map +1 -0
  136. package/dist/jaine/abi/w0g.js +34 -0
  137. package/dist/jaine/abi/w0g.js.map +1 -0
  138. package/dist/jaine/allowance.d.ts +48 -0
  139. package/dist/jaine/allowance.d.ts.map +1 -0
  140. package/dist/jaine/allowance.js +192 -0
  141. package/dist/jaine/allowance.js.map +1 -0
  142. package/dist/jaine/coreTokens.d.ts +32 -0
  143. package/dist/jaine/coreTokens.d.ts.map +1 -0
  144. package/dist/jaine/coreTokens.js +91 -0
  145. package/dist/jaine/coreTokens.js.map +1 -0
  146. package/dist/jaine/pathEncoding.d.ts +39 -0
  147. package/dist/jaine/pathEncoding.d.ts.map +1 -0
  148. package/dist/jaine/pathEncoding.js +98 -0
  149. package/dist/jaine/pathEncoding.js.map +1 -0
  150. package/dist/jaine/paths.d.ts +11 -0
  151. package/dist/jaine/paths.d.ts.map +1 -0
  152. package/dist/jaine/paths.js +20 -0
  153. package/dist/jaine/paths.js.map +1 -0
  154. package/dist/jaine/poolCache.d.ts +42 -0
  155. package/dist/jaine/poolCache.d.ts.map +1 -0
  156. package/dist/jaine/poolCache.js +164 -0
  157. package/dist/jaine/poolCache.js.map +1 -0
  158. package/dist/jaine/routing.d.ts +41 -0
  159. package/dist/jaine/routing.d.ts.map +1 -0
  160. package/dist/jaine/routing.js +247 -0
  161. package/dist/jaine/routing.js.map +1 -0
  162. package/dist/jaine/userTokens.d.ts +27 -0
  163. package/dist/jaine/userTokens.d.ts.map +1 -0
  164. package/dist/jaine/userTokens.js +89 -0
  165. package/dist/jaine/userTokens.js.map +1 -0
  166. package/dist/slop/abi/factory.d.ts +128 -0
  167. package/dist/slop/abi/factory.d.ts.map +1 -0
  168. package/dist/slop/abi/factory.js +70 -0
  169. package/dist/slop/abi/factory.js.map +1 -0
  170. package/dist/slop/abi/feeCollector.d.ts +95 -0
  171. package/dist/slop/abi/feeCollector.d.ts.map +1 -0
  172. package/dist/slop/abi/feeCollector.js +71 -0
  173. package/dist/slop/abi/feeCollector.js.map +1 -0
  174. package/dist/slop/abi/index.d.ts +5 -0
  175. package/dist/slop/abi/index.d.ts.map +1 -0
  176. package/dist/slop/abi/index.js +5 -0
  177. package/dist/slop/abi/index.js.map +1 -0
  178. package/dist/slop/abi/registry.d.ts +135 -0
  179. package/dist/slop/abi/registry.d.ts.map +1 -0
  180. package/dist/slop/abi/registry.js +90 -0
  181. package/dist/slop/abi/registry.js.map +1 -0
  182. package/dist/slop/abi/token.d.ts +320 -0
  183. package/dist/slop/abi/token.d.ts.map +1 -0
  184. package/dist/slop/abi/token.js +251 -0
  185. package/dist/slop/abi/token.js.map +1 -0
  186. package/dist/slop/quote.d.ts +80 -0
  187. package/dist/slop/quote.d.ts.map +1 -0
  188. package/dist/slop/quote.js +174 -0
  189. package/dist/slop/quote.js.map +1 -0
  190. package/dist/utils/canonicalJson.d.ts +8 -0
  191. package/dist/utils/canonicalJson.d.ts.map +1 -0
  192. package/dist/utils/canonicalJson.js +20 -0
  193. package/dist/utils/canonicalJson.js.map +1 -0
  194. package/dist/utils/env.d.ts +11 -0
  195. package/dist/utils/env.d.ts.map +1 -0
  196. package/dist/utils/env.js +20 -0
  197. package/dist/utils/env.js.map +1 -0
  198. package/dist/utils/http.d.ts +19 -0
  199. package/dist/utils/http.d.ts.map +1 -0
  200. package/dist/utils/http.js +61 -0
  201. package/dist/utils/http.js.map +1 -0
  202. package/dist/utils/logger.d.ts +4 -0
  203. package/dist/utils/logger.d.ts.map +1 -0
  204. package/dist/utils/logger.js +21 -0
  205. package/dist/utils/logger.js.map +1 -0
  206. package/dist/utils/output.d.ts +19 -0
  207. package/dist/utils/output.d.ts.map +1 -0
  208. package/dist/utils/output.js +37 -0
  209. package/dist/utils/output.js.map +1 -0
  210. package/dist/utils/respond.d.ts +19 -0
  211. package/dist/utils/respond.d.ts.map +1 -0
  212. package/dist/utils/respond.js +25 -0
  213. package/dist/utils/respond.js.map +1 -0
  214. package/dist/utils/ui.d.ts +38 -0
  215. package/dist/utils/ui.d.ts.map +1 -0
  216. package/dist/utils/ui.js +126 -0
  217. package/dist/utils/ui.js.map +1 -0
  218. package/dist/wallet/client.d.ts +4 -0
  219. package/dist/wallet/client.d.ts.map +1 -0
  220. package/dist/wallet/client.js +53 -0
  221. package/dist/wallet/client.js.map +1 -0
  222. package/dist/wallet/keystore.d.ts +21 -0
  223. package/dist/wallet/keystore.d.ts.map +1 -0
  224. package/dist/wallet/keystore.js +111 -0
  225. package/dist/wallet/keystore.js.map +1 -0
  226. package/package.json +56 -0
  227. package/skills/imm/SKILL.md +617 -0
@@ -0,0 +1,98 @@
1
+ import { concat, pad, toHex } from "viem";
2
+ /**
3
+ * Encode path for Uniswap V3 exactInput
4
+ * Format: token0 + fee0 + token1 + fee1 + token2 + ...
5
+ *
6
+ * @param tokens - Array of token addresses in swap order
7
+ * @param fees - Array of fee tiers (length = tokens.length - 1)
8
+ * @returns Encoded path bytes
9
+ */
10
+ export function encodePath(tokens, fees) {
11
+ if (tokens.length < 2) {
12
+ throw new Error("Path must have at least 2 tokens");
13
+ }
14
+ if (fees.length !== tokens.length - 1) {
15
+ throw new Error("Fees length must be tokens.length - 1");
16
+ }
17
+ // Each address is 20 bytes, each fee is 3 bytes
18
+ const parts = [];
19
+ for (let i = 0; i < tokens.length; i++) {
20
+ // Add token address (20 bytes)
21
+ parts.push(tokens[i].toLowerCase());
22
+ // Add fee if not last token (3 bytes)
23
+ if (i < fees.length) {
24
+ // Fee is uint24, encode as 3 bytes
25
+ const feeHex = pad(toHex(fees[i]), { size: 3 });
26
+ parts.push(feeHex);
27
+ }
28
+ }
29
+ return concat(parts);
30
+ }
31
+ /**
32
+ * Encode path for Uniswap V3 exactOutput
33
+ * Note: exactOutput requires REVERSED path (tokenOut first)
34
+ *
35
+ * @param tokens - Array of token addresses in swap order (tokenIn → tokenOut)
36
+ * @param fees - Array of fee tiers
37
+ * @returns Encoded path bytes (reversed for exactOutput)
38
+ */
39
+ export function encodePathForExactOutput(tokens, fees) {
40
+ // Reverse both arrays for exactOutput
41
+ const reversedTokens = [...tokens].reverse();
42
+ const reversedFees = [...fees].reverse();
43
+ return encodePath(reversedTokens, reversedFees);
44
+ }
45
+ /**
46
+ * Decode path bytes into tokens and fees
47
+ *
48
+ * @param path - Encoded path bytes
49
+ * @returns Object with tokens array and fees array
50
+ */
51
+ export function decodePath(path) {
52
+ // Remove 0x prefix
53
+ const data = path.slice(2);
54
+ // Each token is 20 bytes (40 hex chars), each fee is 3 bytes (6 hex chars)
55
+ const tokens = [];
56
+ const fees = [];
57
+ let offset = 0;
58
+ let isToken = true;
59
+ while (offset < data.length) {
60
+ if (isToken) {
61
+ // Read 20 bytes for token
62
+ const tokenHex = data.slice(offset, offset + 40);
63
+ tokens.push(`0x${tokenHex}`);
64
+ offset += 40;
65
+ isToken = false;
66
+ }
67
+ else {
68
+ // Read 3 bytes for fee
69
+ const feeHex = data.slice(offset, offset + 6);
70
+ fees.push(parseInt(feeHex, 16));
71
+ offset += 6;
72
+ isToken = true;
73
+ }
74
+ }
75
+ return { tokens, fees };
76
+ }
77
+ /**
78
+ * Calculate the number of hops in a path
79
+ */
80
+ export function getPathHops(tokens) {
81
+ return tokens.length - 1;
82
+ }
83
+ /**
84
+ * Format path as human-readable string
85
+ * e.g., "USDC → [0.3%] → w0G → [0.05%] → WETH"
86
+ */
87
+ export function formatPath(tokens, fees, getSymbol) {
88
+ const parts = [];
89
+ for (let i = 0; i < tokens.length; i++) {
90
+ parts.push(getSymbol(tokens[i]));
91
+ if (i < fees.length) {
92
+ const feePercent = (fees[i] / 10000).toFixed(2);
93
+ parts.push(`→ [${feePercent}%] →`);
94
+ }
95
+ }
96
+ return parts.join(" ");
97
+ }
98
+ //# sourceMappingURL=pathEncoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathEncoding.js","sourceRoot":"","sources":["../../src/jaine/pathEncoding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** Jaine-specific data directory */
2
+ export declare const JAINE_DIR: string;
3
+ /** Pool cache file */
4
+ export declare const POOLS_CACHE_FILE: string;
5
+ /** User token aliases file */
6
+ export declare const TOKENS_FILE: string;
7
+ /**
8
+ * Ensure Jaine data directory exists
9
+ */
10
+ export declare function ensureJaineDir(): void;
11
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/jaine/paths.ts"],"names":[],"mappings":"AAKA,oCAAoC;AACpC,eAAO,MAAM,SAAS,QAA4B,CAAC;AAEnD,sBAAsB;AACtB,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AAEvE,8BAA8B;AAC9B,eAAO,MAAM,WAAW,QAAiC,CAAC;AAE1D;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAKrC"}
@@ -0,0 +1,20 @@
1
+ import { existsSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { CONFIG_DIR } from "../config/paths.js";
4
+ import logger from "../utils/logger.js";
5
+ /** Jaine-specific data directory */
6
+ export const JAINE_DIR = join(CONFIG_DIR, "jaine");
7
+ /** Pool cache file */
8
+ export const POOLS_CACHE_FILE = join(JAINE_DIR, "pools-cache.v1.json");
9
+ /** User token aliases file */
10
+ export const TOKENS_FILE = join(JAINE_DIR, "tokens.json");
11
+ /**
12
+ * Ensure Jaine data directory exists
13
+ */
14
+ export function ensureJaineDir() {
15
+ if (!existsSync(JAINE_DIR)) {
16
+ mkdirSync(JAINE_DIR, { recursive: true });
17
+ logger.debug(`Created Jaine directory: ${JAINE_DIR}`);
18
+ }
19
+ }
20
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/jaine/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,oCAAoC;AACpC,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAEnD,sBAAsB;AACtB,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;AAEvE,8BAA8B;AAC9B,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,4BAA4B,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;AACH,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { Address } from "viem";
2
+ import { type FeeTier } from "./abi/factory.js";
3
+ export interface PoolInfo {
4
+ address: Address;
5
+ token0: Address;
6
+ token1: Address;
7
+ fee: FeeTier;
8
+ }
9
+ export interface PoolsCache {
10
+ version: number;
11
+ chainId: number;
12
+ generatedAt: string;
13
+ pools: PoolInfo[];
14
+ }
15
+ /**
16
+ * Load pools cache from disk
17
+ */
18
+ export declare function loadPoolsCache(): PoolsCache | null;
19
+ /**
20
+ * Save pools cache to disk (atomic write)
21
+ */
22
+ export declare function savePoolsCache(cache: PoolsCache): void;
23
+ /**
24
+ * Scan factory for pools between core tokens
25
+ * @param feeTiers - Fee tiers to scan (defaults to all standard tiers)
26
+ * @param onProgress - Optional progress callback (poolsFound, pairsScanned)
27
+ */
28
+ export declare function scanCorePools(feeTiers?: readonly FeeTier[], onProgress?: (poolsFound: number, pairsScanned: number) => void): Promise<PoolInfo[]>;
29
+ /**
30
+ * Get pool for specific token pair and fee
31
+ */
32
+ export declare function getPool(tokenA: Address, tokenB: Address, fee: FeeTier): Promise<Address | null>;
33
+ /**
34
+ * Find pools containing a specific token from cache
35
+ */
36
+ export declare function findPoolsForToken(token: Address, cache?: PoolsCache | null): PoolInfo[];
37
+ /**
38
+ * Find pool between two tokens from cache
39
+ * Returns all matching pools (different fee tiers)
40
+ */
41
+ export declare function findPoolsBetweenTokens(tokenA: Address, tokenB: Address, cache?: PoolsCache | null): PoolInfo[];
42
+ //# sourceMappingURL=poolCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poolCache.d.ts","sourceRoot":"","sources":["../../src/jaine/poolCache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQxE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CA0BlD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAoBtD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,QAAQ,GAAE,SAAS,OAAO,EAAc,EACxC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,GAC9D,OAAO,CAAC,QAAQ,EAAE,CAAC,CAsDrB;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,OAAO,EACf,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAmBzB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,QAAQ,EAAE,CAQvF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,OAAO,EACf,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,GACxB,QAAQ,EAAE,CAYZ"}
@@ -0,0 +1,164 @@
1
+ import { existsSync, readFileSync, writeFileSync, renameSync, unlinkSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { getAddress, zeroAddress } from "viem";
4
+ import { POOLS_CACHE_FILE, ensureJaineDir } from "./paths.js";
5
+ import { FACTORY_ABI, FEE_TIERS } from "./abi/factory.js";
6
+ import { getCoreTokenAddresses } from "./coreTokens.js";
7
+ import { getPublicClient } from "../wallet/client.js";
8
+ import { loadConfig } from "../config/store.js";
9
+ import logger from "../utils/logger.js";
10
+ const CACHE_VERSION = 1;
11
+ /**
12
+ * Load pools cache from disk
13
+ */
14
+ export function loadPoolsCache() {
15
+ if (!existsSync(POOLS_CACHE_FILE)) {
16
+ return null;
17
+ }
18
+ try {
19
+ const raw = readFileSync(POOLS_CACHE_FILE, "utf-8");
20
+ const parsed = JSON.parse(raw);
21
+ // Validate version and chain
22
+ if (parsed.version !== CACHE_VERSION) {
23
+ logger.debug(`Pool cache version mismatch: ${parsed.version} != ${CACHE_VERSION}`);
24
+ return null;
25
+ }
26
+ const cfg = loadConfig();
27
+ if (parsed.chainId !== cfg.chain.chainId) {
28
+ logger.debug(`Pool cache chain mismatch: ${parsed.chainId} != ${cfg.chain.chainId}`);
29
+ return null;
30
+ }
31
+ return parsed;
32
+ }
33
+ catch (err) {
34
+ logger.error(`Failed to parse pool cache: ${err}`);
35
+ return null;
36
+ }
37
+ }
38
+ /**
39
+ * Save pools cache to disk (atomic write)
40
+ */
41
+ export function savePoolsCache(cache) {
42
+ ensureJaineDir();
43
+ const dir = dirname(POOLS_CACHE_FILE);
44
+ const tmpFile = join(dir, `.pools-cache.tmp.${Date.now()}.json`);
45
+ try {
46
+ writeFileSync(tmpFile, JSON.stringify(cache, null, 2), "utf-8");
47
+ renameSync(tmpFile, POOLS_CACHE_FILE);
48
+ logger.debug(`Pool cache saved: ${cache.pools.length} pools`);
49
+ }
50
+ catch (err) {
51
+ try {
52
+ if (existsSync(tmpFile)) {
53
+ unlinkSync(tmpFile);
54
+ }
55
+ }
56
+ catch {
57
+ // Ignore cleanup errors
58
+ }
59
+ throw err;
60
+ }
61
+ }
62
+ /**
63
+ * Scan factory for pools between core tokens
64
+ * @param feeTiers - Fee tiers to scan (defaults to all standard tiers)
65
+ * @param onProgress - Optional progress callback (poolsFound, pairsScanned)
66
+ */
67
+ export async function scanCorePools(feeTiers = FEE_TIERS, onProgress) {
68
+ const cfg = loadConfig();
69
+ const client = getPublicClient();
70
+ const factoryAddress = cfg.protocol.jaineFactory;
71
+ const coreTokens = getCoreTokenAddresses();
72
+ const pools = [];
73
+ let pairsScanned = 0;
74
+ // Generate all unique token pairs
75
+ const pairs = [];
76
+ for (let i = 0; i < coreTokens.length; i++) {
77
+ for (let j = i + 1; j < coreTokens.length; j++) {
78
+ pairs.push([coreTokens[i], coreTokens[j]]);
79
+ }
80
+ }
81
+ // Scan each pair × fee tier sequentially (avoid rate limiting)
82
+ for (const [tokenA, tokenB] of pairs) {
83
+ for (const fee of feeTiers) {
84
+ try {
85
+ const poolAddress = await client.readContract({
86
+ address: factoryAddress,
87
+ abi: FACTORY_ABI,
88
+ functionName: "getPool",
89
+ args: [tokenA, tokenB, fee],
90
+ });
91
+ if (poolAddress && poolAddress !== zeroAddress) {
92
+ // Sort tokens to ensure consistent ordering (token0 < token1)
93
+ const [token0, token1] = tokenA.toLowerCase() < tokenB.toLowerCase()
94
+ ? [tokenA, tokenB]
95
+ : [tokenB, tokenA];
96
+ pools.push({
97
+ address: getAddress(poolAddress),
98
+ token0: getAddress(token0),
99
+ token1: getAddress(token1),
100
+ fee,
101
+ });
102
+ }
103
+ }
104
+ catch (err) {
105
+ logger.debug(`Failed to query pool ${tokenA}/${tokenB}/${fee}: ${err}`);
106
+ // Continue scanning other pools
107
+ }
108
+ }
109
+ pairsScanned++;
110
+ if (onProgress) {
111
+ onProgress(pools.length, pairsScanned);
112
+ }
113
+ }
114
+ return pools;
115
+ }
116
+ /**
117
+ * Get pool for specific token pair and fee
118
+ */
119
+ export async function getPool(tokenA, tokenB, fee) {
120
+ const cfg = loadConfig();
121
+ const client = getPublicClient();
122
+ try {
123
+ const poolAddress = await client.readContract({
124
+ address: cfg.protocol.jaineFactory,
125
+ abi: FACTORY_ABI,
126
+ functionName: "getPool",
127
+ args: [tokenA, tokenB, fee],
128
+ });
129
+ if (poolAddress && poolAddress !== zeroAddress) {
130
+ return getAddress(poolAddress);
131
+ }
132
+ return null;
133
+ }
134
+ catch {
135
+ return null;
136
+ }
137
+ }
138
+ /**
139
+ * Find pools containing a specific token from cache
140
+ */
141
+ export function findPoolsForToken(token, cache) {
142
+ const c = cache ?? loadPoolsCache();
143
+ if (!c)
144
+ return [];
145
+ const tokenLower = token.toLowerCase();
146
+ return c.pools.filter((p) => p.token0.toLowerCase() === tokenLower || p.token1.toLowerCase() === tokenLower);
147
+ }
148
+ /**
149
+ * Find pool between two tokens from cache
150
+ * Returns all matching pools (different fee tiers)
151
+ */
152
+ export function findPoolsBetweenTokens(tokenA, tokenB, cache) {
153
+ const c = cache ?? loadPoolsCache();
154
+ if (!c)
155
+ return [];
156
+ const aLower = tokenA.toLowerCase();
157
+ const bLower = tokenB.toLowerCase();
158
+ return c.pools.filter((p) => {
159
+ const t0 = p.token0.toLowerCase();
160
+ const t1 = p.token1.toLowerCase();
161
+ return (t0 === aLower && t1 === bLower) || (t0 === bLower && t1 === aLower);
162
+ });
163
+ }
164
+ //# sourceMappingURL=poolCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poolCache.js","sourceRoot":"","sources":["../../src/jaine/poolCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { Address, Hex } from "viem";
2
+ import { type PoolsCache } from "./poolCache.js";
3
+ export interface Route {
4
+ tokens: Address[];
5
+ fees: number[];
6
+ pools: Address[];
7
+ }
8
+ export interface QuotedRoute extends Route {
9
+ amountIn: bigint;
10
+ amountOut: bigint;
11
+ encodedPath: Hex;
12
+ gasEstimate: bigint;
13
+ }
14
+ export interface FindRouteOptions {
15
+ maxHops?: number;
16
+ maxCandidates?: number;
17
+ cache?: PoolsCache | null;
18
+ }
19
+ /**
20
+ * Find the best route for a swap (exactInput)
21
+ * @param tokenIn - Input token address
22
+ * @param tokenOut - Output token address
23
+ * @param amountIn - Input amount
24
+ * @param options - Routing options
25
+ * @returns Best route or null if no route found
26
+ */
27
+ export declare function findBestRouteExactInput(tokenIn: Address, tokenOut: Address, amountIn: bigint, options?: FindRouteOptions): Promise<QuotedRoute | null>;
28
+ /**
29
+ * Find the best route for a swap (exactOutput)
30
+ * @param tokenIn - Input token address
31
+ * @param tokenOut - Output token address
32
+ * @param amountOut - Desired output amount
33
+ * @param options - Routing options
34
+ * @returns Best route or null if no route found
35
+ */
36
+ export declare function findBestRouteExactOutput(tokenIn: Address, tokenOut: Address, amountOut: bigint, options?: FindRouteOptions): Promise<QuotedRoute | null>;
37
+ /**
38
+ * Format route for display
39
+ */
40
+ export declare function formatRoute(route: Route, userAliases?: Record<string, Address>): string;
41
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/jaine/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,EAAiC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAYhF,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,WAAY,SAAQ,KAAK;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AA8KD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyD7B;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAwD7B;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,MAAM,CAIR"}
@@ -0,0 +1,247 @@
1
+ import { getAddress } from "viem";
2
+ import { loadPoolsCache } from "./poolCache.js";
3
+ import { encodePath, encodePathForExactOutput, formatPath } from "./pathEncoding.js";
4
+ import { getTokenSymbol } from "./coreTokens.js";
5
+ import { QUOTER_ABI } from "./abi/quoter.js";
6
+ import { getPublicClient } from "../wallet/client.js";
7
+ import { loadConfig } from "../config/store.js";
8
+ import { ImmError, ErrorCodes } from "../errors.js";
9
+ import logger from "../utils/logger.js";
10
+ const DEFAULT_MAX_HOPS = 3;
11
+ const DEFAULT_MAX_CANDIDATES = 20;
12
+ /**
13
+ * Build a graph of pools for routing
14
+ */
15
+ function buildPoolGraph(pools) {
16
+ // Graph: token -> (neighbor token -> pools)
17
+ const graph = new Map();
18
+ const ensureNode = (token) => {
19
+ if (!graph.has(token)) {
20
+ graph.set(token, new Map());
21
+ }
22
+ };
23
+ for (const pool of pools) {
24
+ const t0 = pool.token0.toLowerCase();
25
+ const t1 = pool.token1.toLowerCase();
26
+ ensureNode(t0);
27
+ ensureNode(t1);
28
+ // Add bidirectional edges
29
+ const t0Neighbors = graph.get(t0);
30
+ const t1Neighbors = graph.get(t1);
31
+ if (!t0Neighbors.has(t1)) {
32
+ t0Neighbors.set(t1, []);
33
+ }
34
+ t0Neighbors.get(t1).push(pool);
35
+ if (!t1Neighbors.has(t0)) {
36
+ t1Neighbors.set(t0, []);
37
+ }
38
+ t1Neighbors.get(t0).push(pool);
39
+ }
40
+ return graph;
41
+ }
42
+ /**
43
+ * BFS to find all routes between tokenIn and tokenOut
44
+ */
45
+ function findAllRoutes(tokenIn, tokenOut, pools, maxHops) {
46
+ const graph = buildPoolGraph(pools);
47
+ const routes = [];
48
+ const inLower = tokenIn.toLowerCase();
49
+ const outLower = tokenOut.toLowerCase();
50
+ const queue = [
51
+ {
52
+ current: inLower,
53
+ tokens: [getAddress(tokenIn)],
54
+ fees: [],
55
+ pools: [],
56
+ visited: new Set([inLower]),
57
+ },
58
+ ];
59
+ while (queue.length > 0) {
60
+ const state = queue.shift();
61
+ const { current, tokens, fees, pools: routePools, visited } = state;
62
+ // Check if we reached destination
63
+ if (current === outLower) {
64
+ routes.push({
65
+ tokens: [...tokens],
66
+ fees: [...fees],
67
+ pools: [...routePools],
68
+ });
69
+ continue;
70
+ }
71
+ // Don't explore further if max hops reached
72
+ if (tokens.length > maxHops) {
73
+ continue;
74
+ }
75
+ // Get neighbors
76
+ const neighbors = graph.get(current);
77
+ if (!neighbors)
78
+ continue;
79
+ for (const [neighborToken, poolsToNeighbor] of neighbors) {
80
+ // Skip if already visited (no cycles)
81
+ if (visited.has(neighborToken))
82
+ continue;
83
+ // For each pool option to this neighbor
84
+ for (const pool of poolsToNeighbor) {
85
+ queue.push({
86
+ current: neighborToken,
87
+ tokens: [...tokens, getAddress(neighborToken)],
88
+ fees: [...fees, pool.fee],
89
+ pools: [...routePools, pool.address],
90
+ visited: new Set([...visited, neighborToken]),
91
+ });
92
+ }
93
+ }
94
+ }
95
+ return routes;
96
+ }
97
+ /**
98
+ * Quote a route using the quoter contract
99
+ */
100
+ async function quoteRoute(route, amountIn, quoterAddress, direction) {
101
+ const client = getPublicClient();
102
+ try {
103
+ if (direction === "exactInput") {
104
+ const path = encodePath(route.tokens, route.fees);
105
+ // QuoterV1 returns single uint256, not tuple
106
+ const amountOut = await client.readContract({
107
+ address: quoterAddress,
108
+ abi: QUOTER_ABI,
109
+ functionName: "quoteExactInput",
110
+ args: [path, amountIn],
111
+ });
112
+ return {
113
+ ...route,
114
+ amountIn,
115
+ amountOut,
116
+ encodedPath: path,
117
+ gasEstimate: 0n,
118
+ };
119
+ }
120
+ else {
121
+ // exactOutput - path is reversed
122
+ const path = encodePathForExactOutput(route.tokens, route.fees);
123
+ // QuoterV1 returns single uint256, not tuple
124
+ const amountInRequired = await client.readContract({
125
+ address: quoterAddress,
126
+ abi: QUOTER_ABI,
127
+ functionName: "quoteExactOutput",
128
+ args: [path, amountIn], // amountIn is actually amountOut for exactOutput
129
+ });
130
+ return {
131
+ ...route,
132
+ amountIn: amountInRequired,
133
+ amountOut: amountIn, // The desired output
134
+ encodedPath: path,
135
+ gasEstimate: 0n,
136
+ };
137
+ }
138
+ }
139
+ catch (err) {
140
+ logger.debug(`Quote failed for route: ${err}`);
141
+ return null;
142
+ }
143
+ }
144
+ /**
145
+ * Find the best route for a swap (exactInput)
146
+ * @param tokenIn - Input token address
147
+ * @param tokenOut - Output token address
148
+ * @param amountIn - Input amount
149
+ * @param options - Routing options
150
+ * @returns Best route or null if no route found
151
+ */
152
+ export async function findBestRouteExactInput(tokenIn, tokenOut, amountIn, options = {}) {
153
+ const { maxHops = DEFAULT_MAX_HOPS, maxCandidates = DEFAULT_MAX_CANDIDATES } = options;
154
+ const cache = options.cache !== undefined ? options.cache : loadPoolsCache();
155
+ if (!cache || cache.pools.length === 0) {
156
+ throw new ImmError(ErrorCodes.NO_ROUTE_FOUND, "Pool cache is empty", "Run: imm jaine pools scan-core");
157
+ }
158
+ const cfg = loadConfig();
159
+ const quoterAddress = cfg.protocol.quoter;
160
+ // Find all possible routes
161
+ const routes = findAllRoutes(tokenIn, tokenOut, cache.pools, maxHops);
162
+ if (routes.length === 0) {
163
+ return null;
164
+ }
165
+ // Limit candidates
166
+ const candidates = routes.slice(0, maxCandidates);
167
+ // Quote all routes in parallel (with limit)
168
+ const quotedRoutes = [];
169
+ // Process in batches of 5 to avoid rate limiting
170
+ const batchSize = 5;
171
+ for (let i = 0; i < candidates.length; i += batchSize) {
172
+ const batch = candidates.slice(i, i + batchSize);
173
+ const results = await Promise.all(batch.map((route) => quoteRoute(route, amountIn, quoterAddress, "exactInput")));
174
+ for (const result of results) {
175
+ if (result) {
176
+ quotedRoutes.push(result);
177
+ }
178
+ }
179
+ }
180
+ if (quotedRoutes.length === 0) {
181
+ return null;
182
+ }
183
+ // Sort by amountOut descending, then by fewer hops
184
+ quotedRoutes.sort((a, b) => {
185
+ const amountDiff = b.amountOut - a.amountOut;
186
+ if (amountDiff !== 0n) {
187
+ return amountDiff > 0n ? 1 : -1;
188
+ }
189
+ return a.tokens.length - b.tokens.length;
190
+ });
191
+ return quotedRoutes[0];
192
+ }
193
+ /**
194
+ * Find the best route for a swap (exactOutput)
195
+ * @param tokenIn - Input token address
196
+ * @param tokenOut - Output token address
197
+ * @param amountOut - Desired output amount
198
+ * @param options - Routing options
199
+ * @returns Best route or null if no route found
200
+ */
201
+ export async function findBestRouteExactOutput(tokenIn, tokenOut, amountOut, options = {}) {
202
+ const { maxHops = DEFAULT_MAX_HOPS, maxCandidates = DEFAULT_MAX_CANDIDATES } = options;
203
+ const cache = options.cache !== undefined ? options.cache : loadPoolsCache();
204
+ if (!cache || cache.pools.length === 0) {
205
+ throw new ImmError(ErrorCodes.NO_ROUTE_FOUND, "Pool cache is empty", "Run: imm jaine pools scan-core");
206
+ }
207
+ const cfg = loadConfig();
208
+ const quoterAddress = cfg.protocol.quoter;
209
+ // Find all possible routes
210
+ const routes = findAllRoutes(tokenIn, tokenOut, cache.pools, maxHops);
211
+ if (routes.length === 0) {
212
+ return null;
213
+ }
214
+ // Limit candidates
215
+ const candidates = routes.slice(0, maxCandidates);
216
+ // Quote all routes
217
+ const quotedRoutes = [];
218
+ const batchSize = 5;
219
+ for (let i = 0; i < candidates.length; i += batchSize) {
220
+ const batch = candidates.slice(i, i + batchSize);
221
+ const results = await Promise.all(batch.map((route) => quoteRoute(route, amountOut, quoterAddress, "exactOutput")));
222
+ for (const result of results) {
223
+ if (result) {
224
+ quotedRoutes.push(result);
225
+ }
226
+ }
227
+ }
228
+ if (quotedRoutes.length === 0) {
229
+ return null;
230
+ }
231
+ // Sort by amountIn ascending (minimize input), then by fewer hops
232
+ quotedRoutes.sort((a, b) => {
233
+ const amountDiff = a.amountIn - b.amountIn;
234
+ if (amountDiff !== 0n) {
235
+ return amountDiff > 0n ? 1 : -1;
236
+ }
237
+ return a.tokens.length - b.tokens.length;
238
+ });
239
+ return quotedRoutes[0];
240
+ }
241
+ /**
242
+ * Format route for display
243
+ */
244
+ export function formatRoute(route, userAliases) {
245
+ return formatPath(route.tokens, route.fees, (addr) => getTokenSymbol(addr, userAliases));
246
+ }
247
+ //# sourceMappingURL=routing.js.map