@zktx.io/sui-mcp 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/@mysten-bcs-2.0.5-Apache-2.0.txt +205 -0
  3. package/LICENSES/@mysten-sui-2.17.0-Apache-2.0.txt +201 -0
  4. package/LICENSES/@mysten-utils-0.3.3-Apache-2.0.txt +205 -0
  5. package/LICENSES/fancy-canvas-2.1.0-MIT.txt +7 -0
  6. package/LICENSES/lightweight-charts-5.2.0-NOTICE.txt +2 -0
  7. package/README.md +288 -0
  8. package/dist/adapters/adapterLifecycleValidators.js +5 -0
  9. package/dist/adapters/adapterPromptSurfaces.js +60 -0
  10. package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +178 -0
  11. package/dist/adapters/deepbook/deepbookQuotePolicy.js +112 -0
  12. package/dist/adapters/deepbook/deepbookReviewEvidence.js +507 -0
  13. package/dist/adapters/deepbook/deepbookReviewLifecycle.js +85 -0
  14. package/dist/adapters/deepbook/deepbookSwapIntent.js +79 -0
  15. package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +254 -0
  16. package/dist/adapters/intentPlanFactories.js +51 -0
  17. package/dist/adapters/reviewAdapters.js +47 -0
  18. package/dist/core/action/adapterLifecycleValidation.js +12 -0
  19. package/dist/core/action/contractNameRegistry.js +151 -0
  20. package/dist/core/action/forbiddenFields.js +43 -0
  21. package/dist/core/action/humanReadableReviewEvidence.js +193 -0
  22. package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
  23. package/dist/core/action/ptbVisualizationProducer.js +71 -0
  24. package/dist/core/action/receiptPtbGraph.js +29 -0
  25. package/dist/core/action/reviewCheckResults.js +6 -0
  26. package/dist/core/action/reviewStateValidation.js +11 -0
  27. package/dist/core/action/reviewTimeSimulationEvidence.js +470 -0
  28. package/dist/core/action/schemas.js +491 -0
  29. package/dist/core/action/signableAdapterContract.js +998 -0
  30. package/dist/core/action/suiChainReceiptEvidence.js +106 -0
  31. package/dist/core/action/suiChainReceiptMapping.js +107 -0
  32. package/dist/core/action/suiChainReceiptReader.js +211 -0
  33. package/dist/core/action/suiChainReceiptVerifier.js +178 -0
  34. package/dist/core/action/swapHumanReadableReviewProjection.js +130 -0
  35. package/dist/core/action/swapQuotePolicyEvidence.js +271 -0
  36. package/dist/core/action/transactionFunding.js +244 -0
  37. package/dist/core/action/transactionObjectOwnershipEvidence.js +256 -0
  38. package/dist/core/action/transactionObjectOwnershipProducer.js +323 -0
  39. package/dist/core/action/types.js +33 -0
  40. package/dist/core/action/walletReviewContractAssembler.js +286 -0
  41. package/dist/core/activity/accountAssetTimeline.js +157 -0
  42. package/dist/core/activity/accountAssetTimelineUsdcReferences.js +120 -0
  43. package/dist/core/activity/activityStore.js +16 -0
  44. package/dist/core/activity/externalActivityCoverage.js +76 -0
  45. package/dist/core/activity/externalActivityTransactionStream.js +82 -0
  46. package/dist/core/activity/localDataService.js +296 -0
  47. package/dist/core/activity/localDataTypes.js +11 -0
  48. package/dist/core/activity/localDataValidation.js +439 -0
  49. package/dist/core/activity/schemaVersion.js +2 -0
  50. package/dist/core/activity/sqliteActivityStore.js +1068 -0
  51. package/dist/core/activity/sqliteActivityStoreRows.js +389 -0
  52. package/dist/core/activity/sqliteActivityStoreSchema.js +367 -0
  53. package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
  54. package/dist/core/activity/suiFunctionTarget.js +43 -0
  55. package/dist/core/activity/transactionActivityAccountEffects.js +186 -0
  56. package/dist/core/activity/transactionActivityAnalysis.js +295 -0
  57. package/dist/core/activity/transactionActivityClassifier.js +306 -0
  58. package/dist/core/activity/transactionActivityDetails.js +229 -0
  59. package/dist/core/activity/transactionActivityProtocolRules.js +218 -0
  60. package/dist/core/activity/transactionActivityScanPolicy.js +170 -0
  61. package/dist/core/activity/transactionActivityService.js +379 -0
  62. package/dist/core/activity/transactionActivityTypes.js +18 -0
  63. package/dist/core/eventlog/sink.js +35 -0
  64. package/dist/core/evidence/settlementFamilies.js +85 -0
  65. package/dist/core/evidence/userAnswerUse.js +1 -0
  66. package/dist/core/numeric/rawU64.js +63 -0
  67. package/dist/core/preferences/preferencesStore.js +26 -0
  68. package/dist/core/preferences/sqlitePreferencesRepository.js +136 -0
  69. package/dist/core/proposal/externalProposalReview.js +347 -0
  70. package/dist/core/proposal/schemas.js +208 -0
  71. package/dist/core/proposal/types.js +35 -0
  72. package/dist/core/read/amounts.js +14 -0
  73. package/dist/core/read/coinMetadata.js +60 -0
  74. package/dist/core/read/deepbookOfficialIndexerSource.js +373 -0
  75. package/dist/core/read/deepbookRawQuoteClient.js +86 -0
  76. package/dist/core/read/deepbookReadHelpers.js +321 -0
  77. package/dist/core/read/deepbookRegistry.js +157 -0
  78. package/dist/core/read/deepbookSourceOwners.js +159 -0
  79. package/dist/core/read/deepbookUsdcChartService.js +342 -0
  80. package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
  81. package/dist/core/read/readCardInputs.js +19 -0
  82. package/dist/core/read/readCardResult.js +40 -0
  83. package/dist/core/read/readResponseGuidance.js +402 -0
  84. package/dist/core/read/readService.js +1639 -0
  85. package/dist/core/read/readServiceTypes.js +88 -0
  86. package/dist/core/read/settlementParityFormatting.js +82 -0
  87. package/dist/core/read/walletReadHelpers.js +99 -0
  88. package/dist/core/review/reviewChecks.js +45 -0
  89. package/dist/core/review/reviewComputation.js +38 -0
  90. package/dist/core/review/reviewComputationResult.js +87 -0
  91. package/dist/core/session/cardSession.js +31 -0
  92. package/dist/core/session/cardSessionStore.js +204 -0
  93. package/dist/core/session/keyedRecordStore.js +18 -0
  94. package/dist/core/session/liveReviewSessionContract.js +3 -0
  95. package/dist/core/session/localSession.js +31 -0
  96. package/dist/core/session/privateReviewArtifacts.js +75 -0
  97. package/dist/core/session/reviewValidity.js +49 -0
  98. package/dist/core/session/sessionErrors.js +9 -0
  99. package/dist/core/session/sessionRecordStore.js +40 -0
  100. package/dist/core/session/sessionStore.js +655 -0
  101. package/dist/core/session/settingsSession.js +1 -0
  102. package/dist/core/session/settingsSessions.js +45 -0
  103. package/dist/core/session/sqliteCardStore.js +88 -0
  104. package/dist/core/session/sqliteSessionStore.js +213 -0
  105. package/dist/core/session/sqliteTransactionMaterialStore.js +64 -0
  106. package/dist/core/session/sqliteWalletWorkflowStore.js +821 -0
  107. package/dist/core/session/status.js +60 -0
  108. package/dist/core/session/transactionMaterialStore.js +221 -0
  109. package/dist/core/session/transactionRequest.js +72 -0
  110. package/dist/core/session/wait.js +79 -0
  111. package/dist/core/session/walletConnection.js +92 -0
  112. package/dist/core/session/walletRuntime.js +38 -0
  113. package/dist/core/session/walletWorkflow.js +608 -0
  114. package/dist/core/session/workflowState.js +80 -0
  115. package/dist/core/session/workflowView.js +150 -0
  116. package/dist/core/suiAddress.js +18 -0
  117. package/dist/core/suiEndpoint.js +72 -0
  118. package/dist/mcp/activeAccountResponse.js +24 -0
  119. package/dist/mcp/prompts.js +146 -0
  120. package/dist/mcp/registerTool.js +19 -0
  121. package/dist/mcp/resources.js +72 -0
  122. package/dist/mcp/responseGuidance.js +326 -0
  123. package/dist/mcp/result.js +17 -0
  124. package/dist/mcp/schemas.js +11 -0
  125. package/dist/mcp/server.js +32 -0
  126. package/dist/mcp/serverInfo.js +131 -0
  127. package/dist/mcp/toolErrors.js +118 -0
  128. package/dist/mcp/toolNames.js +58 -0
  129. package/dist/mcp/tools/account/index.js +44 -0
  130. package/dist/mcp/tools/action/prepareSuiActionReview.js +126 -0
  131. package/dist/mcp/tools/read/commonSchemas.js +43 -0
  132. package/dist/mcp/tools/read/deepbookReadTools.js +686 -0
  133. package/dist/mcp/tools/read/index.js +14 -0
  134. package/dist/mcp/tools/read/readToolHelpers.js +97 -0
  135. package/dist/mcp/tools/read/reviewActivityTools.js +179 -0
  136. package/dist/mcp/tools/read/serverStatusTools.js +100 -0
  137. package/dist/mcp/tools/read/transactionActivityOutput.js +371 -0
  138. package/dist/mcp/tools/read/transactionActivityTools.js +858 -0
  139. package/dist/mcp/tools/read/walletReadTools.js +734 -0
  140. package/dist/mcp/tools/session/executionResultTools.js +44 -0
  141. package/dist/mcp/tools/session/index.js +8 -0
  142. package/dist/mcp/tools/session/shared.js +36 -0
  143. package/dist/mcp/tools/session/statusTools.js +69 -0
  144. package/dist/mcp/tools/session/walletConnectionTools.js +69 -0
  145. package/dist/mcp/tools/settings/index.js +66 -0
  146. package/dist/mcp-app/account.html +3133 -0
  147. package/dist/mcp-app/account.notices.txt +973 -0
  148. package/dist/mcp-app/chart.html +3354 -0
  149. package/dist/mcp-app/chart.notices.txt +1194 -0
  150. package/dist/mcp-app/connect.html +3179 -0
  151. package/dist/mcp-app/connect.notices.txt +1012 -0
  152. package/dist/mcp-app/receipt.html +8430 -0
  153. package/dist/mcp-app/receipt.notices.txt +3549 -0
  154. package/dist/mcp-app/review.html +8430 -0
  155. package/dist/mcp-app/review.notices.txt +3549 -0
  156. package/dist/mcp-ui/contracts.js +31 -0
  157. package/dist/mcp-ui/readCards.js +28 -0
  158. package/dist/mcp-ui/tools.js +134 -0
  159. package/dist/review-app/brand-dark.svg +1 -0
  160. package/dist/review-app/brand-light.svg +1 -0
  161. package/dist/review-app/favicon.svg +1 -0
  162. package/dist/review-app/settings.css +1 -0
  163. package/dist/review-app/settings.js +1 -0
  164. package/dist/review-app/ui.css +809 -0
  165. package/dist/review-server/assets.js +48 -0
  166. package/dist/review-server/html.js +45 -0
  167. package/dist/review-server/http.js +47 -0
  168. package/dist/review-server/middleware/hostOrigin.js +48 -0
  169. package/dist/review-server/middleware/reviewToken.js +7 -0
  170. package/dist/review-server/reviewServerPolicy.js +1 -0
  171. package/dist/review-server/server.js +72 -0
  172. package/dist/review-server/settingsApi.js +158 -0
  173. package/dist/runtime/application.js +203 -0
  174. package/dist/runtime/config.js +97 -0
  175. package/dist/runtime/localSettingsService.js +198 -0
  176. package/dist/runtime/logger.js +66 -0
  177. package/dist/runtime/reviewDependencies.js +58 -0
  178. package/dist/runtime/reviewServerAcquire.js +93 -0
  179. package/dist/runtime/runtimeTermination.js +60 -0
  180. package/dist/runtime/shared/authenticatedFetch.js +127 -0
  181. package/dist/runtime/shared/control.js +93 -0
  182. package/dist/runtime/shared/dataAccess.js +66 -0
  183. package/dist/runtime/shared/mcpHttp.js +84 -0
  184. package/dist/runtime/shared/ownerLease.js +50 -0
  185. package/dist/runtime/shared/server.js +98 -0
  186. package/dist/runtime/shared/stdio.js +113 -0
  187. package/dist/runtime/smokeMainnetRead.js +391 -0
  188. package/dist/runtime/smokeMainnetReadAssertions.js +306 -0
  189. package/dist/runtime/smokeReview.js +40 -0
  190. package/dist/runtime/start.js +90 -0
  191. package/dist/runtime/suiEndpoint.js +97 -0
  192. package/dist/runtime/suiTransactionGraphqlMapping.js +200 -0
  193. package/dist/runtime/suiTransactionGraphqlQueries.js +231 -0
  194. package/dist/runtime/suiTransactionGraphqlSource.js +148 -0
  195. package/dist/runtime/walletConnectConfig.js +3 -0
  196. package/dist/runtime/walletConnectStorage.js +99 -0
  197. package/dist/runtime/walletConnectTransport.js +128 -0
  198. package/dist/runtime/walletSdkChild.js +3 -0
  199. package/dist/runtime/walletSdkChildRuntime.js +160 -0
  200. package/dist/runtime/walletSdkIpc.js +26 -0
  201. package/dist/runtime/walletSdkProcess.js +358 -0
  202. package/docs/AGENT_BEHAVIOR.md +524 -0
  203. package/docs/AGENT_DEVELOPMENT_POLICY.md +815 -0
  204. package/docs/FRONTEND_POLICY.md +534 -0
  205. package/docs/LOCAL_DB_ARCHITECTURE.md +381 -0
  206. package/docs/MCP_SETUP.md +742 -0
  207. package/docs/MCP_TOOLS.md +1318 -0
  208. package/docs/SDK_API.md +206 -0
  209. package/docs/SIGNABLE_ADAPTER_CONTRACT.md +396 -0
  210. package/docs/TRANSACTION_ACTIVITY_LOG.md +194 -0
  211. package/docs/UTILITY_INDEX.md +275 -0
  212. package/docs/WALLET_CONNECTION.md +238 -0
  213. package/docs/golden-scenarios/BEHAVIOR_MATRIX.md +166 -0
  214. package/docs/golden-scenarios/INTENT_EVIDENCE_GOLDEN_ANSWERS.md +161 -0
  215. package/docs/golden-scenarios/INTENT_EVIDENCE_MATRIX.md +259 -0
  216. package/package.json +79 -0
  217. package/protocols/deepbook-margin.md +15 -0
  218. package/protocols/deepbook-v3.md +24 -0
@@ -0,0 +1,342 @@
1
+ import { DEFAULT_DEEPBOOK_OFFICIAL_INDEXER_INTERVAL, DEEPBOOK_OFFICIAL_INDEXER_INTERVALS, DeepbookOfficialIndexerSource, DeepbookOfficialIndexerSourceError, parseDeepbookOfficialIndexerInterval, selectDeepbookOfficialIndexerCanonicalUsdcPools } from "./deepbookOfficialIndexerSource.js";
2
+ import { deepbookUsdcPriceHistoryPairFromOfficialPool, deepbookUsdcPriceHistoryQuantitySemantics, deepbookUsdcPriceHistoryResponseSummary } from "./deepbookReadHelpers.js";
3
+ import { curateUsdcChartPools } from "./deepbookRegistry.js";
4
+ import { DEEPBOOK_USDC_PRICE_HISTORY_UNSUPPORTED_CLAIMS } from "./readServiceTypes.js";
5
+ export const DEEPBOOK_USDC_CHART_DEFAULT_LIMIT = 500;
6
+ export const DEEPBOOK_USDC_CHART_MAX_CANDLES = 10_000;
7
+ export const DEEPBOOK_USDC_CHART_CACHE_TTL_MS = 5 * 60 * 1000;
8
+ export const DEEPBOOK_USDC_CHART_CANDLE_CACHE_SIZE = 256;
9
+ const ALLOWED_CANDLE_QUERY_FIELDS = new Set(["poolName", "interval", "startTimeMs", "endTimeMs", "limit"]);
10
+ export function createDeepbookUsdcChartService(options = {}) {
11
+ const source = options.source ?? new DeepbookOfficialIndexerSource();
12
+ const now = options.now ?? (() => new Date());
13
+ const cacheTtlMs = options.cacheTtlMs ?? DEEPBOOK_USDC_CHART_CACHE_TTL_MS;
14
+ const maxCandleCacheEntries = options.maxCandleCacheEntries ?? DEEPBOOK_USDC_CHART_CANDLE_CACHE_SIZE;
15
+ let poolCache;
16
+ const candleCache = new Map();
17
+ async function getPools(searchParams = new URLSearchParams()) {
18
+ const unsupportedField = firstUnsupportedField(searchParams, new Set());
19
+ if (unsupportedField) {
20
+ return {
21
+ status: "unsupported_input",
22
+ reason: "unsupported_query_field",
23
+ field: unsupportedField,
24
+ ...chartCommonFields()
25
+ };
26
+ }
27
+ let poolResult;
28
+ try {
29
+ poolResult = await fetchPoolsCached();
30
+ }
31
+ catch (error) {
32
+ return {
33
+ status: "source_unavailable",
34
+ reason: chartSourceUnavailableReason(error),
35
+ ...chartCommonFields()
36
+ };
37
+ }
38
+ // Curate to the hand-picked allowlist of meaningful pairs (SUI/USDC, DEEP/USDC,
39
+ // …), in display order; the indexer's dead/dust pools never appear.
40
+ const pools = curateUsdcChartPools(selectDeepbookOfficialIndexerCanonicalUsdcPools(poolResult.pools).map(deepbookUsdcPriceHistoryPairFromOfficialPool));
41
+ return {
42
+ status: "ok",
43
+ poolCount: pools.length,
44
+ pools,
45
+ intervals: DEEPBOOK_OFFICIAL_INDEXER_INTERVALS,
46
+ defaultInterval: DEFAULT_DEEPBOOK_OFFICIAL_INDEXER_INTERVAL,
47
+ defaultLimit: DEEPBOOK_USDC_CHART_DEFAULT_LIMIT,
48
+ maxCandles: DEEPBOOK_USDC_CHART_MAX_CANDLES,
49
+ source: poolResult.source,
50
+ ...chartCommonFields()
51
+ };
52
+ }
53
+ async function getCandles(searchParams) {
54
+ const parsed = parseCandlesQuery(searchParams);
55
+ if (parsed.status !== "ok") {
56
+ return parsed.body;
57
+ }
58
+ let poolResult;
59
+ try {
60
+ poolResult = await fetchPoolsCached();
61
+ }
62
+ catch (error) {
63
+ return {
64
+ status: "source_unavailable",
65
+ reason: chartSourceUnavailableReason(error),
66
+ query: parsed.query,
67
+ ...chartCommonFields()
68
+ };
69
+ }
70
+ const pools = selectDeepbookOfficialIndexerCanonicalUsdcPools(poolResult.pools);
71
+ const pool = pools.find((candidate) => candidate.pool_name === parsed.query.poolName);
72
+ if (pool === undefined) {
73
+ return {
74
+ status: "unsupported_pool",
75
+ reason: "pool_not_in_official_usdc_pools",
76
+ query: parsed.query,
77
+ availablePoolNames: pools.map((candidate) => candidate.pool_name),
78
+ source: poolResult.source,
79
+ ...chartCommonFields()
80
+ };
81
+ }
82
+ const pair = deepbookUsdcPriceHistoryPairFromOfficialPool(pool);
83
+ let candleResult;
84
+ try {
85
+ candleResult = await fetchCandlesCached(parsed.query);
86
+ }
87
+ catch (error) {
88
+ return {
89
+ status: "source_unavailable",
90
+ reason: chartSourceUnavailableReason(error),
91
+ query: parsed.query,
92
+ pair,
93
+ source: poolResult.source,
94
+ ...chartCommonFields()
95
+ };
96
+ }
97
+ if (candleResult.candles.length === 0) {
98
+ return {
99
+ status: "empty_result",
100
+ query: parsed.query,
101
+ pair,
102
+ candleCount: 0,
103
+ candles: [],
104
+ source: candleResult.source,
105
+ ...chartCommonFields()
106
+ };
107
+ }
108
+ return {
109
+ status: "ok",
110
+ query: parsed.query,
111
+ pair,
112
+ candleCount: candleResult.candles.length,
113
+ candles: candleResult.candles,
114
+ source: candleResult.source,
115
+ ...chartCommonFields()
116
+ };
117
+ }
118
+ async function fetchPoolsCached() {
119
+ const currentTime = now().getTime();
120
+ if (poolCache !== undefined && poolCache.expiresAtMs > currentTime) {
121
+ return poolCache.value;
122
+ }
123
+ const value = await source.fetchPools();
124
+ options.assertCurrent?.();
125
+ poolCache = { expiresAtMs: currentTime + cacheTtlMs, value };
126
+ return value;
127
+ }
128
+ async function fetchCandlesCached(query) {
129
+ const key = JSON.stringify(query);
130
+ const currentTime = now().getTime();
131
+ const cached = candleCache.get(key);
132
+ if (cached !== undefined && cached.expiresAtMs > currentTime) {
133
+ candleCache.delete(key);
134
+ options.assertCurrent?.();
135
+ candleCache.set(key, cached);
136
+ return cached.value;
137
+ }
138
+ const value = await source.fetchCandles(query);
139
+ options.assertCurrent?.();
140
+ candleCache.set(key, { expiresAtMs: currentTime + cacheTtlMs, value });
141
+ while (candleCache.size > maxCandleCacheEntries) {
142
+ const oldestKey = candleCache.keys().next().value;
143
+ if (oldestKey === undefined) {
144
+ break;
145
+ }
146
+ candleCache.delete(oldestKey);
147
+ }
148
+ return value;
149
+ }
150
+ return { getPools, getCandles, clearCache: () => { poolCache = undefined; candleCache.clear(); } };
151
+ }
152
+ function parseCandlesQuery(searchParams) {
153
+ const unsupportedField = firstUnsupportedField(searchParams, ALLOWED_CANDLE_QUERY_FIELDS);
154
+ if (unsupportedField) {
155
+ return chartQueryError({
156
+ status: "unsupported_input",
157
+ reason: "unsupported_query_field",
158
+ field: unsupportedField,
159
+ ...chartCommonFields()
160
+ });
161
+ }
162
+ const duplicateField = firstDuplicateField(searchParams);
163
+ if (duplicateField) {
164
+ return chartQueryError({
165
+ status: "unsupported_input",
166
+ reason: "duplicate_query_field",
167
+ field: duplicateField,
168
+ ...chartCommonFields()
169
+ });
170
+ }
171
+ const poolName = searchParams.get("poolName");
172
+ if (poolName === null || poolName.trim() === "") {
173
+ return chartQueryError({
174
+ status: "unsupported_input",
175
+ reason: "missing_pool_name",
176
+ field: "poolName",
177
+ ...chartCommonFields()
178
+ });
179
+ }
180
+ let interval;
181
+ const intervalText = searchParams.get("interval") ?? DEFAULT_DEEPBOOK_OFFICIAL_INDEXER_INTERVAL;
182
+ try {
183
+ interval = parseDeepbookOfficialIndexerInterval(intervalText);
184
+ }
185
+ catch (error) {
186
+ if (error instanceof DeepbookOfficialIndexerSourceError) {
187
+ return chartQueryError({
188
+ status: "unsupported_input",
189
+ reason: "unsupported_interval",
190
+ field: "interval",
191
+ ...chartCommonFields()
192
+ });
193
+ }
194
+ throw error;
195
+ }
196
+ const startTimeMs = parseOptionalTimestamp(searchParams.get("startTimeMs"), "startTimeMs");
197
+ if (startTimeMs.status === "error") {
198
+ return chartQueryError(startTimeMs.body);
199
+ }
200
+ const endTimeMs = parseOptionalTimestamp(searchParams.get("endTimeMs"), "endTimeMs");
201
+ if (endTimeMs.status === "error") {
202
+ return chartQueryError(endTimeMs.body);
203
+ }
204
+ if (startTimeMs.value !== undefined &&
205
+ endTimeMs.value !== undefined &&
206
+ startTimeMs.value >= endTimeMs.value) {
207
+ return chartQueryError({
208
+ status: "unsupported_input",
209
+ reason: "invalid_timestamp_window",
210
+ query: { poolName, interval, startTimeMs: startTimeMs.value, endTimeMs: endTimeMs.value },
211
+ ...chartCommonFields()
212
+ });
213
+ }
214
+ const limit = parseLimit(searchParams.get("limit"));
215
+ if (limit.status === "error") {
216
+ return chartQueryError(limit.body);
217
+ }
218
+ return {
219
+ status: "ok",
220
+ query: {
221
+ poolName,
222
+ interval,
223
+ ...(startTimeMs.value !== undefined ? { startTimeMs: startTimeMs.value } : {}),
224
+ ...(endTimeMs.value !== undefined ? { endTimeMs: endTimeMs.value } : {}),
225
+ limit: limit.value
226
+ }
227
+ };
228
+ }
229
+ function parseOptionalTimestamp(value, field) {
230
+ if (value === null || value === "") {
231
+ return { status: "ok", value: undefined };
232
+ }
233
+ if (!/^(0|[1-9][0-9]*)$/.test(value)) {
234
+ return {
235
+ status: "error",
236
+ body: {
237
+ status: "unsupported_input",
238
+ reason: "invalid_timestamp",
239
+ field,
240
+ ...chartCommonFields()
241
+ }
242
+ };
243
+ }
244
+ const parsed = Number(value);
245
+ if (!Number.isSafeInteger(parsed)) {
246
+ return {
247
+ status: "error",
248
+ body: {
249
+ status: "unsupported_input",
250
+ reason: "invalid_timestamp",
251
+ field,
252
+ ...chartCommonFields()
253
+ }
254
+ };
255
+ }
256
+ return { status: "ok", value: parsed };
257
+ }
258
+ function parseLimit(value) {
259
+ if (value === null || value === "") {
260
+ return { status: "ok", value: DEEPBOOK_USDC_CHART_DEFAULT_LIMIT };
261
+ }
262
+ if (!/^[1-9][0-9]*$/.test(value)) {
263
+ return {
264
+ status: "error",
265
+ body: {
266
+ status: "unsupported_input",
267
+ reason: "invalid_limit",
268
+ field: "limit",
269
+ ...chartCommonFields()
270
+ }
271
+ };
272
+ }
273
+ const parsed = Number(value);
274
+ if (!Number.isSafeInteger(parsed)) {
275
+ return {
276
+ status: "error",
277
+ body: {
278
+ status: "unsupported_input",
279
+ reason: "invalid_limit",
280
+ field: "limit",
281
+ ...chartCommonFields()
282
+ }
283
+ };
284
+ }
285
+ if (parsed > DEEPBOOK_USDC_CHART_MAX_CANDLES) {
286
+ return {
287
+ status: "error",
288
+ body: {
289
+ status: "over_limit",
290
+ reason: "limit_exceeds_chart_cap",
291
+ maxCandles: DEEPBOOK_USDC_CHART_MAX_CANDLES,
292
+ requestedLimit: parsed,
293
+ ...chartCommonFields()
294
+ }
295
+ };
296
+ }
297
+ return { status: "ok", value: parsed };
298
+ }
299
+ function firstUnsupportedField(searchParams, allowed) {
300
+ for (const key of searchParams.keys()) {
301
+ if (!allowed.has(key)) {
302
+ return key;
303
+ }
304
+ }
305
+ return undefined;
306
+ }
307
+ function firstDuplicateField(searchParams) {
308
+ const seen = new Set();
309
+ for (const key of searchParams.keys()) {
310
+ if (seen.has(key)) {
311
+ return key;
312
+ }
313
+ seen.add(key);
314
+ }
315
+ return undefined;
316
+ }
317
+ function chartSourceUnavailableReason(error) {
318
+ if (error instanceof DeepbookOfficialIndexerSourceError) {
319
+ switch (error.reason) {
320
+ case "invalid_payload":
321
+ return "official_indexer_invalid_payload";
322
+ case "source_timeout":
323
+ return "source_timeout";
324
+ case "source_http_error":
325
+ return "source_http_error";
326
+ case "invalid_source_url":
327
+ case "source_unavailable":
328
+ return "source_unavailable";
329
+ }
330
+ }
331
+ return "source_unavailable";
332
+ }
333
+ function chartCommonFields() {
334
+ return {
335
+ responseSummary: deepbookUsdcPriceHistoryResponseSummary(),
336
+ quantitySemantics: deepbookUsdcPriceHistoryQuantitySemantics(),
337
+ unsupportedClaims: [...DEEPBOOK_USDC_PRICE_HISTORY_UNSUPPORTED_CLAIMS]
338
+ };
339
+ }
340
+ function chartQueryError(body) {
341
+ return { status: "error", body };
342
+ }
@@ -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
+ }
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ import { suiAddressStringSchema, suiTransactionDigestSchema } from "../suiAddress.js";
3
+ import { DEEPBOOK_OFFICIAL_INDEXER_INTERVALS, DEFAULT_DEEPBOOK_OFFICIAL_INDEXER_INTERVAL } from "./deepbookOfficialIndexerSource.js";
4
+ import { DEEPBOOK_USDC_CHART_DEFAULT_LIMIT, DEEPBOOK_USDC_CHART_MAX_CANDLES } from "./deepbookUsdcChartService.js";
5
+ export const accountInputSchema = z.object({ account: suiAddressStringSchema }).strict();
6
+ export const receiptInputSchema = z.object({ digest: suiTransactionDigestSchema }).strict();
7
+ const chartInputBaseSchema = z.object({
8
+ poolName: z.string().min(1),
9
+ interval: z.enum(DEEPBOOK_OFFICIAL_INDEXER_INTERVALS).default(DEFAULT_DEEPBOOK_OFFICIAL_INDEXER_INTERVAL),
10
+ startTimeMs: z.number().int().nonnegative().optional(),
11
+ endTimeMs: z.number().int().nonnegative().optional(),
12
+ limit: z.number().int().min(1).max(DEEPBOOK_USDC_CHART_MAX_CANDLES).default(DEEPBOOK_USDC_CHART_DEFAULT_LIMIT)
13
+ }).strict();
14
+ const validWindow = (value) => value.startTimeMs === undefined || value.endTimeMs === undefined || value.startTimeMs < value.endTimeMs;
15
+ export const chartInputSchema = chartInputBaseSchema.refine(validWindow, "Start must precede end.");
16
+ export const chartOpenInputSchema = chartInputBaseSchema.partial().refine(validWindow, "Start must precede end.");
17
+ export function parseCardInput(kind, input) {
18
+ return kind === "account" ? accountInputSchema.parse(input) : kind === "receipt" ? receiptInputSchema.parse(input) : chartInputSchema.parse(input);
19
+ }
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { assertNoForbiddenMcpFields } from "../action/forbiddenFields.js";
3
+ import { suiTransactionDigestSchema } from "../suiAddress.js";
4
+ import { receiptDisplaySchema } from "../session/cardSession.js";
5
+ const receiptInput = z.object({
6
+ index: z.number().int().nonnegative(),
7
+ kind: z.enum(["object", "shared_object", "receiving", "pure", "withdrawal", "unknown"]),
8
+ objectId: z.string().optional(), bytes: z.string().optional()
9
+ }).strict();
10
+ const foundReceipt = z.object({ status: z.literal("found"), receipt: z.object({
11
+ txDigest: suiTransactionDigestSchema,
12
+ inputs: z.array(receiptInput).refine((items) => new Set(items.map((item) => item.index)).size === items.length),
13
+ ptbGraph: receiptDisplaySchema.shape.ptbGraph
14
+ }).passthrough() }).strict();
15
+ // Partition the same source result before persistence. Never weaken the public
16
+ // forbidden-field check or turn arbitrary fields into private metadata.
17
+ export function projectReadCardResult(kind, input, source) {
18
+ if (kind !== "receipt" || !source || typeof source !== "object" || !("status" in source) || source.status !== "found") {
19
+ assertNoForbiddenMcpFields(source);
20
+ return { data: source };
21
+ }
22
+ const result = foundReceipt.parse(source);
23
+ if (result.receipt.txDigest !== input.digest)
24
+ throw new Error("Receipt digest differs from the selected transaction.");
25
+ const { inputs, ptbGraph, ...facts } = result.receipt;
26
+ const pureInputs = [];
27
+ const publicInputs = inputs.map(({ bytes, ...item }) => {
28
+ if (bytes !== undefined) {
29
+ if (item.kind !== "pure")
30
+ throw new Error("Only a Pure input may contain a display value.");
31
+ pureInputs.push({ index: item.index, bytes });
32
+ }
33
+ return item;
34
+ });
35
+ const receiptDisplay = receiptDisplaySchema.parse({ transactionDigest: facts.txDigest, pureInputs, ptbGraph });
36
+ const data = { status: "found", receipt: { ...facts, inputs: publicInputs },
37
+ uiDetails: { inputValues: "ui_only", ptbGraph: "ui_only" } };
38
+ assertNoForbiddenMcpFields(data);
39
+ return { data, receiptDisplay };
40
+ }