@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,471 @@
1
+ import { Transaction } from "@mysten/sui/transactions";
2
+ import { z } from "zod";
3
+ import { assertNoForbiddenMcpFields } from "./forbiddenFields.js";
4
+ import { WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS } from "./signableAdapterContract.js";
5
+ import { failReviewCheck, passReviewCheck } from "./reviewCheckResults.js";
6
+ import { makeRawU64StringSchema, makeSignedRawIntegerStringSchema, parseRawU64 } from "../numeric/rawU64.js";
7
+ import { normalizedSuiAddressSchema, parseSuiAddress, suiTransactionDigestSchema } from "../suiAddress.js";
8
+ import { normalizeCoinType } from "../read/coinMetadata.js";
9
+ import { LocalTransactionMaterialStoreError, verifyLocalTransactionMaterialArtifacts } from "../session/transactionMaterialStore.js";
10
+ export const REVIEW_TIME_SIMULATION_EVIDENCE_VERSION = "review-time-simulation-v1";
11
+ const isoUtcStringSchema = z.string().refine((value) => {
12
+ const parsed = new Date(value);
13
+ return Number.isFinite(parsed.getTime()) && parsed.toISOString() === value;
14
+ }, "Expected ISO 8601 UTC timestamp");
15
+ const simulationRequiredFieldSchema = z.enum(WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS);
16
+ const simulationBalanceChangeSchema = z.object({
17
+ address: normalizedSuiAddressSchema,
18
+ coinType: z.string().min(1).max(512).refine((value) => {
19
+ try {
20
+ return normalizeCoinType(value) === value;
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }, "Expected a normalized Sui struct tag coin type"),
26
+ amount: makeSignedRawIntegerStringSchema("balanceChanges[].amount")
27
+ }).strict();
28
+ const simulationObjectChangeSchema = z.object({
29
+ objectId: normalizedSuiAddressSchema,
30
+ objectType: z.string().min(1).max(512).optional(),
31
+ inputState: z.string().min(1).max(80),
32
+ outputState: z.string().min(1).max(80),
33
+ idOperation: z.string().min(1).max(80)
34
+ }).strict();
35
+ const simulationTransactionSummarySchema = z.object({
36
+ sender: normalizedSuiAddressSchema,
37
+ gasPaymentCount: z.number().int().min(1),
38
+ inputCount: z.number().int().min(0),
39
+ commandCount: z.number().int().min(0),
40
+ gasBudgetRaw: makeRawU64StringSchema("gasBudgetRaw").optional(),
41
+ gasPriceRaw: makeRawU64StringSchema("gasPriceRaw").optional()
42
+ }).strict();
43
+ const simulationGasCostSummarySchema = z.object({
44
+ computationCostRaw: makeRawU64StringSchema("computationCostRaw"),
45
+ storageCostRaw: makeRawU64StringSchema("storageCostRaw"),
46
+ storageRebateRaw: makeRawU64StringSchema("storageRebateRaw"),
47
+ nonRefundableStorageFeeRaw: makeRawU64StringSchema("nonRefundableStorageFeeRaw")
48
+ }).strict();
49
+ export const reviewTimeSimulationEvidenceSchema = z.object({
50
+ evidenceVersion: z.literal(REVIEW_TIME_SIMULATION_EVIDENCE_VERSION),
51
+ materialId: z.string().min(1),
52
+ reviewSessionId: z.string().min(1),
53
+ planId: z.string().min(1),
54
+ account: normalizedSuiAddressSchema,
55
+ transactionDigest: suiTransactionDigestSchema,
56
+ kind: z.literal("review_time_simulation"),
57
+ provider: z.literal("client.core.simulateTransaction"),
58
+ network: z.literal("sui:mainnet"),
59
+ checksEnabled: z.literal(true),
60
+ requiredFields: z.array(simulationRequiredFieldSchema).min(WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS.length),
61
+ missingFields: z.array(simulationRequiredFieldSchema).default([]),
62
+ status: z.literal("success"),
63
+ simulatedAt: isoUtcStringSchema,
64
+ expiresAt: isoUtcStringSchema,
65
+ effects: z.object({
66
+ transactionDigest: suiTransactionDigestSchema,
67
+ gasCostSummary: simulationGasCostSummarySchema,
68
+ changedObjectCount: z.number().int().min(0)
69
+ }).strict(),
70
+ balanceChanges: z.array(simulationBalanceChangeSchema),
71
+ objectChanges: z.array(simulationObjectChangeSchema),
72
+ transaction: simulationTransactionSummarySchema
73
+ }).strict().superRefine((value, ctx) => {
74
+ if (!WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS.every((field) => value.requiredFields.includes(field))) {
75
+ ctx.addIssue({
76
+ code: "custom",
77
+ path: ["requiredFields"],
78
+ message: "review-time simulation evidence must include every required simulation field"
79
+ });
80
+ }
81
+ if (value.missingFields.length !== 0) {
82
+ ctx.addIssue({
83
+ code: "custom",
84
+ path: ["missingFields"],
85
+ message: "successful review-time simulation evidence must not have missing fields"
86
+ });
87
+ }
88
+ if (value.effects.transactionDigest !== value.transactionDigest) {
89
+ ctx.addIssue({
90
+ code: "custom",
91
+ path: ["effects", "transactionDigest"],
92
+ message: "simulation effects transaction digest must match evidence transactionDigest"
93
+ });
94
+ }
95
+ if (value.effects.changedObjectCount !== value.objectChanges.length) {
96
+ ctx.addIssue({
97
+ code: "custom",
98
+ path: ["effects", "changedObjectCount"],
99
+ message: "simulation changedObjectCount must match objectChanges length"
100
+ });
101
+ }
102
+ });
103
+ export function parseReviewTimeSimulationEvidence(value) {
104
+ return reviewTimeSimulationEvidenceSchema.parse(value);
105
+ }
106
+ export function verifyReviewTimeSimulationEvidence(input) {
107
+ const evidence = parseReviewTimeSimulationEvidence(input.evidence);
108
+ const now = input.now ?? new Date();
109
+ const nowMs = now.getTime();
110
+ if (!Number.isFinite(nowMs)) {
111
+ throw new Error("now must be a valid Date");
112
+ }
113
+ if (evidence.materialId !== input.transactionMaterial.materialId ||
114
+ evidence.reviewSessionId !== input.transactionMaterial.reviewSessionId ||
115
+ evidence.planId !== input.transactionMaterial.planId ||
116
+ evidence.account !== input.transactionMaterial.account ||
117
+ evidence.expiresAt !== input.transactionMaterial.expiresAt ||
118
+ evidence.transactionDigest !== input.transactionMaterialDigest.transactionDigest) {
119
+ throw new Error("review-time simulation evidence must match material and digest identity");
120
+ }
121
+ if (input.transactionMaterialDigest.materialId !== input.transactionMaterial.materialId ||
122
+ input.transactionMaterialDigest.reviewSessionId !== input.transactionMaterial.reviewSessionId ||
123
+ input.transactionMaterialDigest.planId !== input.transactionMaterial.planId ||
124
+ input.transactionMaterialDigest.account !== input.transactionMaterial.account ||
125
+ input.transactionMaterialDigest.expiresAt !== input.transactionMaterial.expiresAt) {
126
+ throw new Error("transaction material digest must match material identity before review-time simulation evidence is accepted");
127
+ }
128
+ const materialCreatedAtMs = Date.parse(input.transactionMaterial.createdAt);
129
+ const simulatedAtMs = Date.parse(evidence.simulatedAt);
130
+ const expiresAtMs = Date.parse(evidence.expiresAt);
131
+ if (simulatedAtMs < materialCreatedAtMs || simulatedAtMs > nowMs || simulatedAtMs >= expiresAtMs) {
132
+ throw new Error("review-time simulation simulatedAt must be between material creation, now, and material expiry");
133
+ }
134
+ if (expiresAtMs <= nowMs) {
135
+ throw new Error("review-time simulation evidence must not be expired");
136
+ }
137
+ if (evidence.transaction.sender !== evidence.account) {
138
+ throw new Error("review-time simulation transaction sender must match reviewed account");
139
+ }
140
+ assertNoForbiddenMcpFields(evidence);
141
+ return evidence;
142
+ }
143
+ export function publicTransactionSimulationSummaryFromEvidence(evidenceInput) {
144
+ const evidence = parseReviewTimeSimulationEvidence(evidenceInput);
145
+ const summary = {
146
+ provider: evidence.provider,
147
+ checksEnabled: evidence.checksEnabled,
148
+ success: true,
149
+ gasCostSummary: { ...evidence.effects.gasCostSummary },
150
+ balanceChanges: evidence.balanceChanges.map((change) => ({ ...change })),
151
+ objectChanges: evidence.objectChanges.map((change) => ({ ...change }))
152
+ };
153
+ assertNoForbiddenMcpFields(summary);
154
+ return summary;
155
+ }
156
+ export function createReviewTimeSimulationProducer(options) {
157
+ return async (input) => {
158
+ if (options.network !== "mainnet" || options.chainIdentifier !== options.expectedChainIdentifier) {
159
+ return {
160
+ status: "blocked",
161
+ blockedReason: "network_mismatch",
162
+ checks: [
163
+ failReviewCheck("review_time_simulation_network_mismatch", "Review-time simulation network", "Review-time simulation requires a verified Sui mainnet gRPC endpoint and matching mainnet chain identifier.", "network")
164
+ ]
165
+ };
166
+ }
167
+ let parsed;
168
+ try {
169
+ parsed = await verifyLocalTransactionMaterialArtifacts({
170
+ materialStore: options.materialStore,
171
+ transactionMaterial: input.transactionMaterial,
172
+ transactionMaterialDigest: input.transactionMaterialDigest,
173
+ now: input.now
174
+ });
175
+ }
176
+ catch (error) {
177
+ const message = error instanceof Error ? error.message : "Stored transaction material could not be verified.";
178
+ const check = failReviewCheck("review_time_simulation_material_unavailable", "Review-time simulation material", message, "adapter");
179
+ if (error instanceof LocalTransactionMaterialStoreError && /expired|unavailable/i.test(message)) {
180
+ return { status: "refresh_required", refreshReason: "quote_stale", checks: [check] };
181
+ }
182
+ return { status: "blocked", blockedReason: "object_resolution_failed", checks: [check] };
183
+ }
184
+ const material = options.materialStore.getTransactionMaterial(parsed.transactionMaterial, input.now);
185
+ if (!material) {
186
+ return {
187
+ status: "refresh_required",
188
+ refreshReason: "quote_stale",
189
+ checks: [
190
+ failReviewCheck("review_time_simulation_material_unavailable", "Review-time simulation material", "Review-time simulation could not run because the stored local transaction material is unavailable or expired.", "adapter")
191
+ ]
192
+ };
193
+ }
194
+ let simulationResult;
195
+ try {
196
+ simulationResult = await options.client.core.simulateTransaction({
197
+ transaction: material.transactionBytes,
198
+ include: {
199
+ transaction: true,
200
+ effects: true,
201
+ balanceChanges: true,
202
+ objectTypes: true
203
+ },
204
+ checksEnabled: true
205
+ });
206
+ }
207
+ catch (error) {
208
+ const classification = classifySimulationException(error);
209
+ if (classification.status === "refresh_required") {
210
+ return {
211
+ status: "refresh_required",
212
+ refreshReason: "simulation_transient_failure",
213
+ checks: [
214
+ failReviewCheck("review_time_simulation_transient_failure", "Review-time simulation", "Review-time simulation could not reach the Sui simulation endpoint or timed out before returning a result. Refreshing the review may retry this transport-level simulation step.", "simulation")
215
+ ]
216
+ };
217
+ }
218
+ return {
219
+ status: "blocked",
220
+ blockedReason: classification.blockedReason,
221
+ checks: [
222
+ failReviewCheck("review_time_simulation_exception_blocked", "Review-time simulation", "Review-time simulation threw a non-transient error before returning a result. The review is blocked until the transaction material, simulation request shape, or adapter implementation is corrected.", "simulation")
223
+ ]
224
+ };
225
+ }
226
+ const simulatedTransaction = simulationResult.$kind === "Transaction"
227
+ ? simulationResult.Transaction
228
+ : simulationResult.FailedTransaction;
229
+ if (simulationResult.$kind !== "Transaction" || !simulatedTransaction.status.success) {
230
+ const failureReason = simulationFailureReason(simulatedTransaction.status);
231
+ const checks = [
232
+ failReviewCheck("review_time_simulation_result_failed", "Review-time simulation", `Review-time simulation did not succeed: ${failureReason}`, "simulation")
233
+ ];
234
+ return {
235
+ status: "blocked",
236
+ blockedReason: blockedReasonForSimulationFailure(failureReason),
237
+ checks
238
+ };
239
+ }
240
+ let recomputedTransactionDigest;
241
+ try {
242
+ recomputedTransactionDigest = await Transaction.from(material.transactionBytes).getDigest();
243
+ }
244
+ catch {
245
+ return {
246
+ status: "blocked",
247
+ blockedReason: "object_resolution_failed",
248
+ checks: [
249
+ failReviewCheck("review_time_simulation_result_invalid", "Review-time simulation", "Stored transaction material bytes could not produce a Sui transaction digest for the simulation binding.", "simulation")
250
+ ]
251
+ };
252
+ }
253
+ let evidence;
254
+ try {
255
+ evidence = createReviewTimeSimulationEvidenceFromTransaction({
256
+ transactionMaterial: parsed.transactionMaterial,
257
+ transactionMaterialDigest: parsed.transactionMaterialDigest,
258
+ recomputedTransactionDigest,
259
+ transaction: simulatedTransaction,
260
+ simulatedAt: input.now
261
+ });
262
+ verifyReviewTimeSimulationEvidence({
263
+ transactionMaterial: parsed.transactionMaterial,
264
+ transactionMaterialDigest: parsed.transactionMaterialDigest,
265
+ evidence,
266
+ now: input.now
267
+ });
268
+ }
269
+ catch (error) {
270
+ return {
271
+ status: "blocked",
272
+ blockedReason: "object_resolution_failed",
273
+ checks: [
274
+ failReviewCheck("review_time_simulation_result_invalid", "Review-time simulation", error instanceof Error ? error.message : "Review-time simulation returned incomplete or invalid required fields.", "simulation")
275
+ ]
276
+ };
277
+ }
278
+ return {
279
+ status: "completed",
280
+ evidence,
281
+ checks: [
282
+ passReviewCheck("review_time_simulation_evidence", "Review-time simulation", "Simulated the stored local unsigned transaction material with validation checks enabled and bound the resulting effects, balance changes, object types, and transaction summary to the internal transaction digest. This is review evidence only, not wallet handoff, signing readiness, or execution readiness.", "simulation")
283
+ ]
284
+ };
285
+ };
286
+ }
287
+ function createReviewTimeSimulationEvidenceFromTransaction(input) {
288
+ // The digest binding is recomputed locally from the exact bytes submitted to
289
+ // the simulation endpoint. Public fullnodes differ in whether they echo the
290
+ // transaction digest back, so node-provided digests are cross-checks only.
291
+ if (input.recomputedTransactionDigest !== input.transactionMaterialDigest.transactionDigest) {
292
+ throw new Error("simulated transaction digest must match the stored material digest");
293
+ }
294
+ const nodeDigest = input.transaction.digest;
295
+ if (nodeDigest !== undefined && nodeDigest !== input.transactionMaterialDigest.transactionDigest) {
296
+ throw new Error("simulation node returned a different transaction digest than the submitted bytes");
297
+ }
298
+ const effectsDigest = input.transaction.effects?.transactionDigest;
299
+ if (effectsDigest !== undefined && effectsDigest !== input.transactionMaterialDigest.transactionDigest) {
300
+ throw new Error("simulated effects digest must match the stored material digest");
301
+ }
302
+ if (!input.transaction.transaction) {
303
+ throw new Error("simulation result is missing parsed transaction data");
304
+ }
305
+ if (!input.transaction.effects) {
306
+ throw new Error("simulation result is missing effects");
307
+ }
308
+ if (!input.transaction.balanceChanges) {
309
+ throw new Error("simulation result is missing balance changes");
310
+ }
311
+ if (!input.transaction.objectTypes) {
312
+ throw new Error("simulation result is missing object types");
313
+ }
314
+ const transactionSummary = summarizeSimulatedTransaction(input.transaction.transaction);
315
+ const evidence = {
316
+ evidenceVersion: REVIEW_TIME_SIMULATION_EVIDENCE_VERSION,
317
+ materialId: input.transactionMaterial.materialId,
318
+ reviewSessionId: input.transactionMaterial.reviewSessionId,
319
+ planId: input.transactionMaterial.planId,
320
+ account: input.transactionMaterial.account,
321
+ transactionDigest: input.transactionMaterialDigest.transactionDigest,
322
+ kind: "review_time_simulation",
323
+ provider: "client.core.simulateTransaction",
324
+ network: "sui:mainnet",
325
+ checksEnabled: true,
326
+ requiredFields: [...WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS],
327
+ missingFields: [],
328
+ status: "success",
329
+ simulatedAt: input.simulatedAt.toISOString(),
330
+ expiresAt: input.transactionMaterial.expiresAt,
331
+ effects: {
332
+ transactionDigest: input.transaction.effects.transactionDigest,
333
+ gasCostSummary: summarizeGasCost(input.transaction.effects.gasUsed),
334
+ changedObjectCount: input.transaction.effects.changedObjects.length
335
+ },
336
+ balanceChanges: input.transaction.balanceChanges.map((change) => ({
337
+ address: normalizeSimulationAddress(change.address, "balance change address"),
338
+ coinType: normalizeCoinType(change.coinType),
339
+ amount: change.amount
340
+ })),
341
+ objectChanges: input.transaction.effects.changedObjects.map((change) => ({
342
+ objectId: normalizeSimulationAddress(change.objectId, "object change objectId"),
343
+ ...(input.transaction.objectTypes[change.objectId]
344
+ ? { objectType: input.transaction.objectTypes[change.objectId] }
345
+ : {}),
346
+ inputState: change.inputState,
347
+ outputState: change.outputState,
348
+ idOperation: change.idOperation
349
+ })),
350
+ transaction: transactionSummary
351
+ };
352
+ return reviewTimeSimulationEvidenceSchema.parse(evidence);
353
+ }
354
+ function summarizeGasCost(gasUsed) {
355
+ const computationCost = parseRawU64(gasUsed.computationCost, "computationCost");
356
+ const storageCost = parseRawU64(gasUsed.storageCost, "storageCost");
357
+ const storageRebate = parseRawU64(gasUsed.storageRebate, "storageRebate");
358
+ const nonRefundableStorageFee = parseRawU64(gasUsed.nonRefundableStorageFee, "nonRefundableStorageFee");
359
+ return {
360
+ computationCostRaw: computationCost.toString(),
361
+ storageCostRaw: storageCost.toString(),
362
+ storageRebateRaw: storageRebate.toString(),
363
+ nonRefundableStorageFeeRaw: nonRefundableStorageFee.toString()
364
+ };
365
+ }
366
+ function summarizeSimulatedTransaction(transaction) {
367
+ if (transaction.sender === null || transaction.sender === undefined) {
368
+ throw new Error("simulation transaction sender is missing");
369
+ }
370
+ const sender = normalizeSimulationAddress(transaction.sender, "transaction sender");
371
+ const gasData = transaction.gasData;
372
+ return {
373
+ sender,
374
+ gasPaymentCount: Array.isArray(gasData.payment) ? gasData.payment.length : 0,
375
+ inputCount: transaction.inputs.length,
376
+ commandCount: transaction.commands.length,
377
+ ...(gasData.budget === null || gasData.budget === undefined
378
+ ? {}
379
+ : { gasBudgetRaw: parseRawU64(String(gasData.budget), "gasBudgetRaw").toString() }),
380
+ ...(gasData.price === null || gasData.price === undefined
381
+ ? {}
382
+ : { gasPriceRaw: parseRawU64(String(gasData.price), "gasPriceRaw").toString() })
383
+ };
384
+ }
385
+ function normalizeSimulationAddress(value, label) {
386
+ const normalized = parseSuiAddress(value);
387
+ if (!normalized) {
388
+ throw new Error(`simulation ${label} must be a valid Sui address`);
389
+ }
390
+ return normalized;
391
+ }
392
+ function simulationFailureReason(status) {
393
+ if (status.success) {
394
+ return "simulation succeeded";
395
+ }
396
+ const error = status.error;
397
+ if (typeof error === "string") {
398
+ return error;
399
+ }
400
+ if (error && typeof error === "object") {
401
+ const maybeMessage = error.message;
402
+ if (typeof maybeMessage === "string" && maybeMessage.length > 0) {
403
+ return maybeMessage;
404
+ }
405
+ return JSON.stringify(error);
406
+ }
407
+ return "unknown simulation failure";
408
+ }
409
+ function blockedReasonForSimulationFailure(failureReason) {
410
+ if (/gas/i.test(failureReason)) {
411
+ return "insufficient_gas";
412
+ }
413
+ if (/balance|coin|insufficient/i.test(failureReason)) {
414
+ return "insufficient_balance";
415
+ }
416
+ return "object_resolution_failed";
417
+ }
418
+ function classifySimulationException(error) {
419
+ if (isTransientSimulationException(error)) {
420
+ return { status: "refresh_required" };
421
+ }
422
+ return { status: "blocked", blockedReason: "object_resolution_failed" };
423
+ }
424
+ function isTransientSimulationException(error) {
425
+ const code = errorCode(error);
426
+ if (code === "UNAVAILABLE" ||
427
+ code === "DEADLINE_EXCEEDED" ||
428
+ code === "RESOURCE_EXHAUSTED" ||
429
+ code === "ECONNRESET" ||
430
+ code === "ECONNREFUSED" ||
431
+ code === "ETIMEDOUT" ||
432
+ code === "ENOTFOUND" ||
433
+ code === "EAI_AGAIN" ||
434
+ code === 4 ||
435
+ code === 8 ||
436
+ code === 14) {
437
+ return true;
438
+ }
439
+ const message = errorMessage(error).toLowerCase();
440
+ if (message.length === 0) {
441
+ return false;
442
+ }
443
+ return [
444
+ /\b(grpc|rpc|transport|network|endpoint|connection|connect|socket|fetch)\b[\s\S]{0,80}\b(unavailable|timeout|timed out|deadline|reset|refused|failed|hang up|exhausted)\b/,
445
+ /\b(unavailable|timeout|timed out|deadline exceeded|temporarily unavailable|service unavailable|gateway timeout|too many requests)\b[\s\S]{0,80}\b(grpc|rpc|transport|network|endpoint|connection|connect|socket|fetch)\b/,
446
+ /\b(econnreset|econnrefused|etimedout|enotfound|eai_again|socket hang up|fetch failed|network error|deadline exceeded|request timeout|service unavailable|gateway timeout|too many requests)\b/
447
+ ].some((pattern) => pattern.test(message));
448
+ }
449
+ function errorCode(error) {
450
+ if (typeof error !== "object" || error === null) {
451
+ return undefined;
452
+ }
453
+ const value = error.code ??
454
+ error.status;
455
+ return typeof value === "string" || typeof value === "number" ? value : undefined;
456
+ }
457
+ function errorMessage(error) {
458
+ if (error instanceof Error) {
459
+ return error.message;
460
+ }
461
+ if (typeof error === "string") {
462
+ return error;
463
+ }
464
+ if (typeof error === "object" && error !== null) {
465
+ const message = error.message;
466
+ if (typeof message === "string") {
467
+ return message;
468
+ }
469
+ }
470
+ return "";
471
+ }