@eco-incorp/sauce 0.99.6 → 0.99.8

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 (1159) hide show
  1. package/README.md +58 -16
  2. package/actions/action-program.schema.json +480 -379
  3. package/actions/dist/abis.d.ts +19 -18
  4. package/actions/dist/abis.d.ts.map +1 -1
  5. package/actions/dist/abis.js +29 -29
  6. package/actions/dist/compile.d.ts +4 -4
  7. package/actions/dist/compile.d.ts.map +1 -1
  8. package/actions/dist/compile.js +3 -1
  9. package/actions/dist/compose.d.ts +63 -6
  10. package/actions/dist/compose.d.ts.map +1 -1
  11. package/actions/dist/compose.js +100 -16
  12. package/actions/dist/index.d.ts +1 -1
  13. package/actions/dist/index.d.ts.map +1 -1
  14. package/actions/dist/names.d.ts +88 -0
  15. package/actions/dist/names.d.ts.map +1 -0
  16. package/actions/dist/names.js +334 -0
  17. package/actions/dist/program.d.ts.map +1 -1
  18. package/actions/dist/program.js +115 -5
  19. package/actions/dist/registry.d.ts +10 -8
  20. package/actions/dist/registry.d.ts.map +1 -1
  21. package/actions/dist/registry.js +10 -8
  22. package/actions/dist/schema.d.ts.map +1 -1
  23. package/actions/dist/schema.js +99 -12
  24. package/actions/dist/semantics.d.ts +12 -2
  25. package/actions/dist/semantics.d.ts.map +1 -1
  26. package/actions/dist/semantics.js +78 -8
  27. package/actions/dist/spec.d.ts +30 -0
  28. package/actions/dist/spec.d.ts.map +1 -1
  29. package/actions/dist/spec.js +151 -138
  30. package/actions/dist/split-swap.d.ts +10 -5
  31. package/actions/dist/split-swap.d.ts.map +1 -1
  32. package/actions/dist/split-swap.js +48 -7
  33. package/actions/dist/to-quote.d.ts +14 -5
  34. package/actions/dist/to-quote.d.ts.map +1 -1
  35. package/actions/dist/to-quote.js +210 -244
  36. package/actions/dist/to-sauce.d.ts +18 -4
  37. package/actions/dist/to-sauce.d.ts.map +1 -1
  38. package/actions/dist/to-sauce.js +232 -205
  39. package/actions/dist/types.d.ts +245 -147
  40. package/actions/dist/types.d.ts.map +1 -1
  41. package/actions/dist/types.js +4 -0
  42. package/docs/README.md +38 -0
  43. package/docs/api/README.md +37 -23
  44. package/docs/api/compiler.md +53 -12
  45. package/docs/api/contracts.md +105 -0
  46. package/docs/api/coverage.md +96 -57
  47. package/docs/api/router.md +238 -0
  48. package/docs/api/routes.md +31 -22
  49. package/docs/concepts/architecture.md +26 -3
  50. package/docs/concepts/saucescript.md +35 -55
  51. package/docs/examples/README.md +21 -14
  52. package/docs/examples/action-program.ts +51 -35
  53. package/docs/examples/cross-chain-cascade.sauce.ts +4 -0
  54. package/docs/examples/cross-chain-intent.sauce.ts +2 -1
  55. package/docs/examples/evm-execution.ts +2 -4
  56. package/docs/examples/first-intent.ts +7 -2
  57. package/docs/examples/pot-router.ts +19 -0
  58. package/docs/examples/registry-names.ts +52 -0
  59. package/docs/examples/router-route.sauce.ts +31 -0
  60. package/docs/examples/router-route.ts +72 -0
  61. package/docs/examples/router-swap.sauce.ts +16 -0
  62. package/docs/examples/router-swap.ts +47 -0
  63. package/docs/examples/venue-where-deployed.sauce.ts +14 -0
  64. package/docs/guides/actions.md +230 -120
  65. package/docs/guides/builders-and-actions.md +20 -14
  66. package/docs/guides/cli.md +1446 -0
  67. package/docs/guides/compiling.md +19 -7
  68. package/docs/guides/intents.md +228 -15
  69. package/docs/guides/mcp.md +540 -0
  70. package/docs/guides/nested-intents.md +21 -6
  71. package/docs/guides/protocols-and-tokens.md +218 -39
  72. package/docs/guides/quick-start.md +5 -0
  73. package/docs/guides/solana.md +199 -52
  74. package/docs/guides/verification.md +2 -2
  75. package/mcp/dist/config.js +78 -0
  76. package/mcp/dist/config.js.map +1 -0
  77. package/mcp/dist/entry.js +112 -0
  78. package/mcp/dist/entry.js.map +1 -0
  79. package/mcp/dist/files.js +64 -0
  80. package/mcp/dist/files.js.map +1 -0
  81. package/mcp/dist/guard.js +262 -0
  82. package/mcp/dist/guard.js.map +1 -0
  83. package/mcp/dist/http.js +111 -0
  84. package/mcp/dist/http.js.map +1 -0
  85. package/mcp/dist/intents.js +579 -0
  86. package/mcp/dist/intents.js.map +1 -0
  87. package/mcp/dist/prompts.js +153 -0
  88. package/mcp/dist/prompts.js.map +1 -0
  89. package/mcp/dist/reach.js +98 -0
  90. package/mcp/dist/reach.js.map +1 -0
  91. package/mcp/dist/resources.js +154 -0
  92. package/mcp/dist/resources.js.map +1 -0
  93. package/mcp/dist/sdk.js +34 -0
  94. package/mcp/dist/sdk.js.map +1 -0
  95. package/mcp/dist/server.js +119 -0
  96. package/mcp/dist/server.js.map +1 -0
  97. package/mcp/dist/setup.js +189 -0
  98. package/mcp/dist/setup.js.map +1 -0
  99. package/mcp/dist/skilltools.js +520 -0
  100. package/mcp/dist/skilltools.js.map +1 -0
  101. package/mcp/dist/terms.js +93 -0
  102. package/mcp/dist/terms.js.map +1 -0
  103. package/mcp/dist/tools.js +1499 -0
  104. package/mcp/dist/tools.js.map +1 -0
  105. package/mcp/dist/wallets.js +168 -0
  106. package/mcp/dist/wallets.js.map +1 -0
  107. package/package.json +18 -13
  108. package/sdk/dist/artifacts/V12Deployments.json +3 -1
  109. package/sdk/dist/artifacts/V12EngineGate.json +1 -2
  110. package/sdk/dist/artifacts/V12KitchenProxy.json +1 -0
  111. package/sdk/dist/chains/canonical.d.ts +15 -24
  112. package/sdk/dist/chains/canonical.d.ts.map +1 -1
  113. package/sdk/dist/chains/canonical.js +18 -29
  114. package/sdk/dist/chains/canonical.js.map +1 -1
  115. package/sdk/dist/cli/actions.d.ts +29 -0
  116. package/sdk/dist/cli/actions.d.ts.map +1 -0
  117. package/sdk/dist/cli/actions.js +122 -0
  118. package/sdk/dist/cli/actions.js.map +1 -0
  119. package/sdk/dist/cli/args.d.ts +118 -0
  120. package/sdk/dist/cli/args.d.ts.map +1 -0
  121. package/sdk/dist/cli/args.js +354 -0
  122. package/sdk/dist/cli/args.js.map +1 -0
  123. package/sdk/dist/cli/assume.d.ts +51 -0
  124. package/sdk/dist/cli/assume.d.ts.map +1 -0
  125. package/sdk/dist/cli/assume.js +207 -0
  126. package/sdk/dist/cli/assume.js.map +1 -0
  127. package/sdk/dist/cli/chain.d.ts +173 -0
  128. package/sdk/dist/cli/chain.d.ts.map +1 -0
  129. package/sdk/dist/cli/chain.js +462 -0
  130. package/sdk/dist/cli/chain.js.map +1 -0
  131. package/sdk/dist/cli/commands.d.ts +226 -0
  132. package/sdk/dist/cli/commands.d.ts.map +1 -0
  133. package/sdk/dist/cli/commands.js +637 -0
  134. package/sdk/dist/cli/commands.js.map +1 -0
  135. package/sdk/dist/cli/create.d.ts +70 -0
  136. package/sdk/dist/cli/create.d.ts.map +1 -0
  137. package/sdk/dist/cli/create.js +483 -0
  138. package/sdk/dist/cli/create.js.map +1 -0
  139. package/sdk/dist/cli/diagnostics.d.ts +12 -0
  140. package/sdk/dist/cli/diagnostics.d.ts.map +1 -0
  141. package/sdk/dist/cli/diagnostics.js +225 -0
  142. package/sdk/dist/cli/diagnostics.js.map +1 -0
  143. package/sdk/dist/cli/effects.d.ts +71 -0
  144. package/sdk/dist/cli/effects.d.ts.map +1 -0
  145. package/sdk/dist/cli/effects.js +279 -0
  146. package/sdk/dist/cli/effects.js.map +1 -0
  147. package/sdk/dist/cli/fill.d.ts +83 -0
  148. package/sdk/dist/cli/fill.d.ts.map +1 -0
  149. package/sdk/dist/cli/fill.js +734 -0
  150. package/sdk/dist/cli/fill.js.map +1 -0
  151. package/sdk/dist/cli/funding.d.ts +126 -0
  152. package/sdk/dist/cli/funding.d.ts.map +1 -0
  153. package/sdk/dist/cli/funding.js +514 -0
  154. package/sdk/dist/cli/funding.js.map +1 -0
  155. package/sdk/dist/cli/globals.d.ts +16 -0
  156. package/sdk/dist/cli/globals.d.ts.map +1 -0
  157. package/sdk/dist/cli/globals.js +219 -0
  158. package/sdk/dist/cli/globals.js.map +1 -0
  159. package/sdk/dist/cli/init.d.ts +34 -0
  160. package/sdk/dist/cli/init.d.ts.map +1 -0
  161. package/sdk/dist/cli/init.js +181 -0
  162. package/sdk/dist/cli/init.js.map +1 -0
  163. package/sdk/dist/cli/inputs.d.ts +72 -0
  164. package/sdk/dist/cli/inputs.d.ts.map +1 -0
  165. package/sdk/dist/cli/inputs.js +152 -0
  166. package/sdk/dist/cli/inputs.js.map +1 -0
  167. package/sdk/dist/cli/inspect.d.ts +48 -0
  168. package/sdk/dist/cli/inspect.d.ts.map +1 -0
  169. package/sdk/dist/cli/inspect.js +536 -0
  170. package/sdk/dist/cli/inspect.js.map +1 -0
  171. package/sdk/dist/cli/intent-commands.d.ts +71 -0
  172. package/sdk/dist/cli/intent-commands.d.ts.map +1 -0
  173. package/sdk/dist/cli/intent-commands.js +698 -0
  174. package/sdk/dist/cli/intent-commands.js.map +1 -0
  175. package/sdk/dist/cli/intent-svm.d.ts +15 -0
  176. package/sdk/dist/cli/intent-svm.d.ts.map +1 -0
  177. package/sdk/dist/cli/intent-svm.js +222 -0
  178. package/sdk/dist/cli/intent-svm.js.map +1 -0
  179. package/sdk/dist/cli/intents.d.ts +43 -0
  180. package/sdk/dist/cli/intents.d.ts.map +1 -0
  181. package/sdk/dist/cli/intents.js +89 -0
  182. package/sdk/dist/cli/intents.js.map +1 -0
  183. package/sdk/dist/cli/interactive.d.ts +11 -0
  184. package/sdk/dist/cli/interactive.d.ts.map +1 -0
  185. package/sdk/dist/cli/interactive.js +161 -0
  186. package/sdk/dist/cli/interactive.js.map +1 -0
  187. package/sdk/dist/cli/lifecycle-svm.d.ts +109 -0
  188. package/sdk/dist/cli/lifecycle-svm.d.ts.map +1 -0
  189. package/sdk/dist/cli/lifecycle-svm.js +299 -0
  190. package/sdk/dist/cli/lifecycle-svm.js.map +1 -0
  191. package/sdk/dist/cli/lifecycle.d.ts +439 -0
  192. package/sdk/dist/cli/lifecycle.d.ts.map +1 -0
  193. package/sdk/dist/cli/lifecycle.js +1721 -0
  194. package/sdk/dist/cli/lifecycle.js.map +1 -0
  195. package/sdk/dist/cli/main.d.ts +3 -0
  196. package/sdk/dist/cli/main.d.ts.map +1 -0
  197. package/sdk/dist/cli/main.js +8 -0
  198. package/sdk/dist/cli/main.js.map +1 -0
  199. package/sdk/dist/cli/mcp.d.ts +66 -0
  200. package/sdk/dist/cli/mcp.d.ts.map +1 -0
  201. package/sdk/dist/cli/mcp.js +169 -0
  202. package/sdk/dist/cli/mcp.js.map +1 -0
  203. package/sdk/dist/cli/password.d.ts +54 -0
  204. package/sdk/dist/cli/password.d.ts.map +1 -0
  205. package/sdk/dist/cli/password.js +148 -0
  206. package/sdk/dist/cli/password.js.map +1 -0
  207. package/sdk/dist/cli/policy.d.ts +130 -0
  208. package/sdk/dist/cli/policy.d.ts.map +1 -0
  209. package/sdk/dist/cli/policy.js +702 -0
  210. package/sdk/dist/cli/policy.js.map +1 -0
  211. package/sdk/dist/cli/pools.d.ts +140 -0
  212. package/sdk/dist/cli/pools.d.ts.map +1 -0
  213. package/sdk/dist/cli/pools.js +658 -0
  214. package/sdk/dist/cli/pools.js.map +1 -0
  215. package/sdk/dist/cli/price.d.ts +74 -0
  216. package/sdk/dist/cli/price.d.ts.map +1 -0
  217. package/sdk/dist/cli/price.js +321 -0
  218. package/sdk/dist/cli/price.js.map +1 -0
  219. package/sdk/dist/cli/prompt.d.ts +30 -0
  220. package/sdk/dist/cli/prompt.d.ts.map +1 -0
  221. package/sdk/dist/cli/prompt.js +53 -0
  222. package/sdk/dist/cli/prompt.js.map +1 -0
  223. package/sdk/dist/cli/publish.d.ts +48 -0
  224. package/sdk/dist/cli/publish.d.ts.map +1 -0
  225. package/sdk/dist/cli/publish.js +480 -0
  226. package/sdk/dist/cli/publish.js.map +1 -0
  227. package/sdk/dist/cli/receipt.d.ts +35 -0
  228. package/sdk/dist/cli/receipt.d.ts.map +1 -0
  229. package/sdk/dist/cli/receipt.js +63 -0
  230. package/sdk/dist/cli/receipt.js.map +1 -0
  231. package/sdk/dist/cli/rehearse.d.ts +80 -0
  232. package/sdk/dist/cli/rehearse.d.ts.map +1 -0
  233. package/sdk/dist/cli/rehearse.js +265 -0
  234. package/sdk/dist/cli/rehearse.js.map +1 -0
  235. package/sdk/dist/cli/report.d.ts +69 -0
  236. package/sdk/dist/cli/report.d.ts.map +1 -0
  237. package/sdk/dist/cli/report.js +206 -0
  238. package/sdk/dist/cli/report.js.map +1 -0
  239. package/sdk/dist/cli/returned.d.ts +16 -0
  240. package/sdk/dist/cli/returned.d.ts.map +1 -0
  241. package/sdk/dist/cli/returned.js +111 -0
  242. package/sdk/dist/cli/returned.js.map +1 -0
  243. package/sdk/dist/cli/run.d.ts +40 -0
  244. package/sdk/dist/cli/run.d.ts.map +1 -0
  245. package/sdk/dist/cli/run.js +3163 -0
  246. package/sdk/dist/cli/run.js.map +1 -0
  247. package/sdk/dist/cli/signer.d.ts +72 -0
  248. package/sdk/dist/cli/signer.d.ts.map +1 -0
  249. package/sdk/dist/cli/signer.js +243 -0
  250. package/sdk/dist/cli/signer.js.map +1 -0
  251. package/sdk/dist/cli/simulate.d.ts +11 -0
  252. package/sdk/dist/cli/simulate.d.ts.map +1 -0
  253. package/sdk/dist/cli/simulate.js +246 -0
  254. package/sdk/dist/cli/simulate.js.map +1 -0
  255. package/sdk/dist/cli/skills.d.ts +77 -0
  256. package/sdk/dist/cli/skills.d.ts.map +1 -0
  257. package/sdk/dist/cli/skills.js +527 -0
  258. package/sdk/dist/cli/skills.js.map +1 -0
  259. package/sdk/dist/cli/solana.d.ts +184 -0
  260. package/sdk/dist/cli/solana.d.ts.map +1 -0
  261. package/sdk/dist/cli/solana.js +1370 -0
  262. package/sdk/dist/cli/solana.js.map +1 -0
  263. package/sdk/dist/cli/store.d.ts +60 -0
  264. package/sdk/dist/cli/store.d.ts.map +1 -0
  265. package/sdk/dist/cli/store.js +196 -0
  266. package/sdk/dist/cli/store.js.map +1 -0
  267. package/sdk/dist/cli/support.d.ts +144 -0
  268. package/sdk/dist/cli/support.d.ts.map +1 -0
  269. package/sdk/dist/cli/support.js +217 -0
  270. package/sdk/dist/cli/support.js.map +1 -0
  271. package/sdk/dist/cli/svm-effects.d.ts +50 -0
  272. package/sdk/dist/cli/svm-effects.d.ts.map +1 -0
  273. package/sdk/dist/cli/svm-effects.js +196 -0
  274. package/sdk/dist/cli/svm-effects.js.map +1 -0
  275. package/sdk/dist/cli/terminal.d.ts +42 -0
  276. package/sdk/dist/cli/terminal.d.ts.map +1 -0
  277. package/sdk/dist/cli/terminal.js +136 -0
  278. package/sdk/dist/cli/terminal.js.map +1 -0
  279. package/sdk/dist/cli/verify.d.ts +32 -0
  280. package/sdk/dist/cli/verify.d.ts.map +1 -0
  281. package/sdk/dist/cli/verify.js +185 -0
  282. package/sdk/dist/cli/verify.js.map +1 -0
  283. package/sdk/dist/cli/wallet-commands.d.ts +59 -0
  284. package/sdk/dist/cli/wallet-commands.d.ts.map +1 -0
  285. package/sdk/dist/cli/wallet-commands.js +222 -0
  286. package/sdk/dist/cli/wallet-commands.js.map +1 -0
  287. package/sdk/dist/cli/wallet-send.d.ts +38 -0
  288. package/sdk/dist/cli/wallet-send.d.ts.map +1 -0
  289. package/sdk/dist/cli/wallet-send.js +303 -0
  290. package/sdk/dist/cli/wallet-send.js.map +1 -0
  291. package/sdk/dist/cli/wallets.d.ts +79 -0
  292. package/sdk/dist/cli/wallets.d.ts.map +1 -0
  293. package/sdk/dist/cli/wallets.js +297 -0
  294. package/sdk/dist/cli/wallets.js.map +1 -0
  295. package/sdk/dist/deployments/index.d.ts +4 -62
  296. package/sdk/dist/deployments/index.d.ts.map +1 -1
  297. package/sdk/dist/deployments/index.js +4 -84
  298. package/sdk/dist/deployments/index.js.map +1 -1
  299. package/sdk/dist/deployments/pot.d.ts +17 -7
  300. package/sdk/dist/deployments/pot.d.ts.map +1 -1
  301. package/sdk/dist/deployments/pot.js +25 -10
  302. package/sdk/dist/deployments/pot.js.map +1 -1
  303. package/sdk/dist/deployments/releases.d.ts +36 -0
  304. package/sdk/dist/deployments/releases.d.ts.map +1 -0
  305. package/sdk/dist/deployments/releases.js +61 -0
  306. package/sdk/dist/deployments/releases.js.map +1 -0
  307. package/sdk/dist/deployments/releases.json +76 -0
  308. package/sdk/dist/deployments/v12-addresses.d.ts +13 -0
  309. package/sdk/dist/deployments/v12-addresses.d.ts.map +1 -1
  310. package/sdk/dist/deployments/v12-addresses.js +16 -3
  311. package/sdk/dist/deployments/v12-addresses.js.map +1 -1
  312. package/sdk/dist/deposit/index.d.ts +6 -6
  313. package/sdk/dist/deposit/index.d.ts.map +1 -1
  314. package/sdk/dist/deposit/index.js +1 -1
  315. package/sdk/dist/deposit/index.js.map +1 -1
  316. package/sdk/dist/deposit/params.d.ts +4 -4
  317. package/sdk/dist/deposit/params.d.ts.map +1 -1
  318. package/sdk/dist/deposit/params.js +7 -4
  319. package/sdk/dist/deposit/params.js.map +1 -1
  320. package/sdk/dist/deposit/source.d.ts +3 -30
  321. package/sdk/dist/deposit/source.d.ts.map +1 -1
  322. package/sdk/dist/deposit/source.js +7 -83
  323. package/sdk/dist/deposit/source.js.map +1 -1
  324. package/sdk/dist/deposit/templates.d.ts +1 -2
  325. package/sdk/dist/deposit/templates.d.ts.map +1 -1
  326. package/sdk/dist/deposit/templates.js +10 -2
  327. package/sdk/dist/deposit/templates.js.map +1 -1
  328. package/sdk/dist/deposit/types.d.ts +14 -12
  329. package/sdk/dist/deposit/types.d.ts.map +1 -1
  330. package/sdk/dist/deposit/types.js +6 -0
  331. package/sdk/dist/deposit/types.js.map +1 -1
  332. package/sdk/dist/descriptors/accessors.d.ts +38 -35
  333. package/sdk/dist/descriptors/accessors.d.ts.map +1 -1
  334. package/sdk/dist/descriptors/accessors.js +16 -0
  335. package/sdk/dist/descriptors/accessors.js.map +1 -1
  336. package/sdk/dist/descriptors/call.d.ts +66 -14
  337. package/sdk/dist/descriptors/call.d.ts.map +1 -1
  338. package/sdk/dist/descriptors/call.js +94 -13
  339. package/sdk/dist/descriptors/call.js.map +1 -1
  340. package/sdk/dist/descriptors/contracts.generated.d.ts +3393 -0
  341. package/sdk/dist/descriptors/contracts.generated.d.ts.map +1 -0
  342. package/sdk/dist/descriptors/contracts.generated.js +728 -0
  343. package/sdk/dist/descriptors/contracts.generated.js.map +1 -0
  344. package/sdk/dist/descriptors/derive.d.ts +20 -11
  345. package/sdk/dist/descriptors/derive.d.ts.map +1 -1
  346. package/sdk/dist/descriptors/derive.js +68 -30
  347. package/sdk/dist/descriptors/derive.js.map +1 -1
  348. package/sdk/dist/descriptors/index.d.ts +6 -7
  349. package/sdk/dist/descriptors/index.d.ts.map +1 -1
  350. package/sdk/dist/descriptors/index.js +2 -2
  351. package/sdk/dist/descriptors/index.js.map +1 -1
  352. package/sdk/dist/descriptors/links.d.ts +23 -214
  353. package/sdk/dist/descriptors/links.d.ts.map +1 -1
  354. package/sdk/dist/descriptors/links.js +1 -232
  355. package/sdk/dist/descriptors/links.js.map +1 -1
  356. package/sdk/dist/descriptors/query.d.ts +1 -1
  357. package/sdk/dist/descriptors/query.d.ts.map +1 -1
  358. package/sdk/dist/descriptors/query.js +1 -1
  359. package/sdk/dist/descriptors/query.js.map +1 -1
  360. package/sdk/dist/descriptors/registry.d.ts +2 -5
  361. package/sdk/dist/descriptors/registry.d.ts.map +1 -1
  362. package/sdk/dist/descriptors/registry.js +11 -66
  363. package/sdk/dist/descriptors/registry.js.map +1 -1
  364. package/sdk/dist/embedded/resolve.d.ts +4 -4
  365. package/sdk/dist/embedded/resolve.d.ts.map +1 -1
  366. package/sdk/dist/embedded/resolve.js +12 -8
  367. package/sdk/dist/embedded/resolve.js.map +1 -1
  368. package/sdk/dist/embedded/skills.generated.d.ts +1 -1
  369. package/sdk/dist/embedded/skills.generated.d.ts.map +1 -1
  370. package/sdk/dist/embedded/skills.generated.js +137 -136
  371. package/sdk/dist/embedded/skills.generated.js.map +1 -1
  372. package/sdk/dist/embedded/sources.generated.d.ts.map +1 -1
  373. package/sdk/dist/embedded/sources.generated.js +40 -6
  374. package/sdk/dist/embedded/sources.generated.js.map +1 -1
  375. package/sdk/dist/evm/engine.d.ts +813 -10
  376. package/sdk/dist/evm/engine.d.ts.map +1 -1
  377. package/sdk/dist/evm/engine.js +127 -8
  378. package/sdk/dist/evm/engine.js.map +1 -1
  379. package/sdk/dist/index.d.ts +3 -2
  380. package/sdk/dist/index.d.ts.map +1 -1
  381. package/sdk/dist/index.js +6 -2
  382. package/sdk/dist/index.js.map +1 -1
  383. package/sdk/dist/price.d.ts +40 -0
  384. package/sdk/dist/price.d.ts.map +1 -0
  385. package/sdk/dist/price.js +101 -0
  386. package/sdk/dist/price.js.map +1 -0
  387. package/sdk/dist/protocols/aerodrome/abis.d.ts +76 -0
  388. package/sdk/dist/protocols/aerodrome/abis.d.ts.map +1 -1
  389. package/sdk/dist/protocols/aerodrome/abis.js +61 -0
  390. package/sdk/dist/protocols/aerodrome/abis.js.map +1 -1
  391. package/sdk/dist/protocols/aerodrome-slipstream/abis.d.ts +70 -0
  392. package/sdk/dist/protocols/aerodrome-slipstream/abis.d.ts.map +1 -1
  393. package/sdk/dist/protocols/aerodrome-slipstream/abis.js +54 -0
  394. package/sdk/dist/protocols/aerodrome-slipstream/abis.js.map +1 -1
  395. package/sdk/dist/protocols/camelot/abis.d.ts +178 -0
  396. package/sdk/dist/protocols/camelot/abis.d.ts.map +1 -1
  397. package/sdk/dist/protocols/camelot/abis.js +139 -0
  398. package/sdk/dist/protocols/camelot/abis.js.map +1 -1
  399. package/sdk/dist/protocols/eco-routes/abis.d.ts +792 -50
  400. package/sdk/dist/protocols/eco-routes/abis.d.ts.map +1 -1
  401. package/sdk/dist/protocols/eco-routes/abis.js +1058 -49
  402. package/sdk/dist/protocols/eco-routes/abis.js.map +1 -1
  403. package/sdk/dist/protocols/eco-routes/addresses.generated.d.ts +44 -61
  404. package/sdk/dist/protocols/eco-routes/addresses.generated.d.ts.map +1 -1
  405. package/sdk/dist/protocols/eco-routes/addresses.generated.js +45 -62
  406. package/sdk/dist/protocols/eco-routes/addresses.generated.js.map +1 -1
  407. package/sdk/dist/protocols/eco-routes/lookup.d.ts +10 -0
  408. package/sdk/dist/protocols/eco-routes/lookup.d.ts.map +1 -1
  409. package/sdk/dist/protocols/eco-routes/lookup.js +16 -0
  410. package/sdk/dist/protocols/eco-routes/lookup.js.map +1 -1
  411. package/sdk/dist/protocols/maverick/abis.d.ts +77 -0
  412. package/sdk/dist/protocols/maverick/abis.d.ts.map +1 -1
  413. package/sdk/dist/protocols/maverick/abis.js +58 -0
  414. package/sdk/dist/protocols/maverick/abis.js.map +1 -1
  415. package/sdk/dist/protocols/maverick/addresses.d.ts.map +1 -1
  416. package/sdk/dist/protocols/maverick/addresses.js +4 -0
  417. package/sdk/dist/protocols/maverick/addresses.js.map +1 -1
  418. package/sdk/dist/protocols/pancakeswap-v2/abis.d.ts +52 -0
  419. package/sdk/dist/protocols/pancakeswap-v2/abis.d.ts.map +1 -1
  420. package/sdk/dist/protocols/pancakeswap-v2/abis.js +43 -0
  421. package/sdk/dist/protocols/pancakeswap-v2/abis.js.map +1 -1
  422. package/sdk/dist/protocols/pancakeswap-v3/abis.d.ts +73 -0
  423. package/sdk/dist/protocols/pancakeswap-v3/abis.d.ts.map +1 -1
  424. package/sdk/dist/protocols/pancakeswap-v3/abis.js +56 -0
  425. package/sdk/dist/protocols/pancakeswap-v3/abis.js.map +1 -1
  426. package/sdk/dist/protocols/permit2/abis.d.ts +113 -0
  427. package/sdk/dist/protocols/permit2/abis.d.ts.map +1 -1
  428. package/sdk/dist/protocols/permit2/abis.js +63 -0
  429. package/sdk/dist/protocols/permit2/abis.js.map +1 -1
  430. package/sdk/dist/protocols/quickswap/abis.d.ts +148 -0
  431. package/sdk/dist/protocols/quickswap/abis.d.ts.map +1 -1
  432. package/sdk/dist/protocols/quickswap/abis.js +119 -0
  433. package/sdk/dist/protocols/quickswap/abis.js.map +1 -1
  434. package/sdk/dist/protocols/sushiswap-v2/abis.d.ts +52 -0
  435. package/sdk/dist/protocols/sushiswap-v2/abis.d.ts.map +1 -1
  436. package/sdk/dist/protocols/sushiswap-v2/abis.js +42 -0
  437. package/sdk/dist/protocols/sushiswap-v2/abis.js.map +1 -1
  438. package/sdk/dist/protocols/synthra-v3/abis.d.ts +73 -0
  439. package/sdk/dist/protocols/synthra-v3/abis.d.ts.map +1 -1
  440. package/sdk/dist/protocols/synthra-v3/abis.js +55 -0
  441. package/sdk/dist/protocols/synthra-v3/abis.js.map +1 -1
  442. package/sdk/dist/protocols/trader-joe/abis.d.ts +133 -0
  443. package/sdk/dist/protocols/trader-joe/abis.d.ts.map +1 -1
  444. package/sdk/dist/protocols/trader-joe/abis.js +101 -0
  445. package/sdk/dist/protocols/trader-joe/abis.js.map +1 -1
  446. package/sdk/dist/protocols/trader-joe/addresses.d.ts.map +1 -1
  447. package/sdk/dist/protocols/trader-joe/addresses.js +5 -0
  448. package/sdk/dist/protocols/trader-joe/addresses.js.map +1 -1
  449. package/sdk/dist/protocols/uniswap-v2/abis.d.ts +52 -0
  450. package/sdk/dist/protocols/uniswap-v2/abis.d.ts.map +1 -1
  451. package/sdk/dist/protocols/uniswap-v2/abis.js +44 -0
  452. package/sdk/dist/protocols/uniswap-v2/abis.js.map +1 -1
  453. package/sdk/dist/protocols/uniswap-v3/abis.d.ts +73 -0
  454. package/sdk/dist/protocols/uniswap-v3/abis.d.ts.map +1 -1
  455. package/sdk/dist/protocols/uniswap-v3/abis.js +55 -0
  456. package/sdk/dist/protocols/uniswap-v3/abis.js.map +1 -1
  457. package/sdk/dist/protocols/uniswap-v4/abis.d.ts +247 -0
  458. package/sdk/dist/protocols/uniswap-v4/abis.d.ts.map +1 -1
  459. package/sdk/dist/protocols/uniswap-v4/abis.js +167 -0
  460. package/sdk/dist/protocols/uniswap-v4/abis.js.map +1 -1
  461. package/sdk/dist/protocols/uniswap-v4/addresses.d.ts.map +1 -1
  462. package/sdk/dist/protocols/uniswap-v4/addresses.js +50 -0
  463. package/sdk/dist/protocols/uniswap-v4/addresses.js.map +1 -1
  464. package/sdk/dist/protocols/unitflow-v3/abis.d.ts +73 -0
  465. package/sdk/dist/protocols/unitflow-v3/abis.d.ts.map +1 -1
  466. package/sdk/dist/protocols/unitflow-v3/abis.js +56 -0
  467. package/sdk/dist/protocols/unitflow-v3/abis.js.map +1 -1
  468. package/sdk/dist/protocols/velodrome/abis.d.ts +76 -0
  469. package/sdk/dist/protocols/velodrome/abis.d.ts.map +1 -1
  470. package/sdk/dist/protocols/velodrome/abis.js +61 -0
  471. package/sdk/dist/protocols/velodrome/abis.js.map +1 -1
  472. package/sdk/dist/recipes/cctp-split.sauce.ts +2 -2
  473. package/sdk/dist/recipes/plain-transfer.sauce.ts +2 -2
  474. package/sdk/dist/routes/accessor-index.d.ts +2 -2
  475. package/sdk/dist/routes/accessor-index.d.ts.map +1 -1
  476. package/sdk/dist/routes/accessor-index.js +4 -3
  477. package/sdk/dist/routes/accessor-index.js.map +1 -1
  478. package/sdk/dist/routes/ambient.d.ts +5 -0
  479. package/sdk/dist/routes/ambient.d.ts.map +1 -1
  480. package/sdk/dist/routes/ambient.js +20 -0
  481. package/sdk/dist/routes/ambient.js.map +1 -1
  482. package/sdk/dist/routes/ast-walk.d.ts +17 -3
  483. package/sdk/dist/routes/ast-walk.d.ts.map +1 -1
  484. package/sdk/dist/routes/ast-walk.js +24 -2
  485. package/sdk/dist/routes/ast-walk.js.map +1 -1
  486. package/sdk/dist/routes/available.d.ts +43 -0
  487. package/sdk/dist/routes/available.d.ts.map +1 -0
  488. package/sdk/dist/routes/available.js +230 -0
  489. package/sdk/dist/routes/available.js.map +1 -0
  490. package/sdk/dist/routes/builtins.generated.d.ts +180 -0
  491. package/sdk/dist/routes/builtins.generated.d.ts.map +1 -0
  492. package/sdk/dist/routes/builtins.generated.js +2 -0
  493. package/sdk/dist/routes/builtins.generated.js.map +1 -0
  494. package/sdk/dist/routes/chain-exports.generated.d.ts +13 -8
  495. package/sdk/dist/routes/chain-exports.generated.d.ts.map +1 -1
  496. package/sdk/dist/routes/chain-exports.generated.js.map +1 -1
  497. package/sdk/dist/routes/closure.d.ts.map +1 -1
  498. package/sdk/dist/routes/closure.js +13 -26
  499. package/sdk/dist/routes/closure.js.map +1 -1
  500. package/sdk/dist/routes/composed.d.ts.map +1 -1
  501. package/sdk/dist/routes/composed.js +20 -8
  502. package/sdk/dist/routes/composed.js.map +1 -1
  503. package/sdk/dist/routes/encode.d.ts +17 -0
  504. package/sdk/dist/routes/encode.d.ts.map +1 -1
  505. package/sdk/dist/routes/encode.js +14 -11
  506. package/sdk/dist/routes/encode.js.map +1 -1
  507. package/sdk/dist/routes/entry.d.ts +76 -0
  508. package/sdk/dist/routes/entry.d.ts.map +1 -0
  509. package/sdk/dist/routes/entry.js +478 -0
  510. package/sdk/dist/routes/entry.js.map +1 -0
  511. package/sdk/dist/routes/index.d.ts +19 -12
  512. package/sdk/dist/routes/index.d.ts.map +1 -1
  513. package/sdk/dist/routes/index.js +11 -8
  514. package/sdk/dist/routes/index.js.map +1 -1
  515. package/sdk/dist/routes/intent-body.d.ts +97 -0
  516. package/sdk/dist/routes/intent-body.d.ts.map +1 -0
  517. package/sdk/dist/routes/intent-body.js +441 -0
  518. package/sdk/dist/routes/intent-body.js.map +1 -0
  519. package/sdk/dist/routes/intent-dsl.d.ts +21 -6
  520. package/sdk/dist/routes/intent-dsl.d.ts.map +1 -1
  521. package/sdk/dist/routes/intent-dsl.js +34 -17
  522. package/sdk/dist/routes/intent-dsl.js.map +1 -1
  523. package/sdk/dist/routes/intent-sugar.d.ts +77 -4
  524. package/sdk/dist/routes/intent-sugar.d.ts.map +1 -1
  525. package/sdk/dist/routes/intent-sugar.js +318 -129
  526. package/sdk/dist/routes/intent-sugar.js.map +1 -1
  527. package/sdk/dist/routes/intent.d.ts +13 -1
  528. package/sdk/dist/routes/intent.d.ts.map +1 -1
  529. package/sdk/dist/routes/intent.js +37 -1
  530. package/sdk/dist/routes/intent.js.map +1 -1
  531. package/sdk/dist/routes/nest.d.ts +3 -2
  532. package/sdk/dist/routes/nest.d.ts.map +1 -1
  533. package/sdk/dist/routes/nest.js +5 -3
  534. package/sdk/dist/routes/nest.js.map +1 -1
  535. package/sdk/dist/routes/parse.d.ts +6 -0
  536. package/sdk/dist/routes/parse.d.ts.map +1 -0
  537. package/sdk/dist/routes/parse.js +39 -0
  538. package/sdk/dist/routes/parse.js.map +1 -0
  539. package/sdk/dist/routes/portal.d.ts +258 -4
  540. package/sdk/dist/routes/portal.d.ts.map +1 -1
  541. package/sdk/dist/routes/portal.js +588 -9
  542. package/sdk/dist/routes/portal.js.map +1 -1
  543. package/sdk/dist/routes/protocol-rewrite.d.ts +71 -1
  544. package/sdk/dist/routes/protocol-rewrite.d.ts.map +1 -1
  545. package/sdk/dist/routes/protocol-rewrite.js +178 -54
  546. package/sdk/dist/routes/protocol-rewrite.js.map +1 -1
  547. package/sdk/dist/routes/rs-compile.d.ts +25 -22
  548. package/sdk/dist/routes/rs-compile.d.ts.map +1 -1
  549. package/sdk/dist/routes/rs-compile.js +55 -49
  550. package/sdk/dist/routes/rs-compile.js.map +1 -1
  551. package/sdk/dist/routes/sauce-calls.d.ts +26 -12
  552. package/sdk/dist/routes/sauce-calls.d.ts.map +1 -1
  553. package/sdk/dist/routes/sauce-calls.js +16 -23
  554. package/sdk/dist/routes/sauce-calls.js.map +1 -1
  555. package/sdk/dist/routes/sauce-route.d.ts +74 -7
  556. package/sdk/dist/routes/sauce-route.d.ts.map +1 -1
  557. package/sdk/dist/routes/sauce-route.js +225 -75
  558. package/sdk/dist/routes/sauce-route.js.map +1 -1
  559. package/sdk/dist/routes/source-globals.d.ts +107 -0
  560. package/sdk/dist/routes/source-globals.d.ts.map +1 -0
  561. package/sdk/dist/routes/source-globals.generated.d.ts +5601 -933
  562. package/sdk/dist/routes/source-globals.generated.d.ts.map +1 -1
  563. package/sdk/dist/routes/source-globals.generated.js +3 -4
  564. package/sdk/dist/routes/source-globals.generated.js.map +1 -1
  565. package/sdk/dist/routes/source-globals.js +175 -0
  566. package/sdk/dist/routes/source-globals.js.map +1 -0
  567. package/sdk/dist/routes/stock-tokens.d.ts +89 -0
  568. package/sdk/dist/routes/stock-tokens.d.ts.map +1 -0
  569. package/sdk/dist/routes/stock-tokens.generated.d.ts +7 -0
  570. package/sdk/dist/routes/stock-tokens.generated.d.ts.map +1 -0
  571. package/sdk/dist/routes/stock-tokens.generated.js +3664 -0
  572. package/sdk/dist/routes/stock-tokens.generated.js.map +1 -0
  573. package/sdk/dist/routes/stock-tokens.js +89 -0
  574. package/sdk/dist/routes/stock-tokens.js.map +1 -0
  575. package/sdk/dist/routes/token-registry.d.ts +68 -8
  576. package/sdk/dist/routes/token-registry.d.ts.map +1 -1
  577. package/sdk/dist/routes/token-registry.js +218 -32
  578. package/sdk/dist/routes/token-registry.js.map +1 -1
  579. package/sdk/dist/routes/token-rewrite.d.ts +1 -1
  580. package/sdk/dist/routes/token-rewrite.d.ts.map +1 -1
  581. package/sdk/dist/routes/token-rewrite.js +5 -9
  582. package/sdk/dist/routes/token-rewrite.js.map +1 -1
  583. package/sdk/dist/routes/unknown-global.d.ts +32 -0
  584. package/sdk/dist/routes/unknown-global.d.ts.map +1 -0
  585. package/sdk/dist/routes/unknown-global.js +106 -0
  586. package/sdk/dist/routes/unknown-global.js.map +1 -0
  587. package/sdk/dist/routes/vault.d.ts +38 -8
  588. package/sdk/dist/routes/vault.d.ts.map +1 -1
  589. package/sdk/dist/routes/vault.js +47 -8
  590. package/sdk/dist/routes/vault.js.map +1 -1
  591. package/sdk/dist/sauce-script/builtins.d.ts +309 -0
  592. package/sdk/dist/sauce-script/declarations.d.ts +3 -0
  593. package/sdk/dist/sauce-script/declarations.d.ts.map +1 -0
  594. package/sdk/dist/sauce-script/declarations.js +229 -0
  595. package/sdk/dist/sauce-script/declarations.js.map +1 -0
  596. package/sdk/dist/sauce-script/index.d.ts +2714 -0
  597. package/sdk/dist/sauce-script/ts-plugin.cjs +85 -0
  598. package/sdk/dist/skills/loader.d.ts.map +1 -1
  599. package/sdk/dist/skills/loader.js +4 -3
  600. package/sdk/dist/skills/loader.js.map +1 -1
  601. package/sdk/dist/std/router/balancer-v2-vault.abi.json +78 -0
  602. package/sdk/dist/std/router/curve-cryptoswap.abi.json +29 -0
  603. package/sdk/dist/std/router/curve-stableswap.abi.json +29 -0
  604. package/sdk/dist/std/router/dodo-v2-pool.abi.json +39 -0
  605. package/sdk/dist/std/router/lb-pair.abi.json +55 -0
  606. package/sdk/dist/std/router/package.json +7 -0
  607. package/sdk/dist/std/router/router.evm.js +567 -0
  608. package/sdk/dist/std/router/sauce-router.abi.json +202 -0
  609. package/sdk/dist/std/router/uniswap-v2-pair.abi.json +49 -0
  610. package/sdk/dist/std/router/woo-pp-v2.abi.json +42 -0
  611. package/sdk/dist/std/token/permit2.abi.json +226 -0
  612. package/sdk/dist/std/token/token.evm.js +73 -0
  613. package/sdk/dist/std/token/token.svm.js +194 -41
  614. package/sdk/dist/svm/client.d.ts +62 -15
  615. package/sdk/dist/svm/client.d.ts.map +1 -1
  616. package/sdk/dist/svm/client.js +103 -42
  617. package/sdk/dist/svm/client.js.map +1 -1
  618. package/sdk/dist/svm/engine.d.ts +66 -5
  619. package/sdk/dist/svm/engine.d.ts.map +1 -1
  620. package/sdk/dist/svm/engine.js +73 -5
  621. package/sdk/dist/svm/engine.js.map +1 -1
  622. package/sdk/dist/svm/index.d.ts +2 -0
  623. package/sdk/dist/svm/index.d.ts.map +1 -1
  624. package/sdk/dist/svm/index.js +2 -0
  625. package/sdk/dist/svm/index.js.map +1 -1
  626. package/sdk/dist/svm/instructions.d.ts +72 -1
  627. package/sdk/dist/svm/instructions.d.ts.map +1 -1
  628. package/sdk/dist/svm/instructions.js +81 -2
  629. package/sdk/dist/svm/instructions.js.map +1 -1
  630. package/sdk/dist/svm/kitchen.d.ts +20 -1
  631. package/sdk/dist/svm/kitchen.d.ts.map +1 -1
  632. package/sdk/dist/svm/kitchen.js +47 -1
  633. package/sdk/dist/svm/kitchen.js.map +1 -1
  634. package/sdk/dist/svm/portal.d.ts +250 -0
  635. package/sdk/dist/svm/portal.d.ts.map +1 -0
  636. package/sdk/dist/svm/portal.js +462 -0
  637. package/sdk/dist/svm/portal.js.map +1 -0
  638. package/sdk/dist/svm/send.d.ts +18 -2
  639. package/sdk/dist/svm/send.d.ts.map +1 -1
  640. package/sdk/dist/svm/send.js +28 -3
  641. package/sdk/dist/svm/send.js.map +1 -1
  642. package/sdk/dist/svm/token-accounts.d.ts +49 -0
  643. package/sdk/dist/svm/token-accounts.d.ts.map +1 -0
  644. package/sdk/dist/svm/token-accounts.js +58 -0
  645. package/sdk/dist/svm/token-accounts.js.map +1 -0
  646. package/sdk/dist/svm/token-extensions.d.ts +18 -7
  647. package/sdk/dist/svm/token-extensions.d.ts.map +1 -1
  648. package/sdk/dist/svm/token-extensions.js +58 -5
  649. package/sdk/dist/svm/token-extensions.js.map +1 -1
  650. package/sdk/dist/token/evm.js +1 -1
  651. package/sdk/dist/token/index.d.ts +1 -1
  652. package/sdk/dist/token/index.js +1 -1
  653. package/sdk/dist/token/params.js +1 -1
  654. package/sdk/dist/token/source.js +3 -3
  655. package/sdk/dist/token/source.js.map +1 -1
  656. package/sdk/dist/token/types.d.ts +2 -2
  657. package/sdk/dist/token/types.js +2 -2
  658. package/sdk/src/protocols/aerodrome/AerodromePoolABI.json +105 -0
  659. package/sdk/src/protocols/aerodrome/abis.ts +62 -0
  660. package/sdk/src/protocols/aerodrome-slipstream/AerodromeSlipstreamPoolABI.json +96 -0
  661. package/sdk/src/protocols/aerodrome-slipstream/abis.ts +55 -0
  662. package/sdk/src/protocols/camelot/CamelotV2FactoryABI.json +25 -0
  663. package/sdk/src/protocols/camelot/CamelotV2PairABI.json +109 -0
  664. package/sdk/src/protocols/camelot/CamelotV3FactoryABI.json +25 -0
  665. package/sdk/src/protocols/camelot/CamelotV3PoolABI.json +92 -0
  666. package/sdk/src/protocols/camelot/abis.ts +143 -0
  667. package/sdk/src/protocols/eco-routes/PortalABI.json +1448 -0
  668. package/sdk/src/protocols/eco-routes/ProverABI.json +162 -0
  669. package/sdk/src/protocols/eco-routes/abis.ts +1060 -51
  670. package/sdk/src/protocols/eco-routes/addresses.generated.ts +45 -62
  671. package/sdk/src/protocols/eco-routes/lookup.ts +18 -0
  672. package/sdk/src/protocols/maverick/MaverickV2PoolABI.json +107 -0
  673. package/sdk/src/protocols/maverick/abis.ts +59 -0
  674. package/sdk/src/protocols/maverick/addresses.ts +4 -0
  675. package/sdk/src/protocols/pancakeswap-v2/PancakeSwapV2PairABI.json +72 -0
  676. package/sdk/src/protocols/pancakeswap-v2/abis.ts +44 -0
  677. package/sdk/src/protocols/pancakeswap-v3/PancakeSwapV3PoolABI.json +100 -0
  678. package/sdk/src/protocols/pancakeswap-v3/abis.ts +57 -0
  679. package/sdk/src/protocols/permit2/Permit2ABI.json +154 -0
  680. package/sdk/src/protocols/permit2/abis.ts +63 -0
  681. package/sdk/src/protocols/quickswap/QuickSwapV2FactoryABI.json +25 -0
  682. package/sdk/src/protocols/quickswap/QuickSwapV2PairABI.json +72 -0
  683. package/sdk/src/protocols/quickswap/QuickSwapV3FactoryABI.json +25 -0
  684. package/sdk/src/protocols/quickswap/QuickSwapV3PoolABI.json +88 -0
  685. package/sdk/src/protocols/quickswap/abis.ts +123 -0
  686. package/sdk/src/protocols/sushiswap-v2/SushiSwapV2PairABI.json +72 -0
  687. package/sdk/src/protocols/sushiswap-v2/abis.ts +43 -0
  688. package/sdk/src/protocols/synthra-v3/SynthraV3PoolABI.json +100 -0
  689. package/sdk/src/protocols/synthra-v3/abis.ts +56 -0
  690. package/sdk/src/protocols/trader-joe/LBPairABI.json +185 -0
  691. package/sdk/src/protocols/trader-joe/abis.ts +102 -0
  692. package/sdk/src/protocols/trader-joe/addresses.ts +5 -0
  693. package/sdk/src/protocols/uniswap-v2/UniswapV2PairABI.json +72 -0
  694. package/sdk/src/protocols/uniswap-v2/abis.ts +45 -0
  695. package/sdk/src/protocols/uniswap-v3/UniswapV3PoolABI.json +100 -0
  696. package/sdk/src/protocols/uniswap-v3/abis.ts +56 -0
  697. package/sdk/src/protocols/uniswap-v4/UniswapV4PoolManagerABI.json +38 -0
  698. package/sdk/src/protocols/uniswap-v4/UniswapV4StateViewABI.json +307 -0
  699. package/sdk/src/protocols/uniswap-v4/abis.ts +168 -0
  700. package/sdk/src/protocols/uniswap-v4/addresses.ts +50 -0
  701. package/sdk/src/protocols/unitflow-v3/UnitFlowV3PoolABI.json +100 -0
  702. package/sdk/src/protocols/unitflow-v3/abis.ts +57 -0
  703. package/sdk/src/protocols/velodrome/VelodromePoolABI.json +105 -0
  704. package/sdk/src/protocols/velodrome/abis.ts +62 -0
  705. package/skills/sauce-actions/SKILL.md +166 -0
  706. package/skills/sauce-actions/examples/swap-and-supply.json +24 -0
  707. package/skills/sauce-actions/examples/swap-by-key.json +15 -0
  708. package/skills/sauce-actions/references/actions.md +731 -0
  709. package/skills/sauce-chains/SKILL.md +137 -0
  710. package/skills/sauce-chains/examples/chains.sauce.ts +25 -0
  711. package/skills/sauce-chains/references/arbitrum.md +158 -0
  712. package/skills/sauce-chains/references/arc.md +107 -0
  713. package/skills/sauce-chains/references/aurora.md +33 -0
  714. package/skills/sauce-chains/references/avalanche.md +106 -0
  715. package/skills/sauce-chains/references/base-stocks.md +77 -0
  716. package/skills/sauce-chains/references/base.md +141 -0
  717. package/skills/sauce-chains/references/berachain.md +33 -0
  718. package/skills/sauce-chains/references/blast.md +60 -0
  719. package/skills/sauce-chains/references/boba.md +33 -0
  720. package/skills/sauce-chains/references/bsc.md +97 -0
  721. package/skills/sauce-chains/references/celo.md +57 -0
  722. package/skills/sauce-chains/references/core.md +33 -0
  723. package/skills/sauce-chains/references/cronos.md +33 -0
  724. package/skills/sauce-chains/references/ethereum-stocks.md +1741 -0
  725. package/skills/sauce-chains/references/ethereum.md +255 -0
  726. package/skills/sauce-chains/references/evmos.md +33 -0
  727. package/skills/sauce-chains/references/fantom.md +61 -0
  728. package/skills/sauce-chains/references/fuse.md +33 -0
  729. package/skills/sauce-chains/references/gnosis.md +57 -0
  730. package/skills/sauce-chains/references/index.md +58 -0
  731. package/skills/sauce-chains/references/ink.md +55 -0
  732. package/skills/sauce-chains/references/kava.md +33 -0
  733. package/skills/sauce-chains/references/klaytn.md +33 -0
  734. package/skills/sauce-chains/references/linea.md +65 -0
  735. package/skills/sauce-chains/references/manta.md +33 -0
  736. package/skills/sauce-chains/references/mantle.md +33 -0
  737. package/skills/sauce-chains/references/metis.md +54 -0
  738. package/skills/sauce-chains/references/mode.md +55 -0
  739. package/skills/sauce-chains/references/monad.md +79 -0
  740. package/skills/sauce-chains/references/moonbeam.md +33 -0
  741. package/skills/sauce-chains/references/opbnb.md +55 -0
  742. package/skills/sauce-chains/references/optimism.md +123 -0
  743. package/skills/sauce-chains/references/plasma.md +35 -0
  744. package/skills/sauce-chains/references/polygon.md +123 -0
  745. package/skills/sauce-chains/references/pulsechain.md +33 -0
  746. package/skills/sauce-chains/references/ronin.md +35 -0
  747. package/skills/sauce-chains/references/scroll.md +62 -0
  748. package/skills/sauce-chains/references/sei.md +55 -0
  749. package/skills/sauce-chains/references/solana-stocks.md +1812 -0
  750. package/skills/sauce-chains/references/solana.md +56 -0
  751. package/skills/sauce-chains/references/sonic.md +57 -0
  752. package/skills/sauce-chains/references/unichain.md +61 -0
  753. package/skills/sauce-chains/references/zetachain.md +33 -0
  754. package/skills/sauce-chains/references/zksync.md +59 -0
  755. package/skills/sauce-chains/references/zora.md +57 -0
  756. package/skills/sauce-cli/SKILL.md +366 -0
  757. package/skills/sauce-cli/examples/pay.sauce.ts +23 -0
  758. package/skills/sauce-cli/examples/split.sauce.ts +30 -0
  759. package/skills/sauce-distributed-swap/SKILL.md +392 -0
  760. package/skills/sauce-distributed-swap/examples/distributed-swap.mts +251 -0
  761. package/skills/sauce-distributed-swap/examples/distributed-swap.sauce.ts +115 -0
  762. package/skills/sauce-examples/SKILL.md +96 -0
  763. package/skills/sauce-globals/SKILL.md +213 -0
  764. package/skills/sauce-globals/examples/globals.mts +111 -0
  765. package/skills/sauce-globals/examples/globals.sauce.ts +47 -0
  766. package/skills/sauce-globals/references/chains.md +53 -0
  767. package/skills/sauce-globals/references/protocols.md +405 -0
  768. package/skills/sauce-globals/references/stocks.md +3635 -0
  769. package/skills/sauce-globals/references/tokens.md +53 -0
  770. package/skills/sauce-intents/SKILL.md +505 -0
  771. package/skills/sauce-intents/examples/cross-chain.sauce.ts +37 -0
  772. package/skills/sauce-intents/examples/fund-by-transfer.sauce.ts +54 -0
  773. package/skills/sauce-intents/examples/intents.mts +343 -0
  774. package/skills/sauce-intents/examples/swap-on-base.sauce.ts +135 -0
  775. package/skills/sauce-intents/references/portal.md +77 -0
  776. package/skills/sauce-overview/SKILL.md +161 -0
  777. package/skills/sauce-protocols/SKILL.md +118 -0
  778. package/skills/sauce-protocols/examples/protocols.mts +77 -0
  779. package/skills/sauce-protocols/examples/protocols.sauce.ts +27 -0
  780. package/{sdk/src/skills → skills/sauce-protocols/references}/aave-v2.md +35 -17
  781. package/skills/sauce-protocols/references/aave-v3.md +144 -0
  782. package/skills/sauce-protocols/references/aave-v4.md +50 -0
  783. package/skills/sauce-protocols/references/abracadabra.md +72 -0
  784. package/skills/sauce-protocols/references/across.md +73 -0
  785. package/skills/sauce-protocols/references/aerodrome-slipstream.md +50 -0
  786. package/{sdk/src/skills → skills/sauce-protocols/references}/aerodrome.md +43 -24
  787. package/skills/sauce-protocols/references/aevo.md +49 -0
  788. package/{sdk/src/skills → skills/sauce-protocols/references}/alchemix.md +10 -25
  789. package/{sdk/src/skills → skills/sauce-protocols/references}/ambient.md +14 -21
  790. package/{sdk/src/skills → skills/sauce-protocols/references}/arbitrum-bridge.md +11 -14
  791. package/{sdk/src/skills → skills/sauce-protocols/references}/arrakis.md +10 -26
  792. package/skills/sauce-protocols/references/axelar.md +56 -0
  793. package/{sdk/src/skills → skills/sauce-protocols/references}/balancer-v2.md +13 -29
  794. package/{sdk/src/skills → skills/sauce-protocols/references}/base-bridge.md +11 -16
  795. package/{sdk/src/skills → skills/sauce-protocols/references}/baseswap.md +12 -19
  796. package/{sdk/src/skills → skills/sauce-protocols/references}/beefy.md +10 -30
  797. package/{sdk/src/skills → skills/sauce-protocols/references}/benqi.md +11 -21
  798. package/{sdk/src/skills → skills/sauce-protocols/references}/camelot.md +13 -27
  799. package/{sdk/src/skills → skills/sauce-protocols/references}/cbeth.md +10 -22
  800. package/skills/sauce-protocols/references/cctp.md +47 -0
  801. package/{sdk/src/skills → skills/sauce-protocols/references}/celer.md +11 -18
  802. package/{sdk/src/skills → skills/sauce-protocols/references}/chainlink-ccip.md +11 -21
  803. package/skills/sauce-protocols/references/chainlink.md +47 -0
  804. package/{sdk/src/skills → skills/sauce-protocols/references}/circle-gateway.md +12 -38
  805. package/{sdk/src/skills → skills/sauce-protocols/references}/compound-v2.md +11 -25
  806. package/{sdk/src/skills → skills/sauce-protocols/references}/compound-v3.md +43 -27
  807. package/{sdk/src/skills → skills/sauce-protocols/references}/connext.md +11 -15
  808. package/{sdk/src/skills → skills/sauce-protocols/references}/convex.md +10 -28
  809. package/{sdk/src/skills → skills/sauce-protocols/references}/cowswap.md +12 -19
  810. package/{sdk/src/skills → skills/sauce-protocols/references}/crvusd.md +10 -19
  811. package/skills/sauce-protocols/references/curve.md +98 -0
  812. package/{sdk/src/skills → skills/sauce-protocols/references}/debridge.md +11 -33
  813. package/{sdk/src/skills → skills/sauce-protocols/references}/dodo.md +13 -18
  814. package/skills/sauce-protocols/references/eigenlayer.md +48 -0
  815. package/{sdk/src/skills → skills/sauce-protocols/references}/ens.md +10 -26
  816. package/{sdk/src/skills → skills/sauce-protocols/references}/erc20.md +10 -24
  817. package/{sdk/src/skills → skills/sauce-protocols/references}/erc3156.md +10 -13
  818. package/{sdk/src/skills → skills/sauce-protocols/references}/erc4626.md +11 -27
  819. package/{sdk/src/skills → skills/sauce-protocols/references}/ethena.md +10 -27
  820. package/{sdk/src/skills → skills/sauce-protocols/references}/etherfi.md +10 -32
  821. package/{sdk/src/skills → skills/sauce-protocols/references}/euler-v2.md +11 -21
  822. package/{sdk/src/skills → skills/sauce-protocols/references}/fenix.md +12 -18
  823. package/{sdk/src/skills → skills/sauce-protocols/references}/fluid.md +11 -20
  824. package/{sdk/src/skills → skills/sauce-protocols/references}/frax-ether.md +10 -26
  825. package/{sdk/src/skills → skills/sauce-protocols/references}/frax.md +10 -19
  826. package/{sdk/src/skills → skills/sauce-protocols/references}/gains-network.md +11 -28
  827. package/skills/sauce-protocols/references/gamma.md +57 -0
  828. package/{sdk/src/skills → skills/sauce-protocols/references}/gelato.md +12 -20
  829. package/{sdk/src/skills → skills/sauce-protocols/references}/gho.md +10 -19
  830. package/{sdk/src/skills → skills/sauce-protocols/references}/gmx-v1.md +12 -34
  831. package/{sdk/src/skills → skills/sauce-protocols/references}/gmx-v2.md +15 -28
  832. package/skills/sauce-protocols/references/harvest.md +41 -0
  833. package/{sdk/src/skills → skills/sauce-protocols/references}/hegic.md +10 -18
  834. package/{sdk/src/skills → skills/sauce-protocols/references}/hop.md +11 -21
  835. package/{sdk/src/skills → skills/sauce-protocols/references}/hyperlane.md +11 -21
  836. package/skills/sauce-protocols/references/index.md +355 -0
  837. package/{sdk/src/skills → skills/sauce-protocols/references}/instadapp.md +10 -18
  838. package/skills/sauce-protocols/references/kelp.md +46 -0
  839. package/{sdk/src/skills → skills/sauce-protocols/references}/kim.md +12 -18
  840. package/{sdk/src/skills → skills/sauce-protocols/references}/kyberswap-aggregator.md +12 -35
  841. package/skills/sauce-protocols/references/kyberswap.md +72 -0
  842. package/{sdk/src/skills → skills/sauce-protocols/references}/layerbank.md +11 -26
  843. package/{sdk/src/skills → skills/sauce-protocols/references}/layerzero.md +11 -25
  844. package/{sdk/src/skills → skills/sauce-protocols/references}/level-finance.md +10 -24
  845. package/{sdk/src/skills → skills/sauce-protocols/references}/lido.md +10 -28
  846. package/{sdk/src/skills → skills/sauce-protocols/references}/lifi.md +11 -25
  847. package/{sdk/src/skills → skills/sauce-protocols/references}/linea-bridge.md +11 -14
  848. package/{sdk/src/skills → skills/sauce-protocols/references}/liquity-v1.md +10 -21
  849. package/{sdk/src/skills → skills/sauce-protocols/references}/liquity-v2.md +10 -19
  850. package/{sdk/src/skills → skills/sauce-protocols/references}/lynex.md +12 -18
  851. package/skills/sauce-protocols/references/maker.md +57 -0
  852. package/skills/sauce-protocols/references/mantle-meth.md +43 -0
  853. package/{sdk/src/skills → skills/sauce-protocols/references}/maverick.md +13 -25
  854. package/{sdk/src/skills → skills/sauce-protocols/references}/moonwell.md +11 -21
  855. package/{sdk/src/skills → skills/sauce-protocols/references}/morpho-blue.md +44 -21
  856. package/{sdk/src/skills → skills/sauce-protocols/references}/mux-protocol.md +10 -30
  857. package/skills/sauce-protocols/references/olympus.md +39 -0
  858. package/skills/sauce-protocols/references/oneinch.md +81 -0
  859. package/skills/sauce-protocols/references/openocean.md +69 -0
  860. package/{sdk/src/skills → skills/sauce-protocols/references}/optimism-bridge.md +11 -16
  861. package/{sdk/src/skills → skills/sauce-protocols/references}/opyn.md +10 -21
  862. package/{sdk/src/skills → skills/sauce-protocols/references}/pancakeswap-v2.md +39 -41
  863. package/skills/sauce-protocols/references/pancakeswap-v3.md +72 -0
  864. package/skills/sauce-protocols/references/paraswap.md +39 -0
  865. package/{sdk/src/skills → skills/sauce-protocols/references}/pendle.md +47 -29
  866. package/skills/sauce-protocols/references/permit2.md +101 -0
  867. package/skills/sauce-protocols/references/perpetual-protocol.md +53 -0
  868. package/{sdk/src/skills → skills/sauce-protocols/references}/polygon-bridge.md +11 -17
  869. package/{sdk/src/skills → skills/sauce-protocols/references}/premia.md +10 -19
  870. package/{sdk/src/skills → skills/sauce-protocols/references}/puffer.md +10 -21
  871. package/skills/sauce-protocols/references/pyth.md +45 -0
  872. package/{sdk/src/skills → skills/sauce-protocols/references}/quickswap.md +13 -27
  873. package/{sdk/src/skills → skills/sauce-protocols/references}/radiant.md +11 -15
  874. package/{sdk/src/skills → skills/sauce-protocols/references}/ramses.md +12 -18
  875. package/skills/sauce-protocols/references/reflexer.md +52 -0
  876. package/skills/sauce-protocols/references/registry/aave-v2.md +43 -0
  877. package/skills/sauce-protocols/references/registry/aave-v3.md +62 -0
  878. package/skills/sauce-protocols/references/registry/aave-v4.md +80 -0
  879. package/skills/sauce-protocols/references/registry/abracadabra.md +54 -0
  880. package/skills/sauce-protocols/references/registry/across.md +57 -0
  881. package/skills/sauce-protocols/references/registry/aerodrome-slipstream.md +72 -0
  882. package/skills/sauce-protocols/references/registry/aerodrome.md +58 -0
  883. package/skills/sauce-protocols/references/registry/aevo.md +39 -0
  884. package/skills/sauce-protocols/references/registry/alchemix.md +46 -0
  885. package/skills/sauce-protocols/references/registry/ambient.md +40 -0
  886. package/skills/sauce-protocols/references/registry/arbitrum-bridge.md +40 -0
  887. package/skills/sauce-protocols/references/registry/arrakis.md +49 -0
  888. package/skills/sauce-protocols/references/registry/axelar.md +65 -0
  889. package/skills/sauce-protocols/references/registry/balancer-v2.md +50 -0
  890. package/skills/sauce-protocols/references/registry/base-bridge.md +42 -0
  891. package/skills/sauce-protocols/references/registry/baseswap.md +40 -0
  892. package/skills/sauce-protocols/references/registry/beefy.md +51 -0
  893. package/skills/sauce-protocols/references/registry/benqi.md +49 -0
  894. package/skills/sauce-protocols/references/registry/camelot.md +82 -0
  895. package/skills/sauce-protocols/references/registry/cbeth.md +43 -0
  896. package/skills/sauce-protocols/references/registry/cctp.md +48 -0
  897. package/skills/sauce-protocols/references/registry/celer.md +44 -0
  898. package/skills/sauce-protocols/references/registry/chainlink-ccip.md +45 -0
  899. package/skills/sauce-protocols/references/registry/chainlink.md +49 -0
  900. package/skills/sauce-protocols/references/registry/circle-gateway.md +70 -0
  901. package/skills/sauce-protocols/references/registry/compound-v2.md +53 -0
  902. package/skills/sauce-protocols/references/registry/compound-v3.md +52 -0
  903. package/skills/sauce-protocols/references/registry/connext.md +41 -0
  904. package/skills/sauce-protocols/references/registry/convex.md +51 -0
  905. package/skills/sauce-protocols/references/registry/cowswap.md +40 -0
  906. package/skills/sauce-protocols/references/registry/crvusd.md +40 -0
  907. package/skills/sauce-protocols/references/registry/curve.md +81 -0
  908. package/skills/sauce-protocols/references/registry/debridge.md +59 -0
  909. package/skills/sauce-protocols/references/registry/dodo.md +39 -0
  910. package/skills/sauce-protocols/references/registry/eco-routes.md +65 -0
  911. package/skills/sauce-protocols/references/registry/eigenlayer.md +58 -0
  912. package/skills/sauce-protocols/references/registry/ens.md +49 -0
  913. package/skills/sauce-protocols/references/registry/erc20.md +44 -0
  914. package/skills/sauce-protocols/references/registry/erc3156.md +38 -0
  915. package/skills/sauce-protocols/references/registry/erc4626.md +51 -0
  916. package/skills/sauce-protocols/references/registry/ethena.md +50 -0
  917. package/skills/sauce-protocols/references/registry/etherfi.md +57 -0
  918. package/skills/sauce-protocols/references/registry/euler-v2.md +49 -0
  919. package/skills/sauce-protocols/references/registry/fenix.md +39 -0
  920. package/skills/sauce-protocols/references/registry/fluid.md +48 -0
  921. package/skills/sauce-protocols/references/registry/frax-ether.md +49 -0
  922. package/skills/sauce-protocols/references/registry/frax.md +40 -0
  923. package/skills/sauce-protocols/references/registry/gains-network.md +43 -0
  924. package/skills/sauce-protocols/references/registry/gamma.md +56 -0
  925. package/skills/sauce-protocols/references/registry/gelato.md +45 -0
  926. package/skills/sauce-protocols/references/registry/gho.md +40 -0
  927. package/skills/sauce-protocols/references/registry/gmx-v1.md +59 -0
  928. package/skills/sauce-protocols/references/registry/gmx-v2.md +41 -0
  929. package/skills/sauce-protocols/references/registry/harvest.md +44 -0
  930. package/skills/sauce-protocols/references/registry/hegic.md +39 -0
  931. package/skills/sauce-protocols/references/registry/hop.md +49 -0
  932. package/skills/sauce-protocols/references/registry/hyperlane.md +48 -0
  933. package/skills/sauce-protocols/references/registry/instadapp.md +39 -0
  934. package/skills/sauce-protocols/references/registry/kelp.md +47 -0
  935. package/skills/sauce-protocols/references/registry/kim.md +39 -0
  936. package/skills/sauce-protocols/references/registry/kyberswap-aggregator.md +49 -0
  937. package/skills/sauce-protocols/references/registry/kyberswap.md +63 -0
  938. package/skills/sauce-protocols/references/registry/layerbank.md +54 -0
  939. package/skills/sauce-protocols/references/registry/layerzero.md +49 -0
  940. package/skills/sauce-protocols/references/registry/level-finance.md +41 -0
  941. package/skills/sauce-protocols/references/registry/lido.md +51 -0
  942. package/skills/sauce-protocols/references/registry/lifi.md +48 -0
  943. package/skills/sauce-protocols/references/registry/linea-bridge.md +40 -0
  944. package/skills/sauce-protocols/references/registry/liquity-v1.md +42 -0
  945. package/skills/sauce-protocols/references/registry/liquity-v2.md +40 -0
  946. package/skills/sauce-protocols/references/registry/lynex.md +39 -0
  947. package/skills/sauce-protocols/references/registry/maker.md +55 -0
  948. package/skills/sauce-protocols/references/registry/mantle-meth.md +48 -0
  949. package/skills/sauce-protocols/references/registry/maverick.md +60 -0
  950. package/skills/sauce-protocols/references/registry/moonwell.md +49 -0
  951. package/skills/sauce-protocols/references/registry/morpho-blue.md +47 -0
  952. package/skills/sauce-protocols/references/registry/mux-protocol.md +49 -0
  953. package/skills/sauce-protocols/references/registry/olympus.md +42 -0
  954. package/skills/sauce-protocols/references/registry/oneinch.md +45 -0
  955. package/skills/sauce-protocols/references/registry/openocean.md +44 -0
  956. package/skills/sauce-protocols/references/registry/optimism-bridge.md +42 -0
  957. package/skills/sauce-protocols/references/registry/opyn.md +42 -0
  958. package/skills/sauce-protocols/references/registry/pancakeswap-v2.md +71 -0
  959. package/skills/sauce-protocols/references/registry/pancakeswap-v3.md +76 -0
  960. package/skills/sauce-protocols/references/registry/paraswap.md +51 -0
  961. package/skills/sauce-protocols/references/registry/pendle.md +43 -0
  962. package/skills/sauce-protocols/references/registry/permit2.md +50 -0
  963. package/skills/sauce-protocols/references/registry/perpetual-protocol.md +49 -0
  964. package/skills/sauce-protocols/references/registry/polygon-bridge.md +43 -0
  965. package/skills/sauce-protocols/references/registry/premia.md +40 -0
  966. package/skills/sauce-protocols/references/registry/puffer.md +43 -0
  967. package/skills/sauce-protocols/references/registry/pyth.md +40 -0
  968. package/skills/sauce-protocols/references/registry/quickswap.md +80 -0
  969. package/skills/sauce-protocols/references/registry/radiant.md +41 -0
  970. package/skills/sauce-protocols/references/registry/ramses.md +39 -0
  971. package/skills/sauce-protocols/references/registry/reflexer.md +56 -0
  972. package/skills/sauce-protocols/references/registry/renzo.md +47 -0
  973. package/skills/sauce-protocols/references/registry/rocket-pool.md +49 -0
  974. package/skills/sauce-protocols/references/registry/sablier.md +40 -0
  975. package/skills/sauce-protocols/references/registry/safe.md +47 -0
  976. package/skills/sauce-protocols/references/registry/scroll-bridge.md +48 -0
  977. package/skills/sauce-protocols/references/registry/seamless.md +42 -0
  978. package/skills/sauce-protocols/references/registry/seaport.md +44 -0
  979. package/skills/sauce-protocols/references/registry/silo.md +48 -0
  980. package/skills/sauce-protocols/references/registry/socket.md +44 -0
  981. package/skills/sauce-protocols/references/registry/sommelier.md +43 -0
  982. package/skills/sauce-protocols/references/registry/spark.md +42 -0
  983. package/skills/sauce-protocols/references/registry/spookyswap.md +40 -0
  984. package/skills/sauce-protocols/references/registry/squid.md +45 -0
  985. package/skills/sauce-protocols/references/registry/stader.md +47 -0
  986. package/skills/sauce-protocols/references/registry/stargate.md +45 -0
  987. package/skills/sauce-protocols/references/registry/superfluid.md +49 -0
  988. package/skills/sauce-protocols/references/registry/sushiswap-v2.md +71 -0
  989. package/skills/sauce-protocols/references/registry/swell.md +49 -0
  990. package/skills/sauce-protocols/references/registry/synapse.md +46 -0
  991. package/skills/sauce-protocols/references/registry/syncswap.md +38 -0
  992. package/skills/sauce-protocols/references/registry/synthetix-v3.md +48 -0
  993. package/skills/sauce-protocols/references/registry/synthra-v3.md +77 -0
  994. package/skills/sauce-protocols/references/registry/thales.md +51 -0
  995. package/skills/sauce-protocols/references/registry/thena.md +39 -0
  996. package/skills/sauce-protocols/references/registry/thruster.md +38 -0
  997. package/skills/sauce-protocols/references/registry/tokemak.md +45 -0
  998. package/skills/sauce-protocols/references/registry/trader-joe.md +66 -0
  999. package/skills/sauce-protocols/references/registry/uniswap-v2.md +77 -0
  1000. package/skills/sauce-protocols/references/registry/uniswap-v3.md +113 -0
  1001. package/skills/sauce-protocols/references/registry/uniswap-v4.md +117 -0
  1002. package/skills/sauce-protocols/references/registry/unitflow-v3.md +65 -0
  1003. package/skills/sauce-protocols/references/registry/velodrome.md +58 -0
  1004. package/skills/sauce-protocols/references/registry/venus.md +62 -0
  1005. package/skills/sauce-protocols/references/registry/vertex.md +46 -0
  1006. package/skills/sauce-protocols/references/registry/wormhole.md +59 -0
  1007. package/skills/sauce-protocols/references/registry/yearn-v3.md +46 -0
  1008. package/skills/sauce-protocols/references/registry/zerolend.md +41 -0
  1009. package/skills/sauce-protocols/references/registry/zerox.md +44 -0
  1010. package/skills/sauce-protocols/references/registry/zksync-bridge.md +40 -0
  1011. package/{sdk/src/skills → skills/sauce-protocols/references}/renzo.md +10 -24
  1012. package/{sdk/src/skills → skills/sauce-protocols/references}/rocket-pool.md +10 -26
  1013. package/{sdk/src/skills → skills/sauce-protocols/references}/sablier.md +10 -27
  1014. package/skills/sauce-protocols/references/safe.md +42 -0
  1015. package/{sdk/src/skills → skills/sauce-protocols/references}/scroll-bridge.md +11 -20
  1016. package/{sdk/src/skills → skills/sauce-protocols/references}/seamless.md +11 -16
  1017. package/skills/sauce-protocols/references/seaport.md +38 -0
  1018. package/{sdk/src/skills → skills/sauce-protocols/references}/silo.md +11 -20
  1019. package/{sdk/src/skills → skills/sauce-protocols/references}/socket.md +11 -18
  1020. package/skills/sauce-protocols/references/sommelier.md +40 -0
  1021. package/{sdk/src/skills → skills/sauce-protocols/references}/spark.md +11 -16
  1022. package/{sdk/src/skills → skills/sauce-protocols/references}/spookyswap.md +12 -19
  1023. package/{sdk/src/skills → skills/sauce-protocols/references}/squid.md +11 -21
  1024. package/skills/sauce-protocols/references/stader.md +39 -0
  1025. package/{sdk/src/skills → skills/sauce-protocols/references}/stargate.md +11 -22
  1026. package/{sdk/src/skills → skills/sauce-protocols/references}/superfluid.md +10 -28
  1027. package/{sdk/src/skills → skills/sauce-protocols/references}/sushiswap-v2.md +38 -43
  1028. package/skills/sauce-protocols/references/swell.md +49 -0
  1029. package/skills/sauce-protocols/references/synapse.md +54 -0
  1030. package/{sdk/src/skills → skills/sauce-protocols/references}/syncswap.md +12 -17
  1031. package/{sdk/src/skills → skills/sauce-protocols/references}/synthetix-v3.md +10 -29
  1032. package/skills/sauce-protocols/references/synthra-v3.md +63 -0
  1033. package/skills/sauce-protocols/references/thales.md +58 -0
  1034. package/{sdk/src/skills → skills/sauce-protocols/references}/thena.md +12 -18
  1035. package/{sdk/src/skills → skills/sauce-protocols/references}/thruster.md +13 -18
  1036. package/skills/sauce-protocols/references/tokemak.md +40 -0
  1037. package/{sdk/src/skills → skills/sauce-protocols/references}/trader-joe.md +13 -26
  1038. package/{sdk/src/skills → skills/sauce-protocols/references}/uniswap-v2.md +46 -44
  1039. package/skills/sauce-protocols/references/uniswap-v3.md +188 -0
  1040. package/skills/sauce-protocols/references/uniswap-v4.md +155 -0
  1041. package/skills/sauce-protocols/references/unitflow-v3.md +63 -0
  1042. package/{sdk/src/skills → skills/sauce-protocols/references}/velodrome.md +12 -24
  1043. package/{sdk/src/skills → skills/sauce-protocols/references}/venus.md +12 -31
  1044. package/skills/sauce-protocols/references/vertex.md +42 -0
  1045. package/skills/sauce-protocols/references/wormhole.md +57 -0
  1046. package/{sdk/src/skills → skills/sauce-protocols/references}/yearn-v3.md +10 -25
  1047. package/{sdk/src/skills → skills/sauce-protocols/references}/zerolend.md +11 -15
  1048. package/skills/sauce-protocols/references/zerox.md +39 -0
  1049. package/{sdk/src/skills → skills/sauce-protocols/references}/zksync-bridge.md +11 -14
  1050. package/skills/sauce-script/SKILL.md +407 -0
  1051. package/skills/sauce-script/examples/IOracle.json +12 -0
  1052. package/skills/sauce-script/examples/saucescript.mts +167 -0
  1053. package/skills/sauce-script/examples/twap.sauce.ts +29 -0
  1054. package/skills/sauce-script/references/builtins.json +823 -0
  1055. package/skills/sauce-script/references/builtins.md +674 -0
  1056. package/skills/sauce-solana/SKILL.md +324 -0
  1057. package/skills/sauce-solana/examples/solana.mts +166 -0
  1058. package/skills/sauce-solana/examples/solana.sauce.ts +45 -0
  1059. package/skills/sauce-solana/examples/token-2022.sauce.ts +38 -0
  1060. package/skills/sauce-swaps/SKILL.md +200 -0
  1061. package/skills/sauce-swaps/examples/swap-leg.sauce.ts +50 -0
  1062. package/skills/sauce-swaps/examples/swaps.mts +124 -0
  1063. package/skills/sauce-typescript/SKILL.md +178 -0
  1064. package/skills/sauce-typescript/examples/actions.mts +100 -0
  1065. package/skills/sauce-typescript/examples/compiler.mts +69 -0
  1066. package/skills/sauce-typescript/examples/cook.mts +65 -0
  1067. package/skills/sauce-typescript/examples/verify.mts +104 -0
  1068. package/dev-tools/README.md +0 -16
  1069. package/dev-tools/artifacts/IERC20.json +0 -1
  1070. package/dev-tools/artifacts/ISauceRouter.json +0 -1
  1071. package/dev-tools/artifacts/IUniswapV3Pool.json +0 -1
  1072. package/dev-tools/artifacts/Router.json +0 -1
  1073. package/dev-tools/hardhat.config.cjs +0 -18
  1074. package/dev-tools/sauce/js/add.js +0 -4
  1075. package/dev-tools/sauce/js/call.js +0 -8
  1076. package/dev-tools/sauce/js/erc20.js +0 -18
  1077. package/dev-tools/sauce/js/example.js +0 -6
  1078. package/dev-tools/sauce/js/fibonacci.js +0 -13
  1079. package/dev-tools/sauce/ts/add.ts +0 -4
  1080. package/dev-tools/sauce/ts/call.ts +0 -8
  1081. package/dev-tools/sauce/ts/erc20.ts +0 -18
  1082. package/dev-tools/sauce/ts/example.ts +0 -6
  1083. package/dev-tools/sauce/ts/fibonacci.ts +0 -13
  1084. package/dev-tools/sauce/ts/saucescript.d.ts +0 -1
  1085. package/dev-tools/sauce/ts/tsconfig.json +0 -12
  1086. package/dev-tools/scripts/deploy.ts +0 -107
  1087. package/dev-tools/scripts/init.js +0 -132
  1088. package/dev-tools/scripts/run.ts +0 -67
  1089. package/dev-tools/scripts/start-fork.sh +0 -92
  1090. package/dev-tools/scripts/start-local.sh +0 -120
  1091. package/dev-tools/scripts/stop-local.sh +0 -40
  1092. package/dev-tools/scripts/sync-artifacts.js +0 -46
  1093. package/dev-tools/scripts/sync-price.ts +0 -58
  1094. package/dev-tools/src/contracts.ts +0 -59
  1095. package/dev-tools/src/runner.ts +0 -355
  1096. package/dev-tools/src/svm-local.ts +0 -305
  1097. package/dev-tools/src/sync-price.ts +0 -217
  1098. package/sdk/dist/deployments/v12.generated.d.ts +0 -95
  1099. package/sdk/dist/deployments/v12.generated.d.ts.map +0 -1
  1100. package/sdk/dist/deployments/v12.generated.js +0 -50
  1101. package/sdk/dist/deployments/v12.generated.js.map +0 -1
  1102. package/sdk/dist/swap/index.d.ts +0 -29
  1103. package/sdk/dist/swap/index.d.ts.map +0 -1
  1104. package/sdk/dist/swap/index.js +0 -27
  1105. package/sdk/dist/swap/index.js.map +0 -1
  1106. package/sdk/dist/swap/params.d.ts +0 -29
  1107. package/sdk/dist/swap/params.d.ts.map +0 -1
  1108. package/sdk/dist/swap/params.js +0 -123
  1109. package/sdk/dist/swap/params.js.map +0 -1
  1110. package/sdk/dist/swap/source.d.ts +0 -30
  1111. package/sdk/dist/swap/source.d.ts.map +0 -1
  1112. package/sdk/dist/swap/source.js +0 -101
  1113. package/sdk/dist/swap/source.js.map +0 -1
  1114. package/sdk/dist/swap/types.d.ts +0 -160
  1115. package/sdk/dist/swap/types.d.ts.map +0 -1
  1116. package/sdk/dist/swap/types.js +0 -106
  1117. package/sdk/dist/swap/types.js.map +0 -1
  1118. package/sdk/src/skills/aave-v3.md +0 -134
  1119. package/sdk/src/skills/aave-v4.md +0 -91
  1120. package/sdk/src/skills/abracadabra.md +0 -93
  1121. package/sdk/src/skills/across.md +0 -90
  1122. package/sdk/src/skills/aerodrome-slipstream.md +0 -57
  1123. package/sdk/src/skills/aevo.md +0 -58
  1124. package/sdk/src/skills/axelar.md +0 -80
  1125. package/sdk/src/skills/chainlink.md +0 -62
  1126. package/sdk/src/skills/curve.md +0 -141
  1127. package/sdk/src/skills/eigenlayer.md +0 -71
  1128. package/sdk/src/skills/gamma.md +0 -79
  1129. package/sdk/src/skills/harvest.md +0 -49
  1130. package/sdk/src/skills/index.md +0 -299
  1131. package/sdk/src/skills/kelp.md +0 -60
  1132. package/sdk/src/skills/kyberswap.md +0 -100
  1133. package/sdk/src/skills/loader.ts +0 -46
  1134. package/sdk/src/skills/maker.md +0 -79
  1135. package/sdk/src/skills/mantle-meth.md +0 -60
  1136. package/sdk/src/skills/olympus.md +0 -46
  1137. package/sdk/src/skills/oneinch.md +0 -64
  1138. package/sdk/src/skills/openocean.md +0 -86
  1139. package/sdk/src/skills/pancakeswap-v3.md +0 -104
  1140. package/sdk/src/skills/paraswap.md +0 -67
  1141. package/sdk/src/skills/permit2.md +0 -73
  1142. package/sdk/src/skills/perpetual-protocol.md +0 -73
  1143. package/sdk/src/skills/pyth.md +0 -58
  1144. package/sdk/src/skills/reflexer.md +0 -73
  1145. package/sdk/src/skills/safe.md +0 -56
  1146. package/sdk/src/skills/seaport.md +0 -65
  1147. package/sdk/src/skills/sommelier.md +0 -47
  1148. package/sdk/src/skills/stader.md +0 -53
  1149. package/sdk/src/skills/swell.md +0 -65
  1150. package/sdk/src/skills/synapse.md +0 -63
  1151. package/sdk/src/skills/synthra-v3.md +0 -57
  1152. package/sdk/src/skills/thales.md +0 -74
  1153. package/sdk/src/skills/tokemak.md +0 -48
  1154. package/sdk/src/skills/uniswap-v3.md +0 -202
  1155. package/sdk/src/skills/uniswap-v4.md +0 -125
  1156. package/sdk/src/skills/unitflow-v3.md +0 -62
  1157. package/sdk/src/skills/vertex.md +0 -55
  1158. package/sdk/src/skills/wormhole.md +0 -76
  1159. package/sdk/src/skills/zerox.md +0 -51
@@ -0,0 +1,3163 @@
1
+ /**
2
+ * The `sauce` command: compile SauceScript exactly as the SDK does, and run it — simulate the cook,
3
+ * sign and send it, deploy the Pot it runs on — or print the unsigned transaction for a wallet;
4
+ * and set a project up to do all of that. `main.ts` is the executable; this is everything it does,
5
+ * over an injected {@link CliIo} so the tests drive it without a child process.
6
+ *
7
+ * NODE-ONLY, and reached by nothing browser-facing: it is the package's `bin`, not an `exports`
8
+ * entry, and no barrel imports it. It reads the environment once, deliberately, and only the
9
+ * variable `--password-env <NAME>` names (`nodeIo().readEnv`). The network is reached only through
10
+ * `--rpc-url` or a `--config` file named on the command line, and a key only through `--wallet`,
11
+ * `--keystore`, `--private-key` or `--keypair` — and every byte printed passes through
12
+ * `signer.ts#scrub` on the way out.
13
+ */
14
+ import { spawnSync } from "node:child_process";
15
+ import { readFileSync, statSync, writeFileSync } from "node:fs";
16
+ import { requireChain } from "../chains/canonical.js";
17
+ import { addressDefines, CliError, describeFlags, parseAddress, parseChain, parseDefines, parseDefinesFile, parseFlags, parseFundVia, parseLamports, parseSalt, parseTarget, parseUnixSeconds, parseVia, parseWei, repeatedFlag, requiredFlag, stringFlag, UsageError, } from "./args.js";
18
+ import { actionsCommand, actionsProgram, isActionsDocument } from "./actions.js";
19
+ import { chainServedBy, connect, endpointFor } from "./chain.js";
20
+ import { compileCommand, pastDeadline, compileProgram, potCommand, programChains, potDeployCommand, potStatusCommand, readInput, runCommand, txCommand, unapproved, } from "./commands.js";
21
+ import { createIntent } from "./create.js";
22
+ import { defineLabels, fillCommand, fillTargets } from "./fill.js";
23
+ import { cancelCommand, claimCommand, fileTargets, importCommand, isIntentHash, listCommand, proveCommand, refundCommand, rememberPublished, showCommand, storedTargets, } from "./intent-commands.js";
24
+ import { svmFillCommand } from "./intent-svm.js";
25
+ import { interactiveIntents } from "./interactive.js";
26
+ import { intentOf, intentRecord } from "./lifecycle.js";
27
+ import { defaultStoreDir, IntentStore } from "./store.js";
28
+ import { globalsCommand } from "./globals.js";
29
+ import { initProject, writeSauceScriptTsconfig } from "./init.js";
30
+ import { assumedBalances, definesReach, fundingFor, potTarget, programChain, withoutShebang, } from "./inputs.js";
31
+ import { inspectCommand, inspectFile } from "./inspect.js";
32
+ import { checkIntentPots, destinationFee, intentCooks, missingPotNote, uncheckedPotNote, } from "./intents.js";
33
+ import { MCP_FLAGS, mcpCommand } from "./mcp.js";
34
+ import { livePrice, priceCommand, pricedChain, priceGiven, resolvePriceTokens } from "./price.js";
35
+ import { parseV4Key, poolsCommand } from "./pools.js";
36
+ import { publishCommand } from "./publish.js";
37
+ import { simulateCommand } from "./simulate.js";
38
+ import { intentDestinations, previewChainsNote, requireSupported, supportedChainNames, } from "./support.js";
39
+ import { parsePin, verifyCommand } from "./verify.js";
40
+ import { loadKeypair, parseAccounts, parsePubkey, svmPotCommand, svmPotDeployCommand, svmPotStatusCommand, svmRunCommand, svmSimulateCommand, svmTxCommand, svmVerifyCommand, } from "./solana.js";
41
+ import { passwordSource } from "./password.js";
42
+ import { keystoreAddress, loadSigner, scrub, secret } from "./signer.js";
43
+ import { PASSWORD, unlockWallet, WALLETS, walletAddressCommand, walletExportCommand, walletImportCommand, walletListCommand, walletNewCommand, } from "./wallet-commands.js";
44
+ import { defaultWalletsDir, evmAddressOf, walletName, WalletStore, } from "./wallets.js";
45
+ import { askOn, chooseTerminal, confirmOn, controllingTerminal, passwordOn, writeToTerminal, } from "./terminal.js";
46
+ import { AGENTS, describeStatus, DEFAULT_AGENTS, installedTargets, installTarget, PACKAGED_SKILLS, parseAgents, statusOf, targetsFor, updateTarget, } from "./skills.js";
47
+ /** The real process's streams, filesystem, children and terminal. */
48
+ export function nodeIo() {
49
+ let stdinRead = false;
50
+ const terminal = () => chooseTerminal({
51
+ stdinRead,
52
+ stdin: process.stdin,
53
+ stderr: process.stderr,
54
+ controlling: controllingTerminal,
55
+ });
56
+ return {
57
+ readStdin: () => {
58
+ stdinRead = true;
59
+ return readFileSync(0, "utf8");
60
+ },
61
+ canAsk: () => {
62
+ const found = terminal();
63
+ found?.close();
64
+ return found !== undefined;
65
+ },
66
+ confirm: async (question) => {
67
+ const found = terminal();
68
+ if (found === undefined)
69
+ return undefined;
70
+ try {
71
+ return await confirmOn(found, question);
72
+ }
73
+ finally {
74
+ found.close();
75
+ }
76
+ },
77
+ ask: async (question) => {
78
+ const found = terminal();
79
+ if (found === undefined)
80
+ return undefined;
81
+ try {
82
+ return await askOn(found, question);
83
+ }
84
+ finally {
85
+ found.close();
86
+ }
87
+ },
88
+ promptPassword: async (prompt) => {
89
+ const found = terminal();
90
+ if (found === undefined) {
91
+ throw new UsageError(`${stdinRead ? "stdin carried the program, and there is " : ""}no terminal to ask for ` +
92
+ "the password on: pass --password-env <NAME>, --password-file <path> or " +
93
+ "--password-command <command>");
94
+ }
95
+ try {
96
+ return await passwordOn(found, prompt);
97
+ }
98
+ finally {
99
+ found.close();
100
+ }
101
+ },
102
+ // The one read of the environment: the variable the user named, and nothing else.
103
+ readEnv: (name) => process.env[name],
104
+ fileMode: (path) => (process.platform === "win32" ? undefined : statSync(path).mode),
105
+ capture: (command) => {
106
+ const ran = spawnSync(command, {
107
+ shell: true,
108
+ stdio: ["ignore", "pipe", "pipe"],
109
+ encoding: "utf8",
110
+ timeout: 120_000,
111
+ maxBuffer: 64 * 1024,
112
+ });
113
+ const code = ran.error?.code;
114
+ return {
115
+ status: ran.error === undefined ? ran.status : null,
116
+ stdout: ran.stdout ?? "",
117
+ ...(code === undefined ? {} : { error: code }),
118
+ };
119
+ },
120
+ writeTerminal: writeToTerminal,
121
+ stdout: (text) => void process.stdout.write(text),
122
+ stderr: (text) => void process.stderr.write(text),
123
+ readText: (path) => readFileSync(path, "utf8"),
124
+ readModule: (path) => {
125
+ try {
126
+ return readFileSync(path);
127
+ }
128
+ catch (error) {
129
+ const code = error.code;
130
+ // Absent is `undefined` — how the compiler probes a target arm before its fallback. Any
131
+ // other failure means something IS there and could not be read, so it propagates.
132
+ if (code === "ENOENT" || code === "ENOTDIR" || code === "EISDIR")
133
+ return undefined;
134
+ throw error;
135
+ }
136
+ },
137
+ writeText: (path, text) => writeFileSync(path, text),
138
+ run: (command, args, cwd) => spawnSync(command, [...args], {
139
+ cwd,
140
+ stdio: "inherit",
141
+ // npm is `npm.cmd` on Windows, which only a shell resolves.
142
+ shell: process.platform === "win32",
143
+ }).status ?? 1,
144
+ };
145
+ }
146
+ /** This package's name and version, from the manifest three levels above `sdk/{src,dist}/cli`. */
147
+ function packageInfo() {
148
+ const manifest = new URL("../../../package.json", import.meta.url);
149
+ return JSON.parse(readFileSync(manifest, "utf8"));
150
+ }
151
+ const skillsSource = () => {
152
+ const { name, version, dependencies } = packageInfo();
153
+ const typescript = dependencies?.typescript;
154
+ return {
155
+ dir: PACKAGED_SKILLS,
156
+ packageName: name,
157
+ version,
158
+ ...(typescript === undefined ? {} : { typescript }),
159
+ };
160
+ };
161
+ // ---------------------------------------------------------------------------------------------
162
+ // Flags
163
+ // ---------------------------------------------------------------------------------------------
164
+ const HELP = { help: { type: "boolean", short: "h", help: "Show this help" } };
165
+ const PROGRAM = {
166
+ chain: {
167
+ type: "string",
168
+ value: "<slug|id>",
169
+ help: "Chain the program runs on (base, 8453, solana)",
170
+ },
171
+ target: {
172
+ type: "string",
173
+ value: "<evm|svm>",
174
+ help: "Checked against the chain; svm alone means solana",
175
+ },
176
+ define: {
177
+ type: "string",
178
+ multiple: true,
179
+ value: "NAME=VALUE",
180
+ help: "A value the program reads by name: integer, 0x hex, true, false; base58 on Solana",
181
+ },
182
+ defines: {
183
+ type: "string",
184
+ value: "<file.json>",
185
+ help: "Defines from a JSON object of NAME to value; --define wins",
186
+ },
187
+ "intent-deadline": {
188
+ type: "string",
189
+ value: "<unix seconds>",
190
+ help: "For intents the program opens: their deadline",
191
+ },
192
+ "intent-creator": {
193
+ type: "string",
194
+ value: "<address>",
195
+ help: "…their creator, who may reclaim an unearned reward",
196
+ },
197
+ "intent-reward-deadline": {
198
+ type: "string",
199
+ value: "<unix seconds>",
200
+ help: "…from when an unproven one's reward is refundable (default: the deadline)",
201
+ },
202
+ "intent-prover": {
203
+ type: "string",
204
+ value: "<address>",
205
+ help: "…their prover (default: the registry's for the pair)",
206
+ },
207
+ "intent-execution-fee": {
208
+ type: "string",
209
+ value: "<wei|auto>",
210
+ help: "…the destination Kitchen's fee, when one runs a program; auto reads it",
211
+ },
212
+ "intent-fund-via": {
213
+ type: "string",
214
+ value: "<transfer|publishAndFund>",
215
+ help: "…how their reward is funded: paid into the vault (default), or publishAndFund",
216
+ },
217
+ "compact-args": {
218
+ type: "boolean",
219
+ help: "Take main's arguments as compact-v1, not ABI-v1",
220
+ },
221
+ "source-dir": {
222
+ type: "string",
223
+ value: "<dir>",
224
+ help: "Resolve the program's relative imports here (default: beside it; from stdin, .)",
225
+ },
226
+ };
227
+ const SALT = {
228
+ salt: {
229
+ type: "string",
230
+ value: "<label>",
231
+ help: "Name one of the owner's Pots: salt = keccak256(label)",
232
+ },
233
+ "salt-hex": { type: "string", value: "<bytes32>", help: "…or give its salt exactly" },
234
+ };
235
+ const COOK = {
236
+ owner: {
237
+ type: "string",
238
+ value: "<address>",
239
+ help: "The Pot's owner, which derives the Pot with the salt (default 0)",
240
+ },
241
+ pot: { type: "string", value: "<address>", help: "Or the Pot itself, by address", only: "evm" },
242
+ ...SALT,
243
+ value: {
244
+ type: "string",
245
+ value: "<wei>",
246
+ help: "Kitchen fee plus native spent (default: read the fee)",
247
+ only: "evm",
248
+ },
249
+ "args-json": {
250
+ type: "string",
251
+ value: "<json|file>",
252
+ help: "main's arguments as a JSON array, inline or in a file",
253
+ },
254
+ account: {
255
+ type: "string",
256
+ multiple: true,
257
+ value: "NAME=<address>",
258
+ help: "An account main takes, by name: an address, pot, owner, pot:USDC (the Pot's USDC account), mint:USDC or program:USDC (its token program)",
259
+ only: "svm",
260
+ },
261
+ via: {
262
+ type: "string",
263
+ value: "<kitchen|engine>",
264
+ help: "The Kitchen's cook on the Pot (default), or the engine's own, with no Pot",
265
+ only: "svm",
266
+ },
267
+ "max-execution-fee": {
268
+ type: "string",
269
+ value: "<lamports>",
270
+ help: "Refuse a cook whose execution fee is above this",
271
+ only: "svm",
272
+ },
273
+ };
274
+ const ENDPOINT = {
275
+ "rpc-url": { type: "string", value: "<url>", help: "The chain's RPC endpoint" },
276
+ config: {
277
+ type: "string",
278
+ value: "<file>",
279
+ help: 'Or a file of { "rpcUrls": { "<chain id>": "<url>" } }',
280
+ },
281
+ };
282
+ const SIGNER = {
283
+ wallet: {
284
+ type: "string",
285
+ value: "<name>",
286
+ help: "Sign with a wallet of the wallet directory (sauce wallet), EVM or Solana",
287
+ },
288
+ ...WALLETS,
289
+ ...PASSWORD,
290
+ keystore: {
291
+ type: "string",
292
+ value: "<path>",
293
+ help: "Sign with a JSON keystore (v3), with a password source",
294
+ only: "evm",
295
+ },
296
+ "private-key": {
297
+ type: "string",
298
+ value: "<hex>",
299
+ help: "Or sign with a raw key (lands in shell history)",
300
+ only: "evm",
301
+ },
302
+ keypair: {
303
+ type: "string",
304
+ value: "<path>",
305
+ help: "Sign with a keypair file (a JSON array of 64 bytes)",
306
+ only: "svm",
307
+ },
308
+ };
309
+ const FUND = {
310
+ fund: {
311
+ type: "string",
312
+ multiple: true,
313
+ value: "<TOKEN:amount>",
314
+ help: "Pull tokens into the Pot in the cook: USDC:1.5, USDC:1500000n, ETH:0.01",
315
+ only: "evm",
316
+ },
317
+ "fund-mode": {
318
+ type: "string",
319
+ value: "<mode>",
320
+ help: "permit2 (default), permit, allowance or transfer",
321
+ only: "evm",
322
+ },
323
+ sweep: {
324
+ type: "boolean",
325
+ help: "Return what is left of each funded token afterwards",
326
+ only: "evm",
327
+ },
328
+ };
329
+ /** Never parsed as a flag: the words after it that are not flags are main's arguments
330
+ * (`splitArgv`). */
331
+ const ARGS = {
332
+ args: {
333
+ type: "boolean",
334
+ value: "<value>…",
335
+ help: "main's arguments in order (JSON for an array or tuple); -- before one like a flag",
336
+ },
337
+ };
338
+ const JSON_FLAG = { json: { type: "boolean", help: "Print one JSON object instead" } };
339
+ const FORMAT = {
340
+ format: {
341
+ type: "string",
342
+ value: "<json|cast>",
343
+ help: "json (default), or a `cast send` line with placeholders",
344
+ },
345
+ };
346
+ // ---------------------------------------------------------------------------------------------
347
+ // Reading the flags into command inputs
348
+ // ---------------------------------------------------------------------------------------------
349
+ /** The one `<file>` operand a compiling command takes. */
350
+ function fileOperand(args) {
351
+ const [file, ...rest] = args.positionals;
352
+ if (file === undefined) {
353
+ throw new UsageError("missing <file>: the SauceScript program, or - to read it from stdin");
354
+ }
355
+ if (rest.length > 0)
356
+ throw new UsageError(`unexpected argument ${rest[0]}: give one <file>`);
357
+ return file;
358
+ }
359
+ /**
360
+ * The chain a program runs on: `--chain`, else the file's `// @chain`, else — for `--target svm`
361
+ * or `// @target svm` alone — the one SVM chain (`inputs.ts#programChain`).
362
+ */
363
+ function chainOf(args, file, text, fallback) {
364
+ const chain = stringFlag(args, "chain");
365
+ const target = stringFlag(args, "target");
366
+ return programChain({ ...(chain === undefined ? {} : { chain }), ...(target === undefined ? {} : { target }) }, file, text, fallback);
367
+ }
368
+ /**
369
+ * The endpoints the command reaches the chains a program's intents go to with: every chain in
370
+ * `--config`'s `rpcUrls`, or with `--rpc-url` only the program's own `source` chain.
371
+ */
372
+ function endpointsOf(args, io, source) {
373
+ const rpcUrl = stringFlag(args, "rpc-url");
374
+ const config = stringFlag(args, "config");
375
+ let urls;
376
+ return (chain) => {
377
+ if (rpcUrl !== undefined)
378
+ return chain.id === source.id ? endpoint(args, io, chain) : undefined;
379
+ if (config === undefined)
380
+ return undefined;
381
+ urls ??= (() => {
382
+ try {
383
+ const parsed = JSON.parse(readInput(io, config));
384
+ return typeof parsed?.rpcUrls === "object" && parsed.rpcUrls !== null
385
+ ? parsed.rpcUrls
386
+ : {};
387
+ }
388
+ catch {
389
+ return {};
390
+ }
391
+ })();
392
+ // A chain the file has no entry for is one the command does not reach; a bad entry is named.
393
+ return Object.hasOwn(urls, String(chain.id)) ? endpoint(args, io, chain) : undefined;
394
+ };
395
+ }
396
+ /**
397
+ * `--intent-execution-fee auto`: the fee the program's intents' destination Kitchens charge, read
398
+ * from each through `endpoints`. The program is compiled once with a fee of zero to find which
399
+ * intents run a program there; one with none pays no fee.
400
+ */
401
+ async function autoExecutionFee(input, io, endpoints, gate) {
402
+ const probe = compileProgram({ ...input, intents: { ...input.intents, executionFee: 0n } }, io);
403
+ // Before the fee is read: a command refused on these chains reads nothing for them.
404
+ if (gate !== undefined)
405
+ gated(gate, input.chain, probe.intents);
406
+ const cooks = intentCooks(probe.intents);
407
+ if (cooks.length === 0) {
408
+ io.stderr("--intent-execution-fee auto: no intent here runs a program, so none pays a fee\n");
409
+ return undefined;
410
+ }
411
+ const fee = await destinationFee(cooks, endpoints);
412
+ const chains = [...new Set(cooks.map((cook) => cook.destination.slug))].join(" and ");
413
+ io.stderr(`--intent-execution-fee auto: the Kitchen on ${chains} charges ${fee} wei\n`);
414
+ return fee;
415
+ }
416
+ /** Refuses `gate`'s command on a preview chain among `source` and the `intents` it opens. */
417
+ function gated(gate, source, intents = []) {
418
+ requireSupported(gate.action, gate.by === "destinations"
419
+ ? intents.map((intent) => intent.destination)
420
+ : gate.by === "source"
421
+ ? [source]
422
+ : [source, ...intentDestinations(intents)]);
423
+ }
424
+ /** What stdin carried, named in messages. */
425
+ export const STDIN = "<stdin>";
426
+ /** The program's text: a file's, or stdin's for `-`, read once — or one already read. */
427
+ function programText(io, operand) {
428
+ if (typeof operand !== "string")
429
+ return operand;
430
+ // A `#!` line, which makes the file a command, is blanked: the compile never sees it.
431
+ return operand === "-"
432
+ ? { file: STDIN, text: withoutShebang(io.readStdin()), stdin: true }
433
+ : { file: operand, text: withoutShebang(readInput(io, operand)), stdin: false };
434
+ }
435
+ /**
436
+ * A program operand's input — a file, or `-` for stdin — and `fallback` its chain when neither
437
+ * `--chain` nor its header says.
438
+ */
439
+ async function programInput(args, io, operand = fileOperand(args), fallback, gate) {
440
+ const { file, text, stdin } = programText(io, operand);
441
+ const sourceDir = stringFlag(args, "source-dir");
442
+ const chain = chainOf(args, file, text, fallback);
443
+ if (gate !== undefined && gate.by !== "destinations")
444
+ gated(gate, chain);
445
+ const definesFile = stringFlag(args, "defines");
446
+ const deadline = stringFlag(args, "intent-deadline");
447
+ const rewardDeadline = stringFlag(args, "intent-reward-deadline");
448
+ const creator = stringFlag(args, "intent-creator");
449
+ const prover = stringFlag(args, "intent-prover");
450
+ const fee = stringFlag(args, "intent-execution-fee");
451
+ const fundVia = stringFlag(args, "intent-fund-via");
452
+ const defines = {
453
+ ...(definesFile === undefined
454
+ ? {}
455
+ : parseDefinesFile(readInput(io, definesFile), definesFile, chain.kind)),
456
+ ...parseDefines(repeatedFlag(args, "define"), chain.kind),
457
+ };
458
+ definesReach(file, text, Object.keys(defines));
459
+ const addresses = addressDefines(repeatedFlag(args, "define"), definesFile === undefined ? undefined : readInput(io, definesFile), chain.kind);
460
+ const input = {
461
+ file,
462
+ text,
463
+ ...(addresses.length === 0 ? {} : { addressDefines: addresses }),
464
+ ...(stdin ? { stdin } : {}),
465
+ ...(sourceDir === undefined ? {} : { sourceDir }),
466
+ chain,
467
+ compactArgs: args.values["compact-args"] === true,
468
+ defines,
469
+ intents: {
470
+ ...(deadline === undefined
471
+ ? {}
472
+ : { deadline: parseUnixSeconds("intent-deadline", deadline) }),
473
+ ...(rewardDeadline === undefined
474
+ ? {}
475
+ : { rewardDeadline: parseUnixSeconds("intent-reward-deadline", rewardDeadline) }),
476
+ ...(creator === undefined ? {} : { creator: parseAddress("intent-creator", creator) }),
477
+ ...(prover === undefined ? {} : { prover: parseAddress("intent-prover", prover) }),
478
+ ...(fee === undefined || fee === "auto"
479
+ ? {}
480
+ : { executionFee: parseWei("intent-execution-fee", fee) }),
481
+ ...(fundVia === undefined ? {} : { fundVia: parseFundVia(fundVia) }),
482
+ },
483
+ };
484
+ if (fee !== "auto")
485
+ return input;
486
+ const executionFee = await autoExecutionFee(input, io, endpointsOf(args, io, chain), gate);
487
+ return executionFee === undefined
488
+ ? input
489
+ : { ...input, intents: { ...input.intents, executionFee } };
490
+ }
491
+ /**
492
+ * A compiling command's operand: a SauceScript file, or an actions document (a JSON object with
493
+ * `actions`), which `actions.ts` lowers into the same `ProgramInput` — so its compile, cook, Pot,
494
+ * arguments and funding are every program's.
495
+ */
496
+ async function programOperand(args, io, gate) {
497
+ // Read once, from the file or stdin (`-`), then told apart.
498
+ const operand = programText(io, fileOperand(args));
499
+ if (!isActionsDocument(operand.text))
500
+ return programInput(args, io, operand, undefined, gate);
501
+ const program = await actionsProgram(actionsOperand(args, operand.file, operand.text));
502
+ if (gate !== undefined)
503
+ gated(gate, program.chain);
504
+ return program;
505
+ }
506
+ /** An actions document's input, from the flags a program command takes. */
507
+ function actionsOperand(args, file, text) {
508
+ if (repeatedFlag(args, "define").length > 0 || stringFlag(args, "defines") !== undefined) {
509
+ throw new UsageError("--define and --defines give a SauceScript program its defines; an actions document's " +
510
+ "values are its own fields");
511
+ }
512
+ const target = stringFlag(args, "target");
513
+ if (target !== undefined && parseTarget(target) !== "evm") {
514
+ throw new UsageError(`${file} is an actions document, and actions run on EVM chains`);
515
+ }
516
+ const chain = stringFlag(args, "chain");
517
+ return {
518
+ file,
519
+ text,
520
+ ...(chain === undefined ? {} : { chain }),
521
+ compactArgs: args.values["compact-args"] === true,
522
+ };
523
+ }
524
+ /** `main`'s arguments: the words after `--args`, or `--args-json`'s array — never both. */
525
+ function argsInput(args, io, trailing) {
526
+ const json = stringFlag(args, "args-json");
527
+ if (json !== undefined && trailing !== undefined) {
528
+ throw new UsageError("give --args or --args-json, not both");
529
+ }
530
+ if (trailing !== undefined)
531
+ return { args: { from: "--args", values: trailing } };
532
+ if (json === undefined)
533
+ return {};
534
+ // Inline when it reads as JSON (an array, or the object someone meant as one); a path otherwise.
535
+ const text = /^\s*[[{]/.test(json) ? json : readInput(io, json);
536
+ let values;
537
+ try {
538
+ values = JSON.parse(text);
539
+ }
540
+ catch (error) {
541
+ throw new UsageError(`--args-json: not JSON (${error.message})`);
542
+ }
543
+ if (!Array.isArray(values)) {
544
+ throw new UsageError("--args-json: expected a JSON array of main's arguments, in order");
545
+ }
546
+ return { args: { from: "--args-json", values } };
547
+ }
548
+ /** The salt `--salt`/`--salt-hex` choose (zero when neither). */
549
+ const saltOf = (args) => parseSalt(stringFlag(args, "salt"), stringFlag(args, "salt-hex"));
550
+ /**
551
+ * The Pot a cook runs on: `--pot`, or derived from `--owner` — or, when `signer` is given (a run),
552
+ * from the signer, whose Pot it must be anyway (`inputs.ts#potTarget`).
553
+ */
554
+ function potInput(args, signer) {
555
+ return potTarget({
556
+ pot: stringFlag(args, "pot"),
557
+ owner: stringFlag(args, "owner"),
558
+ salt: stringFlag(args, "salt"),
559
+ saltHex: stringFlag(args, "salt-hex"),
560
+ }, signer);
561
+ }
562
+ /** Everything an EVM cook command takes from its flags. */
563
+ function cookInput(args, io, trailing, signer, program) {
564
+ const value = stringFlag(args, "value");
565
+ if (repeatedFlag(args, "account").length > 0) {
566
+ throw new UsageError(`--account names a Solana program's accounts; a program on ${program.chain.slug} takes none`);
567
+ }
568
+ for (const flag of ["via", "max-execution-fee"]) {
569
+ if (stringFlag(args, flag) !== undefined) {
570
+ throw new UsageError(`--${flag} is for a Solana cook, which can reach the engine through the Kitchen or ` +
571
+ `directly; on ${program.chain.slug} a cook is the Pot's, and --value carries the fee`);
572
+ }
573
+ }
574
+ return {
575
+ ...program,
576
+ target: potInput(args, signer),
577
+ ...(value === undefined ? {} : { value: parseWei("value", value) }),
578
+ ...argsInput(args, io, trailing),
579
+ };
580
+ }
581
+ /** The RPC endpoint for `chain`, from `--rpc-url` or `--config`; `undefined` when neither. */
582
+ function endpoint(args, io, chain) {
583
+ const rpcUrl = stringFlag(args, "rpc-url");
584
+ const config = stringFlag(args, "config");
585
+ if (rpcUrl !== undefined && config !== undefined) {
586
+ throw new UsageError("give --rpc-url or --config, not both");
587
+ }
588
+ const url = endpointFor(chain, rpcUrl, config === undefined ? undefined : { path: config, text: readInput(io, config) });
589
+ // A provider URL often carries a key: whatever reports it — this CLI, viem, the Solana client —
590
+ // it is scrubbed from everything printed.
591
+ if (url !== undefined)
592
+ secret(url);
593
+ return url;
594
+ }
595
+ function requiredEndpoint(args, io, chain) {
596
+ const url = endpoint(args, io, chain);
597
+ if (url === undefined) {
598
+ throw new UsageError(`missing --rpc-url <url> (or --config <file>): the ${chain.slug} endpoint`);
599
+ }
600
+ return url;
601
+ }
602
+ /** The password source the flags name: `--password-env`, `--password-file`, `--password-command`,
603
+ * or else the prompt. */
604
+ const passwordOf = (args) => passwordSource({
605
+ env: stringFlag(args, "password-env"),
606
+ file: stringFlag(args, "password-file"),
607
+ command: stringFlag(args, "password-command"),
608
+ });
609
+ /** The wallet directory: `--wallets` (bare, the default), else the one `io` names, else
610
+ * `~/.sauce/wallets`. */
611
+ const walletsOf = (args, io) => new WalletStore(stringFlag(args, "wallets") || io.walletsDir || defaultWalletsDir());
612
+ /** `--wallet`'s wallet as its file names it, read with no password: its kind and address. */
613
+ const walletGiven = (args, io) => {
614
+ const name = stringFlag(args, "wallet");
615
+ return name === undefined ? undefined : walletsOf(args, io).info(name);
616
+ };
617
+ /** `--wallet`, unlocked with the password source given. */
618
+ const unlockGiven = (args, io, info) => unlockWallet(walletsOf(args, io), info.name, passwordOf(args), io);
619
+ /** Refuses two signers for one kind of chain. */
620
+ function oneSigner(args, flags) {
621
+ const given = flags.filter((flag) => stringFlag(args, flag) !== undefined);
622
+ if (given.length > 1) {
623
+ throw new UsageError(`give one signer, not ${given.map((flag) => `--${flag}`).join(" and ")}`);
624
+ }
625
+ }
626
+ /** The EVM signer the flags give — an EVM `--wallet`, `--keystore` or `--private-key` — if any. */
627
+ async function evmSigner(args, io) {
628
+ const wallet = walletGiven(args, io);
629
+ if (wallet?.kind === "evm") {
630
+ oneSigner(args, ["wallet", "keystore", "private-key"]);
631
+ const unlocked = await unlockGiven(args, io, wallet);
632
+ return unlocked.kind === "evm" ? unlocked.account : undefined;
633
+ }
634
+ if (stringFlag(args, "keystore") === undefined && stringFlag(args, "private-key") === undefined) {
635
+ return undefined;
636
+ }
637
+ const keystore = stringFlag(args, "keystore");
638
+ const privateKey = stringFlag(args, "private-key");
639
+ return loadSigner({
640
+ ...(keystore === undefined ? {} : { keystore }),
641
+ ...(privateKey === undefined ? {} : { privateKey }),
642
+ password: passwordOf(args),
643
+ }, io);
644
+ }
645
+ /** The Solana signer the flags give — a Solana `--wallet`, or `--keypair` — if any. */
646
+ async function svmSigner(args, io) {
647
+ const wallet = walletGiven(args, io);
648
+ if (wallet?.kind === "solana") {
649
+ oneSigner(args, ["wallet", "keypair"]);
650
+ const unlocked = await unlockGiven(args, io, wallet);
651
+ return unlocked.kind === "solana" ? unlocked.signer : undefined;
652
+ }
653
+ const keypair = stringFlag(args, "keypair");
654
+ return keypair === undefined ? undefined : loadKeypair(keypair, io);
655
+ }
656
+ /** An EVM command's signer, required: never a Solana key. */
657
+ const signerOf = async (args, io) => {
658
+ if (stringFlag(args, "keypair") !== undefined) {
659
+ throw new UsageError("--keypair is a Solana keypair; an EVM transaction is signed with --wallet, --keystore or " +
660
+ "--private-key");
661
+ }
662
+ const wallet = walletGiven(args, io);
663
+ if (wallet !== undefined)
664
+ evmAddressOf(wallet);
665
+ const account = await evmSigner(args, io);
666
+ if (account !== undefined)
667
+ return account;
668
+ return loadSigner({ password: passwordOf(args) }, io);
669
+ };
670
+ /**
671
+ * The EVM signer's address, read with no more than it needs: a wallet's or a keystore's `address`
672
+ * field (no password), a raw key's own, and only for a keystore without one, the keystore unlocked.
673
+ */
674
+ async function signerAddress(args, io) {
675
+ const wallet = walletGiven(args, io);
676
+ if (wallet !== undefined) {
677
+ oneSigner(args, ["wallet", "keystore", "private-key"]);
678
+ return evmAddressOf(wallet);
679
+ }
680
+ const keystore = stringFlag(args, "keystore");
681
+ if (keystore !== undefined && stringFlag(args, "private-key") === undefined) {
682
+ const named = keystoreAddress(readInput(io, keystore));
683
+ if (named !== undefined)
684
+ return named;
685
+ }
686
+ return (await signerOf(args, io)).address;
687
+ }
688
+ /**
689
+ * Who approves what a run sends before its cook: `--auto-approve`, which says so for each action it
690
+ * approves, or the person at the terminal (`io.confirm`).
691
+ */
692
+ function approverOf(args, io) {
693
+ const auto = args.values["auto-approve"] === true;
694
+ return {
695
+ auto,
696
+ canAsk: auto || io.canAsk(),
697
+ approve: async (action, question) => {
698
+ if (!auto)
699
+ return io.confirm(question);
700
+ io.stderr(`auto-approved: ${action}\n`);
701
+ return true;
702
+ },
703
+ };
704
+ }
705
+ /** Whether the flags give an EVM signer: an EVM `--wallet`, `--keystore` or `--private-key`. */
706
+ const hasSigner = (args, io) => walletGiven(args, io)?.kind === "evm" ||
707
+ stringFlag(args, "keystore") !== undefined ||
708
+ stringFlag(args, "private-key") !== undefined;
709
+ /** Whether the flags give a Solana signer: a Solana `--wallet`, or `--keypair`. */
710
+ const hasSvmSigner = (args, io) => walletGiven(args, io)?.kind === "solana" || stringFlag(args, "keypair") !== undefined;
711
+ // --- The intent lifecycle -------------------------------------------------------------------
712
+ /** The intent store: `--store`, else the one `io` names, else `~/.sauce/intents`. */
713
+ const storeOf = (args, io) => new IntentStore(stringFlag(args, "store") ?? io.storeDir ?? defaultStoreDir());
714
+ /**
715
+ * The endpoint of each chain a lifecycle command reads, when it has one: `--config`'s entry for it,
716
+ * or `--rpc-url` for the one chain that URL serves (asked once). Unlike `endpoint`, a chain with
717
+ * none is `undefined`, not an error: a command reads what it can, and says what it could not.
718
+ */
719
+ async function endpointLookup(args, io) {
720
+ const rpcUrl = stringFlag(args, "rpc-url");
721
+ const config = stringFlag(args, "config");
722
+ if (rpcUrl !== undefined && config !== undefined) {
723
+ throw new UsageError("give --rpc-url or --config, not both");
724
+ }
725
+ if (rpcUrl !== undefined) {
726
+ secret(rpcUrl);
727
+ const served = await chainServedBy(rpcUrl);
728
+ return (chain) => (chain.id === served.id ? rpcUrl : undefined);
729
+ }
730
+ if (config === undefined)
731
+ return () => undefined;
732
+ const text = readInput(io, config);
733
+ let urls = {};
734
+ try {
735
+ urls = (JSON.parse(text).rpcUrls ?? {});
736
+ }
737
+ catch {
738
+ // `endpointFor` names the problem below, for the first chain asked about.
739
+ }
740
+ return (chain) => urls[String(chain.id)] === undefined
741
+ ? undefined
742
+ : (() => {
743
+ const url = endpointFor(chain, undefined, { path: config, text });
744
+ secret(url);
745
+ return url;
746
+ })();
747
+ }
748
+ /** Records what a sent transaction published in the store, with a note per intent stored. */
749
+ const storing = (args, io, chain, rpcUrl) => async (sent) => {
750
+ const store = storeOf(args, io);
751
+ try {
752
+ const records = await rememberPublished(store, chain, rpcUrl, sent);
753
+ return records.map((record) => `stored intent ${record.intentHash} in ${store.dir}`);
754
+ }
755
+ catch (error) {
756
+ return [
757
+ `warning: ${sent.hash} was sent, but what it published was not stored in ${store.dir}: ` +
758
+ (error instanceof Error ? error.message : String(error)),
759
+ ];
760
+ }
761
+ };
762
+ /** What every lifecycle command shares: the store, the endpoints, the signer and the approvals. */
763
+ async function lifecycleContext(args, io) {
764
+ const endpoint = await endpointLookup(args, io);
765
+ const account = await evmSigner(args, io);
766
+ const solanaSigner = await svmSigner(args, io);
767
+ const api = stringFlag(args, "api");
768
+ const keyFile = stringFlag(args, "api-key-file");
769
+ if (keyFile !== undefined && api === undefined) {
770
+ throw new UsageError("--api-key-file goes with --api");
771
+ }
772
+ const key = keyFile === undefined ? undefined : readInput(io, keyFile).trim();
773
+ if (key !== undefined)
774
+ secret(key);
775
+ if (api !== undefined)
776
+ secret(api);
777
+ return {
778
+ store: storeOf(args, io),
779
+ endpoint,
780
+ ...(account === undefined ? {} : { account }),
781
+ ...(solanaSigner === undefined ? {} : { svmSigner: solanaSigner }),
782
+ approver: approverOf(args, io),
783
+ ...(api === undefined ? {} : { api: { url: api, ...(key === undefined ? {} : { key }) } }),
784
+ };
785
+ }
786
+ /**
787
+ * The intents a lifecycle command acts on: the store's, named by hash (one or several), or the
788
+ * file's, built as `publish` builds them (`--chain` its source). `--chain` with hashes must be
789
+ * their source.
790
+ */
791
+ async function lifecycleTargets(args, io, store, gate) {
792
+ const operands = args.positionals;
793
+ if (operands.length === 0) {
794
+ throw new UsageError("missing <file | intent-hash>: the intent, by its file or its hash");
795
+ }
796
+ if (operands.every(isIntentHash)) {
797
+ const targets = operands.flatMap((hash) => storedTargets(store, hash));
798
+ const chainFlag = stringFlag(args, "chain");
799
+ if (chainFlag !== undefined) {
800
+ const chain = parseChain(chainFlag);
801
+ const other = targets.find((target) => target.record.source.chainId !== chain.id);
802
+ if (other !== undefined) {
803
+ throw new UsageError(`--chain ${chain.slug} is not the source of ${other.record.intentHash}, which ` +
804
+ `${other.record.source.chain} published`);
805
+ }
806
+ }
807
+ return targets;
808
+ }
809
+ if (operands.length > 1) {
810
+ throw new UsageError("give one <file>, or one or more intent hashes");
811
+ }
812
+ return fileTargets(await programInput(args, io, operands[0], undefined, gate), io, store);
813
+ }
814
+ /**
815
+ * What a lifecycle command that sends (or prints) a transaction acts on: its intents, refused on a
816
+ * preview chain by `gate` before the context reaches an endpoint or unlocks a key — then the
817
+ * context.
818
+ */
819
+ async function lifecycleOf(args, io, gate) {
820
+ const targets = await lifecycleTargets(args, io, storeOf(args, io), gate);
821
+ requireSupported(gate.action, targets.map(({ record }) => requireChain(gate.by === "source" ? record.source.chainId : record.destination.chainId)));
822
+ return { targets, context: await lifecycleContext(args, io) };
823
+ }
824
+ /** The questions `sauce intent publish` asks with no file, as flags. */
825
+ const CREATE = {
826
+ source: { type: "string", value: "<chain>", help: "No file: the source chain (the reward's)" },
827
+ destination: { type: "string", value: "<chain>", help: "…the destination chain" },
828
+ token: { type: "string", value: "<symbol|address>", help: "…the token delivered there" },
829
+ amount: { type: "string", value: "<n>", help: "…how much, in whole units" },
830
+ recipient: { type: "string", value: "<address>", help: "…to whom (default: the signer)" },
831
+ "reward-token": { type: "string", value: "<symbol|address>", help: "…the reward's token" },
832
+ reward: { type: "string", value: "<n>", help: "…the reward, in whole units" },
833
+ prover: { type: "string", value: "<role|address>", help: "…the prover (HyperProver)" },
834
+ "fill-deadline": {
835
+ type: "string",
836
+ value: "<when>",
837
+ help: "…the last second to fill: unix seconds, or +30m, +2h, +1d",
838
+ },
839
+ "reward-deadline": {
840
+ type: "string",
841
+ value: "<when>",
842
+ help: "…from when it is refundable, if no fill is proven",
843
+ },
844
+ out: { type: "string", value: "<path>", help: "…the .sauce.ts file to write" },
845
+ };
846
+ /**
847
+ * `sauce intent publish` with no file: the intent made step by step (`create.ts`), written as a
848
+ * file, rehearsed on both chains, then — with a signer, once approved — published and stored, as
849
+ * `sauce intent publish <file>` with the same flags would.
850
+ */
851
+ async function createAndPublish(args, io) {
852
+ // The chains the flags name are refused here, before an endpoint or a key; one asked for is
853
+ // refused as soon as it is chosen (`create.ts`), and only supported ones are offered.
854
+ const named = [
855
+ stringFlag(args, "source") ?? stringFlag(args, "chain"),
856
+ stringFlag(args, "destination"),
857
+ ];
858
+ requireSupported("publishing intents", named.flatMap((chain) => (chain === undefined ? [] : [parseChain(chain)])));
859
+ const lookup = await endpointLookup(args, io);
860
+ const account = hasSigner(args, io) ? await signerOf(args, io) : undefined;
861
+ const flag = (name) => stringFlag(args, name);
862
+ const given = {
863
+ ...((flag("source") ?? flag("chain")) ? { source: (flag("source") ?? flag("chain")) } : {}),
864
+ ...(flag("destination") === undefined ? {} : { destination: flag("destination") }),
865
+ ...(flag("token") === undefined ? {} : { token: flag("token") }),
866
+ ...(flag("amount") === undefined ? {} : { amount: flag("amount") }),
867
+ ...(flag("recipient") === undefined ? {} : { recipient: flag("recipient") }),
868
+ ...(flag("reward-token") === undefined ? {} : { rewardToken: flag("reward-token") }),
869
+ ...(flag("reward") === undefined ? {} : { reward: flag("reward") }),
870
+ ...(flag("prover") === undefined ? {} : { prover: flag("prover") }),
871
+ ...(flag("fill-deadline") === undefined ? {} : { fillDeadline: flag("fill-deadline") }),
872
+ ...(flag("reward-deadline") === undefined ? {} : { rewardDeadline: flag("reward-deadline") }),
873
+ ...(flag("intent-fund-via") === undefined ? {} : { fundVia: flag("intent-fund-via") }),
874
+ ...(flag("out") === undefined ? {} : { out: flag("out") }),
875
+ };
876
+ const created = await createIntent({
877
+ given,
878
+ ...(io.ask === undefined ? {} : { ask: io.ask }),
879
+ endpoint: lookup,
880
+ ...(account === undefined ? {} : { signer: account.address }),
881
+ now: BigInt(Math.floor(Date.now() / 1000)),
882
+ writeText: io.writeText,
883
+ exists: (path) => io.readModule(path) !== undefined,
884
+ });
885
+ io.stderr(`${created.summary.join("\n")}\n\n`);
886
+ const creator = account?.address ?? flag("intent-creator");
887
+ if (creator === undefined) {
888
+ throw new UsageError(`${created.file} is written; publishing it needs a signer (the creator), or ` +
889
+ "--intent-creator with --format json to print the transactions unsigned");
890
+ }
891
+ const program = {
892
+ file: created.file,
893
+ text: created.text,
894
+ chain: created.source,
895
+ compactArgs: false,
896
+ defines: {},
897
+ intents: {
898
+ deadline: created.deadline,
899
+ rewardDeadline: created.rewardDeadline,
900
+ creator,
901
+ prover: created.prover,
902
+ fundVia: created.fundVia,
903
+ },
904
+ };
905
+ const rpcUrl = lookup(created.source);
906
+ if (rpcUrl === undefined) {
907
+ throw new UsageError(`publishing needs ${created.source.slug}'s endpoint: --config with it`);
908
+ }
909
+ // Rehearsed on the source, then on the destination, before anything is sent.
910
+ const dry = await publishCommand({ ...program, dryRun: true, rpcUrl, from: creator }, io);
911
+ io.stderr(`Publishing, rehearsed on ${created.source.slug}:\n${dry.text}\n\n`);
912
+ if (dry.exitCode !== undefined && dry.exitCode !== 0) {
913
+ return {
914
+ ...dry,
915
+ notes: [`${created.file} is written, and not published: the rehearsal reverts`],
916
+ };
917
+ }
918
+ if (lookup(created.destination) !== undefined) {
919
+ const fill = await fillCommand({
920
+ intents: fillTargets(program, io),
921
+ from: created.file,
922
+ labels: [],
923
+ endpointOf: (chain) => lookup(chain) ?? requiredEndpoint(args, io, chain),
924
+ sourceEndpointOf: lookup,
925
+ endpointFlag: "--config",
926
+ });
927
+ io.stderr(`Filling, rehearsed on ${created.destination.slug} (as a solver will):\n${fill.text}\n\n`);
928
+ }
929
+ if (account === undefined) {
930
+ return publishCommand({ ...program, dryRun: false, format: "json", rpcUrl, from: creator }, io);
931
+ }
932
+ const action = `publish ${created.file} from ${account.address}`;
933
+ const answer = await approverOf(args, io).approve(action, `Publish ${created.file} from ${account.address}? [y/N] `);
934
+ if (answer === undefined) {
935
+ throw new CliError(`${created.file} is written, and not published: ${unapproved([action]).message}`);
936
+ }
937
+ if (!answer)
938
+ throw new CliError(`${created.file} is written, and not published: you declined`);
939
+ return publishCommand({
940
+ ...program,
941
+ dryRun: false,
942
+ rpcUrl,
943
+ account,
944
+ onSent: storing(args, io, created.source, rpcUrl),
945
+ }, io);
946
+ }
947
+ /** The Eco API gateway, an optional second source of an intent's status. */
948
+ const API = {
949
+ api: {
950
+ type: "string",
951
+ value: "<url>",
952
+ help: "Also ask the Eco API gateway at this URL (none is built in)",
953
+ },
954
+ "api-key-file": { type: "string", value: "<path>", help: "…and send the key in this file" },
955
+ };
956
+ /** The flags every lifecycle command takes. */
957
+ /** An intent command's signer: an EVM one, since the Portal it drives is an EVM contract. */
958
+ const EVM_SIGNER = Object.fromEntries(Object.entries(SIGNER).filter(([name]) => name !== "keypair"));
959
+ const LIFECYCLE = {
960
+ ...PROGRAM,
961
+ ...ENDPOINT,
962
+ ...EVM_SIGNER,
963
+ keypair: {
964
+ type: "string",
965
+ value: "<path>",
966
+ help: "Sign a step on Solana (an intent's fill, proof or cancellation there) with a keypair file",
967
+ only: "svm",
968
+ },
969
+ "auto-approve": {
970
+ type: "boolean",
971
+ help: "Approve what it spends beyond gas (a fee, tokens) without asking",
972
+ },
973
+ store: {
974
+ type: "string",
975
+ value: "<dir>",
976
+ help: "The intent store (default: ~/.sauce/intents)",
977
+ },
978
+ };
979
+ /**
980
+ * `--fund`, `--fund-mode` and `--sweep`, read into the callback `runCommand`/`simulateCommand` call
981
+ * once the Pot is there; `undefined` with no `--fund`. `send` is whether the run may approve and
982
+ * transfer first (`run`) or only say it would (`simulate`).
983
+ */
984
+ function fundingOf(args, io, chain, rpcUrl, send, account) {
985
+ const mode = stringFlag(args, "fund-mode");
986
+ return fundingFor({
987
+ chain,
988
+ rpcUrl,
989
+ fund: repeatedFlag(args, "fund"),
990
+ ...(mode === undefined ? {} : { mode }),
991
+ sweep: args.values.sweep === true,
992
+ send,
993
+ ...(account === undefined ? {} : { account }),
994
+ approver: approverOf(args, io),
995
+ });
996
+ }
997
+ /** `--assume-balance`, each named once. */
998
+ function assumedBalancesOf(args, chain) {
999
+ return assumedBalances(repeatedFlag(args, "assume-balance"), chain);
1000
+ }
1001
+ // --- Solana ----------------------------------------------------------------------------------
1002
+ /** A Solana command's signer, required: a Solana `--wallet` or `--keypair`, never an EVM key. */
1003
+ async function keypairOf(args, io) {
1004
+ if (stringFlag(args, "keystore") !== undefined || stringFlag(args, "private-key") !== undefined) {
1005
+ throw new UsageError("--keystore and --private-key are EVM keys: on Solana, sign with --wallet <name> (a " +
1006
+ "Solana wallet) or --keypair <path>");
1007
+ }
1008
+ const wallet = walletGiven(args, io);
1009
+ if (wallet?.kind === "evm") {
1010
+ throw new UsageError(`wallet ${wallet.name} is an EVM wallet: on Solana, sign with a Solana wallet ` +
1011
+ "(sauce wallet new <name> --solana) or --keypair <path>");
1012
+ }
1013
+ const signer = await svmSigner(args, io);
1014
+ if (signer !== undefined)
1015
+ return signer;
1016
+ throw new UsageError("missing a signer: --wallet <name> (a Solana wallet) or --keypair <path>");
1017
+ }
1018
+ /** The Solana signer's address, read with no password where a wallet names it. */
1019
+ async function keypairAddress(args, io) {
1020
+ const wallet = walletGiven(args, io);
1021
+ if (wallet?.kind === "solana") {
1022
+ oneSigner(args, ["wallet", "keypair"]);
1023
+ return wallet.address;
1024
+ }
1025
+ return (await keypairOf(args, io)).address;
1026
+ }
1027
+ /** The Pot's owner on Solana: the signer when there is one (and `--owner` must agree), else
1028
+ * `--owner`. */
1029
+ function svmOwner(args, signer, why = "with a signer, the owner is the signer") {
1030
+ const owner = stringFlag(args, "owner");
1031
+ if (signer !== undefined) {
1032
+ if (owner !== undefined && parsePubkey("owner", owner) !== signer) {
1033
+ throw new UsageError(`--owner ${owner} is not the signer, ${signer}: ${why}. Leave --owner out, or sign as ` +
1034
+ "its owner.");
1035
+ }
1036
+ return signer;
1037
+ }
1038
+ if (owner === undefined) {
1039
+ throw new UsageError("missing --owner <address>: whose Pot (a base58 public key)");
1040
+ }
1041
+ return parsePubkey("owner", owner);
1042
+ }
1043
+ /** Everything a Solana cook command takes from its flags. */
1044
+ function svmCookInput(args, io, trailing, program, signer) {
1045
+ if (stringFlag(args, "pot") !== undefined) {
1046
+ throw new UsageError("on Solana a cook names its Pot by owner and salt, which the Kitchen derives it from: give " +
1047
+ "--owner (and --salt), not --pot");
1048
+ }
1049
+ if (stringFlag(args, "value") !== undefined) {
1050
+ throw new UsageError("--value is for EVM: on Solana the Kitchen's fee is read from the cluster, and lamports a " +
1051
+ "program spends come from its accounts");
1052
+ }
1053
+ if (stringFlag(args, "format") === "cast") {
1054
+ throw new UsageError("--format cast prints an EVM transaction; a Solana one is base64 JSON");
1055
+ }
1056
+ const via = stringFlag(args, "via");
1057
+ const maxFee = stringFlag(args, "max-execution-fee");
1058
+ return {
1059
+ ...program,
1060
+ owner: svmOwner(args, signer),
1061
+ ...saltOf(args),
1062
+ accounts: parseAccounts(repeatedFlag(args, "account")),
1063
+ ...argsInput(args, io, trailing),
1064
+ rpcUrl: requiredEndpoint(args, io, program.chain),
1065
+ ...(via === undefined ? {} : { via: parseVia(via) }),
1066
+ ...(maxFee === undefined
1067
+ ? {}
1068
+ : { maxExecutionFee: parseLamports("max-execution-fee", maxFee) }),
1069
+ };
1070
+ }
1071
+ /**
1072
+ * The endpoint and chain to fetch a transaction from: `--rpc-url` (its chain from `--chain`, else
1073
+ * from the endpoint itself) or `--config` with `--chain`; `undefined` when neither is given.
1074
+ */
1075
+ async function transactionEndpoint(args, io) {
1076
+ const rpcUrl = stringFlag(args, "rpc-url");
1077
+ const chainFlag = stringFlag(args, "chain");
1078
+ if (rpcUrl === undefined && stringFlag(args, "config") === undefined)
1079
+ return undefined;
1080
+ if (rpcUrl === undefined) {
1081
+ const chain = parseChain(requiredFlag(args, "chain", "<slug|id>"));
1082
+ return { rpcUrl: requiredEndpoint(args, io, chain), chain };
1083
+ }
1084
+ secret(rpcUrl);
1085
+ const chain = chainFlag === undefined ? await chainServedBy(rpcUrl) : parseChain(chainFlag);
1086
+ return { rpcUrl: requiredEndpoint(args, io, chain), chain };
1087
+ }
1088
+ /** A `0x…` operand: calldata, a payload, or (32 bytes, with an endpoint) a transaction hash. */
1089
+ function hexOperand(args, what) {
1090
+ const [operand, ...rest] = args.positionals;
1091
+ if (operand === undefined)
1092
+ throw new UsageError(`missing ${what}`);
1093
+ if (rest.length > 0)
1094
+ throw new UsageError(`unexpected argument ${rest[0]}`);
1095
+ if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(operand)) {
1096
+ throw new UsageError(`'${operand.slice(0, 20)}…' is not 0x-prefixed hex bytes`);
1097
+ }
1098
+ return operand;
1099
+ }
1100
+ const TX_HASH = /^0x[0-9a-fA-F]{64}$/;
1101
+ /** The chain `sauce pot` is for: `--chain`, required — it has no program to say. */
1102
+ const potChain = (args) => parseChain(requiredFlag(args, "chain", "<slug|id>"));
1103
+ const lines = (text) => ({ text: text.join("\n"), json: {} });
1104
+ /** The paragraph every command that builds or sends a transaction ends its details on. */
1105
+ const SUPPORTED_ONLY = (what) => [
1106
+ "",
1107
+ ...wrapped(`${what} only on a supported chain: ${supportedChainNames()}, for the initial release. On ` +
1108
+ "any other (a preview chain) it is refused before anything is read or signed, with the " +
1109
+ "supported chains and the GitHub issue to ask for that chain with; compile and simulate " +
1110
+ "work there."),
1111
+ ];
1112
+ const INTENT_VERBS = {
1113
+ publish: {
1114
+ usage: [
1115
+ "sauce intent publish <file | -> --chain <source> --rpc-url <url> (--keystore <path> | --private-key <hex>) [options]",
1116
+ "sauce intent publish [--source <chain>] [--destination <chain>] [--token <token>] [--amount <n>] …",
1117
+ ],
1118
+ summary: "Publish a file's fixed intents from a wallet (or make one, step by step)",
1119
+ flags: {
1120
+ ...PROGRAM,
1121
+ ...ENDPOINT,
1122
+ ...SIGNER,
1123
+ ...CREATE,
1124
+ "auto-approve": LIFECYCLE["auto-approve"],
1125
+ from: {
1126
+ type: "string",
1127
+ value: "<address>",
1128
+ help: "With --dry-run or --format and no signer: whose wallet",
1129
+ },
1130
+ "dry-run": {
1131
+ type: "boolean",
1132
+ help: "Rehearse the transactions together (eth_simulateV1); send nothing",
1133
+ },
1134
+ "assume-balance": {
1135
+ type: "string",
1136
+ multiple: true,
1137
+ value: "<TOKEN:amount>",
1138
+ help: "With --dry-run: give the wallet this balance, for the rehearsal only",
1139
+ },
1140
+ format: {
1141
+ type: "string",
1142
+ value: "<json|cast>",
1143
+ help: "Print the unsigned transactions instead of sending them",
1144
+ },
1145
+ store: LIFECYCLE.store,
1146
+ ...JSON_FLAG,
1147
+ ...HELP,
1148
+ },
1149
+ details: [
1150
+ "For a file whose intents are fixed when it is built — every amount a literal, a define or a",
1151
+ "top-level `const` of a literal — builds each intent off-chain (the SDK's own lowering) and",
1152
+ "sends the source chain's transactions from the signer's wallet: each reward token",
1153
+ "transferred to the intent's vault (and the native amount sent to it), then Portal.publish.",
1154
+ "No approval is asked for. The vault is the SDK's offline derivation, which the Portal's own",
1155
+ "intentVaultAddress must agree with or nothing is sent; only what the vault does not hold",
1156
+ "yet is transferred, and publish is sent only once the Portal counts the intent funded.",
1157
+ "Prints the intent hashes and the transactions. A file whose intent uses a value the program",
1158
+ "measures or computes while it runs, or that does anything besides open its intents, is",
1159
+ "refused: use `sauce run` on a Pot.",
1160
+ "",
1161
+ "--intent-fund-via publishAndFund funds it through the Portal instead: each reward token",
1162
+ "approved to the Portal (reset to zero first when a smaller allowance stands, as SafeERC20",
1163
+ "does), then publishAndFund, which records the intent Funded and emits IntentFunded.",
1164
+ "",
1165
+ "--dry-run rehearses the transactions together through eth_simulateV1 from the signer's",
1166
+ "wallet, or --from's with no key, then asks the Portal whether each intent is funded, and",
1167
+ "sends nothing. --assume-balance TOKEN:amount gives that wallet a balance for the rehearsal",
1168
+ "only, by state override (repeatable; the amount as `sauce run --fund` takes it;",
1169
+ "ETH:<amount> for the native currency), so a wallet that does not hold the reward yet can",
1170
+ "rehearse publishing it.",
1171
+ "",
1172
+ "With no <file>, it makes one: which chains, what is delivered and to whom, the reward",
1173
+ "(suggested: what is delivered plus a margin over the solver's destination costs — gas, the",
1174
+ "proof's fee, a Kitchen fee where one runs — priced through a Uniswap V3 pool there, and",
1175
+ "doubled so a fill is worth a solver's while), the fill and reward deadlines, the prover",
1176
+ "and how the reward is funded (--intent-fund-via, a transfer to the vault by default), each",
1177
+ "asked at a terminal unless its flag gives it (with no terminal, every flag still needed is",
1178
+ "named). It writes the intent as a .sauce.ts file (--out, default",
1179
+ "intent-<source>-to-<destination>-<time>.sauce.ts) to keep and publish again, rehearses",
1180
+ "publishing it (--dry-run) and filling it on the destination (`sauce intent fill`), and",
1181
+ "with a signer publishes it once you approve (or with --auto-approve), storing it. --config names",
1182
+ "both chains' endpoints.",
1183
+ ...SUPPORTED_ONLY("Publishes (or prints the transactions)"),
1184
+ "",
1185
+ "Examples:",
1186
+ " sauce intent publish bridge.sauce.ts --chain ethereum --rpc-url <url> --keystore ~/.keys/me.json \\",
1187
+ " --intent-deadline 2000000000 --intent-creator 0x…",
1188
+ " sauce intent publish --config sauce.config.json --keystore ~/.keys/me.json",
1189
+ " sauce intent publish --source ethereum --destination base --token USDC --amount 1 \\",
1190
+ " --recipient 0x… --reward-token USDC --reward 1.01 --prover HyperProver \\",
1191
+ " --fill-deadline +1h --reward-deadline +1d --config sauce.config.json --keystore <path>",
1192
+ ].join("\n"),
1193
+ run: async (args, io) => {
1194
+ if (args.positionals.length === 0)
1195
+ return createAndPublish(args, io);
1196
+ const created = Object.keys(CREATE).find((flag) => args.values[flag] !== undefined);
1197
+ if (created !== undefined) {
1198
+ throw new UsageError(`--${created} makes a new intent: give it with no <file>`);
1199
+ }
1200
+ const format = stringFlag(args, "format");
1201
+ // A dry run rehearses on every chain; transactions, printed or sent, need supported ones.
1202
+ const gate = args.values["dry-run"] === true && format === undefined
1203
+ ? undefined
1204
+ : { action: "publishing intents", by: "all" };
1205
+ const program = await programInput(args, io, undefined, undefined, gate);
1206
+ if (program.chain.kind === "svm") {
1207
+ throw new UsageError("sauce intent publish sends a source chain's Portal transactions from an EVM wallet. " +
1208
+ "Publishing from Solana is not supported: the SDK has no Kitchen-built path for an " +
1209
+ "intent that Solana's Portal runs (docs/guides/solana.md). Open the intent from an " +
1210
+ "EVM chain; its destination may be Solana.");
1211
+ }
1212
+ if (format !== undefined && format !== "json" && format !== "cast") {
1213
+ throw new UsageError(`--format: '${format}' is not json or cast`);
1214
+ }
1215
+ // Compiled once: refused before the signer or any endpoint, then the Pots checked.
1216
+ const compiled = compileProgram(program, io);
1217
+ if (gate !== undefined)
1218
+ gated(gate, program.chain, compiled.intents);
1219
+ const account = hasSigner(args, io) ? await signerOf(args, io) : undefined;
1220
+ const from = stringFlag(args, "from");
1221
+ if (from !== undefined && account !== undefined) {
1222
+ throw new UsageError("--from is for when there is no signer: the signer's wallet publishes");
1223
+ }
1224
+ const rpcUrl = format === undefined && args.values["dry-run"] !== true
1225
+ ? requiredEndpoint(args, io, program.chain)
1226
+ : endpoint(args, io, program.chain);
1227
+ const assume = assumedBalancesOf(args, program.chain);
1228
+ if (assume.length > 0 && args.values["dry-run"] !== true) {
1229
+ throw new UsageError("--assume-balance goes with --dry-run: it gives the wallet a balance for a rehearsal, " +
1230
+ "and nothing to a transaction that is sent");
1231
+ }
1232
+ // Before anything is sent: an intent whose Pot is not deployed is one no solver can fill.
1233
+ const pots = await checkIntentPots(intentCooks(compiled.intents), endpointsOf(args, io, program.chain));
1234
+ for (const check of pots) {
1235
+ if (check.deployed !== true) {
1236
+ io.stderr(`${check.deployed === false ? missingPotNote(check) : uncheckedPotNote(check)}\n`);
1237
+ }
1238
+ }
1239
+ return publishCommand({
1240
+ ...program,
1241
+ ...(format === undefined ? {} : { format }),
1242
+ dryRun: args.values["dry-run"] === true,
1243
+ ...(assume.length === 0 ? {} : { assume }),
1244
+ ...(rpcUrl === undefined ? {} : { rpcUrl }),
1245
+ ...(account === undefined ? {} : { account }),
1246
+ ...(from === undefined ? {} : { from: parseAddress("from", from) }),
1247
+ ...(rpcUrl === undefined ? {} : { onSent: storing(args, io, program.chain, rpcUrl) }),
1248
+ }, io);
1249
+ },
1250
+ },
1251
+ fill: {
1252
+ usage: [
1253
+ "sauce intent fill <file | -> --chain <source> (--config <file> | --rpc-url <url>) [options]",
1254
+ "sauce intent fill <intent-hash> (--config <file> | --rpc-url <url>) [options]",
1255
+ "sauce intent fill <file | intent-hash> … --send (--keystore <path> | --private-key <hex>) [--auto-approve]",
1256
+ "sauce intent fill <intent-hash> --config <file> --claimant <address> --send --keypair <path> (to Solana)",
1257
+ ],
1258
+ summary: "Fill a file's (or a stored) intents on their destination: rehearsed, or --send",
1259
+ flags: {
1260
+ ...PROGRAM,
1261
+ "rpc-url": {
1262
+ type: "string",
1263
+ value: "<url>",
1264
+ help: "The destination chain's endpoint (one destination only)",
1265
+ },
1266
+ config: {
1267
+ type: "string",
1268
+ value: "<file>",
1269
+ help: 'Or a file of { "rpcUrls": { "<chain id>": "<url>" } }: each destination\'s',
1270
+ },
1271
+ solver: {
1272
+ type: "string",
1273
+ value: "<address|key>",
1274
+ help: "Rehearse as this account (default: one nobody holds the key of; on Solana, required)",
1275
+ },
1276
+ claimant: {
1277
+ type: "string",
1278
+ value: "<address|bytes32>",
1279
+ help: "Who claims the reward, as fulfill records it (default: the solver; for Solana, required)",
1280
+ },
1281
+ "no-prove": {
1282
+ type: "boolean",
1283
+ help: "fulfill only: send no proof with the fill (prove later: sauce intent prove)",
1284
+ },
1285
+ send: {
1286
+ type: "boolean",
1287
+ help: "Send the fill, from the signer, after rehearsing it",
1288
+ },
1289
+ ...EVM_SIGNER,
1290
+ keypair: LIFECYCLE.keypair,
1291
+ "auto-approve": LIFECYCLE["auto-approve"],
1292
+ store: LIFECYCLE.store,
1293
+ ...JSON_FLAG,
1294
+ ...HELP,
1295
+ },
1296
+ details: [
1297
+ "Builds each intent the file opens, as `sauce intent publish` does (or takes the intent the store",
1298
+ "holds under that hash), and fills it on its destination chain as a solver does: one",
1299
+ "eth_simulateV1 block, every call from the solver — Kitchen.deployPot for the destination's",
1300
+ "shared intent Pot when the route cooks on it and it is not deployed yet (any account may",
1301
+ "send it), the solver's approval of the Portal for each token the route delivers (reset to",
1302
+ "zero first where a smaller allowance stands, as USDT requires), then the fill:",
1303
+ " Portal.fulfillAndProve(intentHash, route, rewardHash, claimant, prover, domain, data)",
1304
+ " when the reward's prover is a Hyperlane prover, with the route's native amount",
1305
+ " (the Kitchen's fee for a cook) plus the Hyperlane fee, quoted from the prover's",
1306
+ " fetchFee, as the value: the proof leaves with the fill;",
1307
+ " Portal.fulfill(intentHash, route, rewardHash, claimant)",
1308
+ " otherwise, or with --no-prove, with the route's native amount: prove it later.",
1309
+ "",
1310
+ "With no --send, nothing is signed or sent: the solver is given the route's tokens and the",
1311
+ "value by state override, where a token keeps the balance found as simulate's",
1312
+ "--assume-balance finds it. With --send the signer is the solver and nothing is assumed: the",
1313
+ "rehearsal runs on its real balances, a fill that would revert is not sent, and what it",
1314
+ "spends (each token, the value and what it is for) is shown for you to approve at the",
1315
+ "terminal, or with --auto-approve. Then the transactions are sent in order, and the intent and its",
1316
+ "fill go into the store (--store, default ~/.sauce/intents).",
1317
+ "",
1318
+ "Prints the gas and what the fill moved — the transfers, each address's net change, labelled",
1319
+ "with the defines that name it (RECIPIENT, REFUND_TO) — what it left in the shared Pot and the",
1320
+ "Portal's Executor, which every intent through that Portal shares, the Portal's",
1321
+ "IntentFulfilled record, and, sent, the Hyperlane message the proof travels as; or the",
1322
+ "decoded reason it reverts (exit 1), a failed route call unwrapped to the program's own",
1323
+ "message.",
1324
+ "",
1325
+ "The endpoint is the DESTINATION's: --config names each one (and the source's, which checks",
1326
+ "the source prover trusts the destination's), and --rpc-url serves intents that all go to",
1327
+ "one chain. The intent must be fixed when it is built, as for publish: one using a value the",
1328
+ "program measures on chain has no route until it runs (name it by the hash `sauce run`",
1329
+ "stored). Needs an endpoint that serves eth_simulateV1.",
1330
+ "",
1331
+ "An intent to Solana (one `sauce intent import` stored from its publishing transaction) is",
1332
+ "filled through Solana's Portal program: Portal.fulfill, the solver's token accounts paying",
1333
+ "the route's tokens, rehearsed by simulateTransaction on the accounts as they are (Solana's",
1334
+ "simulation takes no overrides: --solver names a Solana key, whose accounts pay). --claimant,",
1335
+ "an address on the source chain, is required: the reward pays it, and a Solana key is none.",
1336
+ "With --send and --keypair it is sent, then its proof through the HyperProver, the IGP's gas",
1337
+ "paid in the same transaction, each spend approved.",
1338
+ ...SUPPORTED_ONLY("--send sends a fill"),
1339
+ "",
1340
+ "Examples:",
1341
+ " sauce intent fill swap-on-base.sauce.ts --chain ethereum --config sauce.config.json \\",
1342
+ " --defines swap.defines.json --intent-deadline 2000000000 --intent-creator 0x… \\",
1343
+ " --intent-execution-fee 1000000000000",
1344
+ " sauce intent fill 0x<intent hash> --config sauce.config.json --send --keystore ~/.keys/me.json",
1345
+ ].join("\n"),
1346
+ run: async (args, io) => {
1347
+ const store = storeOf(args, io);
1348
+ const rpcUrl = stringFlag(args, "rpc-url");
1349
+ const config = stringFlag(args, "config");
1350
+ if (rpcUrl === undefined && config === undefined) {
1351
+ throw new UsageError("missing --config <file> (or --rpc-url <url>): the endpoint of each intent's " +
1352
+ "destination chain, where the fill runs");
1353
+ }
1354
+ const solver = stringFlag(args, "solver");
1355
+ const claimant = stringFlag(args, "claimant");
1356
+ if (claimant !== undefined && !/^0x(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$/.test(claimant)) {
1357
+ throw new UsageError(`--claimant: '${claimant}' is neither an address (20 bytes) nor 32 bytes of hex`);
1358
+ }
1359
+ const sending = args.values.send === true;
1360
+ if (!sending && (hasSigner(args, io) || hasSvmSigner(args, io))) {
1361
+ throw new UsageError("a signer goes with --send: without it, fill rehearses and signs nothing (--solver " +
1362
+ "names who it rehearses as)");
1363
+ }
1364
+ if (sending && solver !== undefined) {
1365
+ throw new UsageError("--solver is for a rehearsal: with --send, the signer is the solver");
1366
+ }
1367
+ if (args.values["auto-approve"] === true && !sending) {
1368
+ throw new UsageError("--auto-approve approves what --send spends: give --send");
1369
+ }
1370
+ const operands = args.positionals;
1371
+ let targets;
1372
+ let labels = [];
1373
+ let from;
1374
+ const gate = sending
1375
+ ? { action: "sending a fill", by: "destinations" }
1376
+ : undefined;
1377
+ if (operands.length > 0 && operands.every(isIntentHash)) {
1378
+ targets = operands.flatMap((hash) => storedTargets(store, hash).map(({ record }) => ({
1379
+ intent: intentOf(record),
1380
+ source: parseChain(String(record.source.chainId)),
1381
+ destination: parseChain(String(record.destination.chainId)),
1382
+ sourcePortal: record.source.portal,
1383
+ })));
1384
+ from = operands.length === 1 ? operands[0] : "the intents named";
1385
+ }
1386
+ else {
1387
+ const program = await programInput(args, io, undefined, undefined, gate);
1388
+ // A deadline that has passed is rehearsed anyway, so the Portal's own refusal shows.
1389
+ const past = pastDeadline(program);
1390
+ if (past !== undefined)
1391
+ io.stderr(`${past}: the rehearsal shows the Portal refusing it\n`);
1392
+ targets = fillTargets(program, io);
1393
+ labels = defineLabels(program);
1394
+ from = program.file;
1395
+ }
1396
+ // A rehearsal runs on every chain; a fill is sent only to a supported destination.
1397
+ if (gate !== undefined) {
1398
+ requireSupported(gate.action, targets.map((target) => target.destination));
1399
+ }
1400
+ const onSolana = targets.filter((target) => target.destination.kind === "svm");
1401
+ if (onSolana.length > 0) {
1402
+ if (onSolana.length !== targets.length) {
1403
+ throw new UsageError("fill the intents to Solana apart from the others: they are filled through another " +
1404
+ "Portal, with another signer");
1405
+ }
1406
+ const context = await lifecycleContext(args, io);
1407
+ if (sending && context.svmSigner === undefined) {
1408
+ throw new UsageError("sending a fill on Solana needs its signer: --keypair <path>");
1409
+ }
1410
+ return svmFillCommand({
1411
+ targets: targets.map((target) => {
1412
+ const record = intentRecord(target.intent, { sourcePortal: target.sourcePortal });
1413
+ return store.has(record.intentHash)
1414
+ ? { record, stored: store.load(record.intentHash) }
1415
+ : { record };
1416
+ }),
1417
+ ...(solver === undefined ? {} : { solver: parsePubkey("solver", solver) }),
1418
+ ...(claimant === undefined ? {} : { claimant: claimant }),
1419
+ ...(args.values["no-prove"] === true ? { prove: false } : {}),
1420
+ send: sending,
1421
+ }, context);
1422
+ }
1423
+ const account = sending ? await signerOf(args, io) : undefined;
1424
+ const lookup = config === undefined ? undefined : await endpointLookup(args, io);
1425
+ return fillCommand({
1426
+ intents: targets,
1427
+ from,
1428
+ labels,
1429
+ endpointOf: (chain) => requiredEndpoint(args, io, chain),
1430
+ ...(lookup === undefined ? {} : { sourceEndpointOf: lookup }),
1431
+ endpointFlag: rpcUrl === undefined ? "--config" : "--rpc-url",
1432
+ ...(solver === undefined ? {} : { solver: parseAddress("solver", solver) }),
1433
+ ...(claimant === undefined ? {} : { claimant: claimant }),
1434
+ ...(args.values["no-prove"] === true ? { prove: false } : {}),
1435
+ ...(account === undefined
1436
+ ? {}
1437
+ : { send: { account, approver: approverOf(args, io), store } }),
1438
+ });
1439
+ },
1440
+ },
1441
+ prove: {
1442
+ usage: "sauce intent prove <file | intent-hash…> --config <file> [--keystore <path> | --private-key <hex>]",
1443
+ summary: "Send the proof of filled (or cancelled) intents, paying the prover's fee",
1444
+ flags: { ...LIFECYCLE, ...JSON_FLAG, ...HELP },
1445
+ details: [
1446
+ "For intents fulfilled (or cancelled) on their destination whose proof has not reached the",
1447
+ "source: Portal.prove(prover, sourceDomain, intentHashes, data) on the destination, from",
1448
+ "the signer, with the prover's fee — quoted from its fetchFee — as the value, which you",
1449
+ "approve at the terminal or with --auto-approve. Several hashes share one proof when they have one",
1450
+ "destination, source and prover. An intent the source has proven already is left out.",
1451
+ "Prints the transaction and the Hyperlane message the proof travels as. With no signer,",
1452
+ "prints the unsigned transaction instead.",
1453
+ "",
1454
+ "The intent is a hash the store holds (`sauce intent publish`, `run`, `fill` and `intents import`",
1455
+ "store them), or the file that opens it (with --chain, its source, and the flags it was",
1456
+ "built with). --config names the destination's endpoint, and the source's to skip what is",
1457
+ "proven already.",
1458
+ ...SUPPORTED_ONLY("Proves (or prints the transaction)"),
1459
+ "",
1460
+ "Example:",
1461
+ " sauce intent prove 0x<intent hash> --config sauce.config.json --keystore ~/.keys/me.json",
1462
+ ].join("\n"),
1463
+ run: async (args, io) => {
1464
+ const { targets, context } = await lifecycleOf(args, io, {
1465
+ action: "proving",
1466
+ by: "destinations",
1467
+ });
1468
+ return proveCommand(targets, context);
1469
+ },
1470
+ },
1471
+ claim: {
1472
+ usage: "sauce intent claim <file | intent-hash…> --chain <source> --config <file> [signer]",
1473
+ summary: "Withdraw proven intents' rewards to their claimants, on the source",
1474
+ flags: { ...LIFECYCLE, ...JSON_FLAG, ...HELP },
1475
+ details: [
1476
+ "Checks the reward's prover on the source chain has the intent proven, for this",
1477
+ "destination, and the reward is not withdrawn or refunded; then sends Portal.withdraw",
1478
+ "(Portal.batchWithdraw for several, one transaction) from the signer — anyone may — which",
1479
+ "pays each reward to the claimant its proof records. Prints what moved out of the vault,",
1480
+ "and stores the claim. With no signer, prints the unsigned transaction.",
1481
+ "",
1482
+ "While the proof has not arrived it says so (exit 1), with when the store saw the intent",
1483
+ "filled and the Hyperlane message its proof travels as, which the Hyperlane explorer shows by",
1484
+ "id. A proven CANCELLATION pays no claimant: refund it instead.",
1485
+ ...SUPPORTED_ONLY("Claims (or prints the transaction)"),
1486
+ "",
1487
+ "Example:",
1488
+ " sauce intent claim 0x<intent hash> --chain ethereum --config sauce.config.json \\",
1489
+ " --keystore ~/.keys/me.json",
1490
+ ].join("\n"),
1491
+ run: async (args, io) => {
1492
+ const { targets, context } = await lifecycleOf(args, io, {
1493
+ action: "claiming",
1494
+ by: "source",
1495
+ });
1496
+ return claimCommand(targets, context);
1497
+ },
1498
+ },
1499
+ refund: {
1500
+ usage: "sauce intent refund <file | intent-hash…> --chain <source> --config <file> [signer]",
1501
+ summary: "Return unearned rewards from their vaults to their creators, on the source",
1502
+ flags: { ...LIFECYCLE, ...JSON_FLAG, ...HELP },
1503
+ details: [
1504
+ "Sends Portal.refund from the signer — anyone may — which returns everything the intent's",
1505
+ "vault holds to the reward's creator, once the Portal allows it:",
1506
+ " a proven cancellation at once (eco-routes 2.12: `sauce intent cancel`, then `sauce intent prove`);",
1507
+ " no proof from the reward's deadline on;",
1508
+ " a proof of a fill only after the claimant has withdrawn: the leftovers.",
1509
+ "It reads the status first and says why not, with the time left (exit 1). There is no batch",
1510
+ "refund: several intents are refunded one transaction each. With no signer, prints the",
1511
+ "unsigned transactions.",
1512
+ ...SUPPORTED_ONLY("Refunds (or prints the transactions)"),
1513
+ "",
1514
+ "Example:",
1515
+ " sauce intent refund 0x<intent hash> --chain ethereum --config sauce.config.json \\",
1516
+ " --keystore ~/.keys/me.json",
1517
+ ].join("\n"),
1518
+ run: async (args, io) => {
1519
+ const { targets, context } = await lifecycleOf(args, io, {
1520
+ action: "refunding",
1521
+ by: "source",
1522
+ });
1523
+ return refundCommand(targets, context);
1524
+ },
1525
+ },
1526
+ cancel: {
1527
+ usage: "sauce intent cancel <file | intent-hash…> --config <file> [--and-prove] [signer]",
1528
+ summary: "Cancel unfilled intents after their route's deadline, for an early refund",
1529
+ flags: {
1530
+ ...LIFECYCLE,
1531
+ "and-prove": {
1532
+ type: "boolean",
1533
+ help: "cancelAndProve: prove in the same transaction (before finality)",
1534
+ },
1535
+ ...JSON_FLAG,
1536
+ ...HELP,
1537
+ },
1538
+ details: [
1539
+ "eco-routes 2.12 lets anyone cancel an intent on its DESTINATION once the route's deadline",
1540
+ "has passed and no solver filled it: Portal.cancel records it cancelled, so no fill can",
1541
+ "land after, and proving the cancellation (`sauce intent prove`) lets the creator refund at once,",
1542
+ "without waiting for the reward's deadline (`sauce intent refund`). It is refused, saying why:",
1543
+ " where the destination Portal has no cancel (it predates 2.12): refund after the reward's",
1544
+ " deadline instead;",
1545
+ " where the SOURCE Portal predates 2.12, which would pay a proven cancellation to an",
1546
+ " address nobody controls, burning the reward: it is checked for the CancelledIntent",
1547
+ " refusal 2.12 added, so --config needs both chains' endpoints;",
1548
+ " before the route's deadline, after a fill, and when cancelled already.",
1549
+ "",
1550
+ "eco-routes asks for the proof to wait until the cancel is final on the destination: a",
1551
+ "reorg past the deadline that re-includes a fill would leave that solver unpaid. So cancel",
1552
+ "sends only the cancel; --and-prove sends cancelAndProve, proving at once, with the fee",
1553
+ "approved as for prove. With no signer, prints the unsigned transaction.",
1554
+ ...SUPPORTED_ONLY("Cancels (or prints the transaction)"),
1555
+ "",
1556
+ "Example:",
1557
+ " sauce intent cancel 0x<intent hash> --config sauce.config.json --keystore ~/.keys/me.json",
1558
+ ].join("\n"),
1559
+ run: async (args, io) => {
1560
+ const { targets, context } = await lifecycleOf(args, io, {
1561
+ action: "cancelling",
1562
+ by: "destinations",
1563
+ });
1564
+ return cancelCommand(targets, context, { prove: args.values["and-prove"] === true });
1565
+ },
1566
+ },
1567
+ status: {
1568
+ usage: "sauce intent status <file | intent-hash…> --config <file>",
1569
+ summary: "Where intents stand on both chains, and what can be done next",
1570
+ flags: { ...PROGRAM, ...ENDPOINT, ...API, store: LIFECYCLE.store, ...JSON_FLAG, ...HELP },
1571
+ details: [
1572
+ "Reads each intent on its source chain (the reward's status, what its vault holds, the",
1573
+ "proof its prover records) and its destination (whether the Portal recorded a fill or a",
1574
+ "cancellation, and whether it can cancel), wherever --config gives an endpoint, and prints",
1575
+ "its state — unfunded, funded, filled, cancelled, proven, cancelProven, claimed or refunded",
1576
+ "— its deadlines, and whether it can be filled, proven, claimed, refunded or cancelled now,",
1577
+ "with why not and from when. Nothing is sent. --api <url> also asks the Eco API gateway",
1578
+ "there (GET /v1/intents/status) and prints its word beside the chains' state, which stays",
1579
+ "the truth; --api-key-file sends a key with it. No URL is built in.",
1580
+ "",
1581
+ "Example:",
1582
+ " sauce intent status 0x<intent hash> --config sauce.config.json",
1583
+ ].join("\n"),
1584
+ run: async (args, io) => {
1585
+ const context = await lifecycleContext(args, io);
1586
+ const targets = await lifecycleTargets(args, io, context.store);
1587
+ const shown = await Promise.all(targets.map((target) => showCommand(target, context)));
1588
+ return {
1589
+ text: shown.map((output) => output.text).join("\n\n"),
1590
+ json: { intents: shown.map((output) => output.json) },
1591
+ notes: shown.flatMap((output) => output.notes ?? []),
1592
+ };
1593
+ },
1594
+ },
1595
+ list: {
1596
+ usage: "sauce intent list [--config <file>] [--store <dir>]",
1597
+ summary: "Every intent the store keeps, and with --config where each stands",
1598
+ flags: { ...ENDPOINT, store: LIFECYCLE.store, ...JSON_FLAG, ...HELP },
1599
+ details: [
1600
+ "The store (--store, default ~/.sauce/intents) keeps every intent `sauce intent publish`,",
1601
+ "`sauce run`, and the intent commands touch, and those `sauce intent import` brings in:",
1602
+ "one directory per intent hash, its intent.json written once and never changed, and",
1603
+ "events.jsonl, one line appended per thing that happened (published, funded, filled,",
1604
+ "proving, claimed, refunded, cancelled) with its chain, transaction, block and time. Where",
1605
+ "an intent stands is never stored: with --config it is read from the chains, each time.",
1606
+ ].join("\n"),
1607
+ run: async (args, io) => {
1608
+ if (args.positionals.length > 0) {
1609
+ throw new UsageError(`unexpected argument ${args.positionals[0]}`);
1610
+ }
1611
+ return listCommand(await lifecycleContext(args, io));
1612
+ },
1613
+ },
1614
+ show: {
1615
+ usage: "sauce intent show <intent-hash> [--config <file>] [--store <dir>]",
1616
+ summary: "One stored intent: its route, reward, deadlines and events, and where it stands",
1617
+ flags: { ...ENDPOINT, ...API, store: LIFECYCLE.store, ...JSON_FLAG, ...HELP },
1618
+ details: [
1619
+ "Prints the intent the store keeps under that hash — its route and reward, its deadlines,",
1620
+ "its creator and prover, and every event recorded for it — and, with --config, its state on",
1621
+ "both chains and what can be done next, as `sauce intent status` reads it.",
1622
+ ].join("\n"),
1623
+ run: async (args, io) => {
1624
+ const [hash, ...more] = args.positionals;
1625
+ if (hash === undefined || !isIntentHash(hash) || more.length > 0) {
1626
+ throw new UsageError("show takes one <intent-hash>");
1627
+ }
1628
+ const context = await lifecycleContext(args, io);
1629
+ const [target] = storedTargets(context.store, hash);
1630
+ return showCommand(target, context);
1631
+ },
1632
+ },
1633
+ import: {
1634
+ usage: "sauce intent import <tx-hash> --chain <source> (--config <file> | --rpc-url <url>) [--index <n>]",
1635
+ summary: "Store the intents a transaction published, rebuilt from its logs",
1636
+ flags: {
1637
+ chain: PROGRAM.chain,
1638
+ ...ENDPOINT,
1639
+ store: LIFECYCLE.store,
1640
+ index: {
1641
+ type: "string",
1642
+ value: "<n>",
1643
+ help: "Only the n-th intent the transaction published (from 0)",
1644
+ },
1645
+ ...JSON_FLAG,
1646
+ ...HELP,
1647
+ },
1648
+ details: [
1649
+ "Reads the transaction's receipt on the source chain and rebuilds every intent its",
1650
+ "IntentPublished logs announce — the destination, the route (the bytes the Portal hashed)",
1651
+ "and the whole reward — checking each one hashes to the hash its log names, and stores it",
1652
+ "with the Portal that emitted it and the vault that Portal derives. Then every intent",
1653
+ "command takes it by hash. For an intent someone else published, or one published before",
1654
+ "the store kept it.",
1655
+ "",
1656
+ "Example:",
1657
+ " sauce intent import 0x<tx hash> --chain ethereum --config sauce.config.json",
1658
+ ].join("\n"),
1659
+ run: async (args, io) => {
1660
+ const [hash, ...more] = args.positionals;
1661
+ if (hash === undefined || !TX_HASH.test(hash) || more.length > 0) {
1662
+ throw new UsageError("import takes one <tx-hash>: the transaction that published");
1663
+ }
1664
+ const chain = parseChain(requiredFlag(args, "chain", "<source>"));
1665
+ const index = stringFlag(args, "index");
1666
+ if (index !== undefined && !/^\d+$/.test(index)) {
1667
+ throw new UsageError(`--index: '${index}' is not a whole number`);
1668
+ }
1669
+ return importCommand({
1670
+ txHash: hash,
1671
+ chain,
1672
+ ...(index === undefined ? {} : { index: Number(index) }),
1673
+ }, await lifecycleContext(args, io));
1674
+ },
1675
+ },
1676
+ };
1677
+ /** The flags every wallet verb that reads or writes a key takes: the directory, and the password. */
1678
+ const WALLET_KEY = { ...WALLETS, ...PASSWORD };
1679
+ /** A wallet verb's one `<name>` operand, and any operand after it. */
1680
+ function walletOperand(args, more = 0) {
1681
+ const [name, ...rest] = args.positionals;
1682
+ if (name === undefined)
1683
+ throw new UsageError("missing <name>: the wallet");
1684
+ if (rest.length > more)
1685
+ throw new UsageError(`unexpected argument ${rest[more]}`);
1686
+ return [walletName(name), ...rest];
1687
+ }
1688
+ const WALLET_VERBS = {
1689
+ new: {
1690
+ usage: "sauce wallet new <name> [--solana] [--password-env <NAME> | --password-file <path> | --password-command <command>]",
1691
+ summary: "Create a wallet with a fresh key, encrypted under its password",
1692
+ flags: {
1693
+ solana: { type: "boolean", help: "A Solana keypair (default: an EVM key)" },
1694
+ ...WALLET_KEY,
1695
+ ...JSON_FLAG,
1696
+ ...HELP,
1697
+ },
1698
+ details: [
1699
+ "Generates a key and keeps it in the wallet directory (--wallets, default ~/.sauce/wallets,",
1700
+ "created 0700) as <name>.json, written once, 0600, never overwritten. An EVM wallet is a",
1701
+ "Web3 Secret Storage keystore (scrypt, AES-128-CTR) that --keystore, cast wallet and geth",
1702
+ 'read; a Solana one is the same envelope around its keypair, marked "kind": "solana". Its',
1703
+ "address is in the clear, so list and address need no password. Prints the name, kind,",
1704
+ "address and file.",
1705
+ "",
1706
+ "The password comes from one source: --password-env NAME (that variable, the one the",
1707
+ "command reads from the environment), --password-file (a file only you can read: one",
1708
+ "others can read is refused), --password-command (what the command prints, its output",
1709
+ "never shown), or else a prompt, asked twice. At least 8 characters. An agent keeps it in",
1710
+ "its .env or its secret store and names the source; the password itself is never an",
1711
+ "argument.",
1712
+ "",
1713
+ "Sign with it anywhere a key signs: --wallet <name> with the same password source. Beside",
1714
+ "it, <name>.policy.json limits what it sends (sauce wallet --help). It is a hot wallet:",
1715
+ "keep small balances in it.",
1716
+ "",
1717
+ "Examples:",
1718
+ " sauce wallet new agent --password-env SAUCE_WALLET_PASSWORD",
1719
+ " sauce wallet new agent-sol --solana --password-file ~/.config/sauce/password",
1720
+ ].join("\n"),
1721
+ run: async (args, io) => {
1722
+ const [name] = walletOperand(args);
1723
+ return walletNewCommand(walletsOf(args, io), { name, kind: args.values.solana === true ? "solana" : "evm", password: passwordOf(args) }, io);
1724
+ },
1725
+ },
1726
+ list: {
1727
+ usage: "sauce wallet list [--wallets <dir>] [--json]",
1728
+ summary: "Every wallet: its name, kind and address",
1729
+ flags: { ...WALLETS, ...JSON_FLAG, ...HELP },
1730
+ details: [
1731
+ "Lists the wallet directory (--wallets, default ~/.sauce/wallets): each wallet's name, kind",
1732
+ "(evm or solana), address, and whether a policy limits it. No password is needed: each",
1733
+ "file names its address in the clear.",
1734
+ ].join("\n"),
1735
+ run: (args, io) => {
1736
+ if (args.positionals.length > 0) {
1737
+ throw new UsageError(`unexpected argument ${args.positionals[0]}`);
1738
+ }
1739
+ return walletListCommand(walletsOf(args, io));
1740
+ },
1741
+ },
1742
+ address: {
1743
+ usage: "sauce wallet address <name> [--wallets <dir>] [--json]",
1744
+ summary: "A wallet's address, with no password",
1745
+ flags: { ...WALLETS, ...JSON_FLAG, ...HELP },
1746
+ details: "Prints the wallet's address: a 0x address, or for a Solana wallet a base58 key.",
1747
+ run: (args, io) => walletAddressCommand(walletsOf(args, io), walletOperand(args)[0]),
1748
+ },
1749
+ import: {
1750
+ usage: "sauce wallet import <name> <file | -> [--solana] [password source]",
1751
+ summary: "Keep a key you have as a wallet: a private key, keystore or Solana keypair",
1752
+ flags: {
1753
+ solana: { type: "boolean", help: "Refuse anything but a Solana keypair" },
1754
+ ...WALLET_KEY,
1755
+ ...JSON_FLAG,
1756
+ ...HELP,
1757
+ },
1758
+ details: [
1759
+ "Reads the key from <file>, or from stdin with -, never from the command line: an EVM",
1760
+ "private key (32 bytes of hex), a Web3 Secret Storage keystore (opened with the password,",
1761
+ "which the wallet keeps), or a Solana keypair (a JSON array of 64 bytes, as solana-keygen",
1762
+ "writes, or its base58). It is stored as `sauce wallet new` stores a fresh one, encrypted",
1763
+ "under the password the source gives.",
1764
+ "",
1765
+ "Example:",
1766
+ " sauce wallet import treasury key.txt --password-env SAUCE_WALLET_PASSWORD",
1767
+ ].join("\n"),
1768
+ run: (args, io) => {
1769
+ const [name, from] = walletOperand(args, 1);
1770
+ if (from === undefined) {
1771
+ throw new UsageError("missing <file | ->: where the key is (- reads it from stdin)");
1772
+ }
1773
+ return walletImportCommand(walletsOf(args, io), { name, from, solana: args.values.solana === true, password: passwordOf(args) }, io);
1774
+ },
1775
+ },
1776
+ export: {
1777
+ usage: "sauce wallet export <name> [password source]",
1778
+ summary: "Show a wallet's key at your terminal, once you confirm",
1779
+ flags: { ...WALLET_KEY, ...HELP },
1780
+ details: [
1781
+ "Shows the wallet's private key (a Solana wallet's keypair, as the JSON array a keypair",
1782
+ "file holds) on the terminal itself, never on stdout, after you type the wallet's name to",
1783
+ "confirm. With no terminal it refuses. It is for moving a key to another wallet: anyone",
1784
+ "who sees it controls the wallet. The MCP server has no tool for it.",
1785
+ ].join("\n"),
1786
+ run: (args, io) => walletExportCommand(walletsOf(args, io), { name: walletOperand(args)[0], password: passwordOf(args) }, io),
1787
+ },
1788
+ };
1789
+ const COMMANDS = {
1790
+ compile: {
1791
+ usage: "sauce compile <file | -> --chain <slug|id> [options]",
1792
+ summary: "Compile a SauceScript program; print its bytecode",
1793
+ flags: {
1794
+ ...PROGRAM,
1795
+ "args-json": COOK["args-json"],
1796
+ account: {
1797
+ type: "string",
1798
+ multiple: true,
1799
+ value: "NAME=<address>",
1800
+ help: "Solana: an account main takes (an address, pot, owner, pot:USDC, mint:USDC, program:USDC), to size the cook",
1801
+ },
1802
+ via: {
1803
+ type: "string",
1804
+ value: "<kitchen|engine>",
1805
+ help: "Solana: size the Kitchen's cook (default) or the engine's direct one",
1806
+ },
1807
+ ...ENDPOINT,
1808
+ out: { type: "string", value: "<path>", help: "Write the output to a file, not stdout" },
1809
+ json: {
1810
+ type: "boolean",
1811
+ help: "Print JSON: sizes, defines and contracts applied, main's parameters, engine",
1812
+ },
1813
+ ...HELP,
1814
+ ...ARGS,
1815
+ },
1816
+ details: [
1817
+ "Compiles the file as a standalone program for the chain (routes.compileSauceProgram):",
1818
+ "its token symbols (USDC), protocol namespaces (Uniswap.UniversalRouter), chainId, the",
1819
+ "zero-import @sauce/token functions, SafeERC20 token writes (USDC.transfer,",
1820
+ "Token(addr).approve) and intents opened inside the program all resolve against it, so",
1821
+ "one file compiles for any chain whose names it uses. Relative imports are read from beside",
1822
+ "the file. A file may name its chain in a leading `// @chain base` line. An actions",
1823
+ "document compiles too (`sauce actions`).",
1824
+ "",
1825
+ "--json also says what the compile applied and how large the result is:",
1826
+ " defines each define the file reads, its value, and where it came from: user (--define,",
1827
+ " --defines) or chain (a token symbol, a protocol contract, the chain id)",
1828
+ " contracts each protocol contract it calls or reads (UniswapV3.Factory), resolved on its",
1829
+ " chain: an intent body's on the intent's own",
1830
+ " size the program's bytes; payload: the program with main's arguments (--args)",
1831
+ " cook on Solana, the cook's transaction against the 1232-byte limit, measured",
1832
+ " with --account where given and a distinct account for each other slot, as",
1833
+ " the Kitchen's cook or, --via engine, the engine's direct one",
1834
+ " intentPots each intent that runs a program on its destination: the Pot it cooks on (the",
1835
+ " one the destination Portal's Executor owns, salt 0) and, with an endpoint",
1836
+ " for that chain (--config), whether it is deployed; a missing one is warned",
1837
+ " about, since no solver can fill the intent until it is",
1838
+ "A define the file never reads is named on stderr: it changes nothing.",
1839
+ "",
1840
+ "Examples:",
1841
+ " sauce compile pay.sauce.ts --chain base --define RECIPIENT=0x…",
1842
+ " sauce compile split.sauce.ts --chain base --json --args 0x… 1000000",
1843
+ ].join("\n"),
1844
+ trailing: "args",
1845
+ run: async (args, io, trailing) => {
1846
+ const program = await programOperand(args, io);
1847
+ const accounts = repeatedFlag(args, "account");
1848
+ if (accounts.length > 0 && program.chain.kind !== "svm") {
1849
+ throw new UsageError(`--account names a Solana program's accounts; a program on ${program.chain.slug} takes none`);
1850
+ }
1851
+ const via = stringFlag(args, "via");
1852
+ if (via !== undefined && program.chain.kind !== "svm") {
1853
+ throw new UsageError(`--via chooses how a Solana cook reaches the engine; a cook on ${program.chain.slug} is ` +
1854
+ "the Pot's");
1855
+ }
1856
+ const output = await compileCommand({
1857
+ ...program,
1858
+ ...argsInput(args, io, trailing),
1859
+ ...(accounts.length === 0 ? {} : { accounts: parseAccounts(accounts) }),
1860
+ ...(via === undefined ? {} : { via: parseVia(via) }),
1861
+ endpoints: endpointsOf(args, io, program.chain),
1862
+ }, io);
1863
+ const out = stringFlag(args, "out");
1864
+ if (out === undefined)
1865
+ return output;
1866
+ for (const note of output.notes ?? [])
1867
+ io.stderr(`${note}\n`);
1868
+ io.writeText(out, `${args.values.json === true ? JSON.stringify(output.json, null, 2) : output.text}\n`);
1869
+ return undefined;
1870
+ },
1871
+ },
1872
+ actions: {
1873
+ usage: "sauce actions <file | -> [--chain <slug|id>] [--compact-args] [--json]",
1874
+ summary: "Lower an actions document to SauceScript for a chain; print the source and bytecode",
1875
+ flags: {
1876
+ chain: {
1877
+ type: "string",
1878
+ value: "<slug|id>",
1879
+ help: "The chain to compile for (default: the document's chainId)",
1880
+ },
1881
+ "compact-args": PROGRAM["compact-args"],
1882
+ json: {
1883
+ type: "boolean",
1884
+ help: "Print JSON: the document, source, bytecode and main's parameters",
1885
+ },
1886
+ ...HELP,
1887
+ },
1888
+ details: [
1889
+ 'An actions document is JSON: { "version": 1, "actions": [ … ] }, each action one',
1890
+ "protocol operation (actions/action-program.schema.json lists them). Tokens are registry",
1891
+ "symbols (USDC) and contracts namespace references (UniswapV3.Factory), or addresses; a pool",
1892
+ "may be given by its factory's key (factory and fee). Lowered for the chain, every name is",
1893
+ "the program's global of that name, so a document with no chainId compiles for any chain",
1894
+ "where its names exist, and a name the chain lacks is refused with its path.",
1895
+ "",
1896
+ "Prints the SauceScript the document lowers to, then main's parameters and the bytecode.",
1897
+ "compile, tx, simulate and run take an actions document wherever they take a .sauce.ts",
1898
+ "file, with the same flags: its argument actions are main's parameters (--args), and its",
1899
+ "cook runs on the Pot --owner or --pot names.",
1900
+ "",
1901
+ "Examples:",
1902
+ " sauce actions swap.json --chain base",
1903
+ " sauce simulate swap.json --chain base --owner 0x… --rpc-url <url> --args 1000000",
1904
+ ].join("\n"),
1905
+ run: (args, io) => {
1906
+ const { file, text } = programText(io, fileOperand(args));
1907
+ if (!isActionsDocument(text)) {
1908
+ throw new UsageError(`${file} is not an actions document (a JSON object with "actions"); compile a ` +
1909
+ "SauceScript file with `sauce compile`");
1910
+ }
1911
+ return actionsCommand(actionsOperand(args, file, text), io);
1912
+ },
1913
+ },
1914
+ simulate: {
1915
+ usage: [
1916
+ "sauce simulate <file | -> --chain <slug|id> (--owner <address> | --pot <address>) --rpc-url <url> [options]",
1917
+ "sauce simulate <file | -> --chain solana --owner <pubkey> --rpc-url <url> [--account NAME=<value>]… [options]",
1918
+ ],
1919
+ summary: "Rehearse the cook from the Pot's owner, with no key: what it did, or why it reverts",
1920
+ flags: {
1921
+ ...PROGRAM,
1922
+ ...COOK,
1923
+ ...ENDPOINT,
1924
+ "assume-balance": {
1925
+ type: "string",
1926
+ multiple: true,
1927
+ value: "<TOKEN:amount>",
1928
+ help: "Give the Pot this balance, for the rehearsal only: USDC:2, ETH:0.1",
1929
+ only: "evm",
1930
+ },
1931
+ block: {
1932
+ type: "string",
1933
+ value: "<number|tag>",
1934
+ help: "Rehearse on this block: a number, or latest, safe, finalized (default: latest)",
1935
+ only: "evm",
1936
+ },
1937
+ ...FUND,
1938
+ wallet: {
1939
+ type: "string",
1940
+ value: "<name>",
1941
+ help: "The owner's wallet: names the owner (and on EVM signs --fund's pulls)",
1942
+ },
1943
+ ...WALLETS,
1944
+ ...PASSWORD,
1945
+ keystore: {
1946
+ type: "string",
1947
+ value: "<path>",
1948
+ help: "The owner's keystore: names the owner (and signs --fund's pulls)",
1949
+ only: "evm",
1950
+ },
1951
+ "private-key": { ...SIGNER["private-key"], only: "evm" },
1952
+ keypair: {
1953
+ type: "string",
1954
+ value: "<path>",
1955
+ help: "The owner's keypair, naming the owner; nothing is signed",
1956
+ only: "svm",
1957
+ },
1958
+ ...JSON_FLAG,
1959
+ ...HELP,
1960
+ ...ARGS,
1961
+ },
1962
+ details: [
1963
+ "Compiles the file, builds the cook and rehearses it from the Pot's owner: no key, no",
1964
+ "transaction, no local node. Prints the gas, what the program returns and what the cook",
1965
+ "did, or the decoded reason it reverts (exit 1).",
1966
+ "",
1967
+ "It rehearses through eth_simulateV1, which returns the cook's logs: the output lists the",
1968
+ "ERC-20 transfers and approvals (registry symbols, whole units), the native transfers the",
1969
+ "node traces, and each address's net change. An endpoint without eth_simulateV1 falls back",
1970
+ "to eth_call with state overrides, which gives the result and the gas but no logs. The",
1971
+ "output names the route it took.",
1972
+ "",
1973
+ "A Pot that is not deployed yet is deployed in the rehearsal first, from --owner (and",
1974
+ "--salt): any account may send Kitchen.deployPot, and the Pot is the owner's either way.",
1975
+ "An owner holding less than the cook's value is given it for the rehearsal.",
1976
+ "",
1977
+ "--assume-balance TOKEN:amount gives the Pot that balance for this rehearsal only, by state",
1978
+ "override: repeatable, the amount as --fund takes it, ETH:<amount> for the native currency.",
1979
+ "Where a token keeps the balance is found by asking it, with eth_call; a token that stores",
1980
+ "no balance it reports (rebasing, shares) is refused.",
1981
+ "",
1982
+ "With --fund and the owner's key (--keystore or --private-key), the rehearsal includes the",
1983
+ "pulls `sauce run --fund` would make, signed and not sent; an approval the run would ask for",
1984
+ "is reported, not made. With no key the pulls cannot be signed, so the Pot is credited what",
1985
+ "they would bring, by state override, and --sweep still runs.",
1986
+ "",
1987
+ "On Solana: the Kitchen cook, simulated from --owner with signatures unchecked, with each",
1988
+ "account main takes given as --account NAME=<address | pot | owner> and an Address",
1989
+ "argument as a base58 public key. `pot:USDC` (or pot:<mint>) is the Pot's own token account",
1990
+ "for that mint, its associated token account under the mint's token program; owner:USDC the",
1991
+ "owner's; mint:USDC the mint and program:USDC its token program (SPL Token or Token-2022),",
1992
+ "the accounts a checked write takes. An account the cluster does not have is named in a",
1993
+ "note. Where main declares a return type, what it",
1994
+ "returned is read as that type. A Pot the Kitchen has not created is created first, in the",
1995
+ "same transaction. --via engine rehearses the engine's own paid cook instead: no Kitchen and",
1996
+ "no Pot (so no pot or pot:<token> account), --owner signing as the program's authority and",
1997
+ "paying the fee. Either way the cook pays the Kitchen's execution fee, read from the cluster",
1998
+ "and printed; --max-execution-fee refuses one above it. Prints the compute units and what the",
1999
+ "cook moved — each token account's balance change and each account's lamports, read from the",
2000
+ "accounts the transaction writes before it and as the simulation leaves them — or the reason",
2001
+ "(a program's revert message decoded) and the program logs. Solana's simulateTransaction",
2002
+ "takes no account overrides, so the owner must hold the Pot's rent and the fees, and",
2003
+ "--assume-balance is refused there. A cook too large for one transaction is refused with the",
2004
+ "bytes to shrink: staging it writes a code buffer on chain, which only `sauce run` does.",
2005
+ "",
2006
+ "Examples:",
2007
+ " sauce simulate pay.sauce.ts --chain base --owner 0x… --rpc-url <url> \\",
2008
+ " --assume-balance USDC:2 --args 0x… 1000000",
2009
+ " sauce simulate sweep.sauce.ts --chain solana --owner <pubkey> --rpc-url <url> \\",
2010
+ " --account source=<token account> --account authority=pot",
2011
+ " sauce simulate sweep.sauce.ts --chain solana --owner <pubkey> --rpc-url <url> \\",
2012
+ " --via engine --account source=<token account> --account authority=owner",
2013
+ ].join("\n"),
2014
+ trailing: "args",
2015
+ run: async (args, io, trailing) => {
2016
+ const program = await programOperand(args, io);
2017
+ const funds = repeatedFlag(args, "fund").length > 0;
2018
+ const assume = repeatedFlag(args, "assume-balance");
2019
+ if (program.chain.kind === "svm") {
2020
+ fundingOf(args, io, program.chain, "", false, undefined);
2021
+ if (assume.length > 0) {
2022
+ throw new UsageError("--assume-balance is for EVM chains: a Solana endpoint's simulateTransaction takes no " +
2023
+ "account overrides, so on solana the rehearsal runs on the accounts as they are");
2024
+ }
2025
+ if (stringFlag(args, "block") !== undefined) {
2026
+ throw new UsageError("--block is for EVM chains: Solana's simulateTransaction runs on the cluster's " +
2027
+ "current state, at no slot it can be given");
2028
+ }
2029
+ // A keypair or a wallet names the owner; the rehearsal signs nothing with it.
2030
+ const owner = hasSvmSigner(args, io) ? await keypairAddress(args, io) : undefined;
2031
+ return svmSimulateCommand(svmCookInput(args, io, trailing, program, owner), io);
2032
+ }
2033
+ if (hasSvmSigner(args, io)) {
2034
+ throw new UsageError("a Solana keypair or wallet names no owner on an EVM chain: name the owner with an EVM " +
2035
+ "--wallet, --keystore or --private-key, or --owner");
2036
+ }
2037
+ // A key names the owner, whose Pot the rehearsal runs on, and signs --fund's pulls if any.
2038
+ const account = funds && hasSigner(args, io) ? await signerOf(args, io) : undefined;
2039
+ const owner = account?.address ?? (hasSigner(args, io) ? await signerAddress(args, io) : undefined);
2040
+ if (owner !== undefined && stringFlag(args, "owner") !== undefined) {
2041
+ if (parseAddress("owner", stringFlag(args, "owner")) !== owner) {
2042
+ throw new UsageError(`--owner ${stringFlag(args, "owner")} is not the signer, ${owner}: with a key, the ` +
2043
+ "owner is the key's. Leave --owner out, or give its key.");
2044
+ }
2045
+ }
2046
+ const input = cookInput(args, io, trailing, owner, program);
2047
+ const assumed = assumedBalancesOf(args, input.chain);
2048
+ const rpcUrl = requiredEndpoint(args, io, input.chain);
2049
+ const fund = fundingOf(args, io, input.chain, rpcUrl, false, account);
2050
+ const block = stringFlag(args, "block");
2051
+ return simulateCommand({
2052
+ ...input,
2053
+ rpcUrl,
2054
+ assume: assumed,
2055
+ ...(fund === undefined ? {} : { fund }),
2056
+ ...(block === undefined ? {} : { block }),
2057
+ }, io);
2058
+ },
2059
+ },
2060
+ run: {
2061
+ usage: [
2062
+ "sauce run <file | -> --chain <slug|id> --rpc-url <url> (--keystore <path> | --private-key <hex>) [options]",
2063
+ "sauce run <file | -> --chain solana --rpc-url <url> --keypair <path> [--account NAME=<value>]… [options]",
2064
+ ],
2065
+ summary: "Compile, sign, send and wait for the cook on your Pot",
2066
+ flags: {
2067
+ ...PROGRAM,
2068
+ ...COOK,
2069
+ ...ENDPOINT,
2070
+ ...SIGNER,
2071
+ ...FUND,
2072
+ "auto-approve": {
2073
+ type: "boolean",
2074
+ help: "Approve, without asking, what the run sends first: see below",
2075
+ },
2076
+ store: LIFECYCLE.store,
2077
+ ...JSON_FLAG,
2078
+ ...HELP,
2079
+ ...ARGS,
2080
+ },
2081
+ details: [
2082
+ "Compiles the file, builds the cook on the signer's Pot (or --pot), rehearses it, signs it,",
2083
+ "sends it and waits for the receipt: prints the hash, status and gas used, and the decoded",
2084
+ "reason when it reverts (exit 1). The signer is the owner. The value defaults to the",
2085
+ "Kitchen's execution fee, read from the chain.",
2086
+ "",
2087
+ "What the run sends before its cook, each in a transaction of its own, it asks you to",
2088
+ "approve at the terminal first; --auto-approve approves every one without asking, and says",
2089
+ "`auto-approved: <action>` for each. They are:",
2090
+ " deploying the Pot, when it is not deployed yet (on Solana, creating it)",
2091
+ " approving Permit2 for a token --fund pulls, the first time (--fund-mode permit2)",
2092
+ " approving the Pot for the amount --fund pulls (--fund-mode allowance)",
2093
+ "With no terminal to ask on (CI, a pipe, a program read from stdin with no terminal),",
2094
+ "nothing is sent until they are approved: the run names every one it needs and stops.",
2095
+ "",
2096
+ "--fund TOKEN:amount gets tokens into the Pot in the same cook: the program is wrapped so",
2097
+ "it first pulls each amount from you, then runs, then (--sweep) returns what is left. The",
2098
+ "amount is whole units (USDC:1.5) or base units ending in n (USDC:1500000n); ETH:<amount>",
2099
+ "rides as the cook's value. Every pull is a safeTransferFrom: @sauce/token's SafeERC20",
2100
+ "one, or Permit2's own (Solmate's SafeTransferLib). --fund-mode:",
2101
+ " permit2 (default) you sign a Permit2 transfer of exactly this amount to this Pot, once;",
2102
+ " works for every ERC-20, USDT included, and leaves the Pot no allowance. The",
2103
+ " first time, Permit2 needs your approval for the token: asked for, like the Pot.",
2104
+ " permit the token's own EIP-2612 permit, signed for the Pot (tokens that have one)",
2105
+ " allowance an approval of the Pot for the amount (asked for), sent first: it stands",
2106
+ " until a cook spends it",
2107
+ " transfer a plain transfer to the Pot first, in a transaction of its own",
2108
+ "--sweep sends the Pot's whole balance of each funded token back to you (and of the",
2109
+ "native currency, when ETH is funded), not only what this run brought.",
2110
+ "",
2111
+ "On Solana: sign with --keypair; the Kitchen's fee is read from the cluster, a missing Pot",
2112
+ "is created the same way, and a program too large for one transaction is staged in a code",
2113
+ "buffer first (closed again after the cook). A failure prints the program logs.",
2114
+ "",
2115
+ "--via kitchen|engine (Solana) is how the cook reaches the engine:",
2116
+ " kitchen (default) the Kitchen's cook, which signs the owner's Pot: the program can hold",
2117
+ " and spend what the Pot owns, and write its storage",
2118
+ " engine the engine's own paid cook (cookAndPay), with no Kitchen and no Pot: the program",
2119
+ " acts with the signer's authority (--account NAME=owner), and its own calls get",
2120
+ " one more level of CPI depth. A staged program is pinned to the staged bytes",
2121
+ "Both pay the same execution fee into the Kitchen's treasury. The cook signs the fee it read",
2122
+ "as its max_execution_fee, so it pays that or fails; --max-execution-fee <lamports> refuses",
2123
+ "a fee above it before anything is sent.",
2124
+ ...SUPPORTED_ONLY("Runs"),
2125
+ "",
2126
+ "Examples:",
2127
+ " sauce run pay.sauce.ts --chain base --rpc-url <url> --keystore ~/.keys/me.json",
2128
+ " sauce run sweep.sauce.ts --chain solana --rpc-url <url> --keypair ~/.config/solana/id.json \\",
2129
+ " --account source=<token account> --account authority=pot",
2130
+ " sauce run sweep.sauce.ts --chain solana --rpc-url <url> --keypair ~/.config/solana/id.json \\",
2131
+ " --via engine --max-execution-fee 10000 --account authority=owner …",
2132
+ ].join("\n"),
2133
+ trailing: "args",
2134
+ run: async (args, io, trailing) => {
2135
+ const program = await programOperand(args, io, { action: "sending the cook", by: "all" });
2136
+ if (program.chain.kind === "svm") {
2137
+ fundingOf(args, io, program.chain, "", true, undefined);
2138
+ const signer = await keypairOf(args, io);
2139
+ return svmRunCommand({
2140
+ ...svmCookInput(args, io, trailing, program, signer.address),
2141
+ signer,
2142
+ approver: approverOf(args, io),
2143
+ }, io);
2144
+ }
2145
+ // Every chain the cook involves, its intents' too, before the key is unlocked.
2146
+ requireSupported("sending the cook", programChains(program, io));
2147
+ const account = await signerOf(args, io);
2148
+ const input = cookInput(args, io, trailing, account.address, program);
2149
+ const rpcUrl = requiredEndpoint(args, io, input.chain);
2150
+ const fund = fundingOf(args, io, input.chain, rpcUrl, true, account);
2151
+ return runCommand({
2152
+ ...input,
2153
+ ...(fund === undefined ? {} : { fund }),
2154
+ rpcUrl,
2155
+ account,
2156
+ approver: approverOf(args, io),
2157
+ onSent: storing(args, io, input.chain, rpcUrl),
2158
+ }, io);
2159
+ },
2160
+ },
2161
+ intent: {
2162
+ usage: [
2163
+ "sauce intent <verb> [options]",
2164
+ "sauce intent [--config <file>] [--keystore <path> | --private-key <hex>]",
2165
+ ],
2166
+ summary: "Publish, fill, prove, claim, refund and cancel cross-chain intents",
2167
+ flags: {
2168
+ ...ENDPOINT,
2169
+ ...EVM_SIGNER,
2170
+ "auto-approve": LIFECYCLE["auto-approve"],
2171
+ store: LIFECYCLE.store,
2172
+ ...JSON_FLAG,
2173
+ ...HELP,
2174
+ },
2175
+ details: [
2176
+ "Verbs (`sauce intent <verb> --help` for each):",
2177
+ ...Object.entries(INTENT_VERBS).map(([verb, command]) => ` ${verb.padEnd(8)} ${command.summary}`),
2178
+ "",
2179
+ "An intent is a file that opens one (`Base(() => { … }).reward({ … })`), named with the",
2180
+ "flags it is built with, or its hash once the store keeps it: `publish`, `fill` and",
2181
+ "`import` store every intent they touch (--store, default ~/.sauce/intents), and every verb",
2182
+ "takes the hash. With no verb, at a terminal: a list of the stored intents, read live with",
2183
+ "--config, to pick one from, then a menu that runs these verbs on it, with the same",
2184
+ "approvals (with a signer, they send). With no terminal, the plain list.",
2185
+ "",
2186
+ "Examples:",
2187
+ " sauce intent publish (guided, at a terminal)",
2188
+ " sauce intent fill 0x<intent hash> --config sauce.config.json --send --keystore <path>",
2189
+ " sauce intent claim 0x<intent hash> --config sauce.config.json --keystore <path>",
2190
+ ].join("\n"),
2191
+ run: async (args, io) => {
2192
+ const [verb] = args.positionals;
2193
+ if (verb !== undefined) {
2194
+ throw new UsageError(`unknown verb '${verb}': ${Object.keys(INTENT_VERBS).join(", ")}`);
2195
+ }
2196
+ const context = await lifecycleContext(args, io);
2197
+ if (io.ask !== undefined && process.stdin.isTTY && args.values.json !== true) {
2198
+ const code = await interactiveIntents({ ask: io.ask, stdout: io.stdout, stderr: io.stderr }, context);
2199
+ return code === 0 ? undefined : { text: "", json: {}, exitCode: code };
2200
+ }
2201
+ return listCommand(context);
2202
+ },
2203
+ },
2204
+ wallet: {
2205
+ usage: "sauce wallet <verb> [options]",
2206
+ summary: "Create, list and import the wallets --wallet signs with",
2207
+ flags: { ...WALLETS, ...JSON_FLAG, ...HELP },
2208
+ details: [
2209
+ "Verbs (`sauce wallet <verb> --help` for each):",
2210
+ ...Object.entries(WALLET_VERBS).map(([verb, command]) => ` ${verb.padEnd(8)} ${command.summary}`),
2211
+ "",
2212
+ "A wallet is a key the sauce command keeps in the wallet directory (--wallets, default",
2213
+ "~/.sauce/wallets), encrypted under a password from the source you name: --password-env",
2214
+ "NAME, --password-file <path>, --password-command <command>, or a prompt. Every command",
2215
+ "that signs takes --wallet <name> with that source, on EVM chains and Solana; so does the",
2216
+ "local MCP server (sauce mcp --wallets). It is a hot wallet: keep small balances in it.",
2217
+ "",
2218
+ "A policy limits what a wallet sends: <name>.policy.json beside it, every field optional and",
2219
+ "every amount a string (whole units, or base units ending in n):",
2220
+ ' { "chains": ["base"], "to": ["0x…"],',
2221
+ ' "native": { "perTransaction": "0.01", "perDay": "0.05" },',
2222
+ ' "tokens": { "USDC": { "perTransaction": "100", "perDay": "500" } } }',
2223
+ "What a transaction moves out of the wallet (and the Pot it cooks on) is measured by",
2224
+ "rehearsing it, and a send that breaks a limit is refused, naming it; the last 24 hours are",
2225
+ "counted from <name>.ledger.jsonl. With no policy, sends work, and say no limits are set.",
2226
+ "",
2227
+ "Examples:",
2228
+ " sauce wallet new agent --password-env SAUCE_WALLET_PASSWORD",
2229
+ " sauce run pay.sauce.ts --chain base --config sauce.config.json --wallet agent \\",
2230
+ " --password-env SAUCE_WALLET_PASSWORD --args 0x… 1000000",
2231
+ ].join("\n"),
2232
+ run: (args, io) => {
2233
+ const [verb] = args.positionals;
2234
+ if (verb !== undefined) {
2235
+ throw new UsageError(`unknown verb '${verb}': ${Object.keys(WALLET_VERBS).join(", ")}`);
2236
+ }
2237
+ return walletListCommand(walletsOf(args, io));
2238
+ },
2239
+ },
2240
+ tx: {
2241
+ usage: [
2242
+ "sauce tx <file | -> --chain <slug|id> (--owner <address> | --pot <address>) [options]",
2243
+ "sauce tx <file | -> --chain solana --owner <pubkey> --rpc-url <url> [--account NAME=<value>]… [options]",
2244
+ ],
2245
+ summary: "Print the unsigned cook transaction, for a wallet to sign",
2246
+ flags: { ...PROGRAM, ...COOK, ...ENDPOINT, ...FORMAT, ...HELP, ...ARGS },
2247
+ details: [
2248
+ "Compiles the file and prints the transaction that runs it, unsigned, as JSON:",
2249
+ "{ chainId, to: the Pot, data: Pot.cook(engine, program ++ arguments), value }. Give the",
2250
+ "value, or an endpoint to read the Kitchen's fee (it also checks the Pot). `--format cast`",
2251
+ "prints the same transaction as a `cast send` line instead. What must be true for it to",
2252
+ "land goes to stderr: the Pot deployed and funded, and sent from its owner.",
2253
+ "",
2254
+ "On Solana: { chain, via, feePayer, pot, fee, maxExecutionFee, transaction }, the Kitchen",
2255
+ "cook as a base64 transaction signed by no one, for --owner to sign — or, --via engine, the",
2256
+ "engine's own paid cook, with no Pot. It needs an endpoint (for the blockhash and the fee),",
2257
+ "and the --account flags simulate takes; --max-execution-fee refuses a fee above it.",
2258
+ ...SUPPORTED_ONLY("Prints the transaction"),
2259
+ "",
2260
+ "Example:",
2261
+ " sauce tx pay.sauce.ts --chain base --owner 0x… --value 0",
2262
+ ].join("\n"),
2263
+ trailing: "args",
2264
+ run: async (args, io, trailing) => {
2265
+ const program = await programOperand(args, io, {
2266
+ action: "building the cook transaction",
2267
+ by: "all",
2268
+ });
2269
+ if (program.chain.kind === "svm") {
2270
+ return svmTxCommand(svmCookInput(args, io, trailing, program), io);
2271
+ }
2272
+ const input = cookInput(args, io, trailing, undefined, program);
2273
+ const rpcUrl = endpoint(args, io, input.chain);
2274
+ return txCommand({ ...input, ...(rpcUrl === undefined ? {} : { rpcUrl }) }, io);
2275
+ },
2276
+ },
2277
+ pot: {
2278
+ usage: "sauce pot --chain <slug|id> --owner <address> [--salt <label> | --salt-hex <bytes32>] [--deploy …]",
2279
+ summary: "Predict a Pot's address, and deploy it or print the transaction that does",
2280
+ flags: {
2281
+ owner: { type: "string", value: "<address>", help: "Whose Pot: cook() is onlyOwner" },
2282
+ chain: { type: "string", value: "<slug|id>", help: "The chain the Pot is for" },
2283
+ ...SALT,
2284
+ deploy: { type: "boolean", help: "Send the deployment (needs an endpoint and a signer)" },
2285
+ ...ENDPOINT,
2286
+ ...SIGNER,
2287
+ "auto-approve": {
2288
+ type: "boolean",
2289
+ help: "Accepted, approving nothing: --deploy itself is the approval",
2290
+ },
2291
+ ...FORMAT,
2292
+ ...HELP,
2293
+ },
2294
+ details: [
2295
+ "A Pot's address is CREATE2 from the released Kitchen over (owner, salt), so it is known",
2296
+ "before it exists. Prints it and the unsigned Kitchen.deployPot transaction as JSON; with",
2297
+ "--deploy, sends it unless the Pot is already there, and waits until the endpoint shows its",
2298
+ "code. The owner defaults to the signer. Deploying is permissionless: with --owner, the",
2299
+ "signer sends and pays for another owner's Pot, which is that owner's alone — how the Pot",
2300
+ "intents share on a chain (owner: its Portal's Executor) is deployed. The default salt is",
2301
+ "zero: the one Pot an owner has by default. With a signer and no --owner, it is the",
2302
+ "signer's own Pot, so `sauce pot --chain base --keystore <keystore>` prints your address and",
2303
+ "your Pot (the keystore's own address field is read, with no password, where it has one).",
2304
+ "With an endpoint and no --deploy, it also reads",
2305
+ "the chain: whether the released engine and Kitchen are there, the Kitchen's fee, and",
2306
+ "whether the Pot is deployed and whose it is (under `deployment`, and on stderr).",
2307
+ "",
2308
+ "On Solana a Pot is the Kitchen's PDA over (owner, salt): this prints it and the create_pot",
2309
+ "instruction; --deploy (with --keypair) creates it. There the owner signs create_pot, so",
2310
+ "the signer is the owner.",
2311
+ ...SUPPORTED_ONLY("Deploys (or prints the deployment)"),
2312
+ "",
2313
+ "Examples:",
2314
+ " sauce pot --owner 0x… --chain base",
2315
+ " sauce pot --deploy --chain base --rpc-url <url> --keystore ~/.keys/me.json --salt treasury",
2316
+ " sauce pot --deploy --chain base --owner 0x… --config sauce.config.json --keystore <keystore>",
2317
+ " sauce pot --deploy --chain solana --rpc-url <url> --keypair ~/.config/solana/id.json",
2318
+ ].join("\n"),
2319
+ run: async (args, io) => {
2320
+ if (args.positionals.length > 0) {
2321
+ throw new UsageError(`unexpected argument ${args.positionals[0]}`);
2322
+ }
2323
+ const chain = potChain(args);
2324
+ const owner = stringFlag(args, "owner");
2325
+ // A Pot is predicted on every chain; deployed, or its deployment printed as a cast line,
2326
+ // only on a supported one. (Its JSON on a preview chain leaves the deployment out.)
2327
+ if (args.values.deploy === true)
2328
+ requireSupported("deploying a Pot", [chain]);
2329
+ if (stringFlag(args, "format") === "cast") {
2330
+ requireSupported("building the Pot's deployment", [chain]);
2331
+ }
2332
+ if (chain.kind === "svm") {
2333
+ if (stringFlag(args, "format") === "cast") {
2334
+ throw new UsageError("--format cast prints an EVM transaction; a Solana Pot has none");
2335
+ }
2336
+ if (args.values.deploy !== true) {
2337
+ const rpcUrl = endpoint(args, io, chain);
2338
+ const keyed = hasSvmSigner(args, io) ? await keypairAddress(args, io) : undefined;
2339
+ const target = { owner: svmOwner(args, keyed), ...saltOf(args) };
2340
+ return rpcUrl === undefined
2341
+ ? svmPotCommand(target)
2342
+ : svmPotStatusCommand({ ...target, rpcUrl });
2343
+ }
2344
+ const signer = await keypairOf(args, io);
2345
+ return svmPotDeployCommand({
2346
+ owner: svmOwner(args, signer.address, "on Solana the owner signs create_pot, so the signer creates its own Pot"),
2347
+ ...saltOf(args),
2348
+ rpcUrl: requiredEndpoint(args, io, chain),
2349
+ signer,
2350
+ });
2351
+ }
2352
+ if (args.values.deploy !== true) {
2353
+ // A signer, with no --owner, is asking for its own Pot: its address, without unlocking it
2354
+ // where the keystore names it.
2355
+ if (hasSvmSigner(args, io)) {
2356
+ throw new UsageError("a Solana keypair or wallet names no owner on an EVM chain: an EVM --wallet, " +
2357
+ "--keystore or --private-key");
2358
+ }
2359
+ if (owner === undefined && !hasSigner(args, io)) {
2360
+ throw new UsageError("missing --owner <address>: whose Pot (or a signer, --wallet, --keystore or " +
2361
+ "--private-key, for yours)");
2362
+ }
2363
+ const rpcUrl = endpoint(args, io, chain);
2364
+ const target = {
2365
+ chain,
2366
+ owner: owner === undefined ? await signerAddress(args, io) : parseAddress("owner", owner),
2367
+ ...saltOf(args),
2368
+ };
2369
+ return rpcUrl === undefined ? potCommand(target) : potStatusCommand({ ...target, rpcUrl });
2370
+ }
2371
+ if (stringFlag(args, "format") === "cast") {
2372
+ throw new UsageError("--format cast prints the unsigned transaction; --deploy sends it");
2373
+ }
2374
+ const account = await signerOf(args, io);
2375
+ return potDeployCommand({
2376
+ chain,
2377
+ // Kitchen.deployPot is permissionless: the signer may send another owner's.
2378
+ owner: owner === undefined ? account.address : parseAddress("owner", owner),
2379
+ ...saltOf(args),
2380
+ rpcUrl: requiredEndpoint(args, io, chain),
2381
+ account,
2382
+ });
2383
+ },
2384
+ },
2385
+ globals: {
2386
+ usage: "sauce globals --chain <slug|id> [--tokens] [--protocols] [--protocol <name>] [--stocks] " +
2387
+ "[--search <text>] [--json]",
2388
+ summary: "List the tokens, protocols and other names a program on a chain can use",
2389
+ flags: {
2390
+ chain: { type: "string", value: "<slug|id>", help: "The chain whose names to list" },
2391
+ tokens: { type: "boolean", help: "Only the token symbols" },
2392
+ protocols: { type: "boolean", help: "Only the protocol namespaces" },
2393
+ protocol: {
2394
+ type: "string",
2395
+ value: "<name>",
2396
+ help: "One namespace (UniswapV4, or its slug) with its methods",
2397
+ },
2398
+ stocks: { type: "boolean", help: "Only the chain's tokenized stocks" },
2399
+ search: {
2400
+ type: "string",
2401
+ value: "<text>",
2402
+ help: "Only the tokens, stocks included, whose symbol, name or ticker contains the text",
2403
+ },
2404
+ ...JSON_FLAG,
2405
+ ...HELP,
2406
+ },
2407
+ details: [
2408
+ "Every name a program compiled for the chain may use without declaring it, from the SDK's",
2409
+ "registries (routes.sourceGlobals) — the ones the compile resolves: token symbols with",
2410
+ "their addresses and decimals, protocol namespaces with each contract's address (and,",
2411
+ "with --protocol, its methods), the chain names that open intents, the defines, and the",
2412
+ "zero-import @sauce/token functions. With no filter it lists everything but the chain's",
2413
+ "tokenized stocks, which it counts: Ethereum and Solana have over a thousand each. A stock",
2414
+ "token is named like any other (SPCXc.balanceOf(...), balanceOf(TSLAx, account) on",
2415
+ "Solana); --stocks lists them with what each one is, and --search finds one by symbol,",
2416
+ "company name or ticker.",
2417
+ "",
2418
+ "Examples:",
2419
+ " sauce globals --chain base",
2420
+ " sauce globals --chain base --protocol UniswapV3 --json",
2421
+ " sauce globals --chain base --search spacex",
2422
+ ].join("\n"),
2423
+ run: (args) => {
2424
+ if (args.positionals.length > 0) {
2425
+ throw new UsageError(`unexpected argument ${args.positionals[0]}`);
2426
+ }
2427
+ const protocol = stringFlag(args, "protocol");
2428
+ const search = stringFlag(args, "search");
2429
+ return globalsCommand({
2430
+ chain: parseChain(requiredFlag(args, "chain", "<slug|id>")),
2431
+ tokens: args.values.tokens === true,
2432
+ protocols: args.values.protocols === true,
2433
+ stocks: args.values.stocks === true,
2434
+ ...(protocol === undefined ? {} : { protocol }),
2435
+ ...(search === undefined ? {} : { search }),
2436
+ });
2437
+ },
2438
+ },
2439
+ price: {
2440
+ usage: [
2441
+ "sauce price --chain <slug|id> <price> <quote> per <base> [--rpc-url <url>] [--json]",
2442
+ "sauce price --chain <slug|id> <base> <quote> (<price> | --sqrt-price-x96 <value>) [--json]",
2443
+ ],
2444
+ summary: "Turn a price into a pool's sqrtPriceX96 and a swap's limit and average-price floor",
2445
+ flags: {
2446
+ chain: { type: "string", value: "<slug|id>", help: "The chain the pool is on" },
2447
+ "sqrt-price-x96": {
2448
+ type: "string",
2449
+ value: "<value>",
2450
+ help: "Read a pool's sqrtPriceX96 as a price instead",
2451
+ },
2452
+ ...ENDPOINT,
2453
+ ...JSON_FLAG,
2454
+ ...HELP,
2455
+ },
2456
+ details: [
2457
+ "`2700 USDC per WETH` says it in words: 2,700 USDC for one WETH. The same price is",
2458
+ "`WETH USDC 2700`: <base> <quote> <price>, the price how many <quote> tokens one <base> is",
2459
+ "worth. A token is a symbol the chain registers (sauce globals --tokens), or an address with",
2460
+ "its decimals (0x…:18); with an endpoint, an address alone, its decimals read from the",
2461
+ "token. The first line says what the price means, both ways round",
2462
+ "(1 WETH = 2700 USDC, 1 USDC = 0.00037… WETH). Then the pool's sqrtPriceX96 at that price,",
2463
+ "for the pair's order on the chain (token0 is the lower address), and for each direction:",
2464
+ " sqrtPriceLimitX96 the same number as a swap's limit: a floor when selling token0, a",
2465
+ " ceiling when selling token1",
2466
+ " minAvgPrice output units per input unit times 1e18, rounded up, for a program's",
2467
+ " check out * 1e18 >= minAvgPrice * spent",
2468
+ "Uniswap V3 and V4 and their forks share this price. With --sqrt-price-x96, a pool's",
2469
+ "price is read back the other way.",
2470
+ "",
2471
+ "With --rpc-url (or --config), it also reads the pair's price now, from its deepest Uniswap",
2472
+ "V3 pool on the chain, and warns when the price given is 10x or more away from it, saying so",
2473
+ "when the price looks written the wrong way round. Without, nothing reaches a network.",
2474
+ "",
2475
+ "Examples:",
2476
+ " sauce price --chain base 2700 USDC per WETH",
2477
+ " sauce price --chain base 2700 USDC per WETH --rpc-url <url>",
2478
+ " sauce price --chain base WETH USDC --sqrt-price-x96 4116816085950893928074568",
2479
+ ].join("\n"),
2480
+ run: async (args, io) => {
2481
+ const chain = pricedChain(parseChain(requiredFlag(args, "chain", "<slug|id>")));
2482
+ const sqrt = stringFlag(args, "sqrt-price-x96");
2483
+ // `<price> <quote> per <base>`, or `<base> <quote> <price>`.
2484
+ const worded = args.positionals.length === 4 && args.positionals[2]?.toLowerCase() === "per";
2485
+ const [base, quote, price, ...rest] = worded
2486
+ ? [args.positionals[3], args.positionals[1], args.positionals[0]]
2487
+ : args.positionals;
2488
+ if (base === undefined || quote === undefined) {
2489
+ throw new UsageError("missing the pair: <price> <quote> per <base>, as 2700 USDC per WETH (or WETH USDC 2700)");
2490
+ }
2491
+ if (rest.length > 0)
2492
+ throw new UsageError(`unexpected argument ${rest[0]}`);
2493
+ const given = priceGiven(price, sqrt);
2494
+ const reach = stringFlag(args, "rpc-url") !== undefined || stringFlag(args, "config") !== undefined;
2495
+ const client = reach ? await connect(requiredEndpoint(args, io, chain), chain) : undefined;
2496
+ // A token the chain registers no decimals for has them read from it, with an endpoint.
2497
+ const [baseToken, quoteToken] = await resolvePriceTokens([base, quote], chain, client);
2498
+ const pair = { base: baseToken, quote: quoteToken };
2499
+ const live = client === undefined ? undefined : await livePrice(client, chain, pair.base, pair.quote);
2500
+ const output = priceCommand({
2501
+ chain,
2502
+ ...pair,
2503
+ price: given,
2504
+ ...(live === undefined ? {} : { live }),
2505
+ });
2506
+ return reach && live === undefined
2507
+ ? {
2508
+ ...output,
2509
+ notes: [
2510
+ ...(output.notes ?? []),
2511
+ `no Uniswap V3 pool for ${pair.base.symbol}/${pair.quote.symbol} on ${chain.slug} ` +
2512
+ "to read the price now from",
2513
+ ],
2514
+ }
2515
+ : output;
2516
+ },
2517
+ },
2518
+ pools: {
2519
+ usage: "sauce pools --chain <slug|id> <token> <token> [--v4-key <fee:spacing>]… (--rpc-url <url> | --config <file>) [--json]",
2520
+ summary: "List a pair's price-limit pools on a chain, deepest first, with their prices",
2521
+ flags: {
2522
+ chain: { type: "string", value: "<slug|id>", help: "The chain the pools are on" },
2523
+ "v4-key": {
2524
+ type: "string",
2525
+ multiple: true,
2526
+ value: "<fee:spacing>",
2527
+ help: "Also try this hookless Uniswap V4 pool key (3000:60)",
2528
+ },
2529
+ ...ENDPOINT,
2530
+ ...JSON_FLAG,
2531
+ ...HELP,
2532
+ },
2533
+ details: [
2534
+ "Every pool of the pair at the price-limit venues the registry records on the chain:",
2535
+ "Uniswap V3 and PancakeSwap V3 at each fee tier their factory enables, Aerodrome Slipstream",
2536
+ "at each tick spacing of each of its CLFactories, and hookless Uniswap V4 pools at the keys",
2537
+ "100:1, 500:10, 3000:60 and 10000:200, and any --v4-key. A token is a symbol the chain",
2538
+ "registers (sauce globals --tokens), or an address: its decimals and symbol are read from",
2539
+ "the token (or give them, 0x…:8).",
2540
+ "",
2541
+ "Pools with liquidity come first, deepest first: by the liquidity at each pool's price,",
2542
+ "which is in the same units at every venue for one pair. For each: the venue and the",
2543
+ "contract a program finds it through, its address (a V4 pool's id and key), its fee read",
2544
+ "from the pool (a V4 pool's LP fee and protocol fee, from StateView), tick spacing,",
2545
+ "liquidity, tick and sqrtPriceX96, and both ways round: what one token costs in the other",
2546
+ "before and with the fee, the distributed swap's maxPrice at that price (pay base units per",
2547
+ "buy base unit times 1e18: the price times 10^(18 + pay decimals - buy decimals)), and about",
2548
+ "how much of the paid token, fee included, moves the price 1% against the taker, walked",
2549
+ "through the pool's ticks. Pools with no liquidity at their price are listed after them, as",
2550
+ "skipped. Then what was looked at.",
2551
+ "",
2552
+ "It reads the chain in five requests, each one eth_call for every read in it, and needs an",
2553
+ "endpoint: --rpc-url, or --config with the chain's entry.",
2554
+ "",
2555
+ "Examples:",
2556
+ " sauce pools --chain base USDC WETH --config sauce.config.json",
2557
+ " sauce pools --chain base USDC 0x… --rpc-url <url> --json",
2558
+ " sauce pools --chain base WETH USDC --v4-key 50:1 --config sauce.config.json",
2559
+ ].join("\n"),
2560
+ run: async (args, io) => {
2561
+ const chain = parseChain(requiredFlag(args, "chain", "<slug|id>"));
2562
+ const [first, second, ...rest] = args.positionals;
2563
+ if (first === undefined || second === undefined) {
2564
+ throw new UsageError("missing the pair: <token> <token>, as USDC WETH");
2565
+ }
2566
+ if (rest.length > 0)
2567
+ throw new UsageError(`unexpected argument ${rest[0]}`);
2568
+ if (chain.kind !== "evm") {
2569
+ throw new UsageError(`sauce pools lists Uniswap V3- and V4-style pools, on an EVM chain; ${chain.slug} has none`);
2570
+ }
2571
+ const v4Keys = repeatedFlag(args, "v4-key").map((raw) => parseV4Key(raw));
2572
+ return poolsCommand({
2573
+ chain,
2574
+ client: await connect(requiredEndpoint(args, io, chain), chain),
2575
+ tokens: [first, second],
2576
+ v4Keys,
2577
+ });
2578
+ },
2579
+ },
2580
+ inspect: {
2581
+ usage: "sauce inspect <hex | tx-hash | file | -> [--chain <slug|id>] [--source <file | ->] [options]",
2582
+ summary: "Take a cook, a Portal or Kitchen call, a program or a file apart",
2583
+ flags: {
2584
+ ...PROGRAM,
2585
+ source: {
2586
+ type: "string",
2587
+ value: "<file>",
2588
+ help: "The program a cook was compiled from: decode its arguments",
2589
+ },
2590
+ ...ENDPOINT,
2591
+ ...JSON_FLAG,
2592
+ ...HELP,
2593
+ },
2594
+ details: [
2595
+ "Reads what a SauceScript author wrote back out of bytes: a Pot.cook (its engine, its",
2596
+ "program, the intents the program opens), a Kitchen.deployPot (the Pot it makes), a Portal",
2597
+ "publish or publishAndFund (the route and the reward), an ERC-20 call, or a bare program.",
2598
+ "A 32-byte hash with --rpc-url (or --config and --chain) is a transaction, fetched first.",
2599
+ "With --source, a cook's program is checked against that file's and the arguments after it",
2600
+ "are decoded against its main. A file operand is compiled and its intents listed, with",
2601
+ "each value it measures at run time named. No opcode listing: programs are reported by",
2602
+ "size, hash and what they open.",
2603
+ "",
2604
+ "Examples:",
2605
+ " sauce inspect 0x… --chain base --source split.sauce.ts",
2606
+ " sauce inspect 0x<tx hash> --rpc-url <url>",
2607
+ " sauce inspect bridge.sauce.ts --chain arbitrum --intent-deadline 2000000000 --intent-creator 0x…",
2608
+ ].join("\n"),
2609
+ run: async (args, io) => {
2610
+ const [operand, ...extra] = args.positionals;
2611
+ // `-`: stdin carries the hex, the hash or the program — whichever it reads as.
2612
+ const piped = operand === "-" ? io.readStdin().trim() : undefined;
2613
+ if (piped !== undefined && extra.length > 0) {
2614
+ throw new UsageError(`unexpected argument ${extra[0]}`);
2615
+ }
2616
+ const word = piped ?? operand;
2617
+ if (word === undefined || !/^0x[0-9a-fA-F]*$/.test(word)) {
2618
+ if (stringFlag(args, "source") !== undefined) {
2619
+ throw new UsageError("--source goes with hex: a file operand is its own source");
2620
+ }
2621
+ const input = await programInput(args, io, piped === undefined ? fileOperand(args) : { file: STDIN, text: piped, stdin: true });
2622
+ return inspectFile(input.file, compileProgram(input, io));
2623
+ }
2624
+ const hex = piped === undefined
2625
+ ? hexOperand(args, "<hex | tx-hash | file>")
2626
+ : hexOperand({ ...args, positionals: [piped] }, "<hex | tx-hash | file>");
2627
+ const sourceFile = stringFlag(args, "source");
2628
+ if (piped !== undefined && sourceFile === "-") {
2629
+ throw new UsageError("stdin carries one thing: the hex, or --source's program, not both");
2630
+ }
2631
+ const fetched = TX_HASH.test(hex) ? await transactionEndpoint(args, io) : undefined;
2632
+ if (TX_HASH.test(hex) && fetched === undefined) {
2633
+ throw new UsageError("32 bytes of hex is a transaction hash: give --rpc-url <url> (or --config <file> with " +
2634
+ "--chain) to fetch it");
2635
+ }
2636
+ const source = sourceFile === undefined
2637
+ ? undefined
2638
+ : await programInput(args, io, sourceFile, fetched?.chain);
2639
+ const chainFlag = stringFlag(args, "chain");
2640
+ const chain = fetched?.chain ??
2641
+ source?.chain ??
2642
+ (chainFlag === undefined ? undefined : parseChain(chainFlag));
2643
+ return inspectCommand({
2644
+ hex,
2645
+ ...(chain === undefined ? {} : { chain }),
2646
+ ...(fetched === undefined ? {} : { rpcUrl: fetched.rpcUrl }),
2647
+ ...(source === undefined
2648
+ ? {}
2649
+ : { source: { file: source.file, program: compileProgram(source, io) } }),
2650
+ });
2651
+ },
2652
+ },
2653
+ verify: {
2654
+ usage: "sauce verify <payload | calldata | tx-hash> [--pin <hash:bytes>]… [--engine <address>]… [--rpc-url <url>]",
2655
+ summary: "Check that a payload, cook or intent runs the audited settle program",
2656
+ flags: {
2657
+ pin: {
2658
+ type: "string",
2659
+ multiple: true,
2660
+ value: "<hash:bytes>",
2661
+ help: "Also accept this historical settle program (keccak256:length)",
2662
+ },
2663
+ engine: {
2664
+ type: "string",
2665
+ multiple: true,
2666
+ value: "<address>",
2667
+ help: "Also accept a cook on this engine, besides the released one",
2668
+ },
2669
+ chain: { type: "string", value: "<slug|id>", help: "The chain a transaction hash is on" },
2670
+ "min-out": {
2671
+ type: "string",
2672
+ value: "<amount>",
2673
+ help: "Solana: the floor the settle must enforce on its first escrow",
2674
+ },
2675
+ "spl-count": {
2676
+ type: "string",
2677
+ value: "<n>",
2678
+ help: "Solana: how many escrows the settle sweeps with its first token program",
2679
+ },
2680
+ ...ENDPOINT,
2681
+ ...JSON_FLAG,
2682
+ ...HELP,
2683
+ },
2684
+ details: [
2685
+ "Takes a settle payload, Pot.cook calldata, Portal.publish[AndFund] calldata, or — with an",
2686
+ "endpoint — a transaction hash, and checks the settle it carries with the SDK's",
2687
+ "validateSettleProgram: the program must hash to the current pin (or a --pin), and its",
2688
+ "arguments must be the one canonical encoding. Prints tokens, minOut and recipient. A cook",
2689
+ "must name the released engine (or an --engine); an intent must carry a settle cook. A",
2690
+ "rejection exits 1 with its code: the SDK's SettleFailureCode, or UNKNOWN_ENGINE or",
2691
+ "NO_SETTLE.",
2692
+ "",
2693
+ "On Solana (--chain solana, a transaction signature and an endpoint): an SVM settle's",
2694
+ "floor and split are compiled into it, so give them, --min-out and --spl-count. The",
2695
+ "engine invocation the cook made is checked by the SDK's verifySvmSettleExecution against",
2696
+ "the settle recompiled for those values; a rejection is NO_SETTLE or NOT_GENUINE.",
2697
+ "",
2698
+ "Examples:",
2699
+ " sauce verify 0x<payload>",
2700
+ " sauce verify 0x<tx hash> --rpc-url <url> --pin 0x…:435",
2701
+ " sauce verify <signature> --chain solana --rpc-url <url> --min-out 0 --spl-count 1",
2702
+ ].join("\n"),
2703
+ run: async (args, io) => {
2704
+ const chainFlag = stringFlag(args, "chain");
2705
+ if (chainFlag !== undefined && parseChain(chainFlag).kind === "svm") {
2706
+ const [signature, ...rest] = args.positionals;
2707
+ if (signature === undefined)
2708
+ throw new UsageError("missing <signature>: the cook's transaction");
2709
+ if (rest.length > 0)
2710
+ throw new UsageError(`unexpected argument ${rest[0]}`);
2711
+ const amount = (flag) => {
2712
+ const raw = requiredFlag(args, flag, flag === "min-out" ? "<amount>" : "<n>");
2713
+ if (!/^\d+$/.test(raw))
2714
+ throw new UsageError(`--${flag}: '${raw}' is not a whole number`);
2715
+ return BigInt(raw);
2716
+ };
2717
+ return svmVerifyCommand({
2718
+ signature,
2719
+ rpcUrl: requiredEndpoint(args, io, parseChain(chainFlag)),
2720
+ minOut: amount("min-out"),
2721
+ splCount: amount("spl-count"),
2722
+ });
2723
+ }
2724
+ const hex = hexOperand(args, "<payload | calldata | tx-hash>");
2725
+ const fetched = TX_HASH.test(hex) ? await transactionEndpoint(args, io) : undefined;
2726
+ return verifyCommand({
2727
+ hex,
2728
+ pins: repeatedFlag(args, "pin").map(parsePin),
2729
+ engines: repeatedFlag(args, "engine").map((engine) => parseAddress("engine", engine)),
2730
+ ...(fetched === undefined ? {} : fetched),
2731
+ });
2732
+ },
2733
+ },
2734
+ skills: {
2735
+ usage: "sauce skills <install | update | status> [--agent <agent>,…] [--dir <project>] [--force]",
2736
+ summary: "Install, update or check this package's agent skills in a project",
2737
+ flags: {
2738
+ agent: {
2739
+ type: "string",
2740
+ multiple: true,
2741
+ value: "<agent>",
2742
+ help: `${AGENTS.join(", ")} or all (default: all)`,
2743
+ },
2744
+ dir: { type: "string", value: "<project>", help: "The project (default .)" },
2745
+ force: { type: "boolean", help: "update: overwrite files edited since they were installed" },
2746
+ ...HELP,
2747
+ },
2748
+ details: [
2749
+ "The skills ship once, as Agent Skills directories, and are written where agents read",
2750
+ "them: .claude/skills/ (claude) and .agents/skills/ (codex, cursor, copilot, gemini), which",
2751
+ "between them reach all five. That is the default, and what --agent all means; an agent",
2752
+ "named alone gets the one it reads. --agent agents-md, only when asked for, also writes an",
2753
+ "index of the skills into a block of AGENTS.md, for a tool that reads that file but no",
2754
+ "skills directory. update and status take the targets installed.",
2755
+ "",
2756
+ " install The first install. Never overwrites: on a project already installed it says",
2757
+ " whether the skills are current, and to run update if not.",
2758
+ " update Adds new skill files, replaces changed ones, removes retired ones. A file edited",
2759
+ " since it was installed is kept and shown, unless --force.",
2760
+ " status Each target: up to date, outdated or modified, with its files. Exits 1 while",
2761
+ " any is outdated or not installed.",
2762
+ ].join("\n"),
2763
+ run: (args) => {
2764
+ const [sub, ...rest] = args.positionals;
2765
+ if (sub !== "install" && sub !== "update" && sub !== "status") {
2766
+ throw new UsageError(sub === undefined
2767
+ ? "missing subcommand: install, update or status"
2768
+ : `unknown subcommand '${sub}': install, update or status`);
2769
+ }
2770
+ if (rest.length > 0)
2771
+ throw new UsageError(`unexpected argument ${rest[0]}`);
2772
+ if (args.values.force === true && sub !== "update") {
2773
+ throw new UsageError(`--force goes with update; ${sub} never overwrites`);
2774
+ }
2775
+ const project = stringFlag(args, "dir") ?? ".";
2776
+ const source = skillsSource();
2777
+ const asked = parseAgents(repeatedFlag(args, "agent"));
2778
+ const targets = asked !== undefined
2779
+ ? targetsFor(asked)
2780
+ : sub === "install"
2781
+ ? targetsFor(DEFAULT_AGENTS)
2782
+ : installedTargets(project);
2783
+ if (targets.length === 0) {
2784
+ throw new CliError(`no agent skills are installed in ${project}: run \`sauce skills install\``);
2785
+ }
2786
+ if (sub === "status") {
2787
+ const statuses = targets.map((target) => statusOf(project, source, target));
2788
+ const failing = statuses.some((status) => status.state === "outdated" || status.state === "not installed");
2789
+ return {
2790
+ ...lines(statuses.flatMap((status) => describeStatus(status, source))),
2791
+ ...(failing ? { exitCode: 1 } : {}),
2792
+ };
2793
+ }
2794
+ return lines(targets.flatMap((target) => (sub === "install"
2795
+ ? installTarget(project, source, target)
2796
+ : updateTarget(project, source, target, args.values.force === true)).lines));
2797
+ },
2798
+ },
2799
+ init: {
2800
+ usage: [
2801
+ "sauce init [<dir>] [--agent <agent>,…] [--force] [--install]",
2802
+ "sauce init <dir> --tsconfig [--force]",
2803
+ ],
2804
+ summary: "Scaffold a project that uses this package",
2805
+ flags: {
2806
+ agent: {
2807
+ type: "string",
2808
+ multiple: true,
2809
+ value: "<agent>",
2810
+ help: `Whose skills to install: ${AGENTS.join(", ")} or all`,
2811
+ },
2812
+ force: { type: "boolean", help: "Overwrite files that already exist with other content" },
2813
+ install: { type: "boolean", help: "Run npm install in the project afterwards" },
2814
+ tsconfig: {
2815
+ type: "boolean",
2816
+ help: "Write only <dir>/tsconfig.json: an editor's SauceScript project for programs there",
2817
+ },
2818
+ ...HELP,
2819
+ },
2820
+ details: [
2821
+ "Writes package.json (pinning this exact version), AGENTS.md (the project's instructions,",
2822
+ "which coding agents read), CLAUDE.md and GEMINI.md importing it for those agents, a",
2823
+ ".gitignore for local config, sauce.config.example.json (placeholders only),",
2824
+ "programs/tsconfig.json (SauceScript's names, and a plugin, for an editor checking the",
2825
+ "programs there: kept apart from the project's other TypeScript), and then",
2826
+ "installs the agent skills (`sauce skills install`), for every agent unless --agent names",
2827
+ "some. It runs no package manager unless --install, which runs npm install.",
2828
+ "",
2829
+ "--tsconfig writes only <dir>/tsconfig.json, the same SauceScript project as",
2830
+ "programs/tsconfig.json, for programs in a project init did not write, or in another",
2831
+ "directory: an editor takes a file's nearest tsconfig.json, so every *.sauce.ts under <dir>",
2832
+ "gets SauceScript's names and the plugin. Where the project's own tsconfig.json also covers",
2833
+ 'them, add "exclude": ["**/*.sauce.ts"] there, so its TypeScript does not check them too.',
2834
+ "",
2835
+ "Examples:",
2836
+ " sauce init my-project",
2837
+ " sauce init programs --tsconfig",
2838
+ ].join("\n"),
2839
+ run: (args, io) => {
2840
+ const [dir = ".", ...rest] = args.positionals;
2841
+ if (rest.length > 0)
2842
+ throw new UsageError(`unexpected argument ${rest[0]}: give one <dir>`);
2843
+ if (args.values.tsconfig === true) {
2844
+ for (const flag of ["agent", "install"]) {
2845
+ if (args.values[flag] !== undefined) {
2846
+ throw new UsageError(`--${flag} goes with a whole project: --tsconfig writes one file`);
2847
+ }
2848
+ }
2849
+ const written = writeSauceScriptTsconfig(dir, skillsSource().packageName, args.values.force === true);
2850
+ return lines([
2851
+ `${written.state.padEnd(10)} ${written.path}`,
2852
+ "Every *.sauce.ts under it now has SauceScript's names in an editor. If the project's",
2853
+ 'own tsconfig.json covers these files too, add "exclude": ["**/*.sauce.ts"] to it.',
2854
+ ]);
2855
+ }
2856
+ const agents = parseAgents(repeatedFlag(args, "agent")) ?? DEFAULT_AGENTS;
2857
+ const result = initProject(dir, skillsSource(), agents, args.values.force === true);
2858
+ io.stdout([
2859
+ `Scaffolded ${dir}:`,
2860
+ ...result.files.map((file) => ` ${file.state.padEnd(10)} ${file.path}`),
2861
+ ...result.skills.flatMap((report) => report.lines.map((line) => ` ${line}`)),
2862
+ "",
2863
+ ].join("\n"));
2864
+ if (args.values.install === true) {
2865
+ io.stdout(`Running npm install in ${dir}\n`);
2866
+ const status = io.run("npm", ["install"], dir);
2867
+ if (status !== 0)
2868
+ throw new CliError(`npm install exited with ${status}`);
2869
+ }
2870
+ return lines([
2871
+ "Next:",
2872
+ ...(dir === "." ? [] : [` cd ${dir}`]),
2873
+ ...(args.values.install === true ? [] : [" npm install"]),
2874
+ " npx sauce --help",
2875
+ ]);
2876
+ },
2877
+ },
2878
+ mcp: {
2879
+ usage: [
2880
+ "sauce mcp [--config <file>]",
2881
+ "sauce mcp --wallets [<dir>] (--password-env <NAME> | --password-file <path> | --password-command <command>) [--config <file>]",
2882
+ "sauce mcp --http <port> [--host <address>] [--allowed-host <name>]… [--config <file>]",
2883
+ "sauce mcp setup [--agent <agent>,…] [--dir <project>] [--config <file>] [--force]",
2884
+ ],
2885
+ summary: "Serve the commands and the agent skills to coding agents over MCP",
2886
+ flags: { ...MCP_FLAGS, ...HELP },
2887
+ details: [
2888
+ "The Sauce MCP server. Its tools are this command's building half — sauce_compile,",
2889
+ "sauce_actions, sauce_tx, sauce_pot, sauce_simulate, sauce_intent_publish,",
2890
+ "sauce_intent_fill, sauce_inspect, sauce_verify, sauce_globals, sauce_price, sauce_pools",
2891
+ "and sauce_chains — with the agent skills as tools (sauce_skills, sauce_skill, sauce_dev,",
2892
+ "sauce_install_skills) and as resources, at sauce://skills/<path>. It takes no key: every",
2893
+ "transaction comes back unsigned, for the user's own wallet.",
2894
+ "",
2895
+ "Over stdio, --wallets (the wallet directory, default ~/.sauce/wallets) and a password",
2896
+ "source add sauce_wallet_create, sauce_wallet_list and sauce_wallet_send: the server then",
2897
+ "signs with the wallets of that directory alone, unlocked by that password, which it reads",
2898
+ "once at start (from the variable an MCP client's config passes from the agent's .env, a",
2899
+ "file, or a command) and which no tool takes or returns. sauce_wallet_send rehearses what it",
2900
+ "is given and holds it to the wallet's policy (sauce wallet --help) before it sends.",
2901
+ "The HTTP server never signs: --wallets is refused there, and it has no wallet tools.",
2902
+ "",
2903
+ "Over stdio by default, what a coding agent launches. With --http, Streamable HTTP at /mcp,",
2904
+ "stateless: on 127.0.0.1 unless --host says otherwise, answering only a loopback Host or an",
2905
+ "--allowed-host one. It authenticates no one, so off loopback it needs --allowed-host, and",
2906
+ "goes behind your own authentication. The chains it reads are --config's; it reads no",
2907
+ "environment, and never shows a URL from the file.",
2908
+ "",
2909
+ "setup adds the server to a project for each agent, in the file its vendor documents:",
2910
+ ".mcp.json (claude), .codex/config.toml (codex), .cursor/mcp.json (cursor),",
2911
+ ".vscode/mcp.json (copilot) and .gemini/settings.json (gemini), keeping what else each holds.",
2912
+ "",
2913
+ "Examples:",
2914
+ " npx -y @eco-incorp/sauce mcp",
2915
+ " npx -y @eco-incorp/sauce mcp --wallets --password-env SAUCE_WALLET_PASSWORD",
2916
+ " npx -y @eco-incorp/sauce mcp --http 3000 --config sauce.config.json",
2917
+ " npx sauce mcp setup --agent claude,cursor",
2918
+ ].join("\n"),
2919
+ run: (args, io) => mcpCommand(args, io),
2920
+ },
2921
+ };
2922
+ /** What a command prints on stdout: tx and pot their JSON (or `--format cast`), the rest their
2923
+ * text (or `--json`). */
2924
+ function render(command, output, args) {
2925
+ const format = stringFlag(args, "format");
2926
+ if (format === "cast")
2927
+ return output.cast ?? JSON.stringify(output.json, null, 2);
2928
+ if (format !== undefined && format !== "json") {
2929
+ throw new UsageError(`--format: '${format}' is not json or cast`);
2930
+ }
2931
+ // `tx` and `pot` print a transaction, so JSON is their default; every other command a report.
2932
+ const jsonByDefault = "format" in command.flags && !("json" in command.flags);
2933
+ return format === "json" || jsonByDefault || args.values.json === true
2934
+ ? JSON.stringify(output.json, null, 2)
2935
+ : output.text;
2936
+ }
2937
+ /** The flags of `command` that `only` names (`undefined`: those every chain takes). */
2938
+ const flagsFor = (command, only) => Object.fromEntries(Object.entries(command.flags).filter(([, spec]) => spec.only === only));
2939
+ function commandHelp(command) {
2940
+ const usage = typeof command.usage === "string" ? [command.usage] : command.usage;
2941
+ const sections = [
2942
+ ["Options:", undefined],
2943
+ ["EVM chains only:", "evm"],
2944
+ ["Solana only:", "svm"],
2945
+ ].flatMap(([heading, only]) => {
2946
+ const flags = flagsFor(command, only);
2947
+ return Object.keys(flags).length === 0 ? [] : [heading, describeFlags(flags), ""];
2948
+ });
2949
+ return [
2950
+ `${command.summary}.`,
2951
+ "",
2952
+ `Usage: ${usage.join("\n ")}`,
2953
+ "",
2954
+ ...sections,
2955
+ command.details,
2956
+ "",
2957
+ ].join("\n");
2958
+ }
2959
+ /** `text` in lines of at most 96 characters, as the help is written. */
2960
+ function wrapped(text) {
2961
+ const out = [];
2962
+ let line = "";
2963
+ for (const word of text.split(" ")) {
2964
+ if (line !== "" && line.length + 1 + word.length > 96) {
2965
+ out.push(line);
2966
+ line = word;
2967
+ }
2968
+ else
2969
+ line = line === "" ? word : `${line} ${word}`;
2970
+ }
2971
+ return line === "" ? out : [...out, line];
2972
+ }
2973
+ function mainHelp() {
2974
+ const width = Math.max(...Object.keys(COMMANDS).map((name) => name.length));
2975
+ return [
2976
+ "sauce: compile SauceScript, and run it on a chain.",
2977
+ "",
2978
+ "Usage: sauce <command> [options]",
2979
+ "",
2980
+ "Commands:",
2981
+ ...Object.entries(COMMANDS).map(([name, command]) => ` ${name.padEnd(width)} ${command.summary}`),
2982
+ "",
2983
+ "Run `sauce <command> --help` for its options. Nothing reaches a network without --rpc-url",
2984
+ "or --config, and nothing is signed without --wallet, --keystore or --private-key (on",
2985
+ "Solana, --wallet or --keypair). A password is read only from the source named:",
2986
+ "--password-env NAME (that variable, the one read of the environment), --password-file or",
2987
+ "--password-command; else it is asked for.",
2988
+ "",
2989
+ ...wrapped(previewChainsNote()),
2990
+ "",
2991
+ "A program file may be `-`, read from stdin (`cat pay.sauce.ts | sauce compile - --chain",
2992
+ "base`); it is never read without one. Its relative imports then resolve against the",
2993
+ "current directory, or --source-dir. Questions go to the terminal (/dev/tty) instead of",
2994
+ "stdin; with no terminal, a run names what it needs approved and sends nothing until",
2995
+ "--auto-approve (and a password source for a wallet or keystore) is given.",
2996
+ "",
2997
+ ].join("\n");
2998
+ }
2999
+ /** Every command by the words that name it: `compile`, `run`, …, and `intent <verb>` for each of
3000
+ * the intent verbs. */
3001
+ const ALL_COMMANDS = [
3002
+ ...Object.entries(COMMANDS),
3003
+ ...Object.entries(INTENT_VERBS).map(([verb, command]) => [`intent ${verb}`, command]),
3004
+ ...Object.entries(WALLET_VERBS).map(([verb, command]) => [`wallet ${verb}`, command]),
3005
+ ];
3006
+ /** The commands that take verbs, and their verbs. */
3007
+ const VERBS = {
3008
+ intent: INTENT_VERBS,
3009
+ wallet: WALLET_VERBS,
3010
+ };
3011
+ /** The command `words` name — `intent fill` for `intent fill …` — with the words after it. */
3012
+ function commandOf(words) {
3013
+ const [name, verb, ...more] = words;
3014
+ const verbs = name === undefined || !Object.hasOwn(VERBS, name) ? undefined : VERBS[name];
3015
+ if (verbs !== undefined && verb !== undefined && Object.hasOwn(verbs, verb)) {
3016
+ return { label: `${name} ${verb}`, command: verbs[verb], rest: more };
3017
+ }
3018
+ if (name !== undefined && Object.hasOwn(COMMANDS, name)) {
3019
+ return { label: name, command: COMMANDS[name], rest: words.slice(1) };
3020
+ }
3021
+ return undefined;
3022
+ }
3023
+ /** Every flag any command takes: a flag given to the wrong command is named as that, never
3024
+ * "unknown", and never swallowed as one of `main`'s arguments. */
3025
+ const ANY_FLAG = Object.assign({}, ...ALL_COMMANDS.map(([, c]) => c.flags));
3026
+ /** The flag `word` spells (`--name`, `--name=value`, `-x`), if it is one any command takes. */
3027
+ function flagOf(word) {
3028
+ const long = /^--([\w-]+)(?:=|$)/.exec(word)?.[1];
3029
+ if (long !== undefined)
3030
+ return Object.hasOwn(ANY_FLAG, long) ? ANY_FLAG[long] : undefined;
3031
+ const short = /^-(\w)$/.exec(word)?.[1];
3032
+ return short === undefined ? undefined : Object.values(ANY_FLAG).find((f) => f.short === short);
3033
+ }
3034
+ /**
3035
+ * The command's flag words and its trailing words (`--args …`). Flags may come in any order, and
3036
+ * after the trailing ones too: past `--args`, a word that is a flag is read as one, with its value;
3037
+ * every other word is an argument, in order. After a `--` there, every word is an argument, so one
3038
+ * that looks like a flag can still be passed.
3039
+ */
3040
+ function splitArgv(rest, command) {
3041
+ const at = command.trailing === undefined ? -1 : rest.indexOf(`--${command.trailing}`);
3042
+ if (at < 0)
3043
+ return { flags: [...rest] };
3044
+ const flags = rest.slice(0, at);
3045
+ const trailing = [];
3046
+ for (let i = at + 1; i < rest.length; i++) {
3047
+ const word = rest[i];
3048
+ if (word === "--") {
3049
+ trailing.push(...rest.slice(i + 1));
3050
+ break;
3051
+ }
3052
+ const flag = flagOf(word);
3053
+ if (flag === undefined) {
3054
+ trailing.push(word);
3055
+ continue;
3056
+ }
3057
+ flags.push(word);
3058
+ if (flag.type === "string" && !word.includes("=") && i + 1 < rest.length)
3059
+ flags.push(rest[++i]);
3060
+ }
3061
+ return { flags, trailing };
3062
+ }
3063
+ const SIGNING = new Set([
3064
+ "wallet",
3065
+ "keystore",
3066
+ "password-env",
3067
+ "password-file",
3068
+ "password-command",
3069
+ "private-key",
3070
+ "keypair",
3071
+ ]);
3072
+ const REACHING = new Set(["rpc-url", "config"]);
3073
+ /** Why `flag`, which another command takes, is not one of `name`'s (`intent fill`, say). */
3074
+ function notTaken(name, flag) {
3075
+ const takers = ALL_COMMANDS.filter(([, command]) => flag in command.flags).map(([other]) => other);
3076
+ const own = commandOf(name.split(" ")).command.flags;
3077
+ const why = name === "tx" && SIGNING.has(flag)
3078
+ ? "tx signs nothing: it prints the transaction unsigned, for a wallet (sauce run signs and sends it)"
3079
+ : SIGNING.has(flag) && !Object.keys(own).some((key) => SIGNING.has(key))
3080
+ ? `${name} signs nothing`
3081
+ : REACHING.has(flag) && !("config" in own)
3082
+ ? `${name} reads nothing from a chain`
3083
+ : flag === "auto-approve"
3084
+ ? `${name} has nothing to ask`
3085
+ : undefined;
3086
+ return (`--${flag} is not an option of sauce ${name}` +
3087
+ (why === undefined ? "" : `: ${why}`) +
3088
+ ` (${takers.map((taker) => `sauce ${taker}`).join(", ")} ${takers.length === 1 ? "takes" : "take"} it)`);
3089
+ }
3090
+ /** Registers a `--private-key` value as a secret before anything can fail and print it. */
3091
+ function rememberSecrets(given) {
3092
+ // A word may hold several, from a shell that did not split a variable: split them here too.
3093
+ const argv = given.flatMap((word) => (/^-\S*\s/.test(word) ? word.split(/\s+/) : [word]));
3094
+ argv.forEach((word, index) => {
3095
+ if (word === "--private-key" && argv[index + 1] !== undefined)
3096
+ secret(argv[index + 1]);
3097
+ if (word.startsWith("--private-key="))
3098
+ secret(word.slice("--private-key=".length));
3099
+ });
3100
+ }
3101
+ /** Runs `sauce <argv…>`, returning the exit code: 0, 1 for a failure, 2 for a usage error. */
3102
+ export async function runCli(argv, rawIo) {
3103
+ rememberSecrets(argv);
3104
+ // Everything printed goes through `scrub`, so no key or password can reach a terminal or a log.
3105
+ const io = {
3106
+ ...rawIo,
3107
+ stdout: (text) => rawIo.stdout(scrub(text)),
3108
+ stderr: (text) => rawIo.stderr(scrub(text)),
3109
+ };
3110
+ const [name, ...rest] = argv;
3111
+ if (name === undefined) {
3112
+ io.stderr(mainHelp());
3113
+ return 2;
3114
+ }
3115
+ if (name === "--help" || name === "-h") {
3116
+ io.stdout(mainHelp());
3117
+ return 0;
3118
+ }
3119
+ if (name === "--version") {
3120
+ const { name: pkg, version } = packageInfo();
3121
+ io.stdout(`${pkg} ${version}\n`);
3122
+ return 0;
3123
+ }
3124
+ const named = commandOf(name === "help" ? rest : argv);
3125
+ if (name === "help" && (rest[0] === undefined || named !== undefined)) {
3126
+ io.stdout(named === undefined ? mainHelp() : commandHelp(named.command));
3127
+ return 0;
3128
+ }
3129
+ if (named === undefined) {
3130
+ const unknown = name === "help" ? rest[0] : name;
3131
+ io.stderr(`sauce: unknown command '${unknown}'. Commands: ${Object.keys(COMMANDS).join(", ")}\n`);
3132
+ return 2;
3133
+ }
3134
+ const { label, command } = named;
3135
+ try {
3136
+ const { flags, trailing } = splitArgv(named.rest, command);
3137
+ const args = parseFlags(flags, ANY_FLAG);
3138
+ if (args.values.help === true) {
3139
+ io.stdout(commandHelp(command));
3140
+ return 0;
3141
+ }
3142
+ const foreign = Object.keys(args.values).find((flag) => !(flag in command.flags));
3143
+ if (foreign !== undefined)
3144
+ throw new UsageError(notTaken(label, foreign));
3145
+ const output = await command.run(args, io, trailing);
3146
+ if (output === undefined)
3147
+ return 0;
3148
+ for (const note of output.notes ?? [])
3149
+ io.stderr(`${note}\n`);
3150
+ io.stdout(`${render(command, output, args)}\n`);
3151
+ return output.exitCode ?? 0;
3152
+ }
3153
+ catch (error) {
3154
+ if (error instanceof UsageError) {
3155
+ io.stderr(`sauce ${label}: ${error.message}\nRun \`sauce ${label} --help\` for usage.\n`);
3156
+ return 2;
3157
+ }
3158
+ const message = error instanceof Error ? error.message : String(error);
3159
+ io.stderr(`sauce ${label}: ${message}\n`);
3160
+ return 1;
3161
+ }
3162
+ }
3163
+ //# sourceMappingURL=run.js.map