@stelis/say-ur-intent 0.0.0 → 0.0.2

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 (234) hide show
  1. package/README.md +4 -39
  2. package/dist/adapters/adapterLifecycleValidators.js +7 -0
  3. package/dist/adapters/adapterPromptSurfaces.js +71 -0
  4. package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +175 -0
  5. package/dist/adapters/deepbook/deepbookQuotePolicy.js +112 -0
  6. package/dist/adapters/deepbook/deepbookReviewEvidence.js +507 -0
  7. package/dist/adapters/deepbook/deepbookReviewLifecycle.js +85 -0
  8. package/dist/adapters/deepbook/deepbookSwapIntent.js +79 -0
  9. package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +269 -0
  10. package/dist/adapters/flowx/flowxSwapHumanReviewProducer.js +176 -0
  11. package/dist/adapters/flowx/flowxSwapIntent.js +79 -0
  12. package/dist/adapters/flowx/flowxSwapQuotePolicy.js +104 -0
  13. package/dist/adapters/flowx/flowxSwapReviewEvidence.js +468 -0
  14. package/dist/adapters/flowx/flowxSwapReviewLifecycle.js +85 -0
  15. package/dist/adapters/flowx/flowxSwapTransactionMaterialProducer.js +362 -0
  16. package/dist/adapters/intentPlanFactories.js +59 -0
  17. package/dist/adapters/reviewAdapters.js +81 -0
  18. package/dist/core/action/adapterLifecycleValidation.js +12 -0
  19. package/dist/core/action/forbiddenFields.js +43 -0
  20. package/dist/core/action/humanReadableReviewEvidence.js +203 -0
  21. package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
  22. package/dist/core/action/ptbVisualizationProducer.js +66 -0
  23. package/dist/core/action/reviewCheckResults.js +6 -0
  24. package/dist/core/action/reviewStateValidation.js +11 -0
  25. package/dist/core/action/reviewTimeSimulationEvidence.js +471 -0
  26. package/dist/core/action/schemas.js +529 -0
  27. package/dist/core/action/signableAdapterContract.js +993 -0
  28. package/dist/core/action/swapHumanReadableReviewProjection.js +124 -0
  29. package/dist/core/action/swapQuotePolicyEvidence.js +278 -0
  30. package/dist/core/action/transactionObjectOwnershipEvidence.js +247 -0
  31. package/dist/core/action/transactionObjectOwnershipProducer.js +329 -0
  32. package/dist/core/action/types.js +35 -0
  33. package/dist/core/action/walletReviewContractAssembler.js +282 -0
  34. package/dist/core/activity/activityStore.js +15 -0
  35. package/dist/core/activity/localDataService.js +258 -0
  36. package/dist/core/activity/localDataTypes.js +11 -0
  37. package/dist/core/activity/localDataValidation.js +396 -0
  38. package/dist/core/activity/schemaVersion.js +1 -0
  39. package/dist/core/activity/sqliteActivityStore.js +820 -0
  40. package/dist/core/activity/sqliteActivityStoreRows.js +430 -0
  41. package/dist/core/activity/sqliteActivityStoreSchema.js +258 -0
  42. package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
  43. package/dist/core/activity/suiFunctionTarget.js +43 -0
  44. package/dist/core/activity/transactionActivityAccountEffects.js +189 -0
  45. package/dist/core/activity/transactionActivityAnalysis.js +295 -0
  46. package/dist/core/activity/transactionActivityClassifier.js +306 -0
  47. package/dist/core/activity/transactionActivityDetails.js +229 -0
  48. package/dist/core/activity/transactionActivityProtocolRules.js +218 -0
  49. package/dist/core/activity/transactionActivityScanPolicy.js +170 -0
  50. package/dist/core/activity/transactionActivityService.js +379 -0
  51. package/dist/core/activity/transactionActivityTypes.js +18 -0
  52. package/dist/core/eventlog/sink.js +35 -0
  53. package/dist/core/evidence/settlementFamilies.js +87 -0
  54. package/dist/core/evidence/userAnswerUse.js +1 -0
  55. package/dist/core/numeric/rawU64.js +63 -0
  56. package/dist/core/preferences/preferencesStore.js +26 -0
  57. package/dist/core/preferences/sqlitePreferencesRepository.js +136 -0
  58. package/dist/core/proposal/externalProposalReview.js +347 -0
  59. package/dist/core/proposal/schemas.js +208 -0
  60. package/dist/core/proposal/types.js +35 -0
  61. package/dist/core/read/amounts.js +14 -0
  62. package/dist/core/read/coinMetadata.js +60 -0
  63. package/dist/core/read/deepbookRawQuoteClient.js +86 -0
  64. package/dist/core/read/deepbookReadHelpers.js +265 -0
  65. package/dist/core/read/deepbookRegistry.js +133 -0
  66. package/dist/core/read/flowxQuoteClient.js +117 -0
  67. package/dist/core/read/flowxReadHelpers.js +145 -0
  68. package/dist/core/read/flowxRegistry.js +174 -0
  69. package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
  70. package/dist/core/read/readResponseGuidance.js +451 -0
  71. package/dist/core/read/readService.js +1164 -0
  72. package/dist/core/read/readServiceTypes.js +59 -0
  73. package/dist/core/read/settlementParityFormatting.js +82 -0
  74. package/dist/core/read/walletReadHelpers.js +99 -0
  75. package/dist/core/review/reviewChecks.js +54 -0
  76. package/dist/core/review/reviewComputation.js +38 -0
  77. package/dist/core/review/reviewComputationResult.js +87 -0
  78. package/dist/core/session/localSession.js +31 -0
  79. package/dist/core/session/privateReviewArtifacts.js +73 -0
  80. package/dist/core/session/sessionErrors.js +9 -0
  81. package/dist/core/session/sessionStore.js +821 -0
  82. package/dist/core/session/settingsSession.js +1 -0
  83. package/dist/core/session/settingsSessions.js +43 -0
  84. package/dist/core/session/status.js +86 -0
  85. package/dist/core/session/transactionMaterialStore.js +205 -0
  86. package/dist/core/session/wait.js +102 -0
  87. package/dist/core/session/walletIdentity.js +103 -0
  88. package/dist/core/session/walletIdentitySessions.js +189 -0
  89. package/dist/core/suiAddress.js +18 -0
  90. package/dist/core/suiEndpoint.js +72 -0
  91. package/dist/mcp/activeAccountResponse.js +24 -0
  92. package/dist/mcp/prompts.js +146 -0
  93. package/dist/mcp/registerTool.js +19 -0
  94. package/dist/mcp/resources.js +72 -0
  95. package/dist/mcp/responseGuidance.js +381 -0
  96. package/dist/mcp/result.js +17 -0
  97. package/dist/mcp/schemas.js +8 -0
  98. package/dist/mcp/server.js +30 -0
  99. package/dist/mcp/serverInfo.js +123 -0
  100. package/dist/mcp/toolErrors.js +105 -0
  101. package/dist/mcp/toolNames.js +50 -0
  102. package/dist/mcp/tools/account/index.js +44 -0
  103. package/dist/mcp/tools/action/prepareSuiActionReview.js +120 -0
  104. package/dist/mcp/tools/read/commonSchemas.js +43 -0
  105. package/dist/mcp/tools/read/deepbookReadTools.js +453 -0
  106. package/dist/mcp/tools/read/flowxReadTools.js +135 -0
  107. package/dist/mcp/tools/read/index.js +16 -0
  108. package/dist/mcp/tools/read/readToolHelpers.js +68 -0
  109. package/dist/mcp/tools/read/reviewActivityTools.js +176 -0
  110. package/dist/mcp/tools/read/serverStatusTools.js +103 -0
  111. package/dist/mcp/tools/read/transactionActivityOutput.js +300 -0
  112. package/dist/mcp/tools/read/transactionActivityTools.js +544 -0
  113. package/dist/mcp/tools/read/walletReadTools.js +733 -0
  114. package/dist/mcp/tools/session/executionResultTools.js +92 -0
  115. package/dist/mcp/tools/session/index.js +8 -0
  116. package/dist/mcp/tools/session/shared.js +79 -0
  117. package/dist/mcp/tools/session/statusTools.js +134 -0
  118. package/dist/mcp/tools/session/walletIdentityTools.js +119 -0
  119. package/dist/mcp/tools/settings/index.js +64 -0
  120. package/dist/review-app/analysis.css +1 -0
  121. package/dist/review-app/analysis.js +1 -0
  122. package/dist/review-app/arc-BjIacwQm.js +1 -0
  123. package/dist/review-app/architecture-U656AL7Q-aSB9x1OK.js +1 -0
  124. package/dist/review-app/architectureDiagram-VXUJARFQ-C5W6re2I.js +36 -0
  125. package/dist/review-app/array-BmXUUrU6.js +1 -0
  126. package/dist/review-app/blockDiagram-VD42YOAC-20MLNcUm.js +122 -0
  127. package/dist/review-app/c4Diagram-YG6GDRKO-BZXRrcck.js +10 -0
  128. package/dist/review-app/channel-lk2p_CUu.js +1 -0
  129. package/dist/review-app/chunk-4BX2VUAB-BPITOdjX.js +1 -0
  130. package/dist/review-app/chunk-55IACEB6-Dz-pyw5k.js +1 -0
  131. package/dist/review-app/chunk-76Q3JFCE-cK_X1P_l.js +1 -0
  132. package/dist/review-app/chunk-ABZYJK2D-Dt4W53JI.js +81 -0
  133. package/dist/review-app/chunk-ATLVNIR6-fZHLXURb.js +1 -0
  134. package/dist/review-app/chunk-B4BG7PRW-BbgcjusC.js +165 -0
  135. package/dist/review-app/chunk-BJD4TVEz.js +1 -0
  136. package/dist/review-app/chunk-CVBHYZKI-CViawAKX.js +1 -0
  137. package/dist/review-app/chunk-DI55MBZ5-C5aoul-d.js +220 -0
  138. package/dist/review-app/chunk-FMBD7UC4-Chxmw62A.js +15 -0
  139. package/dist/review-app/chunk-FPAJGGOC-DDHjQ09H.js +80 -0
  140. package/dist/review-app/chunk-FWNWRKHM-CVVQUptk.js +1 -0
  141. package/dist/review-app/chunk-HN2XXSSU-yzNpjaSZ.js +1 -0
  142. package/dist/review-app/chunk-JA3XYJ7Z-C5ZJdU01.js +70 -0
  143. package/dist/review-app/chunk-JZLCHNYA-BBST4Cnk.js +54 -0
  144. package/dist/review-app/chunk-LBM3YZW2-CdwAPuHr.js +1 -0
  145. package/dist/review-app/chunk-LHMN2FUI-BtB5uDcp.js +1 -0
  146. package/dist/review-app/chunk-O7ZBX7Z2-pxdK4Sa3.js +1 -0
  147. package/dist/review-app/chunk-QN33PNHL-CbVv3uGK.js +1 -0
  148. package/dist/review-app/chunk-QXUST7PY-DKM2-t2c.js +7 -0
  149. package/dist/review-app/chunk-QZHKN3VN-C5ni2pN_.js +1 -0
  150. package/dist/review-app/chunk-S3R3BYOJ-BWvOhDs0.js +2 -0
  151. package/dist/review-app/chunk-S6J4BHB3-D9Fk0YeD.js +1 -0
  152. package/dist/review-app/chunk-T53DSG4Q-C1qEyzyV.js +1 -0
  153. package/dist/review-app/chunk-TZMSLE5B-B--7eU69.js +1 -0
  154. package/dist/review-app/classDiagram-2ON5EDUG-DlL1m2bp.js +1 -0
  155. package/dist/review-app/classDiagram-v2-WZHVMYZB-FXRskT1j.js +1 -0
  156. package/dist/review-app/clone-BZZb7gpZ.js +1 -0
  157. package/dist/review-app/cose-bilkent-S5V4N54A-CRIb8XEO.js +1 -0
  158. package/dist/review-app/cytoscape.esm-C7jYqDP5.js +321 -0
  159. package/dist/review-app/dagre-6UL2VRFP-FNCAXbdE.js +4 -0
  160. package/dist/review-app/dagre-Be46QtUd.js +1 -0
  161. package/dist/review-app/defaultLocale-BaWNtAUL.js +1 -0
  162. package/dist/review-app/diagram-PSM6KHXK-ylLWjiNM.js +24 -0
  163. package/dist/review-app/diagram-QEK2KX5R-BCDcESxs.js +43 -0
  164. package/dist/review-app/diagram-S2PKOQOG-Vdrc-vrO.js +24 -0
  165. package/dist/review-app/dist-WPc74x_f.js +1 -0
  166. package/dist/review-app/erDiagram-Q2GNP2WA-E5ZsUbDF.js +60 -0
  167. package/dist/review-app/flatten-DHf9IeNI.js +1 -0
  168. package/dist/review-app/flowDiagram-NV44I4VS-DBSQuj6x.js +162 -0
  169. package/dist/review-app/ganttDiagram-LVOFAZNH-CKUOsqwl.js +267 -0
  170. package/dist/review-app/gitGraph-F6HP7TQM-DsAD6qK1.js +1 -0
  171. package/dist/review-app/gitGraphDiagram-NY62KEGX-BCeIMWdl.js +65 -0
  172. package/dist/review-app/graphlib-CiX5CXxR.js +1 -0
  173. package/dist/review-app/http-DMvwuuFk.js +1 -0
  174. package/dist/review-app/identity-DY8PXc6t.js +1 -0
  175. package/dist/review-app/info-NVLQJR56-Dlx1nZic.js +1 -0
  176. package/dist/review-app/infoDiagram-F6ZHWCRC-CAuANIrz.js +2 -0
  177. package/dist/review-app/init-BvqephKz.js +1 -0
  178. package/dist/review-app/journeyDiagram-XKPGCS4Q-C-Z9phnx.js +139 -0
  179. package/dist/review-app/kanban-definition-3W4ZIXB7-DufgZABq.js +89 -0
  180. package/dist/review-app/katex-B-Z-NXXN.js +257 -0
  181. package/dist/review-app/line-DiIv3Jgw.js +1 -0
  182. package/dist/review-app/linear-Cv-UPvo1.js +1 -0
  183. package/dist/review-app/math-kmyYrkHL.js +1 -0
  184. package/dist/review-app/mermaid-parser.core-DkwUYTPl.js +4 -0
  185. package/dist/review-app/mindmap-definition-VGOIOE7T-TM_CqdmV.js +68 -0
  186. package/dist/review-app/ordinal-BliTlkoG.js +1 -0
  187. package/dist/review-app/packet-BFZMPI3H-DqbnU92v.js +1 -0
  188. package/dist/review-app/path-AEo9W6mQ.js +1 -0
  189. package/dist/review-app/pie-7BOR55EZ-LJzaLkgr.js +1 -0
  190. package/dist/review-app/pieDiagram-ADFJNKIX-BAs8OfRS.js +30 -0
  191. package/dist/review-app/quadrantDiagram-AYHSOK5B-CyUDZP5S.js +7 -0
  192. package/dist/review-app/radar-NHE76QYJ-DBpHc8_Y.js +1 -0
  193. package/dist/review-app/reduce-B-HuPpdd.js +1 -0
  194. package/dist/review-app/requirementDiagram-UZGBJVZJ-BEHix78P.js +64 -0
  195. package/dist/review-app/review.css +1 -0
  196. package/dist/review-app/review.js +43 -0
  197. package/dist/review-app/sankeyDiagram-TZEHDZUN-B2bKbmsm.js +10 -0
  198. package/dist/review-app/sequenceDiagram-WL72ISMW-DVLOORFJ.js +145 -0
  199. package/dist/review-app/settings.css +1 -0
  200. package/dist/review-app/settings.js +1 -0
  201. package/dist/review-app/src-Buml7cM5.js +1 -0
  202. package/dist/review-app/stateDiagram-FKZM4ZOC-sFGGp2kV.js +1 -0
  203. package/dist/review-app/stateDiagram-v2-4FDKWEC3-BHfCF4dX.js +1 -0
  204. package/dist/review-app/timeline-definition-IT6M3QCI-BESnBijC.js +61 -0
  205. package/dist/review-app/treemap-KMMF4GRG-wnVLBDeQ.js +1 -0
  206. package/dist/review-app/walletStatus-CcojOdGy.js +7 -0
  207. package/dist/review-app/xychartDiagram-PRI3JC2R-BGWVfCx4.js +7 -0
  208. package/dist/review-server/assets.js +48 -0
  209. package/dist/review-server/html.js +66 -0
  210. package/dist/review-server/http.js +47 -0
  211. package/dist/review-server/middleware/hostOrigin.js +48 -0
  212. package/dist/review-server/middleware/reviewToken.js +7 -0
  213. package/dist/review-server/reviewServerPolicy.js +10 -0
  214. package/dist/review-server/server.js +568 -0
  215. package/dist/review-server/settingsApi.js +182 -0
  216. package/dist/review-server/walletIdentityResponse.js +13 -0
  217. package/dist/runtime/config.js +103 -0
  218. package/dist/runtime/localSettingsService.js +198 -0
  219. package/dist/runtime/logger.js +50 -0
  220. package/dist/runtime/reviewServerAcquire.js +128 -0
  221. package/dist/runtime/smokeMainnetRead.js +529 -0
  222. package/dist/runtime/smokeMainnetReadAssertions.js +308 -0
  223. package/dist/runtime/start.js +295 -0
  224. package/dist/runtime/suiEndpoint.js +97 -0
  225. package/dist/runtime/suiTransactionGraphqlMapping.js +200 -0
  226. package/dist/runtime/suiTransactionGraphqlQueries.js +231 -0
  227. package/dist/runtime/suiTransactionGraphqlSource.js +148 -0
  228. package/docs/AGENT_BEHAVIOR.md +1 -1
  229. package/docs/AGENT_DEVELOPMENT_POLICY.md +20 -0
  230. package/docs/FRONTEND_POLICY.md +4 -3
  231. package/docs/MCP_SETUP.md +59 -7
  232. package/docs/MCP_TOOLS.md +1 -1
  233. package/docs/SDK_API.md +5 -1
  234. package/package.json +3 -2
@@ -0,0 +1,117 @@
1
+ import { AggregatorQuoter, Protocol } from "@flowx-finance/sdk";
2
+ import { ReadServiceInputError } from "./readServiceTypes.js";
3
+ /**
4
+ * Thin wrapper around the FlowX aggregator quoter, restricted to FlowX CLMM
5
+ * single-hop routes. Normalizes the response into plain data so the read
6
+ * service can validate it against the pinned registry, and so tests can
7
+ * inject fakes without the SDK.
8
+ */
9
+ const FLOWX_QUOTER_MAX_HOPS = 1;
10
+ export function createFlowxQuoteClient() {
11
+ const quoter = new AggregatorQuoter("mainnet");
12
+ return {
13
+ async getSwapRoutes(request) {
14
+ let result;
15
+ try {
16
+ result = await quoter.getRoutes({
17
+ tokenIn: request.tokenInType,
18
+ tokenOut: request.tokenOutType,
19
+ amountIn: request.amountInRaw,
20
+ includeSources: [Protocol.FLOWX_V3],
21
+ maxHops: FLOWX_QUOTER_MAX_HOPS
22
+ });
23
+ }
24
+ catch (error) {
25
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter request failed", {
26
+ reason: error instanceof Error ? error.message : "unknown"
27
+ });
28
+ }
29
+ return normalizeFlowxQuoterResult(result);
30
+ }
31
+ };
32
+ }
33
+ /**
34
+ * Build-grade quote source for the FlowX review adapter: one quoter response
35
+ * yields both the normalized quote (validated against the pinned registry)
36
+ * and the SDK route entities the local transaction build consumes.
37
+ */
38
+ export function createFlowxSwapReviewQuoteSource(options) {
39
+ const quoter = new AggregatorQuoter("mainnet");
40
+ const now = options?.now ?? (() => new Date());
41
+ return {
42
+ async getSwapRoutesForBuild(request) {
43
+ let result;
44
+ try {
45
+ result = await quoter.getRoutes({
46
+ tokenIn: request.tokenInType,
47
+ tokenOut: request.tokenOutType,
48
+ amountIn: request.amountInRaw,
49
+ includeSources: [Protocol.FLOWX_V3],
50
+ maxHops: FLOWX_QUOTER_MAX_HOPS
51
+ });
52
+ }
53
+ catch (error) {
54
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter request failed", {
55
+ reason: error instanceof Error ? error.message : "unknown"
56
+ });
57
+ }
58
+ return {
59
+ normalized: normalizeFlowxQuoterResult(result),
60
+ sdkRoutes: result.routes,
61
+ fetchedAt: now().toISOString()
62
+ };
63
+ }
64
+ };
65
+ }
66
+ export function normalizeFlowxQuoterResult(result) {
67
+ const rawQuote = result.rawQuote;
68
+ if (!rawQuote || !Array.isArray(rawQuote.paths)) {
69
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter response is missing raw route paths", {
70
+ hasRawQuote: rawQuote !== undefined
71
+ });
72
+ }
73
+ const amountInRaw = stringifyAmount(result.amountIn, "amountIn");
74
+ const amountOutRaw = stringifyAmount(result.amountOut, "amountOut");
75
+ const paths = rawQuote.paths.flat().map((path, index) => {
76
+ if (typeof path.poolId !== "string" || path.poolId.length === 0) {
77
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter path is missing a pool id", { index });
78
+ }
79
+ if (typeof path.source !== "string" || path.source.length === 0) {
80
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter path is missing a source label", { index });
81
+ }
82
+ return {
83
+ poolId: path.poolId,
84
+ source: path.source,
85
+ swapXToY: typeof path.extra?.swapXToY === "boolean" ? path.extra.swapXToY : undefined,
86
+ feeRate: typeof path.extra?.fee === "number" ? path.extra.fee : undefined
87
+ };
88
+ });
89
+ if (paths.length === 0) {
90
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter returned no route paths", {});
91
+ }
92
+ return {
93
+ amountInRaw,
94
+ amountOutRaw,
95
+ paths,
96
+ protocolConfig: normalizeProtocolConfig(rawQuote.protocolConfig)
97
+ };
98
+ }
99
+ function normalizeProtocolConfig(config) {
100
+ const clmm = config?.flowx_clmm;
101
+ if (typeof clmm !== "object" || clmm === null) {
102
+ return undefined;
103
+ }
104
+ const record = clmm;
105
+ return {
106
+ poolRegistryObjectId: typeof record.poolRegistryObjectId === "string" ? record.poolRegistryObjectId : undefined,
107
+ versionedObjectId: typeof record.versionedObjectId === "string" ? record.versionedObjectId : undefined,
108
+ wrappedRouterPackageId: typeof record.wrappedRouterPackageId === "string" ? record.wrappedRouterPackageId : undefined
109
+ };
110
+ }
111
+ function stringifyAmount(value, field) {
112
+ const text = typeof value === "string" ? value : value?.toString();
113
+ if (text === undefined || !/^\d+$/.test(text)) {
114
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter amount is not a raw integer", { field });
115
+ }
116
+ return text;
117
+ }
@@ -0,0 +1,145 @@
1
+ import { FLOWX_CLMM_MAINNET, getFlowxPoolById } from "./flowxRegistry.js";
2
+ import { FLOWX_SWAP_QUOTE_QUANTITY_KIND, ReadServiceInputError } from "./readServiceTypes.js";
3
+ export function flowxQuoteQuantitySemantics() {
4
+ return {
5
+ kind: FLOWX_SWAP_QUOTE_QUANTITY_KIND,
6
+ inputAmountKind: "display_source_amount_converted_to_raw",
7
+ allowedUse: "indicative_flowx_route_quote",
8
+ rawAmountAvailable: true,
9
+ rawEvidenceField: "routeEvidence",
10
+ chainVerified: false,
11
+ paymentCoverageAvailable: false,
12
+ shortfallContributionAvailable: false,
13
+ routeDependentPaymentSupportAvailable: false,
14
+ requiresIntentEvidenceForCoverage: true,
15
+ canUseForPaymentAnswer: false,
16
+ canUseForShortfallAnswer: false,
17
+ doNotCombineWithPaymentAnswer: true,
18
+ requiredPaymentAnswerTool: "read.preview_intent_evidence",
19
+ paymentAnswerUseBlockedReason: "quote_output_is_price_reference_not_payment_answer",
20
+ requiredPaymentAnswerField: "responseSummary",
21
+ fiatUsdCashOutAvailable: false,
22
+ externalMarketPriceConversionAvailable: false,
23
+ externalMarketLookupAvailable: false,
24
+ usdPegAssumptionAvailable: false,
25
+ bankCashOutEstimateAvailable: false,
26
+ profitAndLossAvailable: false,
27
+ costBasisAvailable: false,
28
+ priceImpactAvailable: false,
29
+ midPriceSlippageAvailable: false,
30
+ venueComparisonAvailable: false,
31
+ routeRecommendationAvailable: false,
32
+ notFor: [
33
+ "signing",
34
+ "funding",
35
+ "payment_coverage",
36
+ "shortfall_contribution",
37
+ "route_dependent_payment_support",
38
+ "route_liquidity",
39
+ "min_out",
40
+ "liquidity_verdict",
41
+ "price_impact",
42
+ "mid_price_slippage",
43
+ "quote_vs_mid_slippage",
44
+ "effective_price",
45
+ "venue_comparison",
46
+ "best_route",
47
+ "route_recommendation",
48
+ "transaction_building",
49
+ "fiat_usd_cash_out",
50
+ "external_market_price_conversion",
51
+ "external_market_lookup",
52
+ "usd_peg_assumption",
53
+ "bank_cash_out_estimate",
54
+ "profit_or_pnl",
55
+ "cost_basis"
56
+ ]
57
+ };
58
+ }
59
+ /**
60
+ * Validate a normalized FlowX quoter response against the pinned registry and
61
+ * the requested pair. Every check fails closed: an unknown pool, a foreign
62
+ * route source, a multi-hop path, an amount echo mismatch, or a drifted
63
+ * protocol config pin stops the quote instead of being silently accepted.
64
+ */
65
+ export function validateFlowxRouteQuote(input) {
66
+ const { pair, quote } = input;
67
+ if (quote.amountInRaw !== input.requestedAmountInRaw) {
68
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter echoed a different input amount", {
69
+ requested: input.requestedAmountInRaw,
70
+ echoed: quote.amountInRaw
71
+ });
72
+ }
73
+ const pools = [];
74
+ for (const path of quote.paths) {
75
+ if (path.source !== FLOWX_CLMM_MAINNET.quoterSource) {
76
+ throw new ReadServiceInputError("quote_unavailable", "FlowX route includes a non-FlowX-CLMM source", {
77
+ poolId: path.poolId,
78
+ source: path.source
79
+ });
80
+ }
81
+ const pinned = getFlowxPoolById(path.poolId);
82
+ if (!pinned) {
83
+ throw new ReadServiceInputError("quote_unavailable", "FlowX route uses a pool that is not in the pinned registry", {
84
+ poolId: path.poolId,
85
+ action: "regenerate_flowx_registry"
86
+ });
87
+ }
88
+ if (path.swapXToY !== undefined && path.swapXToY !== pair.swapXToY) {
89
+ throw new ReadServiceInputError("quote_unavailable", "FlowX route direction disagrees with the pinned pair orientation", {
90
+ poolId: path.poolId,
91
+ routeSwapXToY: path.swapXToY,
92
+ pinnedSwapXToY: pair.swapXToY
93
+ });
94
+ }
95
+ if (path.feeRate !== undefined && path.feeRate !== pinned.feeRate) {
96
+ throw new ReadServiceInputError("quote_unavailable", "FlowX route fee disagrees with the pinned pool fee", {
97
+ poolId: path.poolId,
98
+ routeFeeRate: path.feeRate,
99
+ pinnedFeeRate: pinned.feeRate
100
+ });
101
+ }
102
+ pools.push({
103
+ poolKey: pinned.poolKey,
104
+ poolId: pinned.poolId,
105
+ feeRate: pinned.feeRate,
106
+ tickSpacing: pinned.tickSpacing,
107
+ swapXToY: pair.swapXToY
108
+ });
109
+ }
110
+ if (pools.length !== 1) {
111
+ throw new ReadServiceInputError("quote_unavailable", "FlowX route is not a single-hop path", {
112
+ hopCount: pools.length
113
+ });
114
+ }
115
+ const config = quote.protocolConfig;
116
+ if (!config) {
117
+ throw new ReadServiceInputError("quote_unavailable", "FlowX quoter response did not carry the protocol config pin", {});
118
+ }
119
+ const pinDrift = {};
120
+ if (config.poolRegistryObjectId !== FLOWX_CLMM_MAINNET.poolRegistry.objectId) {
121
+ pinDrift.poolRegistryObjectId = {
122
+ pinned: FLOWX_CLMM_MAINNET.poolRegistry.objectId,
123
+ observed: config.poolRegistryObjectId
124
+ };
125
+ }
126
+ if (config.versionedObjectId !== FLOWX_CLMM_MAINNET.versioned.objectId) {
127
+ pinDrift.versionedObjectId = {
128
+ pinned: FLOWX_CLMM_MAINNET.versioned.objectId,
129
+ observed: config.versionedObjectId
130
+ };
131
+ }
132
+ if (config.wrappedRouterPackageId !== FLOWX_CLMM_MAINNET.universalRouter.wrappedRouterPackageId) {
133
+ pinDrift.wrappedRouterPackageId = {
134
+ pinned: FLOWX_CLMM_MAINNET.universalRouter.wrappedRouterPackageId,
135
+ observed: config.wrappedRouterPackageId
136
+ };
137
+ }
138
+ if (Object.keys(pinDrift).length > 0) {
139
+ throw new ReadServiceInputError("quote_unavailable", "FlowX protocol config drifted from the pinned registry", {
140
+ pinDrift,
141
+ action: "regenerate_flowx_registry"
142
+ });
143
+ }
144
+ return { pools };
145
+ }
@@ -0,0 +1,174 @@
1
+ import { normalizeCoinType } from "./coinMetadata.js";
2
+ import { ReadServiceInputError } from "./readServiceTypes.js";
3
+ /**
4
+ * Pinned FlowX CLMM mainnet registry.
5
+ *
6
+ * Values were read from Sui mainnet directly (package introspection, the
7
+ * shared PoolRegistry object, and its dynamic fields) on 2026-06-12 and
8
+ * cross-checked against @flowx-finance/sdk@2.1.0 CONFIGS and a live quoter
9
+ * response. `scripts/generate-flowx-registry.ts` re-verifies every value
10
+ * against the chain and fails loudly on drift; it never rewrites this module.
11
+ *
12
+ * Static known metadata only - not live liquidity, balances, quotes, or
13
+ * final execution truth.
14
+ */
15
+ export const FLOWX_CLMM_PROTOCOL_ID = "flowx-clmm";
16
+ export const FLOWX_CLMM_UNIT_SOURCE = "flowx_pinned_registry";
17
+ export const FLOWX_CLMM_MAINNET = {
18
+ /** Current package storage id (upgrade version 7 at probe time). */
19
+ currentPackageId: "0xde2c47eb0da8c74e4d0f6a220c41619681221b9c2590518095f0f0c2d3f3c772",
20
+ /** Original publish id - all on-chain struct types use this address. */
21
+ originalPackageId: "0x25929e7f29e0a30eb4e692952ba1b5b65a3a4d65ab5f2a32e1ba3edcb587f26d",
22
+ poolRegistry: {
23
+ objectId: "0x27565d24a4cd51127ac90e4074a841bbe356cca7bf5759ddc14a975be1632abc",
24
+ initialSharedVersion: "101644053",
25
+ type: "0x25929e7f29e0a30eb4e692952ba1b5b65a3a4d65ab5f2a32e1ba3edcb587f26d::pool_manager::PoolRegistry"
26
+ },
27
+ versioned: {
28
+ objectId: "0x67624a1533b5aff5d0dfcf5e598684350efd38134d2d245f475524c03a64e656",
29
+ initialSharedVersion: "101644053",
30
+ type: "0x25929e7f29e0a30eb4e692952ba1b5b65a3a4d65ab5f2a32e1ba3edcb587f26d::versioned::Versioned"
31
+ },
32
+ /**
33
+ * Universal-router surfaces used by the SDK-built swap transaction. The
34
+ * wrappedRouterPackageId is delivered inside quoter API responses, so the
35
+ * quote path re-checks it against this pin on every quote.
36
+ */
37
+ universalRouter: {
38
+ packageId: "0xc263060d3cbb4155057f0010f92f63ca56d5121c298d01f7a33607342ec299b0",
39
+ treasuryObjectId: "0x25db8128dc9ccbe5fcd15e5700fea555c6b111a8c8a1f20c426b696caac2bea4",
40
+ tradeIdTrackerObjectId: "0x9ab469842f85fd2a1bac9ba695d867adb1caa7d5705809737922b5cee552eb6f",
41
+ partnerRegistryObjectId: "0x29e6c1c2176485dc045a2e39eb8844b4ca1cf8452d964447c11202f84a76cb1a",
42
+ versionedObjectId: "0xada98dd9e028db64e206dd81fdecb3dbc8b4c16be08d9f175550032bfdcf56f3",
43
+ wrappedRouterPackageId: "0x1d200e5a0709f84736d1ec06a5e9a961f4fa86f2d43d15e3a0441ae152440ede"
44
+ },
45
+ /** Aggregator quoter source label for FlowX CLMM routes. */
46
+ quoterSource: "FLOWX_CLMM",
47
+ /** Pool fee rates use a 1_000_000 denominator (e.g. 3000 = 0.3%). */
48
+ feeRateDenominator: 1_000_000
49
+ };
50
+ export const FLOWX_PINNED_COINS = {
51
+ SUI: {
52
+ symbol: "SUI",
53
+ coinType: "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",
54
+ decimals: 9
55
+ },
56
+ USDC: {
57
+ symbol: "USDC",
58
+ coinType: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
59
+ decimals: 6
60
+ }
61
+ };
62
+ function suiUsdcPool(poolId, feeRate, tickSpacing) {
63
+ return {
64
+ poolKey: `SUI_USDC_${feeRate}`,
65
+ poolId,
66
+ symbolX: FLOWX_PINNED_COINS.SUI.symbol,
67
+ symbolY: FLOWX_PINNED_COINS.USDC.symbol,
68
+ coinTypeX: FLOWX_PINNED_COINS.SUI.coinType,
69
+ coinTypeY: FLOWX_PINNED_COINS.USDC.coinType,
70
+ decimalsX: FLOWX_PINNED_COINS.SUI.decimals,
71
+ decimalsY: FLOWX_PINNED_COINS.USDC.decimals,
72
+ feeRate,
73
+ tickSpacing,
74
+ unitSource: FLOWX_CLMM_UNIT_SOURCE
75
+ };
76
+ }
77
+ /**
78
+ * Every SUI/USDC pool discovered by direct PoolRegistry dynamic-field reads
79
+ * (2026-06-12, 1189 pools total). One pool exists per fee tier; the registry
80
+ * lists all of them without ranking - pool selection is never advice here.
81
+ */
82
+ export const FLOWX_PINNED_POOLS = [
83
+ suiUsdcPool("0xf143ac1cc2c012e31df55f21a5d9f406adc8f1ac08d014f84475a3b21953dd37", 10, 1),
84
+ suiUsdcPool("0x9c1cc6fc3c0060b9544dcaba50c9564706a558ef7e089895e86fbca1851c3d43", 100, 2),
85
+ suiUsdcPool("0x6b3791da0ae8b8d94d112c21b682e9f7d49a0b177cddd5b0dd61ca3ff27bc847", 500, 10),
86
+ suiUsdcPool("0xd477e8830f9aa070475149d75f285a4bd0a0386d8ce12f0e88e1c112cda21dfe", 1000, 20),
87
+ suiUsdcPool("0x1aed0146a85e0aa58639bfaca3ae55aa7db119eaeae35d3ec4a90742ebbb3933", 2000, 40),
88
+ suiUsdcPool("0x325239132e2b619147c00052986461cea02815172ea9d000c58e68484f514a90", 3000, 60),
89
+ suiUsdcPool("0x8903db2e9aea9e76d310c52a8745cff1f1d11fe38bc120828bd7280e7497ba8c", 10000, 200)
90
+ ];
91
+ export function listFlowxPoolRegistry() {
92
+ return FLOWX_PINNED_POOLS;
93
+ }
94
+ export function getFlowxPoolById(poolId) {
95
+ return FLOWX_PINNED_POOLS.find((pool) => pool.poolId === poolId);
96
+ }
97
+ export function canonicalFlowxSymbol(symbol) {
98
+ const trimmed = symbol.trim();
99
+ if (!trimmed) {
100
+ return undefined;
101
+ }
102
+ const matches = Object.values(FLOWX_PINNED_COINS).filter((coin) => coin.symbol.toLowerCase() === trimmed.toLowerCase());
103
+ return matches.length === 1 ? matches[0] : undefined;
104
+ }
105
+ export function resolveFlowxSwapPair(input) {
106
+ const source = canonicalFlowxSymbol(input.sourceSymbol);
107
+ const target = canonicalFlowxSymbol(input.targetSymbol);
108
+ if (!source || !target) {
109
+ throw new ReadServiceInputError("registry_miss", "FlowX symbol is not in the pinned registry", {
110
+ sourceSymbol: input.sourceSymbol,
111
+ targetSymbol: input.targetSymbol,
112
+ knownSymbols: Object.keys(FLOWX_PINNED_COINS)
113
+ });
114
+ }
115
+ if (source.symbol === target.symbol) {
116
+ throw new ReadServiceInputError("input_invalid", "FlowX swap pair uses the same symbol twice", {
117
+ sourceSymbol: input.sourceSymbol,
118
+ targetSymbol: input.targetSymbol
119
+ });
120
+ }
121
+ const sourceType = normalizeCoinType(source.coinType);
122
+ const targetType = normalizeCoinType(target.coinType);
123
+ const xToY = FLOWX_PINNED_POOLS.filter((pool) => normalizeCoinType(pool.coinTypeX) === sourceType && normalizeCoinType(pool.coinTypeY) === targetType);
124
+ const yToX = FLOWX_PINNED_POOLS.filter((pool) => normalizeCoinType(pool.coinTypeX) === targetType && normalizeCoinType(pool.coinTypeY) === sourceType);
125
+ if (xToY.length > 0 && yToX.length > 0) {
126
+ throw new ReadServiceInputError("registry_miss", "FlowX pinned pools resolve the pair in both orientations", {
127
+ sourceSymbol: source.symbol,
128
+ targetSymbol: target.symbol
129
+ });
130
+ }
131
+ const pools = xToY.length > 0 ? xToY : yToX;
132
+ if (pools.length === 0) {
133
+ throw new ReadServiceInputError("registry_miss", "FlowX symbol pair has no pinned mainnet pools", {
134
+ sourceSymbol: source.symbol,
135
+ targetSymbol: target.symbol
136
+ });
137
+ }
138
+ return {
139
+ source,
140
+ target,
141
+ swapXToY: xToY.length > 0,
142
+ pools
143
+ };
144
+ }
145
+ export function assertFlowxRegistryShape() {
146
+ const poolKeys = new Set();
147
+ const poolIds = new Set();
148
+ for (const pool of FLOWX_PINNED_POOLS) {
149
+ if (poolKeys.has(pool.poolKey)) {
150
+ throw new ReadServiceInputError("registry_miss", "FlowX pinned registry repeats a pool key", {
151
+ poolKey: pool.poolKey
152
+ });
153
+ }
154
+ if (poolIds.has(pool.poolId)) {
155
+ throw new ReadServiceInputError("registry_miss", "FlowX pinned registry repeats a pool id", {
156
+ poolId: pool.poolId
157
+ });
158
+ }
159
+ poolKeys.add(pool.poolKey);
160
+ poolIds.add(pool.poolId);
161
+ if (!Number.isInteger(pool.feeRate) || pool.feeRate < 0 || pool.feeRate >= FLOWX_CLMM_MAINNET.feeRateDenominator) {
162
+ throw new ReadServiceInputError("registry_miss", "FlowX pinned pool fee rate is outside the 1e6 denominator", {
163
+ poolKey: pool.poolKey,
164
+ feeRate: pool.feeRate
165
+ });
166
+ }
167
+ if (!Number.isInteger(pool.tickSpacing) || pool.tickSpacing <= 0) {
168
+ throw new ReadServiceInputError("registry_miss", "FlowX pinned pool tick spacing is not a positive integer", {
169
+ poolKey: pool.poolKey,
170
+ tickSpacing: pool.tickSpacing
171
+ });
172
+ }
173
+ }
174
+ }
@@ -0,0 +1,228 @@
1
+ import { INTENT_EVIDENCE_QUANTITY_KIND, INTENT_EVIDENCE_TARGET_ASSET_SELECTION_SOURCES } from "./readServiceTypes.js";
2
+ export function intentEvidenceQuantitySemantics() {
3
+ return {
4
+ kind: INTENT_EVIDENCE_QUANTITY_KIND,
5
+ allowedUse: "pre_transaction_evidence",
6
+ naturalLanguageIntentEvidence: true,
7
+ transactionBuildingAvailable: false,
8
+ signingReadinessAvailable: false,
9
+ routeRecommendationAvailable: false,
10
+ fiatUsdCashOutAvailable: false,
11
+ profitAndLossAvailable: false,
12
+ costBasisAvailable: false,
13
+ notFor: [
14
+ "transaction_building",
15
+ "signing_data",
16
+ "signing_readiness",
17
+ "payment_execution",
18
+ "best_route",
19
+ "route_recommendation",
20
+ "fiat_usd_cash_out",
21
+ "external_market_price_conversion",
22
+ "profit_or_pnl",
23
+ "cost_basis"
24
+ ]
25
+ };
26
+ }
27
+ export function isSupportedIntentEvidenceKind(intentKind) {
28
+ return intentKind === "cover_payment_like_amount" || intentKind === "summarize_settlement_asset_group_balance";
29
+ }
30
+ export function isIntentEvidenceTargetAssetSelectionSource(source) {
31
+ return INTENT_EVIDENCE_TARGET_ASSET_SELECTION_SOURCES.includes(source);
32
+ }
33
+ export function intentEvidenceSettlementAssetCoverageBoundary() {
34
+ return [
35
+ "current_wallet_coin_balance_snapshot",
36
+ "settlement_asset_assets_only",
37
+ "not_settlement_token_selection",
38
+ "not_route_dependent_payment_support",
39
+ "not_payment_execution_readiness",
40
+ "not_gas_readiness"
41
+ ];
42
+ }
43
+ export function intentEvidenceResponseEvidence(targetAsset, settlementAssetCoverage, candidateConversions) {
44
+ const settlementAssetClaims = intentEvidenceSettlementAssetResponseClaims(settlementAssetCoverage);
45
+ if (targetAsset === undefined || isIntentEvidenceSettlementAssetCoverageUnavailable(settlementAssetCoverage)) {
46
+ return {
47
+ mode: "settlement_asset_only",
48
+ primaryEvidenceFields: ["responseSummary"],
49
+ supportedResponseClaims: [...settlementAssetClaims, "required_user_choices", "unsupported_inferences"]
50
+ };
51
+ }
52
+ return {
53
+ mode: "selected_target_context",
54
+ primaryEvidenceFields: [
55
+ "responseSummary",
56
+ "selectedTarget",
57
+ "candidateConversions",
58
+ "requiredUserChoices"
59
+ ],
60
+ supportedResponseClaims: [
61
+ ...settlementAssetClaims,
62
+ "selected_target_shortfall",
63
+ ...(candidateConversions.some((candidate) => candidate.status === "quoted")
64
+ ? ["direct_pool_quote_evidence"]
65
+ : []),
66
+ "required_user_choices",
67
+ "unsupported_inferences"
68
+ ]
69
+ };
70
+ }
71
+ function intentEvidenceSettlementAssetResponseClaims(settlementAssetCoverage) {
72
+ if (settlementAssetCoverage.status === "balance_total_only") {
73
+ return ["current_settlement_asset_total"];
74
+ }
75
+ if (isIntentEvidenceSettlementAssetCoverageUnavailable(settlementAssetCoverage)) {
76
+ return ["settlement_asset_coverage_unavailable"];
77
+ }
78
+ return ["settlement_asset_coverage_status", "settlement_asset_shortfall"];
79
+ }
80
+ export function intentEvidenceSupportedClaims(settlementAssetCoverage, selectedTarget, candidateConversions) {
81
+ if (isIntentEvidenceSettlementAssetCoverageUnavailable(settlementAssetCoverage)) {
82
+ return ["settlement_asset_coverage_unavailable"];
83
+ }
84
+ const claims = [
85
+ "current_wallet_usd_settlement_coin_balance_snapshot",
86
+ "verified_display_amounts_from_pinned_or_onchain_decimals",
87
+ "settlement_asset_balance_total_when_common_decimals_are_available"
88
+ ];
89
+ if (settlementAssetCoverage.status !== "balance_total_only") {
90
+ claims.push("settlement_asset_shortfall_when_common_decimals_are_available");
91
+ }
92
+ if (selectedTarget !== undefined && candidateConversions.some((candidate) => candidate.status === "quoted")) {
93
+ claims.push("direct_deepbook_pool_and_quote_evidence_when_target_asset_is_selected");
94
+ }
95
+ return claims;
96
+ }
97
+ function intentEvidenceAnswerCompleteness(input) {
98
+ if (isIntentEvidenceSettlementAssetCoverageUnavailable(input.settlementAssetCoverage)) {
99
+ return {
100
+ answerCompleteFor: "settlement_asset_coverage_unavailable_answer",
101
+ requiredAnswerFields: [
102
+ "responseSummary.unavailableReason",
103
+ "blockedReasons",
104
+ "responseSummary.requiredUserChoices"
105
+ ],
106
+ notCompleteFor: [
107
+ "settlement_asset_balance_total",
108
+ "payment_coverage_status",
109
+ "payment_shortfall",
110
+ "selected_target_context",
111
+ "route_dependent_payment_support",
112
+ "payment_execution_readiness",
113
+ "transaction_building",
114
+ "signing_readiness"
115
+ ]
116
+ };
117
+ }
118
+ if (input.responseEvidenceMode === "selected_target_context") {
119
+ return {
120
+ answerCompleteFor: "selected_target_context_answer",
121
+ requiredAnswerFields: ["responseSummary", "selectedTarget", "candidateConversions", "requiredUserChoices"],
122
+ notCompleteFor: [
123
+ "route_dependent_payment_support",
124
+ "settlement_token_selection",
125
+ "payment_execution_readiness",
126
+ "transaction_building",
127
+ "signing_readiness"
128
+ ]
129
+ };
130
+ }
131
+ return {
132
+ answerCompleteFor: "settlement_asset_group_answer",
133
+ requiredAnswerFields: ["responseSummary"],
134
+ notCompleteFor: [
135
+ "selected_target_context",
136
+ "route_dependent_payment_support",
137
+ "settlement_token_selection",
138
+ "payment_execution_readiness",
139
+ "transaction_building",
140
+ "signing_readiness"
141
+ ]
142
+ };
143
+ }
144
+ export function isIntentEvidenceSettlementAssetCoverageUnavailable(settlementAssetCoverage) {
145
+ return (settlementAssetCoverage.status === "unavailable_mixed_decimals" ||
146
+ settlementAssetCoverage.status === "unavailable_wallet_balance_scan_incomplete");
147
+ }
148
+ export function intentEvidenceResponseSummary(input) {
149
+ const questionKind = input.intentKind === "cover_payment_like_amount" ? "payment_coverage" : "settlement_asset_group_balance_total";
150
+ const answerCompleteness = intentEvidenceAnswerCompleteness({
151
+ settlementAssetCoverage: input.settlementAssetCoverage,
152
+ responseEvidenceMode: input.responseEvidenceMode
153
+ });
154
+ const base = {
155
+ questionKind,
156
+ answerCompleteness,
157
+ doNotCallQuoteToolsForThisQuestion: true,
158
+ coverageBasis: "settlement_asset_wallet_balance_only",
159
+ assetGroupId: input.assetGroupId,
160
+ requiredUserChoices: input.requiredUserChoices,
161
+ separateQuoteOutputs: {
162
+ usedForPaymentAnswer: false,
163
+ usedForShortfallAnswer: false,
164
+ reason: "separate_quote_tool_outputs_are_price_estimates_only",
165
+ paymentAnswerField: "responseSummary"
166
+ },
167
+ doNotUseForConclusion: [
168
+ "separate_quote_tool_results",
169
+ "assets_outside_settlement_group",
170
+ "route_dependent_payment_support"
171
+ ],
172
+ excludedFromConclusion: [
173
+ "separate_quote_tool_results",
174
+ "candidate_conversion_quote_evidence",
175
+ "assets_outside_settlement_group",
176
+ "settlement_token_selection",
177
+ "route_dependent_payment_support",
178
+ "gas_reserve_or_fee_readiness",
179
+ "payment_execution_readiness",
180
+ "transaction_building",
181
+ "signing_readiness",
182
+ "fiat_usd_cash_out",
183
+ "profit_or_pnl",
184
+ "cost_basis"
185
+ ]
186
+ };
187
+ if (input.settlementAssetCoverage.status === "balance_total_only") {
188
+ return {
189
+ ...base,
190
+ conclusionKind: "current_settlement_asset_total",
191
+ currentDisplayAmount: input.settlementAssetCoverage.currentDisplayAmount,
192
+ requiredDisplayAmount: null,
193
+ shortfallDisplayAmount: null,
194
+ amountsUsedForAnswer: {
195
+ currentDisplayAmount: "current_wallet_balance_in_settlement_asset_group",
196
+ requiredDisplayAmount: null,
197
+ shortfallDisplayAmount: null
198
+ }
199
+ };
200
+ }
201
+ if (isIntentEvidenceSettlementAssetCoverageUnavailable(input.settlementAssetCoverage)) {
202
+ return {
203
+ ...base,
204
+ conclusionKind: "settlement_asset_coverage_unavailable",
205
+ currentDisplayAmount: null,
206
+ requiredDisplayAmount: input.settlementAssetCoverage.requiredDisplayAmount ?? null,
207
+ shortfallDisplayAmount: null,
208
+ unavailableReason: input.settlementAssetCoverage.reason,
209
+ amountsUsedForAnswer: {
210
+ currentDisplayAmount: null,
211
+ requiredDisplayAmount: input.settlementAssetCoverage.requiredDisplayAmount === undefined ? null : "amount_requested_by_user",
212
+ shortfallDisplayAmount: null
213
+ }
214
+ };
215
+ }
216
+ return {
217
+ ...base,
218
+ conclusionKind: input.settlementAssetCoverage.status,
219
+ currentDisplayAmount: input.settlementAssetCoverage.currentDisplayAmount,
220
+ requiredDisplayAmount: input.settlementAssetCoverage.requiredDisplayAmount,
221
+ shortfallDisplayAmount: input.settlementAssetCoverage.shortfallDisplayAmount,
222
+ amountsUsedForAnswer: {
223
+ currentDisplayAmount: "current_wallet_balance_in_settlement_asset_group",
224
+ requiredDisplayAmount: "amount_requested_by_user",
225
+ shortfallDisplayAmount: "required_amount_minus_current_settlement_asset_balance"
226
+ }
227
+ };
228
+ }