@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,193 @@
1
+ import { z } from "zod";
2
+ import { assertNoForbiddenMcpFields } from "./forbiddenFields.js";
3
+ import { WALLET_REVIEW_REQUIRED_HUMAN_FIELDS, adapterHumanReadableReviewSchema } from "./signableAdapterContract.js";
4
+ import { humanReadableReviewSummarySchema } from "./schemas.js";
5
+ import { normalizedSuiAddressSchema, parseSuiAddress, suiTransactionDigestSchema } from "../suiAddress.js";
6
+ export const HUMAN_READABLE_REVIEW_EVIDENCE_VERSION = "human-readable-review-v1";
7
+ const isoUtcStringSchema = z.string().refine((value) => {
8
+ const parsed = new Date(value);
9
+ return Number.isFinite(parsed.getTime()) && parsed.toISOString() === value;
10
+ }, "Expected ISO 8601 UTC timestamp");
11
+ export const humanReadableReviewEvidenceSchema = z.object({
12
+ evidenceVersion: z.literal(HUMAN_READABLE_REVIEW_EVIDENCE_VERSION),
13
+ materialId: z.string().min(1),
14
+ reviewSessionId: z.string().min(1),
15
+ planId: z.string().min(1),
16
+ account: normalizedSuiAddressSchema,
17
+ transactionDigest: suiTransactionDigestSchema,
18
+ kind: z.literal("human_readable_review"),
19
+ adapterId: z.string().min(1).max(120),
20
+ protocol: z.string().min(1).max(120),
21
+ actionKind: z.string().min(1).max(120),
22
+ network: z.literal("sui:mainnet"),
23
+ fields: z.array(z.enum(WALLET_REVIEW_REQUIRED_HUMAN_FIELDS)).min(WALLET_REVIEW_REQUIRED_HUMAN_FIELDS.length),
24
+ source: z.literal("review_model_or_adapter_equivalent"),
25
+ purpose: z.literal("human_review_before_wallet_authorization"),
26
+ review: humanReadableReviewSummarySchema,
27
+ derivedAt: isoUtcStringSchema,
28
+ expiresAt: isoUtcStringSchema
29
+ }).strict().superRefine((value, ctx) => {
30
+ const duplicateField = findDuplicate(value.fields);
31
+ if (duplicateField) {
32
+ ctx.addIssue({
33
+ code: "custom",
34
+ path: ["fields"],
35
+ message: `Human-readable review fields contains duplicate field '${duplicateField}'`
36
+ });
37
+ }
38
+ if (!WALLET_REVIEW_REQUIRED_HUMAN_FIELDS.every((field) => value.fields.includes(field))) {
39
+ ctx.addIssue({
40
+ code: "custom",
41
+ path: ["fields"],
42
+ message: "Human-readable review fields must include every required review field"
43
+ });
44
+ }
45
+ if (value.review.freshness.evaluatedAt !== value.derivedAt ||
46
+ value.review.freshness.expiresAt !== value.expiresAt) {
47
+ ctx.addIssue({
48
+ code: "custom",
49
+ path: ["review", "freshness"],
50
+ message: "review freshness must match evidence derivedAt and expiresAt"
51
+ });
52
+ }
53
+ if (value.review.proposedAction.adapterId !== value.adapterId ||
54
+ value.review.proposedAction.protocol !== value.protocol ||
55
+ value.review.proposedAction.actionKind !== value.actionKind) {
56
+ ctx.addIssue({
57
+ code: "custom",
58
+ path: ["review", "proposedAction"],
59
+ message: "review proposedAction must match the human-readable review evidence identity"
60
+ });
61
+ }
62
+ });
63
+ export function parseHumanReadableReviewEvidence(value) {
64
+ return humanReadableReviewEvidenceSchema.parse(value);
65
+ }
66
+ export function createHumanReadableReviewEvidence(input) {
67
+ return verifyHumanReadableReviewEvidence({
68
+ transactionMaterial: input.transactionMaterial,
69
+ transactionMaterialDigest: input.transactionMaterialDigest,
70
+ evidence: {
71
+ evidenceVersion: HUMAN_READABLE_REVIEW_EVIDENCE_VERSION,
72
+ materialId: input.transactionMaterial.materialId,
73
+ reviewSessionId: input.transactionMaterial.reviewSessionId,
74
+ planId: input.transactionMaterial.planId,
75
+ account: input.transactionMaterial.account,
76
+ transactionDigest: input.transactionMaterialDigest.transactionDigest,
77
+ kind: "human_readable_review",
78
+ adapterId: input.adapterId,
79
+ protocol: input.protocol,
80
+ actionKind: input.actionKind,
81
+ network: "sui:mainnet",
82
+ fields: [...WALLET_REVIEW_REQUIRED_HUMAN_FIELDS],
83
+ source: "review_model_or_adapter_equivalent",
84
+ purpose: "human_review_before_wallet_authorization",
85
+ review: input.review,
86
+ derivedAt: input.derivedAt.toISOString(),
87
+ expiresAt: input.transactionMaterial.expiresAt
88
+ },
89
+ now: input.derivedAt
90
+ });
91
+ }
92
+ export function verifyHumanReadableReviewEvidence(input) {
93
+ const evidence = parseHumanReadableReviewEvidence(input.evidence);
94
+ const now = input.now ?? new Date();
95
+ const nowMs = now.getTime();
96
+ if (!Number.isFinite(nowMs)) {
97
+ throw new Error("now must be a valid Date");
98
+ }
99
+ if (evidence.materialId !== input.transactionMaterial.materialId ||
100
+ evidence.reviewSessionId !== input.transactionMaterial.reviewSessionId ||
101
+ evidence.planId !== input.transactionMaterial.planId ||
102
+ evidence.account !== input.transactionMaterial.account ||
103
+ evidence.expiresAt !== input.transactionMaterial.expiresAt ||
104
+ evidence.transactionDigest !== input.transactionMaterialDigest.transactionDigest) {
105
+ throw new Error("human-readable review evidence must match material and digest identity");
106
+ }
107
+ if (input.transactionMaterialDigest.materialId !== input.transactionMaterial.materialId ||
108
+ input.transactionMaterialDigest.reviewSessionId !== input.transactionMaterial.reviewSessionId ||
109
+ input.transactionMaterialDigest.planId !== input.transactionMaterial.planId ||
110
+ input.transactionMaterialDigest.account !== input.transactionMaterial.account ||
111
+ input.transactionMaterialDigest.expiresAt !== input.transactionMaterial.expiresAt) {
112
+ throw new Error("transaction material digest must match material identity before human review evidence is accepted");
113
+ }
114
+ assertHumanReadableReviewConnectedAccount(evidence);
115
+ assertHumanReadableReviewEvidenceSources(evidence);
116
+ const materialCreatedAtMs = Date.parse(input.transactionMaterial.createdAt);
117
+ const derivedAtMs = Date.parse(evidence.derivedAt);
118
+ const expiresAtMs = Date.parse(evidence.expiresAt);
119
+ if (derivedAtMs < materialCreatedAtMs || derivedAtMs > nowMs || derivedAtMs >= expiresAtMs) {
120
+ throw new Error("human-readable review derivedAt must be between material creation, now, and material expiry");
121
+ }
122
+ if (expiresAtMs <= nowMs) {
123
+ throw new Error("human-readable review evidence must not be expired");
124
+ }
125
+ adapterHumanReadableReviewSchema.parse({
126
+ fields: evidence.fields,
127
+ transactionDigest: evidence.transactionDigest,
128
+ source: evidence.source,
129
+ purpose: evidence.purpose
130
+ });
131
+ assertNoForbiddenMcpFields(evidence.review);
132
+ return evidence;
133
+ }
134
+ export function publicHumanReadableReviewFromEvidence(evidenceInput) {
135
+ const evidence = parseHumanReadableReviewEvidence(evidenceInput);
136
+ assertNoForbiddenMcpFields(evidence.review);
137
+ return humanReadableReviewSummarySchema.parse(structuredClone(evidence.review));
138
+ }
139
+ function findDuplicate(values) {
140
+ const seen = new Set();
141
+ for (const value of values) {
142
+ if (seen.has(value)) {
143
+ return value;
144
+ }
145
+ seen.add(value);
146
+ }
147
+ return undefined;
148
+ }
149
+ function assertHumanReadableReviewConnectedAccount(evidence) {
150
+ const recipientsByRole = new Map();
151
+ for (const recipient of evidence.review.recipients) {
152
+ if (recipientsByRole.has(recipient.role)) {
153
+ throw new Error(`human-readable review recipients contains duplicate role '${recipient.role}'`);
154
+ }
155
+ const normalizedAddress = parseSuiAddress(recipient.address);
156
+ if (!normalizedAddress) {
157
+ throw new Error("human-readable review recipients must contain valid Sui addresses");
158
+ }
159
+ recipientsByRole.set(recipient.role, normalizedAddress);
160
+ }
161
+ if (recipientsByRole.get("connected_account") !== evidence.account) {
162
+ throw new Error("human-readable review connected account recipient must match the reviewed account");
163
+ }
164
+ }
165
+ export function assertPreSimulationHumanReadableReviewBoundaryClaims(evidence) {
166
+ requireGapId("missingEvidence", evidence.review.missingEvidence, "review_time_simulation");
167
+ requireGapId("requiredUserChoices", evidence.review.requiredUserChoices, "wallet_authorization_later");
168
+ for (const id of [
169
+ "no_signing_readiness",
170
+ "no_execution_readiness"
171
+ ]) {
172
+ requireGapId("unsupportedClaims", evidence.review.unsupportedClaims, id);
173
+ }
174
+ if (!evidence.review.blockingChecks.some((check) => check.source === "simulation" &&
175
+ check.status === "fail")) {
176
+ throw new Error("human-readable review blockingChecks must include a failed simulation check");
177
+ }
178
+ }
179
+ function assertHumanReadableReviewEvidenceSources(evidence) {
180
+ for (const source of ["digest_commitment"]) {
181
+ requireFactSource(evidence.review.evidenceUsed, source);
182
+ }
183
+ }
184
+ function requireFactSource(facts, source) {
185
+ if (!facts.some((fact) => fact.source === source)) {
186
+ throw new Error(`human-readable review evidenceUsed must include source '${source}'`);
187
+ }
188
+ }
189
+ function requireGapId(label, gaps, id) {
190
+ if (!gaps.some((gap) => gap.id === id)) {
191
+ throw new Error(`human-readable review ${label} must include '${id}'`);
192
+ }
193
+ }
@@ -0,0 +1,29 @@
1
+ import { verifyHumanReadableReviewEvidence } from "./humanReadableReviewEvidence.js";
2
+ import { verifySwapHumanReadableReviewEvidence } from "./swapHumanReadableReviewProjection.js";
3
+ export function verifySupportedHumanReadableReviewEvidence(input) {
4
+ const evidence = verifyHumanReadableReviewEvidence({
5
+ transactionMaterial: input.transactionMaterial,
6
+ transactionMaterialDigest: input.transactionMaterialDigest,
7
+ evidence: input.evidence,
8
+ now: input.now
9
+ });
10
+ switch (evidence.review.kind) {
11
+ case "swap_human_readable_review":
12
+ return verifySwapHumanReadableReviewEvidence({
13
+ transactionMaterial: input.transactionMaterial,
14
+ transactionMaterialDigest: input.transactionMaterialDigest,
15
+ swapQuotePolicy: requireProjectionArtifact(input.swapQuotePolicy, "swap human-readable review evidence requires swap quote policy evidence"),
16
+ transactionObjectOwnership: requireProjectionArtifact(input.transactionObjectOwnership, "swap human-readable review evidence requires transaction object ownership evidence"),
17
+ evidence,
18
+ now: input.now
19
+ });
20
+ }
21
+ const unsupportedKind = evidence.review.kind;
22
+ throw new Error(`unsupported human-readable review projection kind: ${String(unsupportedKind)}`);
23
+ }
24
+ function requireProjectionArtifact(value, message) {
25
+ if (value === undefined) {
26
+ throw new Error(message);
27
+ }
28
+ return value;
29
+ }
@@ -0,0 +1,71 @@
1
+ import { Transaction } from "@mysten/sui/transactions";
2
+ import { rawTransactionToIR, transactionIRToMermaid } from "@zktx.io/ptb-model";
3
+ import { applyContractNamesToMermaid } from "./contractNameRegistry.js";
4
+ import { PTB_VISUALIZATION_CONTRACT_VERSION, PTB_VISUALIZATION_REQUIRED_UNSUPPORTED_USES, ptbVisualizationArtifactSchema } from "./signableAdapterContract.js";
5
+ export const PTB_VISUALIZATION_RENDERER = {
6
+ name: "transactionIRToMermaid",
7
+ packageName: "@zktx.io/ptb-model",
8
+ version: "0.5.0"
9
+ };
10
+ export async function producePtbVisualizationArtifact(input) {
11
+ const material = input.materialStore.getTransactionMaterial(input.transactionMaterial, input.now);
12
+ if (!material) {
13
+ return { status: "declined", reason: "transaction material is unavailable for visualization" };
14
+ }
15
+ let mermaidText;
16
+ try {
17
+ const transaction = Transaction.from(material.transactionBytes);
18
+ const recomputedDigest = await transaction.getDigest();
19
+ if (recomputedDigest !== input.transactionMaterialDigest.transactionDigest) {
20
+ return {
21
+ status: "declined",
22
+ reason: "stored transaction bytes do not match the bound transaction material commitment"
23
+ };
24
+ }
25
+ const data = transaction.getData();
26
+ const ir = rawTransactionToIR({ inputs: data.inputs, commands: data.commands });
27
+ mermaidText = transactionIRToMermaid(ir, { direction: "LR" });
28
+ }
29
+ catch (error) {
30
+ return {
31
+ status: "declined",
32
+ reason: `ptb renderer failed: ${error instanceof Error ? error.message : String(error)}`
33
+ };
34
+ }
35
+ const candidate = {
36
+ contractVersion: PTB_VISUALIZATION_CONTRACT_VERSION,
37
+ artifactKind: "ptb_visualization",
38
+ generatedAt: input.now.toISOString(),
39
+ source: {
40
+ adapterId: input.adapterId,
41
+ ...(input.planId !== undefined ? { planId: input.planId } : {}),
42
+ sourceKind: "review_time_generated_transaction_kind",
43
+ authority: "visualization_only_not_wallet_authorization",
44
+ renderer: PTB_VISUALIZATION_RENDERER
45
+ },
46
+ mermaid: {
47
+ diagramType: "flowchart",
48
+ // text keeps raw package addresses (truth/audit and copyable source);
49
+ // namedText relabels registered packages with their Move Registry name for
50
+ // the default graph, with a review-page toggle back to raw addresses.
51
+ text: mermaidText,
52
+ namedText: applyContractNamesToMermaid(mermaidText)
53
+ },
54
+ diagnostics: [],
55
+ unsupportedUse: [...PTB_VISUALIZATION_REQUIRED_UNSUPPORTED_USES],
56
+ executableMaterial: {
57
+ included: false,
58
+ policy: "mcp_and_review_ui_outputs_must_not_include_executable_transaction_material"
59
+ }
60
+ };
61
+ const parsed = ptbVisualizationArtifactSchema.safeParse(candidate);
62
+ if (!parsed.success) {
63
+ const issue = parsed.error.issues[0];
64
+ const path = issue?.path.join(".") ?? "";
65
+ return {
66
+ status: "declined",
67
+ reason: `ptb visualization artifact rejected: ${path ? `${path}: ` : ""}${issue?.message ?? "unknown issue"}`
68
+ };
69
+ }
70
+ return { status: "rendered", artifact: parsed.data };
71
+ }
@@ -0,0 +1,29 @@
1
+ import { rawTransactionToIR, transactionIRToMermaid } from "@zktx.io/ptb-model";
2
+ import { applyContractNamesToMermaid } from "./contractNameRegistry.js";
3
+ // Produce a left-to-right PTB Mermaid graph for a PUBLIC receipt straight from the
4
+ // already-fetched on-chain transaction's inputs and commands. Unlike the
5
+ // signing-flow `producePtbVisualizationArtifact`, this needs no stored material and
6
+ // no digest commitment — the transaction is the chain's own record, read by digest.
7
+ // It uses the same `@zktx.io/ptb-model` pipeline (LR, matching the review page), so
8
+ // the receipt graph and the review graph render identically.
9
+ //
10
+ // The same contract name registry the review graph uses is applied here, so
11
+ // registered packages/objects show their display name (@deepbook/core, Clock, …)
12
+ // and every other long address is shortened for the graph; the full ids stay in
13
+ // the receipt's Inputs / Move calls / Object changes sections and Markdown.
14
+ //
15
+ // Returns undefined when the model cannot render the transaction (e.g. a
16
+ // non-programmable system transaction); the page then shows a placeholder card in
17
+ // the same slot rather than collapsing the layout.
18
+ export function receiptPtbMermaid(transactionData) {
19
+ try {
20
+ const ir = rawTransactionToIR({ inputs: transactionData.inputs, commands: transactionData.commands });
21
+ // Emit both the raw-address graph and the registry-named graph so the receipt and
22
+ // the review render the same toggleable graph through the shared component.
23
+ const text = transactionIRToMermaid(ir, { direction: "LR" });
24
+ return text.trim().length > 0 ? { text, namedText: applyContractNamesToMermaid(text) } : undefined;
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ export function passReviewCheck(id, label, message, source) {
2
+ return { id, label, status: "pass", message, source };
3
+ }
4
+ export function failReviewCheck(id, label, message, source) {
5
+ return { id, label, status: "fail", message, source };
6
+ }
@@ -0,0 +1,11 @@
1
+ import { reviewStateStructuralInvariantSchema } from "./schemas.js";
2
+ export function parseReviewStateStructuralInvariants(input) {
3
+ return reviewStateStructuralInvariantSchema.parse(input);
4
+ }
5
+ export function parseLifecycleValidatedReviewState(input, validateAdapterLifecycle) {
6
+ const parsed = parseReviewStateStructuralInvariants(input);
7
+ if (parsed.adapterLifecycle) {
8
+ validateAdapterLifecycle(parsed.adapterLifecycle);
9
+ }
10
+ return parsed;
11
+ }