@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.
- package/README.md +4 -39
- 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/docs/AGENT_BEHAVIOR.md +1 -1
- package/docs/AGENT_DEVELOPMENT_POLICY.md +20 -0
- package/docs/FRONTEND_POLICY.md +4 -3
- package/docs/MCP_SETUP.md +59 -7
- package/docs/MCP_TOOLS.md +1 -1
- package/docs/SDK_API.md +5 -1
- package/package.json +3 -2
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
2
|
+
import { mapTransactionObjectOwnershipEvidenceToContractDraft, parseTransactionObjectOwnershipEvidence, TRANSACTION_OBJECT_OWNERSHIP_EVIDENCE_VERSION } from "./transactionObjectOwnershipEvidence.js";
|
|
3
|
+
import { failReviewCheck, passReviewCheck } from "./reviewCheckResults.js";
|
|
4
|
+
import { parseSuiAddress } from "../suiAddress.js";
|
|
5
|
+
import { LocalTransactionMaterialStoreError, verifyLocalTransactionMaterialArtifacts } from "../session/transactionMaterialStore.js";
|
|
6
|
+
export function createTransactionObjectOwnershipProducer(options) {
|
|
7
|
+
return async (input) => {
|
|
8
|
+
if (options.network !== "mainnet" || options.chainIdentifier !== options.expectedChainIdentifier) {
|
|
9
|
+
return {
|
|
10
|
+
status: "blocked",
|
|
11
|
+
blockedReason: "network_mismatch",
|
|
12
|
+
checks: [
|
|
13
|
+
failReviewCheck("transaction_object_ownership_network_mismatch", "Object ownership network", "Object ownership evidence requires a verified Sui mainnet object source and matching mainnet chain identifier.", "network")
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
let materialHandle;
|
|
18
|
+
let materialDigest;
|
|
19
|
+
try {
|
|
20
|
+
const verified = await verifyLocalTransactionMaterialArtifacts({
|
|
21
|
+
materialStore: options.materialStore,
|
|
22
|
+
transactionMaterial: input.materialHandle,
|
|
23
|
+
transactionMaterialDigest: input.materialDigest,
|
|
24
|
+
now: input.now
|
|
25
|
+
});
|
|
26
|
+
materialHandle = verified.transactionMaterial;
|
|
27
|
+
materialDigest = verified.transactionMaterialDigest;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const message = error instanceof Error ? error.message : "transaction material is unavailable";
|
|
31
|
+
const check = failReviewCheck("transaction_object_ownership_material_unavailable", "Object ownership material", "Object ownership evidence was not produced because the stored local transaction material was unavailable, stale, or not bound to its internal digest.", "adapter");
|
|
32
|
+
if (message.includes("expired") || message.includes("unavailable")) {
|
|
33
|
+
return {
|
|
34
|
+
status: "refresh_required",
|
|
35
|
+
refreshReason: "quote_stale",
|
|
36
|
+
checks: [check]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
status: "blocked",
|
|
41
|
+
blockedReason: "object_resolution_failed",
|
|
42
|
+
checks: [check]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const material = options.materialStore.getTransactionMaterial(materialHandle, input.now);
|
|
46
|
+
if (!material) {
|
|
47
|
+
return {
|
|
48
|
+
status: "refresh_required",
|
|
49
|
+
refreshReason: "quote_stale",
|
|
50
|
+
checks: [
|
|
51
|
+
failReviewCheck("transaction_object_ownership_material_unavailable", "Object ownership material", "Object ownership evidence was not produced because the stored local transaction material was unavailable or expired; refresh the review evidence before continuing.", "adapter")
|
|
52
|
+
]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
let objectRefs;
|
|
56
|
+
try {
|
|
57
|
+
objectRefs = extractObjectRefsFromStoredTransactionBytes(material.transactionBytes);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return {
|
|
61
|
+
status: "blocked",
|
|
62
|
+
blockedReason: "object_resolution_failed",
|
|
63
|
+
checks: [
|
|
64
|
+
failReviewCheck("transaction_object_ownership_refs_unavailable", "Object ownership refs", "Object ownership evidence was not produced because the stored local transaction material did not expose a complete resolved transaction object reference set.", "adapter")
|
|
65
|
+
]
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const objectRoles = mergeObjectRoles(objectRefs);
|
|
69
|
+
if (objectRoles.size === 0) {
|
|
70
|
+
return {
|
|
71
|
+
status: "blocked",
|
|
72
|
+
blockedReason: "object_resolution_failed",
|
|
73
|
+
checks: [
|
|
74
|
+
failReviewCheck("transaction_object_ownership_refs_empty", "Object ownership refs", "Object ownership evidence requires at least one resolved transaction object reference.", "adapter")
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (![...objectRoles.values()].some((roles) => roles.includes("gas_object"))) {
|
|
79
|
+
return {
|
|
80
|
+
status: "blocked",
|
|
81
|
+
blockedReason: "insufficient_gas",
|
|
82
|
+
checks: [
|
|
83
|
+
failReviewCheck("transaction_object_ownership_gas_missing", "Gas object ownership", "Object ownership evidence requires at least one gas object from the stored local transaction material.", "wallet")
|
|
84
|
+
]
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const facts = [];
|
|
88
|
+
for (const [objectId, roles] of objectRoles) {
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await options.objectSource.getObject({ objectId });
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return objectReadBlocked();
|
|
95
|
+
}
|
|
96
|
+
if (parseSuiObjectId(response.object.objectId) !== objectId) {
|
|
97
|
+
return objectReadBlocked();
|
|
98
|
+
}
|
|
99
|
+
const fact = classifyObjectOwnership({
|
|
100
|
+
objectId,
|
|
101
|
+
roles,
|
|
102
|
+
owner: response.object.owner,
|
|
103
|
+
objectType: response.object.type,
|
|
104
|
+
account: materialHandle.account
|
|
105
|
+
});
|
|
106
|
+
if (!fact) {
|
|
107
|
+
return objectReadBlocked();
|
|
108
|
+
}
|
|
109
|
+
facts.push(fact);
|
|
110
|
+
}
|
|
111
|
+
const invalidFact = facts.find((fact) => !isAcceptableOwnershipFact(fact));
|
|
112
|
+
if (invalidFact) {
|
|
113
|
+
const blockedReason = invalidFact.roles.includes("gas_object")
|
|
114
|
+
? "insufficient_gas"
|
|
115
|
+
: "object_resolution_failed";
|
|
116
|
+
return {
|
|
117
|
+
status: "blocked",
|
|
118
|
+
blockedReason,
|
|
119
|
+
checks: [
|
|
120
|
+
failReviewCheck("transaction_object_ownership_unverified", "Object ownership", "Object ownership evidence was not accepted because at least one gas or account-owned transaction object is not owned by the connected account, or an object owner could not be classified.", invalidFact.roles.includes("gas_object") ? "wallet" : "adapter")
|
|
121
|
+
]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
let evidence;
|
|
125
|
+
try {
|
|
126
|
+
evidence = parseTransactionObjectOwnershipEvidence({
|
|
127
|
+
evidenceVersion: TRANSACTION_OBJECT_OWNERSHIP_EVIDENCE_VERSION,
|
|
128
|
+
materialId: materialHandle.materialId,
|
|
129
|
+
reviewSessionId: materialHandle.reviewSessionId,
|
|
130
|
+
planId: materialHandle.planId,
|
|
131
|
+
account: materialHandle.account,
|
|
132
|
+
transactionDigest: materialDigest.transactionDigest,
|
|
133
|
+
objectCount: facts.length,
|
|
134
|
+
objects: facts,
|
|
135
|
+
verifiedAt: input.now.toISOString(),
|
|
136
|
+
expiresAt: materialHandle.expiresAt
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return objectReadBlocked();
|
|
141
|
+
}
|
|
142
|
+
const contractMapping = mapTransactionObjectOwnershipEvidenceToContractDraft(evidence);
|
|
143
|
+
if (contractMapping.status === "unsupported") {
|
|
144
|
+
return {
|
|
145
|
+
status: "blocked",
|
|
146
|
+
blockedReason: contractMapping.roles.includes("gas_object")
|
|
147
|
+
? "insufficient_gas"
|
|
148
|
+
: "object_resolution_failed",
|
|
149
|
+
checks: [
|
|
150
|
+
failReviewCheck("transaction_object_ownership_contract_mapping_unsupported", "Object ownership contract mapping", `Object ownership evidence was read but cannot be used for contract objectOwnership evidence: ${contractMapping.reason}.`, contractMapping.roles.includes("gas_object") ? "wallet" : "adapter")
|
|
151
|
+
]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
status: "completed",
|
|
156
|
+
evidence,
|
|
157
|
+
checks: [
|
|
158
|
+
passReviewCheck("transaction_object_ownership_verified", "Object ownership", "Verified contract-mappable transaction object ownership facts from the stored local transaction material and mainnet object reads. Gas and account-owned transaction coin objects are owned by the connected account; shared or immutable protocol objects are recorded as non-account-owned facts. This is not wallet handoff, signing readiness, or execution readiness.", "wallet")
|
|
159
|
+
]
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function extractObjectRefsFromStoredTransactionBytes(transactionBytes) {
|
|
164
|
+
const transaction = Transaction.from(transactionBytes);
|
|
165
|
+
const data = transaction.getData();
|
|
166
|
+
const refs = [];
|
|
167
|
+
const payments = data.gasData.payment ?? [];
|
|
168
|
+
for (const payment of payments) {
|
|
169
|
+
refs.push({ objectId: parseSuiObjectId(payment.objectId), role: "gas_object" });
|
|
170
|
+
}
|
|
171
|
+
for (const input of data.inputs) {
|
|
172
|
+
const inputKind = enumKind(input, [
|
|
173
|
+
"Object",
|
|
174
|
+
"Pure",
|
|
175
|
+
"UnresolvedPure",
|
|
176
|
+
"UnresolvedObject",
|
|
177
|
+
"FundsWithdrawal"
|
|
178
|
+
]);
|
|
179
|
+
if (!inputKind) {
|
|
180
|
+
throw new LocalTransactionMaterialStoreError("unknown transaction input kind");
|
|
181
|
+
}
|
|
182
|
+
if (inputKind === "Pure" || inputKind === "UnresolvedPure" || inputKind === "FundsWithdrawal") {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (inputKind === "UnresolvedObject") {
|
|
186
|
+
throw new LocalTransactionMaterialStoreError("transaction object refs must be resolved");
|
|
187
|
+
}
|
|
188
|
+
const objectInput = input.Object;
|
|
189
|
+
const objectKind = enumKind(objectInput, [
|
|
190
|
+
"ImmOrOwnedObject",
|
|
191
|
+
"SharedObject",
|
|
192
|
+
"Receiving"
|
|
193
|
+
]);
|
|
194
|
+
if (!objectKind) {
|
|
195
|
+
throw new LocalTransactionMaterialStoreError("unknown transaction object input kind");
|
|
196
|
+
}
|
|
197
|
+
if (objectKind === "ImmOrOwnedObject") {
|
|
198
|
+
refs.push({
|
|
199
|
+
objectId: readObjectId(objectInput.ImmOrOwnedObject),
|
|
200
|
+
role: "imm_or_owned_object"
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
else if (objectKind === "SharedObject") {
|
|
204
|
+
refs.push({
|
|
205
|
+
objectId: readObjectId(objectInput.SharedObject),
|
|
206
|
+
role: "shared_object"
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
refs.push({
|
|
211
|
+
objectId: readObjectId(objectInput.Receiving),
|
|
212
|
+
role: "receiving_object"
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return refs;
|
|
217
|
+
}
|
|
218
|
+
function enumKind(value, allowedKinds) {
|
|
219
|
+
if (!isRecord(value)) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
if ("$kind" in value) {
|
|
223
|
+
return typeof value.$kind === "string" && allowedKinds.includes(value.$kind)
|
|
224
|
+
? value.$kind
|
|
225
|
+
: undefined;
|
|
226
|
+
}
|
|
227
|
+
const matchingKeys = allowedKinds.filter((kind) => kind in value);
|
|
228
|
+
return matchingKeys.length === 1 ? matchingKeys[0] : undefined;
|
|
229
|
+
}
|
|
230
|
+
function readObjectId(value) {
|
|
231
|
+
if (!isRecord(value) || typeof value.objectId !== "string") {
|
|
232
|
+
throw new LocalTransactionMaterialStoreError("transaction object ref is missing objectId");
|
|
233
|
+
}
|
|
234
|
+
return parseSuiObjectId(value.objectId);
|
|
235
|
+
}
|
|
236
|
+
function parseSuiObjectId(value) {
|
|
237
|
+
const objectId = parseSuiAddress(value);
|
|
238
|
+
if (!objectId) {
|
|
239
|
+
throw new LocalTransactionMaterialStoreError("transaction object ref has invalid Sui object id");
|
|
240
|
+
}
|
|
241
|
+
return objectId;
|
|
242
|
+
}
|
|
243
|
+
function mergeObjectRoles(refs) {
|
|
244
|
+
const merged = new Map();
|
|
245
|
+
for (const ref of refs) {
|
|
246
|
+
const roles = merged.get(ref.objectId) ?? [];
|
|
247
|
+
if (!roles.includes(ref.role)) {
|
|
248
|
+
roles.push(ref.role);
|
|
249
|
+
}
|
|
250
|
+
merged.set(ref.objectId, roles);
|
|
251
|
+
}
|
|
252
|
+
return merged;
|
|
253
|
+
}
|
|
254
|
+
function classifyObjectOwnership(input) {
|
|
255
|
+
if (!isRecord(input.owner) || typeof input.owner.$kind !== "string") {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
if (typeof input.objectType !== "string") {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
if (input.owner.$kind === "AddressOwner") {
|
|
262
|
+
const ownerAccount = parseSuiAddress(typeof input.owner.AddressOwner === "string" ? input.owner.AddressOwner : "");
|
|
263
|
+
if (!ownerAccount) {
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
objectId: input.objectId,
|
|
268
|
+
roles: input.roles,
|
|
269
|
+
ownership: ownerAccount === input.account ? "owned_by_account" : "not_owned_by_account",
|
|
270
|
+
ownerKind: "AddressOwner",
|
|
271
|
+
ownerAccount,
|
|
272
|
+
objectType: input.objectType,
|
|
273
|
+
source: "stored_transaction_data_and_mainnet_object_read"
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
if (input.owner.$kind === "Shared") {
|
|
277
|
+
return ownershipFact(input, "shared_object", "Shared");
|
|
278
|
+
}
|
|
279
|
+
if (input.owner.$kind === "Immutable") {
|
|
280
|
+
return ownershipFact(input, "immutable_object", "Immutable");
|
|
281
|
+
}
|
|
282
|
+
if (input.owner.$kind === "ObjectOwner") {
|
|
283
|
+
return ownershipFact(input, "object_owner", "ObjectOwner");
|
|
284
|
+
}
|
|
285
|
+
if (input.owner.$kind === "ConsensusAddressOwner") {
|
|
286
|
+
return ownershipFact(input, "consensus_address_owner", "ConsensusAddressOwner");
|
|
287
|
+
}
|
|
288
|
+
if (input.owner.$kind === "Unknown") {
|
|
289
|
+
return ownershipFact(input, "unknown_owner", "Unknown");
|
|
290
|
+
}
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
function ownershipFact(input, ownership, ownerKind) {
|
|
294
|
+
return {
|
|
295
|
+
objectId: input.objectId,
|
|
296
|
+
roles: input.roles,
|
|
297
|
+
ownership,
|
|
298
|
+
ownerKind,
|
|
299
|
+
objectType: input.objectType,
|
|
300
|
+
source: "stored_transaction_data_and_mainnet_object_read"
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function isAcceptableOwnershipFact(fact) {
|
|
304
|
+
if (fact.ownership === "unknown_owner" || fact.ownership === "object_owner" || fact.ownership === "consensus_address_owner") {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
if (fact.roles.includes("gas_object")) {
|
|
308
|
+
return fact.ownership === "owned_by_account";
|
|
309
|
+
}
|
|
310
|
+
if (fact.roles.includes("imm_or_owned_object") || fact.roles.includes("receiving_object")) {
|
|
311
|
+
return fact.ownership === "owned_by_account" ||
|
|
312
|
+
(fact.roles.includes("imm_or_owned_object") && fact.ownership === "immutable_object");
|
|
313
|
+
}
|
|
314
|
+
return fact.roles.every((role) => role === "shared_object")
|
|
315
|
+
? fact.ownership === "shared_object" || fact.ownership === "immutable_object"
|
|
316
|
+
: false;
|
|
317
|
+
}
|
|
318
|
+
function objectReadBlocked() {
|
|
319
|
+
return {
|
|
320
|
+
status: "blocked",
|
|
321
|
+
blockedReason: "object_resolution_failed",
|
|
322
|
+
checks: [
|
|
323
|
+
failReviewCheck("transaction_object_ownership_read_failed", "Object ownership read", "Object ownership evidence was not produced because a transaction object owner could not be read or classified from mainnet object state.", "network")
|
|
324
|
+
]
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function isRecord(value) {
|
|
328
|
+
return typeof value === "object" && value !== null;
|
|
329
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const FAILURE_REASONS = [
|
|
2
|
+
"wallet_rejected",
|
|
3
|
+
"wallet_provider_error",
|
|
4
|
+
"signing_disconnected",
|
|
5
|
+
"network_error",
|
|
6
|
+
"transaction_submit_failed",
|
|
7
|
+
"execution_result_unavailable",
|
|
8
|
+
"unknown_failure"
|
|
9
|
+
];
|
|
10
|
+
export const BLOCKED_REASONS = [
|
|
11
|
+
"adapter_not_implemented",
|
|
12
|
+
"producer_stage_missing",
|
|
13
|
+
"wallet_review_contract_emit_missing",
|
|
14
|
+
"wallet_handoff_not_implemented",
|
|
15
|
+
"network_mismatch",
|
|
16
|
+
"insufficient_balance",
|
|
17
|
+
"insufficient_gas",
|
|
18
|
+
"allowlist_violation",
|
|
19
|
+
"asset_mismatch",
|
|
20
|
+
"amount_mismatch",
|
|
21
|
+
"wallet_mismatch",
|
|
22
|
+
"unsupported_action",
|
|
23
|
+
"object_resolution_failed",
|
|
24
|
+
"proposal_review_only"
|
|
25
|
+
];
|
|
26
|
+
export const REFRESH_REASONS = [
|
|
27
|
+
"quote_stale",
|
|
28
|
+
"quote_unavailable",
|
|
29
|
+
"simulation_transient_failure"
|
|
30
|
+
];
|
|
31
|
+
export const REVIEW_UI_LABELS = {
|
|
32
|
+
ready_for_wallet_review: "Ready for wallet review",
|
|
33
|
+
refresh_required: "Refresh required",
|
|
34
|
+
blocked: "Blocked"
|
|
35
|
+
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { adapterEvidenceClaimSchema, adapterInputProvenanceSchema, adapterOutputBoundarySchema, adapterSimulationEvidenceSchema, adapterSourceOfTruthSchema, walletReviewAdapterContractSchema, WALLET_REVIEW_ADAPTER_CONTRACT_VERSION, WALLET_REVIEW_REQUIRED_PROHIBITED_OUTPUTS, WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS, WALLET_REVIEW_REQUIRED_HUMAN_FIELDS, adapterExpiryEvidenceSchema, adapterHumanReadableReviewSchema, adapterGasEvidenceSchema, SUI_GAS_COIN_TYPE } from "./signableAdapterContract.js";
|
|
2
|
+
import { parseReviewTimeSimulationEvidence } from "./reviewTimeSimulationEvidence.js";
|
|
3
|
+
import { parseHumanReadableReviewEvidence } from "./humanReadableReviewEvidence.js";
|
|
4
|
+
export function buildWalletReviewOutputBoundary() {
|
|
5
|
+
return adapterOutputBoundarySchema.parse({
|
|
6
|
+
runtimeStatus: "emitted_pre_handoff",
|
|
7
|
+
mcpAndReviewUiMayExpose: [
|
|
8
|
+
"human_readable_review",
|
|
9
|
+
"ptb_visualization_artifact",
|
|
10
|
+
"diagnostics",
|
|
11
|
+
"status_checks"
|
|
12
|
+
],
|
|
13
|
+
prohibited: [...WALLET_REVIEW_REQUIRED_PROHIBITED_OUTPUTS]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function buildWalletReviewInputProvenance(input) {
|
|
17
|
+
return adapterInputProvenanceSchema.parse({
|
|
18
|
+
kind: input.kind,
|
|
19
|
+
sourceId: input.sourceId,
|
|
20
|
+
capturedAt: input.capturedAt,
|
|
21
|
+
authority: "untrusted_until_review_regenerates_and_verifies",
|
|
22
|
+
...(input.userSelectionSource ? { userSelectionSource: input.userSelectionSource } : {})
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
import { mapSwapQuotePolicyEvidenceToContractDraft, parseSwapQuotePolicyEvidence } from "./swapQuotePolicyEvidence.js";
|
|
26
|
+
import { mapTransactionObjectOwnershipEvidenceToContractDraft } from "./transactionObjectOwnershipEvidence.js";
|
|
27
|
+
export function draftWalletReviewContractEvidencePool(input) {
|
|
28
|
+
const quote = mapSwapQuotePolicyEvidenceToContractDraft(input.quotePolicy);
|
|
29
|
+
if (quote.status === "unsupported") {
|
|
30
|
+
return { status: "declined", reason: `quote policy draft unsupported: ${quote.reason}` };
|
|
31
|
+
}
|
|
32
|
+
const ownership = mapTransactionObjectOwnershipEvidenceToContractDraft(input.objectOwnership);
|
|
33
|
+
if (ownership.status === "unsupported") {
|
|
34
|
+
return { status: "declined", reason: `object ownership draft unsupported: ${ownership.reason}` };
|
|
35
|
+
}
|
|
36
|
+
const sourceOfTruth = [...quote.sourceOfTruth, ownership.sourceOfTruth];
|
|
37
|
+
const sourceIds = new Set();
|
|
38
|
+
for (const record of sourceOfTruth) {
|
|
39
|
+
if (sourceIds.has(record.id)) {
|
|
40
|
+
return { status: "declined", reason: `duplicate sourceOfTruth id: ${record.id}` };
|
|
41
|
+
}
|
|
42
|
+
sourceIds.add(record.id);
|
|
43
|
+
}
|
|
44
|
+
const evidenceClaims = [...quote.evidenceClaims, ...ownership.evidenceClaims];
|
|
45
|
+
const claimIds = new Set();
|
|
46
|
+
for (const claim of evidenceClaims) {
|
|
47
|
+
if (claimIds.has(claim.id)) {
|
|
48
|
+
return { status: "declined", reason: `duplicate evidence claim id: ${claim.id}` };
|
|
49
|
+
}
|
|
50
|
+
claimIds.add(claim.id);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
status: "drafted",
|
|
54
|
+
sourceOfTruth,
|
|
55
|
+
evidenceClaims,
|
|
56
|
+
rawQuantities: quote.rawQuantities,
|
|
57
|
+
objectOwnership: ownership.objectOwnership,
|
|
58
|
+
gasObjectOwnershipLinks: ownership.gasObjectOwnershipLinks
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function mapReviewTimeSimulationEvidenceToContractDraft(evidenceInput) {
|
|
62
|
+
const evidence = parseReviewTimeSimulationEvidence(evidenceInput);
|
|
63
|
+
const sourceId = "review_time_simulation_source";
|
|
64
|
+
const claimId = "review_time_simulation_claim";
|
|
65
|
+
const sourceOfTruth = adapterSourceOfTruthSchema.parse({
|
|
66
|
+
id: sourceId,
|
|
67
|
+
kind: "review_time_simulation",
|
|
68
|
+
network: "sui:mainnet",
|
|
69
|
+
source: "Checks-enabled client.core.simulateTransaction run over stored local transaction material",
|
|
70
|
+
verifiedAt: evidence.simulatedAt,
|
|
71
|
+
fields: [...WALLET_REVIEW_REQUIRED_SIMULATION_FIELDS]
|
|
72
|
+
});
|
|
73
|
+
const evidenceClaim = adapterEvidenceClaimSchema.parse({
|
|
74
|
+
id: claimId,
|
|
75
|
+
factKind: "simulation_result",
|
|
76
|
+
sourceEvidenceId: sourceId,
|
|
77
|
+
provider: evidence.provider,
|
|
78
|
+
checksEnabled: evidence.checksEnabled,
|
|
79
|
+
simulatedAt: evidence.simulatedAt,
|
|
80
|
+
status: evidence.status,
|
|
81
|
+
requiredFields: [...evidence.requiredFields],
|
|
82
|
+
missingFields: [...evidence.missingFields]
|
|
83
|
+
});
|
|
84
|
+
const simulation = adapterSimulationEvidenceSchema.parse({
|
|
85
|
+
evidenceClaimId: claimId,
|
|
86
|
+
boundToCommitment: evidence.transactionDigest,
|
|
87
|
+
provider: evidence.provider,
|
|
88
|
+
checksEnabled: evidence.checksEnabled,
|
|
89
|
+
simulatedAt: evidence.simulatedAt,
|
|
90
|
+
status: evidence.status,
|
|
91
|
+
requiredFields: [...evidence.requiredFields],
|
|
92
|
+
missingFields: [...evidence.missingFields]
|
|
93
|
+
});
|
|
94
|
+
return { status: "mapped", sourceOfTruth, evidenceClaim, simulation };
|
|
95
|
+
}
|
|
96
|
+
export function mapReviewTimeSimulationGasToContractDraft(evidenceInput, gasObjects) {
|
|
97
|
+
const evidence = parseReviewTimeSimulationEvidence(evidenceInput);
|
|
98
|
+
const summary = evidence.effects.gasCostSummary;
|
|
99
|
+
const gasUsed = BigInt(summary.computationCostRaw) +
|
|
100
|
+
BigInt(summary.storageCostRaw) -
|
|
101
|
+
BigInt(summary.storageRebateRaw);
|
|
102
|
+
if (gasUsed < 0n) {
|
|
103
|
+
return {
|
|
104
|
+
status: "unsupported",
|
|
105
|
+
reason: "net gas used is negative (storage rebate exceeds costs); unsigned gas evidence unavailable"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const sourceOfTruth = [];
|
|
109
|
+
const evidenceClaims = [];
|
|
110
|
+
const gasAsset = { coinType: SUI_GAS_COIN_TYPE };
|
|
111
|
+
const gasUsedSourceId = "review_time_simulation_gas_used_source";
|
|
112
|
+
const gasUsedClaimId = "review_time_simulation_gas_used_claim";
|
|
113
|
+
sourceOfTruth.push(adapterSourceOfTruthSchema.parse({
|
|
114
|
+
id: gasUsedSourceId,
|
|
115
|
+
kind: "review_time_simulation",
|
|
116
|
+
network: "sui:mainnet",
|
|
117
|
+
source: "Gas cost summary components from checks-enabled simulation of stored local transaction material",
|
|
118
|
+
verifiedAt: evidence.simulatedAt,
|
|
119
|
+
fields: ["gasUsedRaw", "asset", "amountRole"]
|
|
120
|
+
}));
|
|
121
|
+
evidenceClaims.push(adapterEvidenceClaimSchema.parse({
|
|
122
|
+
id: gasUsedClaimId,
|
|
123
|
+
factKind: "raw_quantity_amount",
|
|
124
|
+
sourceEvidenceId: gasUsedSourceId,
|
|
125
|
+
role: "gas_used",
|
|
126
|
+
asset: gasAsset,
|
|
127
|
+
rawAmount: gasUsed.toString()
|
|
128
|
+
}));
|
|
129
|
+
const gasBudgetRaw = evidence.transaction.gasBudgetRaw;
|
|
130
|
+
let gasBudgetClaimId;
|
|
131
|
+
if (gasBudgetRaw !== undefined) {
|
|
132
|
+
const gasBudgetSourceId = "review_time_simulation_gas_budget_source";
|
|
133
|
+
gasBudgetClaimId = "review_time_simulation_gas_budget_claim";
|
|
134
|
+
sourceOfTruth.push(adapterSourceOfTruthSchema.parse({
|
|
135
|
+
id: gasBudgetSourceId,
|
|
136
|
+
kind: "review_time_simulation",
|
|
137
|
+
network: "sui:mainnet",
|
|
138
|
+
source: "Gas budget from the simulated stored local transaction data",
|
|
139
|
+
verifiedAt: evidence.simulatedAt,
|
|
140
|
+
fields: ["gasBudgetRaw", "asset", "amountRole"]
|
|
141
|
+
}));
|
|
142
|
+
evidenceClaims.push(adapterEvidenceClaimSchema.parse({
|
|
143
|
+
id: gasBudgetClaimId,
|
|
144
|
+
factKind: "raw_quantity_amount",
|
|
145
|
+
sourceEvidenceId: gasBudgetSourceId,
|
|
146
|
+
role: "gas_budget",
|
|
147
|
+
asset: gasAsset,
|
|
148
|
+
rawAmount: gasBudgetRaw
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
const gas = adapterGasEvidenceSchema.parse({
|
|
152
|
+
source: "review_time_simulation",
|
|
153
|
+
checkedAt: evidence.simulatedAt,
|
|
154
|
+
gasUsedRaw: gasUsed.toString(),
|
|
155
|
+
gasUsedClaimId,
|
|
156
|
+
...(gasBudgetRaw !== undefined && gasBudgetClaimId
|
|
157
|
+
? { gasBudgetRaw, gasBudgetClaimId }
|
|
158
|
+
: {}),
|
|
159
|
+
...(gasObjects.length > 0 ? { gasObjects } : {})
|
|
160
|
+
});
|
|
161
|
+
return { status: "mapped", sourceOfTruth, evidenceClaims, gas };
|
|
162
|
+
}
|
|
163
|
+
export function mapSwapQuotePolicyExpiryToContractDraft(evidenceInput, now) {
|
|
164
|
+
const evidence = parseSwapQuotePolicyEvidence(evidenceInput);
|
|
165
|
+
const checkedAt = now.toISOString();
|
|
166
|
+
const status = Date.parse(evidence.expiresAt) > now.getTime() ? "current" : "expired";
|
|
167
|
+
const sourceId = "swap_quote_policy_expiry_source";
|
|
168
|
+
const claimId = "swap_quote_policy_expiry_claim";
|
|
169
|
+
const sourceOfTruth = adapterSourceOfTruthSchema.parse({
|
|
170
|
+
id: sourceId,
|
|
171
|
+
kind: "validated_request_fact",
|
|
172
|
+
network: "sui:mainnet",
|
|
173
|
+
source: "Quote policy expiry window (quote fetchedAt plus staleAfterMs) checked against the review-time clock",
|
|
174
|
+
verifiedAt: checkedAt,
|
|
175
|
+
fields: ["checkedAt", "expiresAt"]
|
|
176
|
+
});
|
|
177
|
+
const evidenceClaim = adapterEvidenceClaimSchema.parse({
|
|
178
|
+
id: claimId,
|
|
179
|
+
factKind: "expiry_status",
|
|
180
|
+
sourceEvidenceId: sourceId,
|
|
181
|
+
checkedAt,
|
|
182
|
+
status,
|
|
183
|
+
expiresAt: evidence.expiresAt
|
|
184
|
+
});
|
|
185
|
+
const expiry = adapterExpiryEvidenceSchema.parse({
|
|
186
|
+
checkedAt,
|
|
187
|
+
status,
|
|
188
|
+
expiresAt: evidence.expiresAt,
|
|
189
|
+
evidenceClaimId: claimId
|
|
190
|
+
});
|
|
191
|
+
return { status: "mapped", sourceOfTruth, evidenceClaim, expiry };
|
|
192
|
+
}
|
|
193
|
+
export function mapHumanReadableReviewEvidenceToContractDraft(evidenceInput) {
|
|
194
|
+
const evidence = parseHumanReadableReviewEvidence(evidenceInput);
|
|
195
|
+
const humanReadableReview = adapterHumanReadableReviewSchema.parse({
|
|
196
|
+
fields: [...WALLET_REVIEW_REQUIRED_HUMAN_FIELDS],
|
|
197
|
+
boundToCommitment: evidence.boundToCommitment,
|
|
198
|
+
source: "review_model_or_adapter_equivalent",
|
|
199
|
+
purpose: "human_review_before_wallet_authorization"
|
|
200
|
+
});
|
|
201
|
+
return { status: "mapped", humanReadableReview };
|
|
202
|
+
}
|
|
203
|
+
export function assembleWalletReviewAdapterContract(input) {
|
|
204
|
+
const pool = draftWalletReviewContractEvidencePool({
|
|
205
|
+
quotePolicy: input.quotePolicy,
|
|
206
|
+
objectOwnership: input.objectOwnership
|
|
207
|
+
});
|
|
208
|
+
if (pool.status === "declined") {
|
|
209
|
+
return pool;
|
|
210
|
+
}
|
|
211
|
+
const simulation = mapReviewTimeSimulationEvidenceToContractDraft(input.reviewTimeSimulation);
|
|
212
|
+
const gas = mapReviewTimeSimulationGasToContractDraft(input.reviewTimeSimulation, pool.gasObjectOwnershipLinks);
|
|
213
|
+
if (gas.status === "unsupported") {
|
|
214
|
+
return { status: "declined", reason: `gas evidence unsupported: ${gas.reason}` };
|
|
215
|
+
}
|
|
216
|
+
const expiry = mapSwapQuotePolicyExpiryToContractDraft(input.quotePolicy, input.now);
|
|
217
|
+
const human = mapHumanReadableReviewEvidenceToContractDraft(input.humanReadableReview);
|
|
218
|
+
const sourceOfTruth = [
|
|
219
|
+
...pool.sourceOfTruth,
|
|
220
|
+
simulation.sourceOfTruth,
|
|
221
|
+
...gas.sourceOfTruth,
|
|
222
|
+
expiry.sourceOfTruth
|
|
223
|
+
];
|
|
224
|
+
const sourceIds = new Set();
|
|
225
|
+
for (const record of sourceOfTruth) {
|
|
226
|
+
if (sourceIds.has(record.id)) {
|
|
227
|
+
return { status: "declined", reason: `duplicate sourceOfTruth id: ${record.id}` };
|
|
228
|
+
}
|
|
229
|
+
sourceIds.add(record.id);
|
|
230
|
+
}
|
|
231
|
+
const evidenceClaims = [
|
|
232
|
+
...pool.evidenceClaims,
|
|
233
|
+
simulation.evidenceClaim,
|
|
234
|
+
...gas.evidenceClaims,
|
|
235
|
+
expiry.evidenceClaim
|
|
236
|
+
];
|
|
237
|
+
const claimIds = new Set();
|
|
238
|
+
for (const claim of evidenceClaims) {
|
|
239
|
+
if (claimIds.has(claim.id)) {
|
|
240
|
+
return { status: "declined", reason: `duplicate evidence claim id: ${claim.id}` };
|
|
241
|
+
}
|
|
242
|
+
claimIds.add(claim.id);
|
|
243
|
+
}
|
|
244
|
+
const quote = parseSwapQuotePolicyEvidence(input.quotePolicy);
|
|
245
|
+
const candidate = {
|
|
246
|
+
contractVersion: WALLET_REVIEW_ADAPTER_CONTRACT_VERSION,
|
|
247
|
+
adapterId: input.adapterId,
|
|
248
|
+
protocol: input.protocol,
|
|
249
|
+
actionKind: input.actionKind,
|
|
250
|
+
network: "sui:mainnet",
|
|
251
|
+
inputProvenance: buildWalletReviewInputProvenance(input.provenance),
|
|
252
|
+
sourceOfTruth,
|
|
253
|
+
evidenceClaims,
|
|
254
|
+
rawQuantities: pool.rawQuantities,
|
|
255
|
+
gas: gas.gas,
|
|
256
|
+
expiry: expiry.expiry,
|
|
257
|
+
slippageOrMinOut: {
|
|
258
|
+
status: "required_and_verified",
|
|
259
|
+
quoteEvidenceId: quote.quoteEvidenceId,
|
|
260
|
+
quoteEvidenceClaimId: "swap_quote_min_out_claim",
|
|
261
|
+
maxSlippageBps: quote.maxSlippageBps,
|
|
262
|
+
minOutRaw: quote.minimumOutput.raw,
|
|
263
|
+
policySource: "adapter_policy_from_quote_evidence",
|
|
264
|
+
policyEvidenceClaimId: "swap_quote_slippage_policy_claim"
|
|
265
|
+
},
|
|
266
|
+
objectOwnership: pool.objectOwnership,
|
|
267
|
+
simulation: simulation.simulation,
|
|
268
|
+
humanReadableReview: human.humanReadableReview,
|
|
269
|
+
outputBoundary: buildWalletReviewOutputBoundary(),
|
|
270
|
+
transactionMaterialCommitment: input.transactionMaterialCommitment
|
|
271
|
+
};
|
|
272
|
+
const parsed = walletReviewAdapterContractSchema.safeParse(candidate);
|
|
273
|
+
if (!parsed.success) {
|
|
274
|
+
const issue = parsed.error.issues[0];
|
|
275
|
+
const path = issue?.path.join(".") ?? "";
|
|
276
|
+
return {
|
|
277
|
+
status: "declined",
|
|
278
|
+
reason: `contract schema rejected: ${path ? `${path}: ` : ""}${issue?.message ?? "unknown issue"}`
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
return { status: "emitted", contract: parsed.data };
|
|
282
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const REVIEW_ACTIVITY_LOW_SAMPLE_THRESHOLD = 5;
|
|
2
|
+
export const REVIEW_ACTIVITY_LIST_DEFAULT_LIMIT = 20;
|
|
3
|
+
export const REVIEW_ACTIVITY_LIST_MAX_LIMIT = 100;
|
|
4
|
+
export const REVIEW_ACTIVITY_DETAIL_MAX_ITEMS = 100;
|
|
5
|
+
export const EXTERNAL_ACTIVITY_SCAN_DEFAULT_LIMIT = 100;
|
|
6
|
+
export const EXTERNAL_ACTIVITY_SCAN_MAX_LIMIT = 100;
|
|
7
|
+
export class ActivityStoreReadError extends Error {
|
|
8
|
+
kind;
|
|
9
|
+
details;
|
|
10
|
+
constructor(kind, message, details = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.kind = kind;
|
|
13
|
+
this.details = details;
|
|
14
|
+
}
|
|
15
|
+
}
|