@stelis/say-ur-intent 0.0.0 → 0.0.1
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.
- package/dist/adapters/adapterLifecycleValidators.js +7 -0
- package/dist/adapters/adapterPromptSurfaces.js +71 -0
- package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +175 -0
- package/dist/adapters/deepbook/deepbookQuotePolicy.js +112 -0
- package/dist/adapters/deepbook/deepbookReviewEvidence.js +507 -0
- package/dist/adapters/deepbook/deepbookReviewLifecycle.js +85 -0
- package/dist/adapters/deepbook/deepbookSwapIntent.js +79 -0
- package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +269 -0
- package/dist/adapters/flowx/flowxSwapHumanReviewProducer.js +176 -0
- package/dist/adapters/flowx/flowxSwapIntent.js +79 -0
- package/dist/adapters/flowx/flowxSwapQuotePolicy.js +104 -0
- package/dist/adapters/flowx/flowxSwapReviewEvidence.js +468 -0
- package/dist/adapters/flowx/flowxSwapReviewLifecycle.js +85 -0
- package/dist/adapters/flowx/flowxSwapTransactionMaterialProducer.js +362 -0
- package/dist/adapters/intentPlanFactories.js +59 -0
- package/dist/adapters/reviewAdapters.js +81 -0
- package/dist/core/action/adapterLifecycleValidation.js +12 -0
- package/dist/core/action/forbiddenFields.js +43 -0
- package/dist/core/action/humanReadableReviewEvidence.js +203 -0
- package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
- package/dist/core/action/ptbVisualizationProducer.js +66 -0
- package/dist/core/action/reviewCheckResults.js +6 -0
- package/dist/core/action/reviewStateValidation.js +11 -0
- package/dist/core/action/reviewTimeSimulationEvidence.js +471 -0
- package/dist/core/action/schemas.js +529 -0
- package/dist/core/action/signableAdapterContract.js +993 -0
- package/dist/core/action/swapHumanReadableReviewProjection.js +124 -0
- package/dist/core/action/swapQuotePolicyEvidence.js +278 -0
- package/dist/core/action/transactionObjectOwnershipEvidence.js +247 -0
- package/dist/core/action/transactionObjectOwnershipProducer.js +329 -0
- package/dist/core/action/types.js +35 -0
- package/dist/core/action/walletReviewContractAssembler.js +282 -0
- package/dist/core/activity/activityStore.js +15 -0
- package/dist/core/activity/localDataService.js +258 -0
- package/dist/core/activity/localDataTypes.js +11 -0
- package/dist/core/activity/localDataValidation.js +396 -0
- package/dist/core/activity/schemaVersion.js +1 -0
- package/dist/core/activity/sqliteActivityStore.js +820 -0
- package/dist/core/activity/sqliteActivityStoreRows.js +430 -0
- package/dist/core/activity/sqliteActivityStoreSchema.js +258 -0
- package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
- package/dist/core/activity/suiFunctionTarget.js +43 -0
- package/dist/core/activity/transactionActivityAccountEffects.js +189 -0
- package/dist/core/activity/transactionActivityAnalysis.js +295 -0
- package/dist/core/activity/transactionActivityClassifier.js +306 -0
- package/dist/core/activity/transactionActivityDetails.js +229 -0
- package/dist/core/activity/transactionActivityProtocolRules.js +218 -0
- package/dist/core/activity/transactionActivityScanPolicy.js +170 -0
- package/dist/core/activity/transactionActivityService.js +379 -0
- package/dist/core/activity/transactionActivityTypes.js +18 -0
- package/dist/core/eventlog/sink.js +35 -0
- package/dist/core/evidence/settlementFamilies.js +87 -0
- package/dist/core/evidence/userAnswerUse.js +1 -0
- package/dist/core/numeric/rawU64.js +63 -0
- package/dist/core/preferences/preferencesStore.js +26 -0
- package/dist/core/preferences/sqlitePreferencesRepository.js +136 -0
- package/dist/core/proposal/externalProposalReview.js +347 -0
- package/dist/core/proposal/schemas.js +208 -0
- package/dist/core/proposal/types.js +35 -0
- package/dist/core/read/amounts.js +14 -0
- package/dist/core/read/coinMetadata.js +60 -0
- package/dist/core/read/deepbookRawQuoteClient.js +86 -0
- package/dist/core/read/deepbookReadHelpers.js +265 -0
- package/dist/core/read/deepbookRegistry.js +133 -0
- package/dist/core/read/flowxQuoteClient.js +117 -0
- package/dist/core/read/flowxReadHelpers.js +145 -0
- package/dist/core/read/flowxRegistry.js +174 -0
- package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
- package/dist/core/read/readResponseGuidance.js +451 -0
- package/dist/core/read/readService.js +1164 -0
- package/dist/core/read/readServiceTypes.js +59 -0
- package/dist/core/read/settlementParityFormatting.js +82 -0
- package/dist/core/read/walletReadHelpers.js +99 -0
- package/dist/core/review/reviewChecks.js +54 -0
- package/dist/core/review/reviewComputation.js +38 -0
- package/dist/core/review/reviewComputationResult.js +87 -0
- package/dist/core/session/localSession.js +31 -0
- package/dist/core/session/privateReviewArtifacts.js +73 -0
- package/dist/core/session/sessionErrors.js +9 -0
- package/dist/core/session/sessionStore.js +821 -0
- package/dist/core/session/settingsSession.js +1 -0
- package/dist/core/session/settingsSessions.js +43 -0
- package/dist/core/session/status.js +86 -0
- package/dist/core/session/transactionMaterialStore.js +205 -0
- package/dist/core/session/wait.js +102 -0
- package/dist/core/session/walletIdentity.js +103 -0
- package/dist/core/session/walletIdentitySessions.js +189 -0
- package/dist/core/suiAddress.js +18 -0
- package/dist/core/suiEndpoint.js +72 -0
- package/dist/mcp/activeAccountResponse.js +24 -0
- package/dist/mcp/prompts.js +146 -0
- package/dist/mcp/registerTool.js +19 -0
- package/dist/mcp/resources.js +72 -0
- package/dist/mcp/responseGuidance.js +381 -0
- package/dist/mcp/result.js +17 -0
- package/dist/mcp/schemas.js +8 -0
- package/dist/mcp/server.js +30 -0
- package/dist/mcp/serverInfo.js +123 -0
- package/dist/mcp/toolErrors.js +105 -0
- package/dist/mcp/toolNames.js +50 -0
- package/dist/mcp/tools/account/index.js +44 -0
- package/dist/mcp/tools/action/prepareSuiActionReview.js +120 -0
- package/dist/mcp/tools/read/commonSchemas.js +43 -0
- package/dist/mcp/tools/read/deepbookReadTools.js +453 -0
- package/dist/mcp/tools/read/flowxReadTools.js +135 -0
- package/dist/mcp/tools/read/index.js +16 -0
- package/dist/mcp/tools/read/readToolHelpers.js +68 -0
- package/dist/mcp/tools/read/reviewActivityTools.js +176 -0
- package/dist/mcp/tools/read/serverStatusTools.js +103 -0
- package/dist/mcp/tools/read/transactionActivityOutput.js +300 -0
- package/dist/mcp/tools/read/transactionActivityTools.js +544 -0
- package/dist/mcp/tools/read/walletReadTools.js +733 -0
- package/dist/mcp/tools/session/executionResultTools.js +92 -0
- package/dist/mcp/tools/session/index.js +8 -0
- package/dist/mcp/tools/session/shared.js +79 -0
- package/dist/mcp/tools/session/statusTools.js +134 -0
- package/dist/mcp/tools/session/walletIdentityTools.js +119 -0
- package/dist/mcp/tools/settings/index.js +64 -0
- package/dist/review-app/analysis.css +1 -0
- package/dist/review-app/analysis.js +1 -0
- package/dist/review-app/arc-BjIacwQm.js +1 -0
- package/dist/review-app/architecture-U656AL7Q-aSB9x1OK.js +1 -0
- package/dist/review-app/architectureDiagram-VXUJARFQ-C5W6re2I.js +36 -0
- package/dist/review-app/array-BmXUUrU6.js +1 -0
- package/dist/review-app/blockDiagram-VD42YOAC-20MLNcUm.js +122 -0
- package/dist/review-app/c4Diagram-YG6GDRKO-BZXRrcck.js +10 -0
- package/dist/review-app/channel-lk2p_CUu.js +1 -0
- package/dist/review-app/chunk-4BX2VUAB-BPITOdjX.js +1 -0
- package/dist/review-app/chunk-55IACEB6-Dz-pyw5k.js +1 -0
- package/dist/review-app/chunk-76Q3JFCE-cK_X1P_l.js +1 -0
- package/dist/review-app/chunk-ABZYJK2D-Dt4W53JI.js +81 -0
- package/dist/review-app/chunk-ATLVNIR6-fZHLXURb.js +1 -0
- package/dist/review-app/chunk-B4BG7PRW-BbgcjusC.js +165 -0
- package/dist/review-app/chunk-BJD4TVEz.js +1 -0
- package/dist/review-app/chunk-CVBHYZKI-CViawAKX.js +1 -0
- package/dist/review-app/chunk-DI55MBZ5-C5aoul-d.js +220 -0
- package/dist/review-app/chunk-FMBD7UC4-Chxmw62A.js +15 -0
- package/dist/review-app/chunk-FPAJGGOC-DDHjQ09H.js +80 -0
- package/dist/review-app/chunk-FWNWRKHM-CVVQUptk.js +1 -0
- package/dist/review-app/chunk-HN2XXSSU-yzNpjaSZ.js +1 -0
- package/dist/review-app/chunk-JA3XYJ7Z-C5ZJdU01.js +70 -0
- package/dist/review-app/chunk-JZLCHNYA-BBST4Cnk.js +54 -0
- package/dist/review-app/chunk-LBM3YZW2-CdwAPuHr.js +1 -0
- package/dist/review-app/chunk-LHMN2FUI-BtB5uDcp.js +1 -0
- package/dist/review-app/chunk-O7ZBX7Z2-pxdK4Sa3.js +1 -0
- package/dist/review-app/chunk-QN33PNHL-CbVv3uGK.js +1 -0
- package/dist/review-app/chunk-QXUST7PY-DKM2-t2c.js +7 -0
- package/dist/review-app/chunk-QZHKN3VN-C5ni2pN_.js +1 -0
- package/dist/review-app/chunk-S3R3BYOJ-BWvOhDs0.js +2 -0
- package/dist/review-app/chunk-S6J4BHB3-D9Fk0YeD.js +1 -0
- package/dist/review-app/chunk-T53DSG4Q-C1qEyzyV.js +1 -0
- package/dist/review-app/chunk-TZMSLE5B-B--7eU69.js +1 -0
- package/dist/review-app/classDiagram-2ON5EDUG-DlL1m2bp.js +1 -0
- package/dist/review-app/classDiagram-v2-WZHVMYZB-FXRskT1j.js +1 -0
- package/dist/review-app/clone-BZZb7gpZ.js +1 -0
- package/dist/review-app/cose-bilkent-S5V4N54A-CRIb8XEO.js +1 -0
- package/dist/review-app/cytoscape.esm-C7jYqDP5.js +321 -0
- package/dist/review-app/dagre-6UL2VRFP-FNCAXbdE.js +4 -0
- package/dist/review-app/dagre-Be46QtUd.js +1 -0
- package/dist/review-app/defaultLocale-BaWNtAUL.js +1 -0
- package/dist/review-app/diagram-PSM6KHXK-ylLWjiNM.js +24 -0
- package/dist/review-app/diagram-QEK2KX5R-BCDcESxs.js +43 -0
- package/dist/review-app/diagram-S2PKOQOG-Vdrc-vrO.js +24 -0
- package/dist/review-app/dist-WPc74x_f.js +1 -0
- package/dist/review-app/erDiagram-Q2GNP2WA-E5ZsUbDF.js +60 -0
- package/dist/review-app/flatten-DHf9IeNI.js +1 -0
- package/dist/review-app/flowDiagram-NV44I4VS-DBSQuj6x.js +162 -0
- package/dist/review-app/ganttDiagram-LVOFAZNH-CKUOsqwl.js +267 -0
- package/dist/review-app/gitGraph-F6HP7TQM-DsAD6qK1.js +1 -0
- package/dist/review-app/gitGraphDiagram-NY62KEGX-BCeIMWdl.js +65 -0
- package/dist/review-app/graphlib-CiX5CXxR.js +1 -0
- package/dist/review-app/http-DMvwuuFk.js +1 -0
- package/dist/review-app/identity-DY8PXc6t.js +1 -0
- package/dist/review-app/info-NVLQJR56-Dlx1nZic.js +1 -0
- package/dist/review-app/infoDiagram-F6ZHWCRC-CAuANIrz.js +2 -0
- package/dist/review-app/init-BvqephKz.js +1 -0
- package/dist/review-app/journeyDiagram-XKPGCS4Q-C-Z9phnx.js +139 -0
- package/dist/review-app/kanban-definition-3W4ZIXB7-DufgZABq.js +89 -0
- package/dist/review-app/katex-B-Z-NXXN.js +257 -0
- package/dist/review-app/line-DiIv3Jgw.js +1 -0
- package/dist/review-app/linear-Cv-UPvo1.js +1 -0
- package/dist/review-app/math-kmyYrkHL.js +1 -0
- package/dist/review-app/mermaid-parser.core-DkwUYTPl.js +4 -0
- package/dist/review-app/mindmap-definition-VGOIOE7T-TM_CqdmV.js +68 -0
- package/dist/review-app/ordinal-BliTlkoG.js +1 -0
- package/dist/review-app/packet-BFZMPI3H-DqbnU92v.js +1 -0
- package/dist/review-app/path-AEo9W6mQ.js +1 -0
- package/dist/review-app/pie-7BOR55EZ-LJzaLkgr.js +1 -0
- package/dist/review-app/pieDiagram-ADFJNKIX-BAs8OfRS.js +30 -0
- package/dist/review-app/quadrantDiagram-AYHSOK5B-CyUDZP5S.js +7 -0
- package/dist/review-app/radar-NHE76QYJ-DBpHc8_Y.js +1 -0
- package/dist/review-app/reduce-B-HuPpdd.js +1 -0
- package/dist/review-app/requirementDiagram-UZGBJVZJ-BEHix78P.js +64 -0
- package/dist/review-app/review.css +1 -0
- package/dist/review-app/review.js +43 -0
- package/dist/review-app/sankeyDiagram-TZEHDZUN-B2bKbmsm.js +10 -0
- package/dist/review-app/sequenceDiagram-WL72ISMW-DVLOORFJ.js +145 -0
- package/dist/review-app/settings.css +1 -0
- package/dist/review-app/settings.js +1 -0
- package/dist/review-app/src-Buml7cM5.js +1 -0
- package/dist/review-app/stateDiagram-FKZM4ZOC-sFGGp2kV.js +1 -0
- package/dist/review-app/stateDiagram-v2-4FDKWEC3-BHfCF4dX.js +1 -0
- package/dist/review-app/timeline-definition-IT6M3QCI-BESnBijC.js +61 -0
- package/dist/review-app/treemap-KMMF4GRG-wnVLBDeQ.js +1 -0
- package/dist/review-app/walletStatus-CcojOdGy.js +7 -0
- package/dist/review-app/xychartDiagram-PRI3JC2R-BGWVfCx4.js +7 -0
- package/dist/review-server/assets.js +48 -0
- package/dist/review-server/html.js +66 -0
- package/dist/review-server/http.js +47 -0
- package/dist/review-server/middleware/hostOrigin.js +48 -0
- package/dist/review-server/middleware/reviewToken.js +7 -0
- package/dist/review-server/reviewServerPolicy.js +10 -0
- package/dist/review-server/server.js +568 -0
- package/dist/review-server/settingsApi.js +182 -0
- package/dist/review-server/walletIdentityResponse.js +13 -0
- package/dist/runtime/config.js +103 -0
- package/dist/runtime/localSettingsService.js +198 -0
- package/dist/runtime/logger.js +50 -0
- package/dist/runtime/reviewServerAcquire.js +128 -0
- package/dist/runtime/smokeMainnetRead.js +529 -0
- package/dist/runtime/smokeMainnetReadAssertions.js +308 -0
- package/dist/runtime/start.js +295 -0
- package/dist/runtime/suiEndpoint.js +97 -0
- package/dist/runtime/suiTransactionGraphqlMapping.js +200 -0
- package/dist/runtime/suiTransactionGraphqlQueries.js +231 -0
- package/dist/runtime/suiTransactionGraphqlSource.js +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DEEPBOOK_SWAP_REVIEW_LIFECYCLE_STAGE_CATALOG_ID, validateDeepbookSwapReviewLifecycle } from "./deepbook/deepbookReviewLifecycle.js";
|
|
2
|
+
import { FLOWX_SWAP_REVIEW_LIFECYCLE_STAGE_CATALOG_ID, validateFlowxSwapReviewLifecycle } from "./flowx/flowxSwapReviewLifecycle.js";
|
|
3
|
+
import { createAdapterLifecycleValidator } from "../core/action/adapterLifecycleValidation.js";
|
|
4
|
+
export const validateSupportedAdapterLifecycle = createAdapterLifecycleValidator({
|
|
5
|
+
[DEEPBOOK_SWAP_REVIEW_LIFECYCLE_STAGE_CATALOG_ID]: validateDeepbookSwapReviewLifecycle,
|
|
6
|
+
[FLOWX_SWAP_REVIEW_LIFECYCLE_STAGE_CATALOG_ID]: validateFlowxSwapReviewLifecycle
|
|
7
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { DEEPBOOK_SWAP_ACTION_KIND, DEEPBOOK_SWAP_ADAPTER_ID } from "./deepbook/deepbookSwapIntent.js";
|
|
3
|
+
import { FLOWX_SWAP_ACTION_KIND, FLOWX_SWAP_ADAPTER_ID } from "./flowx/flowxSwapIntent.js";
|
|
4
|
+
/**
|
|
5
|
+
* One slash-prompt surface contributed by a review adapter.
|
|
6
|
+
*
|
|
7
|
+
* Prompt names follow action-first naming: `<action>-<protocolSlug>`
|
|
8
|
+
* (for example `swap-deep`). Users reach for the verb before the venue, so
|
|
9
|
+
* action-first keeps autocomplete grouped by what the user wants to do. When
|
|
10
|
+
* an action has exactly one registered protocol, the bare action name (for
|
|
11
|
+
* example `swap`) is also registered as a shorthand.
|
|
12
|
+
*
|
|
13
|
+
* The surface carries only protocol-specific copy. Boundary language (no
|
|
14
|
+
* signing data, no transaction bytes, local-review-only signing) is owned by
|
|
15
|
+
* the platform and appended at registration time; adapters cannot weaken it.
|
|
16
|
+
*/
|
|
17
|
+
export const adapterPromptSurfaceSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
adapterId: z.string().min(1),
|
|
20
|
+
action: z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(/^[a-z][a-z0-9]*$/, "action must be a lowercase slug, e.g. swap"),
|
|
23
|
+
protocolSlug: z
|
|
24
|
+
.string()
|
|
25
|
+
.regex(/^[a-z][a-z0-9]*$/, "protocolSlug must be a lowercase slug, e.g. deep"),
|
|
26
|
+
title: z.string().min(1),
|
|
27
|
+
description: z.string().min(1),
|
|
28
|
+
intentArgDescription: z.string().min(1),
|
|
29
|
+
exampleIntents: z.array(z.string().min(1)).min(1),
|
|
30
|
+
toolName: z.string().min(1)
|
|
31
|
+
})
|
|
32
|
+
.strict();
|
|
33
|
+
export function promptNameFor(surface) {
|
|
34
|
+
return `${surface.action}-${surface.protocolSlug}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Bare action prompts (`swap`) are always registered. With a single
|
|
38
|
+
* registered protocol they go straight to that protocol; with several they
|
|
39
|
+
* carry an optional `protocol` argument (completion suggests the slugs) and
|
|
40
|
+
* instruct the model to ask the user which protocol to use - never to pick a
|
|
41
|
+
* venue silently.
|
|
42
|
+
*/
|
|
43
|
+
export function actionGroups(surfaces) {
|
|
44
|
+
const byAction = new Map();
|
|
45
|
+
for (const surface of surfaces) {
|
|
46
|
+
byAction.set(surface.action, [...(byAction.get(surface.action) ?? []), surface]);
|
|
47
|
+
}
|
|
48
|
+
return byAction;
|
|
49
|
+
}
|
|
50
|
+
export const ADAPTER_PROMPT_SURFACES = [
|
|
51
|
+
{
|
|
52
|
+
adapterId: DEEPBOOK_SWAP_ADAPTER_ID,
|
|
53
|
+
action: DEEPBOOK_SWAP_ACTION_KIND,
|
|
54
|
+
protocolSlug: "deep",
|
|
55
|
+
title: "DeepBook Swap Review",
|
|
56
|
+
description: 'Prepare a reviewable DeepBook mainnet swap from a one-line intent, e.g. "10 sui to usdc".',
|
|
57
|
+
intentArgDescription: 'Swap intent in one line, any language, e.g. "10 sui to usdc" or "10 수이 usdc로 환전"',
|
|
58
|
+
exampleIntents: ["10 sui to usdc", "10 수이 usdc로 환전"],
|
|
59
|
+
toolName: "action.prepare_sui_action_review"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
adapterId: FLOWX_SWAP_ADAPTER_ID,
|
|
63
|
+
action: FLOWX_SWAP_ACTION_KIND,
|
|
64
|
+
protocolSlug: "flowx",
|
|
65
|
+
title: "FlowX Swap Review",
|
|
66
|
+
description: 'Prepare a reviewable FlowX CLMM mainnet swap from a one-line intent, e.g. "10 sui to usdc".',
|
|
67
|
+
intentArgDescription: 'Swap intent in one line, any language, e.g. "10 sui to usdc" or "10 수이 usdc로 환전"',
|
|
68
|
+
exampleIntents: ["10 sui to usdc", "10 수이 usdc로 환전"],
|
|
69
|
+
toolName: "action.prepare_sui_action_review"
|
|
70
|
+
}
|
|
71
|
+
];
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { createSwapHumanReadableReviewEvidence } from "../../core/action/swapHumanReadableReviewProjection.js";
|
|
2
|
+
import { failReviewCheck, passReviewCheck } from "../../core/review/reviewComputationResult.js";
|
|
3
|
+
export function createDeepbookSwapHumanReadableReviewProducer() {
|
|
4
|
+
return (input) => {
|
|
5
|
+
try {
|
|
6
|
+
assertDeepbookHumanReviewSources(input);
|
|
7
|
+
const review = buildDeepbookHumanReadableReview(input);
|
|
8
|
+
const evidence = createSwapHumanReadableReviewEvidence({
|
|
9
|
+
transactionMaterial: input.transactionMaterial,
|
|
10
|
+
transactionMaterialDigest: input.transactionMaterialDigest,
|
|
11
|
+
swapQuotePolicy: input.swapQuotePolicy,
|
|
12
|
+
transactionObjectOwnership: input.transactionObjectOwnership,
|
|
13
|
+
adapterId: input.plan.adapterId,
|
|
14
|
+
protocol: input.plan.protocol,
|
|
15
|
+
actionKind: input.plan.actionKind,
|
|
16
|
+
review,
|
|
17
|
+
derivedAt: input.now
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
status: "completed",
|
|
21
|
+
evidence,
|
|
22
|
+
checks: [
|
|
23
|
+
passReviewCheck("deepbook_human_readable_review_evidence", "Human-readable review", "Prepared a human-readable account-bound swap review from material-bound quote policy and object ownership evidence. This is not wallet handoff, signing data, signing readiness, or execution readiness.", "adapter")
|
|
24
|
+
]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return {
|
|
29
|
+
status: "blocked",
|
|
30
|
+
blockedReason: classifyHumanReviewFailure(error),
|
|
31
|
+
checks: [
|
|
32
|
+
failReviewCheck("deepbook_human_readable_review_failed", "Human-readable review", error instanceof Error ? error.message : "DeepBook human-readable review evidence could not be produced.", "adapter")
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function buildDeepbookHumanReadableReview(input) {
|
|
39
|
+
const sourceAmount = amountFromQuotePolicy("input", input.swapQuotePolicy.sourceAmount, {
|
|
40
|
+
displayAmount: input.requestedIntent.from.amountDisplay,
|
|
41
|
+
displayAmountSource: "user_display_intent_not_signing_input"
|
|
42
|
+
});
|
|
43
|
+
const expectedOutput = amountFromQuotePolicy("expected_output", input.swapQuotePolicy.expectedOutput);
|
|
44
|
+
const minimumOutput = amountFromQuotePolicy("minimum_output", input.swapQuotePolicy.minimumOutput);
|
|
45
|
+
const protocolFee = amountFromQuotePolicy("fee", input.swapQuotePolicy.protocolFee);
|
|
46
|
+
return {
|
|
47
|
+
kind: "swap_human_readable_review",
|
|
48
|
+
proposedAction: {
|
|
49
|
+
title: input.plan.title,
|
|
50
|
+
summary: input.plan.summary,
|
|
51
|
+
actionKind: input.plan.actionKind,
|
|
52
|
+
adapterId: input.plan.adapterId,
|
|
53
|
+
protocol: input.plan.protocol,
|
|
54
|
+
network: "sui:mainnet"
|
|
55
|
+
},
|
|
56
|
+
assetFlow: {
|
|
57
|
+
outgoing: [sourceAmount],
|
|
58
|
+
expectedIncoming: [expectedOutput],
|
|
59
|
+
minimumIncoming: [minimumOutput],
|
|
60
|
+
fees: [protocolFee]
|
|
61
|
+
},
|
|
62
|
+
recipients: [
|
|
63
|
+
{ role: "connected_account", address: input.account },
|
|
64
|
+
{ role: "output_recipient", address: input.account }
|
|
65
|
+
],
|
|
66
|
+
targets: [
|
|
67
|
+
{
|
|
68
|
+
kind: "swap_output_asset",
|
|
69
|
+
symbol: input.swapQuotePolicy.expectedOutput.asset.symbol,
|
|
70
|
+
coinType: input.swapQuotePolicy.expectedOutput.asset.coinType,
|
|
71
|
+
protocol: input.plan.protocol,
|
|
72
|
+
poolKey: input.swapQuotePolicy.quoteSource.poolKey,
|
|
73
|
+
direction: input.swapQuotePolicy.quoteSource.direction
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
evidenceUsed: [
|
|
77
|
+
{
|
|
78
|
+
id: "deepbook_quote_policy",
|
|
79
|
+
label: "Quote policy",
|
|
80
|
+
source: "quote",
|
|
81
|
+
summary: "Quote policy evidence supplies the input, expected output, minimum output, protocol fee, and slippage policy shown in asset flow; it is not route choice or signing readiness."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "transaction_material_digest",
|
|
85
|
+
label: "Transaction material digest",
|
|
86
|
+
source: "digest_commitment",
|
|
87
|
+
summary: "The review is bound internally to the stored local unsigned transaction material digest; the digest and transaction bytes are not public review output."
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "transaction_object_ownership",
|
|
91
|
+
label: "Object ownership",
|
|
92
|
+
source: "wallet",
|
|
93
|
+
summary: "Object ownership evidence is derived from stored transaction data and Sui mainnet object reads."
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
missingEvidence: [
|
|
97
|
+
{
|
|
98
|
+
id: "review_time_simulation",
|
|
99
|
+
label: "Review-time simulation",
|
|
100
|
+
reason: "The review has not simulated the stored transaction material with required effects, balance changes, object types, and transaction fields."
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
requiredUserChoices: [
|
|
104
|
+
{
|
|
105
|
+
id: "wallet_authorization_later",
|
|
106
|
+
label: "Wallet authorization",
|
|
107
|
+
reason: "The wallet signature request happens on this review page after the digest-gated handoff; nothing is signed without your approval in the wallet."
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
unsupportedClaims: [
|
|
111
|
+
{
|
|
112
|
+
id: "no_signing_readiness",
|
|
113
|
+
label: "No signing readiness",
|
|
114
|
+
reason: "Human-readable review evidence does not prove the action is ready to sign."
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "no_execution_readiness",
|
|
118
|
+
label: "No execution readiness",
|
|
119
|
+
reason: "Review-time simulation, wallet handoff, signing, and execution receipt evidence are not complete."
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "no_route_recommendation",
|
|
123
|
+
label: "No route recommendation",
|
|
124
|
+
reason: "The account-bound swap review uses an explicit direct pool path and does not rank venues or recommend routes."
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
freshness: {
|
|
128
|
+
status: "current",
|
|
129
|
+
evaluatedAt: input.now.toISOString(),
|
|
130
|
+
expiresAt: input.transactionMaterial.expiresAt,
|
|
131
|
+
reason: "Human-readable review evidence expires with the stored local transaction material and quote policy."
|
|
132
|
+
},
|
|
133
|
+
blockingChecks: [
|
|
134
|
+
failReviewCheck("deepbook_review_time_simulation_missing", "Review-time simulation", "Review-time simulation evidence is still required before any wallet handoff, signing, or execution.", "simulation")
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function assertDeepbookHumanReviewSources(input) {
|
|
139
|
+
if (input.swapQuotePolicy.adapterId !== input.plan.adapterId ||
|
|
140
|
+
input.swapQuotePolicy.protocol !== input.plan.protocol ||
|
|
141
|
+
input.swapQuotePolicy.actionKind !== input.plan.actionKind) {
|
|
142
|
+
throw new Error("human-readable review quote policy identity must match the action plan");
|
|
143
|
+
}
|
|
144
|
+
if (input.swapQuotePolicy.quoteSource.poolKey !== input.poolResolution.poolKey) {
|
|
145
|
+
throw new Error("human-readable review pool target must match swap quote policy poolKey");
|
|
146
|
+
}
|
|
147
|
+
if (input.swapQuotePolicy.quoteSource.direction !== input.quotePolicy.direction) {
|
|
148
|
+
throw new Error("human-readable review target direction must match swap quote policy direction");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function classifyHumanReviewFailure(error) {
|
|
152
|
+
const message = error instanceof Error ? error.message : "";
|
|
153
|
+
if (/object ownership/i.test(message)) {
|
|
154
|
+
return "object_resolution_failed";
|
|
155
|
+
}
|
|
156
|
+
if (/asset|target|pool|direction|protocol|adapter/i.test(message)) {
|
|
157
|
+
return "asset_mismatch";
|
|
158
|
+
}
|
|
159
|
+
if (/amount|quote|slippage|min/i.test(message)) {
|
|
160
|
+
return "amount_mismatch";
|
|
161
|
+
}
|
|
162
|
+
return "unsupported_action";
|
|
163
|
+
}
|
|
164
|
+
function amountFromQuotePolicy(role, amount, display) {
|
|
165
|
+
return {
|
|
166
|
+
role,
|
|
167
|
+
symbol: amount.asset.symbol,
|
|
168
|
+
coinType: amount.asset.coinType,
|
|
169
|
+
decimals: amount.asset.decimals,
|
|
170
|
+
rawAmount: amount.raw,
|
|
171
|
+
rawAmountSource: "quote_policy_evidence",
|
|
172
|
+
...(display?.displayAmount ? { displayAmount: display.displayAmount } : {}),
|
|
173
|
+
...(display?.displayAmountSource ? { displayAmountSource: display.displayAmountSource } : {})
|
|
174
|
+
};
|
|
175
|
+
}
|
|
@@ -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
|
+
}
|