@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
package/README.md ADDED
@@ -0,0 +1,288 @@
1
+ # Sui MCP
2
+
3
+ Sui MCP is a local-first Sui review and evidence layer for AI clients.
4
+
5
+ It turns a supported Sui action into an internal Review card where you inspect
6
+ verified transaction facts and a PTB graph, then request approval in your own
7
+ wallet. The backend builds or verifies the material, binds the reviewed account
8
+ and digest, and uses WalletConnect for a sign-only request. It verifies the
9
+ wallet's returned bytes and signature before one submission to Sui mainnet.
10
+
11
+ The AI and card never receive executable transaction bytes or signatures.
12
+ Neither a review nor a wallet connection is standing transaction permission.
13
+ Only an explicit user action and that transaction's wallet approval authorize
14
+ the request. Lost replies are resolved by reading the known digest; they do not
15
+ cause another signing or submission request. Request failures and unknown
16
+ outcomes are separate from independently observed chain success/failure.
17
+
18
+ Account, Receipt and Chart cards provide read-only evidence independently of
19
+ signing. Connect and Review also run inside the MCP host. Settings currently
20
+ uses a local token page. Human-readable review is not a guarantee of safety or
21
+ of complete interpretation of every transaction detail; the raw PTB structure
22
+ and addresses remain inspectable.
23
+
24
+ Users can ask ordinary questions:
25
+
26
+ - "Can I cover a 1000 dollar payment with my assets?"
27
+ - "How much are my USD-denominated assets together?"
28
+ - "What is the shortfall?"
29
+
30
+ This document describes `@zktx.io/sui-mcp@0.5.0`. Confirm that version is
31
+ published before using npm installation commands. For a local build, follow
32
+ [Developer Checkout Setup](docs/MCP_SETUP.md#developer-checkout-setup).
33
+
34
+ ## Product Scope in Two Layers
35
+
36
+ - **Implemented:** Sui mainnet read evidence, non-signable external proposal review, and account-bound DeepBook swap review using protocol-agnostic adapters. Five internal cards use the same SQLite state and permission model. The backend verifies stored material, ownership, quote/policy provenance, human-readable facts, simulation and PTB evidence before an explicit user request. WalletConnect carries bytes only between the backend and wallet; ordinary MCP responses expose facts, request status and observed execution results. Settings remains a local token page; an internal Settings card is not implemented.
37
+ - **Never (permanently unsupported at every layer):** no private-key custody, no MCP or AI autonomous execution, no forwarding of opaque external transaction bytes to a wallet, no silent settlement-token or route choice, no fiat cash-out, no P&L, no peg guarantee.
38
+
39
+ DeepBook provides the current scoped Sui conversion, price, and orderbook
40
+ evidence through the shared protocol adapter contracts. Wallet and Sui balance reads
41
+ describe held assets. They do not define the whole product.
42
+
43
+ Sui MCP does not custody funds, hold private keys, or autonomously trade
44
+ on behalf of users.
45
+ By current design, it does not rank venues, choose routes, make best-price
46
+ recommendations, or silently choose settlement tokens for users.
47
+
48
+ Account-bound transaction building, signing requests and chain observation stay
49
+ in the local backend. The Review card displays evidence and current permitted
50
+ actions. Public review JSON, model-facing card data and backups never contain transaction
51
+ bytes, signatures, SDK keys or signing permission. Reopening a card reads its
52
+ stored state and never replays a financial request.
53
+
54
+ The current release flow is:
55
+
56
+ ```text
57
+ The user states an intent in natural language.
58
+ Sui MCP resolves the supported Sui mainnet evidence surface.
59
+ The AI answers only from returned evidence and boundaries.
60
+ Supported swap transaction material build is an account-bound review step, not
61
+ part of the natural-language intent evidence answer.
62
+ ```
63
+
64
+ The current release implements intent evidence for supported Sui mainnet reads.
65
+ It can also create a read-only, non-signable local review session from a
66
+ structured external payment or Sui action proposal. External proposal ingestion
67
+ does not trust external transaction material or send anything for wallet signing.
68
+
69
+ For setup, see [docs/MCP_SETUP.md](docs/MCP_SETUP.md).
70
+ For the MCP API reference, see [docs/MCP_TOOLS.md](docs/MCP_TOOLS.md).
71
+ For the AI-client answer playbook, see [docs/AGENT_BEHAVIOR.md](docs/AGENT_BEHAVIOR.md).
72
+ For manual maintainer and developer utilities, see [docs/UTILITY_INDEX.md](docs/UTILITY_INDEX.md).
73
+
74
+ User-question flows for USD-denominated coverage, balance totals, and shortfall answers live in [docs/AGENT_BEHAVIOR.md](docs/AGENT_BEHAVIOR.md). The response fields for those answers live in [docs/MCP_TOOLS.md](docs/MCP_TOOLS.md).
75
+
76
+ ## What Works Today
77
+
78
+ The current release can run as a local stdio MCP server and expose mainnet Sui DeFi evidence:
79
+
80
+ - wallet balances with verified display units;
81
+ - coin-balance classification;
82
+ - USD-denominated settlement asset groups derived from pinned DeepBook SDK registry metadata;
83
+ - intent evidence with response summaries for natural-language USD-denominated payment coverage, balance-total, and shortfall questions;
84
+ - DeepBook pools, tokens, mid price, orderbook context, raw quotes, display-amount quotes, and account inventory;
85
+ - user-requested bounded Sui transaction digest lookup, account activity scans, sent-function activity scans with known-wallet-only persistence, and stored normalized activity summaries;
86
+ - read-only external proposal review sessions that display proposed action, asset flow, recipient or target, freshness, missing evidence, user choices, unsupported claims, and non-signable reason;
87
+ - local Sui MCP review evidence and review-session status reads;
88
+ - account-bound DeepBook review with verified material, digest, ownership, policy, human-readable facts, simulation and PTB visualization, followed by explicit card selection and wallet approval through the backend;
89
+ - separately recorded request state and chain success/failure, shown in the Review card and available through ordinary reads;
90
+ - a Receipt card for server-read facts about any transaction digest, independent of signing.
91
+
92
+ It also includes:
93
+
94
+ - a local review server bound to `127.0.0.1`;
95
+ - a local SQLite store for active account read context and review evidence;
96
+ - MCP output checks that reject forbidden executable, signing, token, seed, and
97
+ key-material field names from responses.
98
+
99
+ ## Screens
100
+
101
+ **Wallet connection.** Connect one Sui mainnet wallet and use one of its approved
102
+ addresses. A manage card shows Connect wallet when no connection is active;
103
+ opening it alone does not pair. A connect-intent card starts pairing after its
104
+ View confirms permission and current state. Each disconnection requires the
105
+ user to confirm its exact target. Connection is not transaction approval.
106
+
107
+
108
+ **Review and result.** The internal Review card automatically prepares and renews verified conditions for one selected wallet/account. Users inspect its transaction graph, amounts and costs, then choose Request wallet approval and approve in their wallet. One wallet connection is used at a time; choose among its approved addresses when needed. Conflicting saved connections must be resolved through targeted disconnection. Failed preparation has an explicit retry. Receipt and completed Review show the executed transaction graph, actual asset changes and net network fee. Supplementary facts are in one Details slide; earlier estimates in Review remain distinct from actual chain results. Missing graph or receipt data is marked unavailable. Cards use a single document layout without nested card panels.
109
+
110
+ **DeepBook USDC chart.** `ui.open_chart` opens an internal MCP Apps card with
111
+ official DeepBookV3 Indexer candles and volume for one selected USDC pool.
112
+ The saved result shows the selected pair, interval, UTC period and source time. Limited and empty results are identified.
113
+
114
+ ## Current Limits
115
+
116
+ ### Not Implemented
117
+
118
+ External proposal execution is not implemented. Further local analysis views
119
+ beyond the current inline review receipt and internal Receipt card are
120
+ not implemented. Transaction material review, backend WalletConnect requests under user control,
121
+ signature verification, single submission and independent receipt observation
122
+ are implemented for the account-bound DeepBook swap review
123
+ through a plan-factory registry.
124
+
125
+ External proposal ingestion is implemented only for read-only local review
126
+ sessions. It accepts structured proposal facts, rejects forbidden executable or
127
+ signing fields, recognized Sui private-key strings, valid English BIP39
128
+ mnemonic phrases, obvious sensitive markers, and suspicious raw secret-like
129
+ payloads before storage, and records why the review is non-signable.
130
+
131
+ A blocked review lacks required evidence for that session. Only a complete
132
+ `TransactionReviewData` binds human-readable facts and simulation to the exact
133
+ reviewed digest. This is pre-signing evidence, not authority or guaranteed
134
+ execution. The backend checks returned bytes and the selected account's
135
+ signature before submitting. See [the adapter contract](docs/SIGNABLE_ADAPTER_CONTRACT.md).
136
+
137
+ Fiat cash-out, P&L, tax, and cost-basis support are not part of the current release.
138
+
139
+ ### Permanent Safety and Correctness Boundaries
140
+
141
+ These are product boundaries and must not be relaxed by ordinary feature work:
142
+
143
+ - Sui MCP does not custody funds, hold private keys, or autonomously trade.
144
+ - It does not treat USDC, USDT, or any USD-denominated settlement asset as fiat
145
+ USD, a bank cash-out amount, or a USDC/USD peg guarantee.
146
+ - It does not turn quote-only conversion candidates into payment coverage, shortfall evidence, funding readiness, payment execution readiness, or signing readiness.
147
+
148
+ ### Out of Scope by Current Design
149
+
150
+ These product behaviors are out of scope in the current release by design:
151
+
152
+ - It does not silently choose USDC, USDT, or another settlement token for a
153
+ user. It can report supported settlement asset groups and can use a settlement
154
+ token only when the user selected it explicitly.
155
+ - It does not rank venues, choose routes, or make best-price recommendations.
156
+
157
+ ### Quote Response Limits
158
+
159
+ Quote tools such as `read.quote_deepbook_action` and
160
+ `read.quote_deepbook_display_amount` return scoped quote facts and raw quote
161
+ evidence only.
162
+
163
+ Their semantics mark quote output as price evidence, not payment coverage or shortfall evidence. Coverage and shortfall answers come from `read.preview_intent_evidence.responseSummary`.
164
+
165
+ For quote responses alone, these conclusions are unsupported:
166
+
167
+ - payment coverage is not available;
168
+ - shortfall contribution is not available;
169
+ - route-dependent payment support is not available;
170
+ - final min-out values are not available;
171
+ - route recommendations are not available;
172
+ - venue comparisons are not available;
173
+ - effective-price claims are not available;
174
+ - price-impact calculations are not available;
175
+ - quote-vs-mid slippage is not available;
176
+ - fiat cash-out estimates are not available;
177
+ - external market lookups are not available;
178
+ - USDC/USD peg assumptions are not available;
179
+ - P&L is not available;
180
+ - cost basis is not available;
181
+ - actionable signing data is not available.
182
+
183
+ ## Install
184
+
185
+ Use the checkout setup above for unpublished changes. A local commit or successful
186
+ package check does not publish a release.
187
+
188
+ This release uses npm package `@zktx.io/sui-mcp` and MCP Registry name
189
+ `io.github.zktx-mcp/sui-mcp`. Once the requested version is published,
190
+ install through your client's registry support or run `npx -y @zktx.io/sui-mcp`.
191
+ For per-client configuration (Claude Code, Claude Desktop, Codex, Cursor) and
192
+ running from a local checkout, see [docs/MCP_SETUP.md](docs/MCP_SETUP.md).
193
+
194
+ ### Package and repository transition
195
+
196
+ The package for this release is `@zktx.io/sui-mcp@0.5.0`, and its repository is
197
+ `zktx-mcp/sui-mcp`. The previous package is `@zktx.io/say-ur-intent` (through
198
+ 0.4.4). The older `@stelis/say-ur-intent@0.4.0` is also a separate package.
199
+ Existing installations and MCP client registrations do not change names
200
+ automatically. Before switching, confirm the new package with
201
+ `npm view @zktx.io/sui-mcp@0.5.0 version`; renaming the repository does not publish
202
+ an npm package or MCP Registry entry.
203
+
204
+ Use the full scoped package name: the unscoped `sui-mcp` package is a different
205
+ project. Keep the MCP registration name `sui-mcp`, without a suffix. This release
206
+ starts with a new local data directory and does not import or
207
+ convert data from the previous package. See the
208
+ [setup guide](docs/MCP_SETUP.md#switching-the-installed-package) for installation
209
+ and shared-server restart instructions.
210
+
211
+ After the MCP server is connected, use [docs/MCP_SETUP.md](docs/MCP_SETUP.md#first-use-flow) for first-use setup, [docs/MCP_TOOLS.md](docs/MCP_TOOLS.md) for API fields and statuses, and [docs/AGENT_BEHAVIOR.md](docs/AGENT_BEHAVIOR.md) for user-question flow and response wording.
212
+
213
+ ## Mainnet-Only Product Surface
214
+
215
+ Product docs, registry, AI responses, UX copy, and signable actions are mainnet-only.
216
+
217
+ Unsupported protocol experiments are not product functionality and are not included in the package docs, MCP resources, registry support lists, UX copy, or signable-action lists.
218
+
219
+ ## MCP Tools
220
+
221
+ The canonical MCP API reference lives in [docs/MCP_TOOLS.md](docs/MCP_TOOLS.md).
222
+
223
+ The server also exposes `read.get_server_status`. It returns the package version, evidence policy version, `implementedToolsCount`, and implemented tool list at runtime.
224
+
225
+ DeepBook pool-price context is exposed through `read.get_deepbook_mid_price`. Use `docs/MCP_TOOLS.md` for the response fields and unsupported conclusions.
226
+
227
+ Tool names use dot prefixes because the MCP spec recommends ASCII letters, digits, underscore, hyphen, and dot for tool names. `action.prepare_sui_action_review` returns a `reviewSessionId` and an internal `card`; it does not return executable transaction bytes.
228
+
229
+ ## Documentation Map
230
+
231
+ The server exposes only a subset of repository documents as MCP resources.
232
+
233
+ Runtime-facing MCP resources currently include:
234
+
235
+ - this README;
236
+ - `docs/MCP_SETUP.md`;
237
+ - `docs/MCP_TOOLS.md`;
238
+ - `docs/WALLET_CONNECTION.md`;
239
+ - `docs/AGENT_BEHAVIOR.md`;
240
+ - `protocols/deepbook-v3.md`;
241
+ - `protocols/deepbook-margin.md`.
242
+
243
+ Protocol resources are explanatory references. Current support is declared by `read.get_server_status`, `read.list_supported_protocols`, concrete tool schemas, and concrete tool responses, not by protocol Markdown alone.
244
+
245
+ Development-only or release-review documents can define contributor rules and checks.
246
+
247
+ AI client answer behavior must be mirrored in runtime-facing instructions, resources, prompts, schemas, or returned evidence fields before it is treated as product behavior.
248
+
249
+ - `README.md`: Public entry document: product purpose, current release boundary, setup path, and documentation map.
250
+ - `docs/MCP_SETUP.md`: Setup guide: installation, MCP client connection, first-use flow, settings, and troubleshooting.
251
+ - `docs/MCP_TOOLS.md`: API reference: tool contracts, response fields, statuses, follow-up fields, and output boundaries.
252
+ - `docs/AGENT_BEHAVIOR.md`: Answer playbook: user-question flows, tool selection, and response wording boundaries.
253
+ - `docs/WALLET_CONNECTION.md`: Wallet connection reference: active read context, private SDK ownership and user-approved transaction requests.
254
+ - `protocols/deepbook-v3.md`: Protocol reference only; use MCP tool responses and read.list_supported_protocols for current support.
255
+ - `protocols/deepbook-margin.md`: Protocol reference only; no margin MCP read tools or signable actions are exposed in this release.
256
+ - `docs/golden-scenarios/INTENT_EVIDENCE_MATRIX.md`: current-release question, tool-path, and standard-answer matrix for AI client release review.
257
+ - `docs/golden-scenarios/BEHAVIOR_MATRIX.md`: broader behavior scenario matrix for supported and unsupported user prompts.
258
+ - `docs/TRANSACTION_ACTIVITY_LOG.md`: transaction activity evidence, storage, scan, and summary boundaries.
259
+ - `docs/UTILITY_INDEX.md`: manual maintainer and developer utilities. Utility rows are not MCP tools unless they explicitly name an MCP tool, and source-checkout scripts are not packaged product commands.
260
+ - `docs/LOCAL_DB_ARCHITECTURE.md`: local SQLite storage boundaries for maintainers.
261
+ - `docs/SDK_API.md`: pinned SDK API notes and source-verification boundaries.
262
+ - `docs/FRONTEND_POLICY.md`: review-app frontend implementation policy for coding agents.
263
+ - `docs/SIGNABLE_ADAPTER_CONTRACT.md`: wallet-review adapter and PTB visualization contract. It defines the pre-signing review evidence and commitment boundary; wallet signing requires a user card action and approval in the wallet; the backend alone handles bytes.
264
+ - `AGENTS.md`: root repository development contract and non-negotiable product boundaries for coding agents working on this codebase.
265
+ - `docs/AGENT_DEVELOPMENT_POLICY.md`: detailed binding development, review, documentation, source-of-truth, and completion policies for coding agents.
266
+
267
+ ## Contract Name Registry
268
+
269
+ The PTB visualization in the Review card can show human-readable labels in place
270
+ of raw addresses, with a toggle back to raw addresses. A label is identity display only, not a
271
+ safety, trust, route-quality, or signing-readiness signal, and only registered
272
+ addresses are relabeled.
273
+
274
+ Two pinned, context-aware registries in
275
+ [`src/core/action/contractNameRegistry.ts`](src/core/action/contractNameRegistry.ts)
276
+ drive this:
277
+
278
+ - packages, relabeled only in `<address>::` path position — the DeepBook swap
279
+ package by its Move Registry (MVR) name `@deepbook/core`, and the Sui framework
280
+ packages by their Move aliases (`std`, `sui`, `sui_system`);
281
+ - well-known Sui system objects, relabeled only as a bare object id — `Clock`,
282
+ `SuiSystemState`, `Random`, `DenyList`, `CoinRegistry`, and the address-based
283
+ balance `AccumulatorRoot`.
284
+
285
+ If you maintain a Sui DeFi protocol that has a registered MVR name and want its
286
+ package to display that name in the review graph, open a pull request adding your
287
+ mainnet package address and MVR name to the package registry. Every unregistered
288
+ address keeps its raw form.
@@ -0,0 +1,5 @@
1
+ import { DEEPBOOK_SWAP_REVIEW_LIFECYCLE_STAGE_CATALOG_ID, validateDeepbookSwapReviewLifecycle } from "./deepbook/deepbookReviewLifecycle.js";
2
+ import { createAdapterLifecycleValidator } from "../core/action/adapterLifecycleValidation.js";
3
+ export const validateSupportedAdapterLifecycle = createAdapterLifecycleValidator({
4
+ [DEEPBOOK_SWAP_REVIEW_LIFECYCLE_STAGE_CATALOG_ID]: validateDeepbookSwapReviewLifecycle
5
+ });
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { DEEPBOOK_SWAP_ACTION_KIND, DEEPBOOK_SWAP_ADAPTER_ID } from "./deepbook/deepbookSwapIntent.js";
3
+ /**
4
+ * One slash-prompt surface contributed by a review adapter.
5
+ *
6
+ * Prompt names follow action-first naming: `<action>-<protocolSlug>`
7
+ * (for example `swap-deep`). Users reach for the verb before the venue, so
8
+ * action-first keeps autocomplete grouped by what the user wants to do. When
9
+ * an action has exactly one registered protocol, the bare action name (for
10
+ * example `swap`) is also registered as a shorthand.
11
+ *
12
+ * The surface carries only protocol-specific copy. Boundary language (no
13
+ * signing data, no transaction bytes, local-review-only signing) is owned by
14
+ * the platform and appended at registration time; adapters cannot weaken it.
15
+ */
16
+ export const adapterPromptSurfaceSchema = z
17
+ .object({
18
+ adapterId: z.string().min(1),
19
+ action: z
20
+ .string()
21
+ .regex(/^[a-z][a-z0-9]*$/, "action must be a lowercase slug, e.g. swap"),
22
+ protocolSlug: z
23
+ .string()
24
+ .regex(/^[a-z][a-z0-9]*$/, "protocolSlug must be a lowercase slug, e.g. deep"),
25
+ title: z.string().min(1),
26
+ description: z.string().min(1),
27
+ intentArgDescription: z.string().min(1),
28
+ exampleIntents: z.array(z.string().min(1)).min(1),
29
+ toolName: z.string().min(1)
30
+ })
31
+ .strict();
32
+ export function promptNameFor(surface) {
33
+ return `${surface.action}-${surface.protocolSlug}`;
34
+ }
35
+ /**
36
+ * Bare action prompts (`swap`) are always registered. With a single
37
+ * registered protocol they go straight to that protocol; with several they
38
+ * carry an optional `protocol` argument (completion suggests the slugs) and
39
+ * instruct the model to ask the user which protocol to use - never to pick a
40
+ * venue silently.
41
+ */
42
+ export function actionGroups(surfaces) {
43
+ const byAction = new Map();
44
+ for (const surface of surfaces) {
45
+ byAction.set(surface.action, [...(byAction.get(surface.action) ?? []), surface]);
46
+ }
47
+ return byAction;
48
+ }
49
+ export const ADAPTER_PROMPT_SURFACES = [
50
+ {
51
+ adapterId: DEEPBOOK_SWAP_ADAPTER_ID,
52
+ action: DEEPBOOK_SWAP_ACTION_KIND,
53
+ protocolSlug: "deep",
54
+ title: "DeepBook Swap Review",
55
+ description: 'Prepare a reviewable DeepBook mainnet swap from a one-line intent, e.g. "10 sui to usdc".',
56
+ intentArgDescription: 'Swap intent in one line, any language, e.g. "10 sui to usdc" or "10 수이 usdc로 환전"',
57
+ exampleIntents: ["10 sui to usdc", "10 수이 usdc로 환전"],
58
+ toolName: "action.prepare_sui_action_review"
59
+ }
60
+ ];
@@ -0,0 +1,178 @@
1
+ import { transactionFundingSummary } from "../../core/action/transactionFunding.js";
2
+ import { createSwapHumanReadableReviewEvidence } from "../../core/action/swapHumanReadableReviewProjection.js";
3
+ import { failReviewCheck, passReviewCheck } from "../../core/review/reviewComputationResult.js";
4
+ export function createDeepbookSwapHumanReadableReviewProducer() {
5
+ return (input) => {
6
+ try {
7
+ assertDeepbookHumanReviewSources(input);
8
+ const review = buildDeepbookHumanReadableReview(input);
9
+ const evidence = createSwapHumanReadableReviewEvidence({
10
+ transactionMaterial: input.transactionMaterial,
11
+ transactionMaterialDigest: input.transactionMaterialDigest,
12
+ swapQuotePolicy: input.swapQuotePolicy,
13
+ transactionObjectOwnership: input.transactionObjectOwnership,
14
+ adapterId: input.plan.adapterId,
15
+ protocol: input.plan.protocol,
16
+ actionKind: input.plan.actionKind,
17
+ review,
18
+ derivedAt: input.now
19
+ });
20
+ return {
21
+ status: "completed",
22
+ evidence,
23
+ checks: [
24
+ passReviewCheck("deepbook_human_readable_review_evidence", "Readable transaction details", "Prepared the amounts and transaction details for this account from the verified quote, transaction and object owners. These details do not authorize wallet approval or guarantee execution.", "adapter")
25
+ ]
26
+ };
27
+ }
28
+ catch (error) {
29
+ return {
30
+ status: "blocked",
31
+ blockedReason: classifyHumanReviewFailure(error),
32
+ checks: [
33
+ failReviewCheck("deepbook_human_readable_review_failed", "Readable transaction details", error instanceof Error ? error.message : "The transaction details could not be prepared for this account.", "adapter")
34
+ ]
35
+ };
36
+ }
37
+ };
38
+ }
39
+ function buildDeepbookHumanReadableReview(input) {
40
+ const sourceAmount = amountFromQuotePolicy("input", input.swapQuotePolicy.sourceAmount, {
41
+ displayAmount: input.requestedIntent.from.amountDisplay,
42
+ displayAmountSource: "user_display_intent_not_signing_input"
43
+ });
44
+ const expectedOutput = amountFromQuotePolicy("expected_output", input.swapQuotePolicy.expectedOutput);
45
+ const minimumOutput = amountFromQuotePolicy("minimum_output", input.swapQuotePolicy.minimumOutput);
46
+ const protocolFee = amountFromQuotePolicy("fee", input.swapQuotePolicy.protocolFee);
47
+ return {
48
+ kind: "swap_human_readable_review",
49
+ proposedAction: {
50
+ title: input.plan.title,
51
+ summary: input.plan.summary,
52
+ actionKind: input.plan.actionKind,
53
+ adapterId: input.plan.adapterId,
54
+ protocol: input.plan.protocol,
55
+ network: "sui:mainnet"
56
+ },
57
+ assetFlow: {
58
+ outgoing: [sourceAmount],
59
+ expectedIncoming: [expectedOutput],
60
+ minimumIncoming: [minimumOutput],
61
+ fees: [protocolFee]
62
+ },
63
+ recipients: [
64
+ { role: "connected_account", address: input.account },
65
+ { role: "output_recipient", address: input.account }
66
+ ],
67
+ targets: [
68
+ {
69
+ kind: "swap_output_asset",
70
+ symbol: input.swapQuotePolicy.expectedOutput.asset.symbol,
71
+ coinType: input.swapQuotePolicy.expectedOutput.asset.coinType,
72
+ protocol: input.plan.protocol,
73
+ poolKey: input.swapQuotePolicy.quoteSource.poolKey,
74
+ direction: input.swapQuotePolicy.quoteSource.direction
75
+ }
76
+ ],
77
+ evidenceUsed: [
78
+ { id: "transaction_funding", label: "Transaction funding", source: "transaction_material",
79
+ summary: transactionFundingSummary(input.transactionObjectOwnership.funding) },
80
+ {
81
+ id: "deepbook_quote_policy",
82
+ label: "Quote and slippage rules",
83
+ source: "quote",
84
+ summary: "The quote and its rules supply the send amount, expected and minimum receive amounts, trading fee, and slippage limit shown here. They do not choose a route or establish permission to sign."
85
+ },
86
+ {
87
+ id: "transaction_material_digest",
88
+ label: "Transaction identity (digest)",
89
+ source: "digest_commitment",
90
+ summary: "This review is tied to the exact unsigned transaction stored by Sui MCP through its verification digest. The private transaction bytes are not included in the card."
91
+ },
92
+ {
93
+ id: "transaction_object_ownership",
94
+ label: "Object ownership",
95
+ source: "wallet",
96
+ summary: "The transaction objects and their owners were checked using the stored transaction and Sui mainnet data."
97
+ }
98
+ ],
99
+ missingEvidence: [
100
+ {
101
+ id: "review_time_simulation",
102
+ label: "Review-time simulation",
103
+ reason: "At this step, the stored transaction has not yet been simulated to check its effects, balance changes, object types, and transaction details."
104
+ }
105
+ ],
106
+ requiredUserChoices: [
107
+ {
108
+ id: "wallet_authorization_later",
109
+ label: "Wallet approval required",
110
+ reason: "The backend requests a signature only after your explicit Review card action; nothing is signed without your approval in the wallet."
111
+ }
112
+ ],
113
+ unsupportedClaims: [
114
+ {
115
+ id: "no_signing_readiness",
116
+ label: "Wallet approval not established",
117
+ reason: "These review details alone do not establish permission to request a wallet signature."
118
+ },
119
+ {
120
+ id: "no_execution_readiness",
121
+ label: "Execution not confirmed",
122
+ reason: "At this step, simulation, wallet approval, signing, and confirmation of the transaction result are not complete."
123
+ },
124
+ {
125
+ id: "no_route_recommendation",
126
+ label: "No route recommendation",
127
+ reason: "The account-bound swap review uses an explicit direct pool path and does not rank venues or recommend routes."
128
+ }
129
+ ],
130
+ freshness: {
131
+ status: "current",
132
+ evaluatedAt: input.now.toISOString(),
133
+ expiresAt: input.transactionMaterial.expiresAt,
134
+ reason: "These details expire with the transaction and quote used to prepare them."
135
+ },
136
+ blockingChecks: [
137
+ failReviewCheck("deepbook_review_time_simulation_missing", "Review-time simulation", "Review-time simulation evidence is still required before any wallet handoff, signing, or execution.", "simulation")
138
+ ]
139
+ };
140
+ }
141
+ function assertDeepbookHumanReviewSources(input) {
142
+ if (input.swapQuotePolicy.adapterId !== input.plan.adapterId ||
143
+ input.swapQuotePolicy.protocol !== input.plan.protocol ||
144
+ input.swapQuotePolicy.actionKind !== input.plan.actionKind) {
145
+ throw new Error("human-readable review quote policy identity must match the action plan");
146
+ }
147
+ if (input.swapQuotePolicy.quoteSource.poolKey !== input.poolResolution.poolKey) {
148
+ throw new Error("human-readable review pool target must match swap quote policy poolKey");
149
+ }
150
+ if (input.swapQuotePolicy.quoteSource.direction !== input.quotePolicy.direction) {
151
+ throw new Error("human-readable review target direction must match swap quote policy direction");
152
+ }
153
+ }
154
+ function classifyHumanReviewFailure(error) {
155
+ const message = error instanceof Error ? error.message : "";
156
+ if (/object ownership/i.test(message)) {
157
+ return "object_resolution_failed";
158
+ }
159
+ if (/asset|target|pool|direction|protocol|adapter/i.test(message)) {
160
+ return "asset_mismatch";
161
+ }
162
+ if (/amount|quote|slippage|min/i.test(message)) {
163
+ return "amount_mismatch";
164
+ }
165
+ return "unsupported_action";
166
+ }
167
+ function amountFromQuotePolicy(role, amount, display) {
168
+ return {
169
+ role,
170
+ symbol: amount.asset.symbol,
171
+ coinType: amount.asset.coinType,
172
+ decimals: amount.asset.decimals,
173
+ rawAmount: amount.raw,
174
+ rawAmountSource: "quote_policy_evidence",
175
+ ...(display?.displayAmount ? { displayAmount: display.displayAmount } : {}),
176
+ ...(display?.displayAmountSource ? { displayAmountSource: display.displayAmountSource } : {})
177
+ };
178
+ }
@@ -0,0 +1,112 @@
1
+ import { parseDeepbookRawU64 } from "../../core/read/deepbookReadHelpers.js";
2
+ export const DEEPBOOK_REVIEW_QUOTE_STALE_AFTER_MS = 30_000;
3
+ // Same-machine pipelines capture `now` before the network quote fetch, so the
4
+ // fetch timestamp can land a few hundred milliseconds "in the future". Treat
5
+ // skew within this tolerance as a fresh quote (age 0) and record the skew;
6
+ // anything beyond it is a real clock-integrity violation and refuses.
7
+ export const DEEPBOOK_QUOTE_FUTURE_SKEW_TOLERANCE_MS = 5_000;
8
+ export const DEEPBOOK_MAX_SLIPPAGE_BPS = 1000;
9
+ export const DEEPBOOK_MIN_SLIPPAGE_BPS = 1;
10
+ const BPS_DENOMINATOR = 10000n;
11
+ export function deriveDeepbookSwapQuotePolicy(input) {
12
+ assertSlippageBps(input.maxSlippageBps);
13
+ const staleAfterMs = input.staleAfterMs ?? DEEPBOOK_REVIEW_QUOTE_STALE_AFTER_MS;
14
+ if (!Number.isInteger(staleAfterMs) || staleAfterMs < 1) {
15
+ throw new Error("staleAfterMs must be a positive integer");
16
+ }
17
+ const fetchedAtMs = parseIsoUtcTimestampMs(input.fetchedAt, "fetchedAt");
18
+ const nowMs = parseValidDateMs(input.now, "now");
19
+ const rawQuoteAgeMs = nowMs - fetchedAtMs;
20
+ const direction = directionFromRawQuote(input.rawQuote);
21
+ if (rawQuoteAgeMs < -DEEPBOOK_QUOTE_FUTURE_SKEW_TOLERANCE_MS) {
22
+ return {
23
+ status: "refresh_required",
24
+ refreshReason: "quote_stale",
25
+ reason: "quote_timestamp_in_future",
26
+ direction,
27
+ fetchedAt: input.fetchedAt,
28
+ quoteAgeMs: 0,
29
+ staleAfterMs,
30
+ clockSkewMs: -rawQuoteAgeMs
31
+ };
32
+ }
33
+ const clockSkewMs = rawQuoteAgeMs < 0 ? -rawQuoteAgeMs : undefined;
34
+ const quoteAgeMs = rawQuoteAgeMs < 0 ? 0 : rawQuoteAgeMs;
35
+ if (quoteAgeMs > staleAfterMs) {
36
+ return {
37
+ status: "refresh_required",
38
+ refreshReason: "quote_stale",
39
+ reason: "quote_stale",
40
+ direction,
41
+ fetchedAt: input.fetchedAt,
42
+ quoteAgeMs,
43
+ staleAfterMs
44
+ };
45
+ }
46
+ const expectedOut = parseUnsignedRaw(input.rawQuote.directionalOutput.raw, "directionalOutput.raw");
47
+ if (expectedOut === 0n) {
48
+ return unavailableQuote(input, direction, quoteAgeMs, staleAfterMs, "zero_expected_output");
49
+ }
50
+ const minOut = (expectedOut * (BPS_DENOMINATOR - BigInt(input.maxSlippageBps))) / BPS_DENOMINATOR;
51
+ if (minOut === 0n) {
52
+ return unavailableQuote(input, direction, quoteAgeMs, staleAfterMs, "zero_min_out");
53
+ }
54
+ return {
55
+ status: "ok",
56
+ direction,
57
+ quoteFresh: true,
58
+ fetchedAt: input.fetchedAt,
59
+ quoteAgeMs,
60
+ staleAfterMs,
61
+ ...(clockSkewMs !== undefined ? { clockSkewMs } : {}),
62
+ feeMode: input.feeMode ?? "deep",
63
+ maxSlippageBps: input.maxSlippageBps,
64
+ sourceAmountRaw: parsePositiveRaw(input.rawQuote.inputAmount.raw, "inputAmount.raw").toString(),
65
+ expectedOutRaw: expectedOut.toString(),
66
+ minOutRaw: minOut.toString(),
67
+ deepAmountRaw: parseUnsignedRaw(input.rawQuote.deepRequired.raw, "deepRequired.raw").toString()
68
+ };
69
+ }
70
+ function assertSlippageBps(value) {
71
+ if (!Number.isInteger(value) || value < DEEPBOOK_MIN_SLIPPAGE_BPS || value > DEEPBOOK_MAX_SLIPPAGE_BPS) {
72
+ throw new Error(`maxSlippageBps must be an integer from ${DEEPBOOK_MIN_SLIPPAGE_BPS} to ${DEEPBOOK_MAX_SLIPPAGE_BPS}`);
73
+ }
74
+ }
75
+ function parseIsoUtcTimestampMs(value, field) {
76
+ const parsed = new Date(value);
77
+ const timestampMs = parsed.getTime();
78
+ if (!Number.isFinite(timestampMs) || parsed.toISOString() !== value) {
79
+ throw new Error(`${field} must be an ISO 8601 UTC timestamp`);
80
+ }
81
+ return timestampMs;
82
+ }
83
+ function parseValidDateMs(value, field) {
84
+ if (!(value instanceof Date)) {
85
+ throw new Error(`${field} must be a valid Date`);
86
+ }
87
+ const timestampMs = value.getTime();
88
+ if (!Number.isFinite(timestampMs)) {
89
+ throw new Error(`${field} must be a valid Date`);
90
+ }
91
+ return timestampMs;
92
+ }
93
+ function directionFromRawQuote(rawQuote) {
94
+ return rawQuote.sourceMoveFunction.startsWith("pool::get_quote_quantity_out") ? "base_to_quote" : "quote_to_base";
95
+ }
96
+ function unavailableQuote(input, direction, quoteAgeMs, staleAfterMs, reason) {
97
+ return {
98
+ status: "refresh_required",
99
+ refreshReason: "quote_unavailable",
100
+ reason,
101
+ direction,
102
+ fetchedAt: input.fetchedAt,
103
+ quoteAgeMs,
104
+ staleAfterMs
105
+ };
106
+ }
107
+ function parsePositiveRaw(value, field) {
108
+ return parseDeepbookRawU64(value, field, { positive: true });
109
+ }
110
+ function parseUnsignedRaw(value, field) {
111
+ return parseDeepbookRawU64(value, field);
112
+ }