@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,136 @@
|
|
|
1
|
+
import { PreferencesStoreError, assertLocalSettingKey } from "./preferencesStore.js";
|
|
2
|
+
import { parseGraphqlUrl, parseGrpcUrl } from "../suiEndpoint.js";
|
|
3
|
+
export class SqlitePreferencesRepository {
|
|
4
|
+
db;
|
|
5
|
+
constructor(db) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
}
|
|
8
|
+
async ensureDefaultLocalSettings(defaults, now = new Date()) {
|
|
9
|
+
const insert = this.db.prepare(`INSERT INTO local_settings (key, value_json, updated_at)
|
|
10
|
+
VALUES (?, ?, ?)
|
|
11
|
+
ON CONFLICT(key) DO NOTHING`);
|
|
12
|
+
insert.run("suiGrpcUrl", encodeSettingValue("suiGrpcUrl", defaults.suiGrpcUrl), now.toISOString());
|
|
13
|
+
insert.run("suiGraphqlUrl", encodeSettingValue("suiGraphqlUrl", defaults.suiGraphqlUrl), now.toISOString());
|
|
14
|
+
}
|
|
15
|
+
async getSuiGrpcUrl() {
|
|
16
|
+
const record = await this.getLocalSetting("suiGrpcUrl");
|
|
17
|
+
return record
|
|
18
|
+
? {
|
|
19
|
+
key: "suiGrpcUrl",
|
|
20
|
+
value: asSuiGrpcUrlValue(record.value),
|
|
21
|
+
updatedAt: record.updatedAt
|
|
22
|
+
}
|
|
23
|
+
: undefined;
|
|
24
|
+
}
|
|
25
|
+
async getSuiGraphqlUrl() {
|
|
26
|
+
const record = await this.getLocalSetting("suiGraphqlUrl");
|
|
27
|
+
return record
|
|
28
|
+
? {
|
|
29
|
+
key: "suiGraphqlUrl",
|
|
30
|
+
value: asSuiGraphqlUrlValue(record.value),
|
|
31
|
+
updatedAt: record.updatedAt
|
|
32
|
+
}
|
|
33
|
+
: undefined;
|
|
34
|
+
}
|
|
35
|
+
async setSuiGrpcUrl(url, now = new Date()) {
|
|
36
|
+
const previous = await this.getSuiGrpcUrl();
|
|
37
|
+
const record = await this.setLocalSetting("suiGrpcUrl", url, now);
|
|
38
|
+
return {
|
|
39
|
+
storedValue: asSuiGrpcUrlValue(record.value),
|
|
40
|
+
previousStoredValue: previous?.value,
|
|
41
|
+
updatedAt: record.updatedAt
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async setSuiGraphqlUrl(url, now = new Date()) {
|
|
45
|
+
const previous = await this.getSuiGraphqlUrl();
|
|
46
|
+
const record = await this.setLocalSetting("suiGraphqlUrl", url, now);
|
|
47
|
+
return {
|
|
48
|
+
storedValue: asSuiGraphqlUrlValue(record.value),
|
|
49
|
+
previousStoredValue: previous?.value,
|
|
50
|
+
updatedAt: record.updatedAt
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async resetSuiGrpcUrl(defaultUrl, now = new Date()) {
|
|
54
|
+
return this.setSuiGrpcUrl(defaultUrl, now);
|
|
55
|
+
}
|
|
56
|
+
async resetSuiGraphqlUrl(defaultUrl, now = new Date()) {
|
|
57
|
+
return this.setSuiGraphqlUrl(defaultUrl, now);
|
|
58
|
+
}
|
|
59
|
+
async getLocalSetting(key) {
|
|
60
|
+
const settingKey = assertLocalSettingKey(key);
|
|
61
|
+
const row = this.db
|
|
62
|
+
.prepare(`SELECT key, value_json, updated_at
|
|
63
|
+
FROM local_settings
|
|
64
|
+
WHERE key = ?`)
|
|
65
|
+
.get(settingKey);
|
|
66
|
+
return row ? rowToLocalSetting(row) : undefined;
|
|
67
|
+
}
|
|
68
|
+
async setLocalSetting(key, value, now = new Date()) {
|
|
69
|
+
const settingKey = assertLocalSettingKey(key);
|
|
70
|
+
this.db
|
|
71
|
+
.prepare(`INSERT INTO local_settings (key, value_json, updated_at)
|
|
72
|
+
VALUES (?, ?, ?)
|
|
73
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
74
|
+
value_json = excluded.value_json,
|
|
75
|
+
updated_at = excluded.updated_at`)
|
|
76
|
+
.run(settingKey, encodeSettingValue(settingKey, value), now.toISOString());
|
|
77
|
+
const record = await this.getLocalSetting(settingKey);
|
|
78
|
+
if (!record) {
|
|
79
|
+
throw new PreferencesStoreError("not_recorded", "Local setting was not recorded", { key: settingKey });
|
|
80
|
+
}
|
|
81
|
+
return record;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function rowToLocalSetting(row) {
|
|
85
|
+
const key = assertLocalSettingKey(row.key);
|
|
86
|
+
return {
|
|
87
|
+
key,
|
|
88
|
+
value: decodeSettingValue(key, row.value_json),
|
|
89
|
+
updatedAt: row.updated_at
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function encodeSettingValue(key, value) {
|
|
93
|
+
if (key === "suiGrpcUrl") {
|
|
94
|
+
if (typeof value !== "string") {
|
|
95
|
+
throw new PreferencesStoreError("invalid_value", "suiGrpcUrl setting value must be a string", { key });
|
|
96
|
+
}
|
|
97
|
+
return JSON.stringify(parseGrpcUrl(value));
|
|
98
|
+
}
|
|
99
|
+
if (key === "suiGraphqlUrl") {
|
|
100
|
+
if (typeof value !== "string") {
|
|
101
|
+
throw new PreferencesStoreError("invalid_value", "suiGraphqlUrl setting value must be a string", { key });
|
|
102
|
+
}
|
|
103
|
+
return JSON.stringify(parseGraphqlUrl(value));
|
|
104
|
+
}
|
|
105
|
+
throw new PreferencesStoreError("unknown_key", "Unknown local setting key", { key });
|
|
106
|
+
}
|
|
107
|
+
function decodeSettingValue(key, valueJson) {
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
parsed = JSON.parse(valueJson);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
throw new PreferencesStoreError("malformed_json", "Malformed local setting JSON", { key });
|
|
114
|
+
}
|
|
115
|
+
if (key === "suiGrpcUrl") {
|
|
116
|
+
return asSuiGrpcUrlValue(parsed);
|
|
117
|
+
}
|
|
118
|
+
if (key === "suiGraphqlUrl") {
|
|
119
|
+
return asSuiGraphqlUrlValue(parsed);
|
|
120
|
+
}
|
|
121
|
+
throw new PreferencesStoreError("unknown_key", "Unknown local setting key", { key });
|
|
122
|
+
}
|
|
123
|
+
function asSuiGraphqlUrlValue(value) {
|
|
124
|
+
if (typeof value !== "string") {
|
|
125
|
+
throw new PreferencesStoreError("invalid_value", "suiGraphqlUrl setting value must be a string", {
|
|
126
|
+
key: "suiGraphqlUrl"
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return parseGraphqlUrl(value);
|
|
130
|
+
}
|
|
131
|
+
function asSuiGrpcUrlValue(value) {
|
|
132
|
+
if (typeof value !== "string") {
|
|
133
|
+
throw new PreferencesStoreError("invalid_value", "suiGrpcUrl setting value must be a string", { key: "suiGrpcUrl" });
|
|
134
|
+
}
|
|
135
|
+
return parseGrpcUrl(value);
|
|
136
|
+
}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { EXTERNAL_PROPOSAL_CONTRACT_VERSION, PROPOSAL_REVIEW_MODEL_VERSION, EXTERNAL_PROPOSAL_REVIEW_ALWAYS_UNSUPPORTED_CLAIMS } from "./types.js";
|
|
3
|
+
import { externalProposalSchema } from "./schemas.js";
|
|
4
|
+
const REJECTED_EXECUTABLE_FIELDS = [
|
|
5
|
+
"transactionBytes",
|
|
6
|
+
"serializedTransaction",
|
|
7
|
+
"signingRequest",
|
|
8
|
+
"signature",
|
|
9
|
+
"privateKey",
|
|
10
|
+
"secretKey",
|
|
11
|
+
"seed",
|
|
12
|
+
"mnemonic",
|
|
13
|
+
"routeSelectedPlan"
|
|
14
|
+
];
|
|
15
|
+
export function externalProposalToActionPlan(proposal, now = new Date()) {
|
|
16
|
+
const sanitizedProposal = externalProposalSchema.parse(proposal);
|
|
17
|
+
const reviewModel = proposalReviewModel(sanitizedProposal, now);
|
|
18
|
+
return {
|
|
19
|
+
id: `plan_${randomUUID()}`,
|
|
20
|
+
actionKind: sanitizedProposal.type,
|
|
21
|
+
adapterId: "external-proposal-review",
|
|
22
|
+
protocol: "Sui",
|
|
23
|
+
title: reviewModel.proposedAction.title,
|
|
24
|
+
summary: "This local review records an external proposal as untrusted structured input. It is non-signable and does not include transaction bytes, signing data, wallet authorization, route selection, fiat cash-out, P&L, tax, or cost-basis support.",
|
|
25
|
+
assetFlowPreview: {
|
|
26
|
+
outgoing: reviewModel.assetFlow.outgoing.map(toDisplayIntentAmount),
|
|
27
|
+
expectedIncoming: reviewModel.assetFlow.expectedIncoming.map(toDisplayIntentAmount),
|
|
28
|
+
...(reviewModel.assetFlow.fees.length > 0
|
|
29
|
+
? { fees: reviewModel.assetFlow.fees.map(toDisplayIntentAmount) }
|
|
30
|
+
: {})
|
|
31
|
+
},
|
|
32
|
+
reviewModel,
|
|
33
|
+
adapterData: {
|
|
34
|
+
requestedIntent: sanitizedProposal,
|
|
35
|
+
implementationStatus: "read_only_review_only",
|
|
36
|
+
contractVersion: EXTERNAL_PROPOSAL_CONTRACT_VERSION
|
|
37
|
+
},
|
|
38
|
+
createdAt: now.toISOString(),
|
|
39
|
+
...(sanitizedProposal.expiresAt ? { expiresAt: sanitizedProposal.expiresAt } : {}),
|
|
40
|
+
preliminaryChecks: reviewModel.blockingChecks
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function proposalReviewModel(proposal, now) {
|
|
44
|
+
const freshness = freshnessSummary(proposal, now);
|
|
45
|
+
const missingEvidence = missingEvidenceForProposal(proposal);
|
|
46
|
+
const requiredUserChoices = requiredUserChoicesForProposal(proposal);
|
|
47
|
+
const blockingChecks = blockingChecksForProposal(proposal, freshness.status);
|
|
48
|
+
const { title, recipient, target } = proposedActionDisplay(proposal);
|
|
49
|
+
const assetFlow = assetFlowForProposal(proposal);
|
|
50
|
+
const recipients = recipientsForProposal(proposal);
|
|
51
|
+
const targets = targetsForProposal(proposal);
|
|
52
|
+
return {
|
|
53
|
+
modelVersion: PROPOSAL_REVIEW_MODEL_VERSION,
|
|
54
|
+
contractVersion: EXTERNAL_PROPOSAL_CONTRACT_VERSION,
|
|
55
|
+
proposalId: proposal.id,
|
|
56
|
+
proposalType: proposal.type,
|
|
57
|
+
proposalSource: proposal.source,
|
|
58
|
+
proposedAction: {
|
|
59
|
+
kind: proposal.type,
|
|
60
|
+
title,
|
|
61
|
+
purpose: proposal.purpose,
|
|
62
|
+
network: proposal.network,
|
|
63
|
+
...(recipient ? { recipient } : {}),
|
|
64
|
+
...(target ? { target } : {})
|
|
65
|
+
},
|
|
66
|
+
assetFlow,
|
|
67
|
+
recipients,
|
|
68
|
+
targets,
|
|
69
|
+
evidenceUsed: [
|
|
70
|
+
{
|
|
71
|
+
id: "external_proposal_contract",
|
|
72
|
+
label: "External proposal contract",
|
|
73
|
+
source: "local_schema",
|
|
74
|
+
summary: "The proposal matched the read-only external proposal schema and was stored as untrusted review input."
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "proposal_declared_network",
|
|
78
|
+
label: "Declared network",
|
|
79
|
+
source: "external_proposal",
|
|
80
|
+
summary: `The proposal declares ${proposal.network}. This is not a connected-chain verification.`
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "proposal_display_amounts",
|
|
84
|
+
label: "Display proposal amounts",
|
|
85
|
+
source: "external_proposal",
|
|
86
|
+
summary: "Returned amount fields are display proposal facts only and are not raw amounts, min-out values, or signing input."
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
missingEvidence,
|
|
90
|
+
requiredUserChoices,
|
|
91
|
+
unsupportedClaims: [
|
|
92
|
+
...EXTERNAL_PROPOSAL_REVIEW_ALWAYS_UNSUPPORTED_CLAIMS,
|
|
93
|
+
...(proposal.assumptions && proposal.assumptions.length > 0
|
|
94
|
+
? [{
|
|
95
|
+
id: "source_assumptions_unverified",
|
|
96
|
+
label: "Source assumptions",
|
|
97
|
+
reason: "Source assumptions are displayed for review but are not verified by this read-only ingestion step."
|
|
98
|
+
}]
|
|
99
|
+
: [])
|
|
100
|
+
],
|
|
101
|
+
rejectedExecutableFields: REJECTED_EXECUTABLE_FIELDS.map((fieldName) => ({
|
|
102
|
+
fieldName,
|
|
103
|
+
reason: "This field is outside the external proposal contract because external executable material is not trusted review authority."
|
|
104
|
+
})),
|
|
105
|
+
freshness,
|
|
106
|
+
blockingChecks,
|
|
107
|
+
nonSignableReason: {
|
|
108
|
+
code: "external_proposal_review_only",
|
|
109
|
+
message: "This review is non-signable because it only records an untrusted external proposal and does not build or verify transaction material.",
|
|
110
|
+
blockedCapabilities: [
|
|
111
|
+
"transaction_building",
|
|
112
|
+
"wallet_signing",
|
|
113
|
+
"execution",
|
|
114
|
+
"signing_data_or_readiness",
|
|
115
|
+
"external_transaction_material_authority"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function freshnessSummary(proposal, now) {
|
|
121
|
+
const createdAtMs = Date.parse(proposal.createdAt);
|
|
122
|
+
const nowMs = now.getTime();
|
|
123
|
+
if (createdAtMs > nowMs) {
|
|
124
|
+
return {
|
|
125
|
+
proposalCreatedAt: proposal.createdAt,
|
|
126
|
+
...(proposal.expiresAt ? { proposalExpiresAt: proposal.expiresAt } : {}),
|
|
127
|
+
evaluatedAt: now.toISOString(),
|
|
128
|
+
status: "created_in_future",
|
|
129
|
+
reason: "The proposal createdAt timestamp is after the local review evaluation time."
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (!proposal.expiresAt) {
|
|
133
|
+
return {
|
|
134
|
+
proposalCreatedAt: proposal.createdAt,
|
|
135
|
+
evaluatedAt: now.toISOString(),
|
|
136
|
+
status: "expiry_not_provided",
|
|
137
|
+
reason: "The proposal did not provide an expiry timestamp."
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (Date.parse(proposal.expiresAt) <= nowMs) {
|
|
141
|
+
return {
|
|
142
|
+
proposalCreatedAt: proposal.createdAt,
|
|
143
|
+
proposalExpiresAt: proposal.expiresAt,
|
|
144
|
+
evaluatedAt: now.toISOString(),
|
|
145
|
+
status: "expired",
|
|
146
|
+
reason: "The proposal expiry timestamp is not after the local review evaluation time."
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
proposalCreatedAt: proposal.createdAt,
|
|
151
|
+
proposalExpiresAt: proposal.expiresAt,
|
|
152
|
+
evaluatedAt: now.toISOString(),
|
|
153
|
+
status: "current",
|
|
154
|
+
reason: "The proposal createdAt and expiresAt timestamps are consistent with the local review evaluation time."
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function missingEvidenceForProposal(proposal) {
|
|
158
|
+
const gaps = [
|
|
159
|
+
{
|
|
160
|
+
id: "account_bound_wallet_assets",
|
|
161
|
+
label: "Account-bound wallet evidence",
|
|
162
|
+
reason: "This ingestion step has not read wallet balances, gas assets, object ownership, or before/after balance changes."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: "review_time_simulation",
|
|
166
|
+
label: "Review-time simulation",
|
|
167
|
+
reason: "No transaction is built or simulated for this external proposal in the current release."
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: "recipient_or_target_verification",
|
|
171
|
+
label: "Recipient or target verification",
|
|
172
|
+
reason: "The proposal recipient or action target is displayed as provided and has not been independently verified as intended by the user."
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
if (proposal.type === "payment" && !proposal.payment.amount.coinType) {
|
|
176
|
+
gaps.push({
|
|
177
|
+
id: "settlement_asset_selection",
|
|
178
|
+
label: "Settlement asset selection",
|
|
179
|
+
reason: "The proposal did not identify a verified coin type. Symbol and denomination fields are external display labels, not user-selected settlement assets."
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (proposal.type === "payment" && proposal.payment.amount.coinType) {
|
|
183
|
+
gaps.push({
|
|
184
|
+
id: "settlement_asset_metadata_verification",
|
|
185
|
+
label: "Settlement asset metadata verification",
|
|
186
|
+
reason: "The proposal supplied a coinType, but this read-only ingestion step has not verified its mainnet metadata or user selection provenance."
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (proposal.type === "sui_action") {
|
|
190
|
+
gaps.push({
|
|
191
|
+
id: "action_adapter_support",
|
|
192
|
+
label: "Action adapter support",
|
|
193
|
+
reason: "No reviewed adapter currently verifies this external Sui action target or converts it into wallet-review material."
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return gaps;
|
|
197
|
+
}
|
|
198
|
+
function requiredUserChoicesForProposal(proposal) {
|
|
199
|
+
const choices = (proposal.requiredUserChoices ?? []).map((choice, index) => ({
|
|
200
|
+
id: `source_required_choice_${index + 1}`,
|
|
201
|
+
label: "Source-required user choice",
|
|
202
|
+
reason: choice
|
|
203
|
+
}));
|
|
204
|
+
if (proposal.type === "payment" && !proposal.payment.amount.coinType) {
|
|
205
|
+
choices.push({
|
|
206
|
+
id: "choose_settlement_asset",
|
|
207
|
+
label: "Choose settlement asset",
|
|
208
|
+
reason: "A concrete settlement asset remains a user choice when the proposal names only a symbol, denomination, or display amount."
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (proposal.type === "payment" && proposal.payment.amount.coinType) {
|
|
212
|
+
choices.push({
|
|
213
|
+
id: "confirm_settlement_asset",
|
|
214
|
+
label: "Confirm settlement asset",
|
|
215
|
+
reason: "The proposal supplied a settlement asset identifier, but this read-only review has not verified that the user selected it. Confirm the displayed settlement asset before treating it as intended."
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
return choices;
|
|
219
|
+
}
|
|
220
|
+
function blockingChecksForProposal(proposal, freshnessStatus) {
|
|
221
|
+
const checks = [
|
|
222
|
+
{
|
|
223
|
+
id: "external_proposal_contract",
|
|
224
|
+
label: "External proposal contract",
|
|
225
|
+
status: "pass",
|
|
226
|
+
message: "The external proposal matched the read-only proposal schema.",
|
|
227
|
+
source: "proposal"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: "proposal_declared_mainnet",
|
|
231
|
+
label: "Declared network",
|
|
232
|
+
status: "warning",
|
|
233
|
+
message: `The proposal declares ${proposal.network}, but this is not connected-chain verification.`,
|
|
234
|
+
source: "proposal"
|
|
235
|
+
}
|
|
236
|
+
];
|
|
237
|
+
if (freshnessStatus === "expired" || freshnessStatus === "created_in_future") {
|
|
238
|
+
checks.push({
|
|
239
|
+
id: "proposal_freshness",
|
|
240
|
+
label: "Proposal freshness",
|
|
241
|
+
status: "fail",
|
|
242
|
+
message: `Proposal freshness status is ${freshnessStatus}.`,
|
|
243
|
+
source: "proposal"
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
else if (freshnessStatus === "expiry_not_provided") {
|
|
247
|
+
checks.push({
|
|
248
|
+
id: "proposal_freshness",
|
|
249
|
+
label: "Proposal freshness",
|
|
250
|
+
status: "warning",
|
|
251
|
+
message: "The proposal did not include an expiry timestamp.",
|
|
252
|
+
source: "proposal"
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
checks.push({
|
|
257
|
+
id: "proposal_freshness",
|
|
258
|
+
label: "Proposal freshness",
|
|
259
|
+
status: "pass",
|
|
260
|
+
message: "The proposal timestamps are current for this local review.",
|
|
261
|
+
source: "proposal"
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
checks.push({
|
|
265
|
+
id: "external_proposal_review_only",
|
|
266
|
+
label: "Non-signable review",
|
|
267
|
+
status: "fail",
|
|
268
|
+
message: "External proposal ingestion is read-only; it does not build transactions, request signatures, or create wallet actions.",
|
|
269
|
+
source: "adapter"
|
|
270
|
+
});
|
|
271
|
+
return checks;
|
|
272
|
+
}
|
|
273
|
+
function proposedActionDisplay(proposal) {
|
|
274
|
+
if (proposal.type === "payment") {
|
|
275
|
+
const recipient = proposal.payment.recipient;
|
|
276
|
+
const recipientLabel = partyLabel(recipient);
|
|
277
|
+
const assetLabel = amountLabel(proposal.payment.amount);
|
|
278
|
+
return {
|
|
279
|
+
title: `Review payment proposal: ${assetLabel} to ${recipientLabel}`,
|
|
280
|
+
recipient,
|
|
281
|
+
target: proposal.payment.target
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
title: `Review Sui action proposal: ${proposal.action.actionKind}`,
|
|
286
|
+
...(proposal.action.recipient ? { recipient: proposal.action.recipient } : {}),
|
|
287
|
+
target: proposal.action.target
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function assetFlowForProposal(proposal) {
|
|
291
|
+
if (proposal.type === "payment") {
|
|
292
|
+
return {
|
|
293
|
+
outgoing: [proposal.payment.amount],
|
|
294
|
+
expectedIncoming: [],
|
|
295
|
+
fees: []
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
outgoing: amountsForDirection(proposal.action.assetFlow, "outgoing"),
|
|
300
|
+
expectedIncoming: amountsForDirection(proposal.action.assetFlow, "expected_incoming"),
|
|
301
|
+
fees: amountsForDirection(proposal.action.assetFlow, "fee")
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function amountsForDirection(flows, direction) {
|
|
305
|
+
return (flows ?? []).filter((flow) => flow.direction === direction).map((flow) => flow.amount);
|
|
306
|
+
}
|
|
307
|
+
function recipientsForProposal(proposal) {
|
|
308
|
+
if (proposal.type === "payment") {
|
|
309
|
+
return [proposal.payment.recipient];
|
|
310
|
+
}
|
|
311
|
+
const recipients = [
|
|
312
|
+
...(proposal.action.recipient ? [proposal.action.recipient] : []),
|
|
313
|
+
...(proposal.action.assetFlow ?? []).flatMap((flow) => (flow.recipient ? [flow.recipient] : []))
|
|
314
|
+
];
|
|
315
|
+
return dedupeParties(recipients);
|
|
316
|
+
}
|
|
317
|
+
function targetsForProposal(proposal) {
|
|
318
|
+
if (proposal.type === "payment") {
|
|
319
|
+
return proposal.payment.target ? [proposal.payment.target] : [];
|
|
320
|
+
}
|
|
321
|
+
return [proposal.action.target];
|
|
322
|
+
}
|
|
323
|
+
function dedupeParties(parties) {
|
|
324
|
+
const seen = new Set();
|
|
325
|
+
return parties.filter((party) => {
|
|
326
|
+
const key = `${party.address ?? ""}|${party.label ?? ""}`;
|
|
327
|
+
if (seen.has(key)) {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
seen.add(key);
|
|
331
|
+
return true;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function toDisplayIntentAmount(amount) {
|
|
335
|
+
return {
|
|
336
|
+
symbol: amount.symbol ?? amount.denomination ?? "unspecified_asset",
|
|
337
|
+
amount: amount.amountDisplay,
|
|
338
|
+
...(amount.coinType ? { coinType: amount.coinType } : {}),
|
|
339
|
+
amountKind: "display_intent"
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function partyLabel(party) {
|
|
343
|
+
return party.label ?? party.address ?? "unspecified recipient";
|
|
344
|
+
}
|
|
345
|
+
function amountLabel(amount) {
|
|
346
|
+
return `${amount.amountDisplay} ${amount.symbol ?? amount.denomination ?? "unspecified asset"}`;
|
|
347
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { validateMnemonic } from "@scure/bip39";
|
|
2
|
+
import { wordlist as englishBip39Wordlist } from "@scure/bip39/wordlists/english.js";
|
|
3
|
+
import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { suiAddressStringSchema } from "../suiAddress.js";
|
|
6
|
+
import { EXTERNAL_PROPOSAL_CONTRACT_VERSION, PROPOSAL_REVIEW_MODEL_VERSION } from "./types.js";
|
|
7
|
+
const isoUtcStringSchema = z.string().refine((value) => {
|
|
8
|
+
const parsed = new Date(value);
|
|
9
|
+
return !Number.isNaN(parsed.getTime()) && parsed.toISOString() === value;
|
|
10
|
+
}, "Expected ISO 8601 UTC timestamp");
|
|
11
|
+
const EXECUTABLE_MATERIAL_TEXT_PATTERN = /transaction\s*bytes?|transactionBytes|tx\s*bytes?|serialized\s*transaction|serializedTransaction|signed\s*transaction|signing\s*request|signingRequest|wallet\s*authorization|walletAuthorization|private\s*key|privateKey|secret\s*key|secretKey|seed\s*phrase|mnemonic|suiprivkey|signature|route[-_\s]*selected|routeSelectedPlan|bcs\s*transaction|programmable\s*transaction/i;
|
|
12
|
+
const LONG_HEX_OR_BASE64LIKE_PAYLOAD_PATTERN = /(?:0x[0-9a-fA-F]{160,}|[A-Za-z0-9+/_=-]{160,})/;
|
|
13
|
+
const SUI_PRIVATE_KEY_CANDIDATE_PATTERN = /suiprivkey1[023456789acdefghjklmnpqrstuvwxyz]+/gi;
|
|
14
|
+
const RAW_SECRET_HEX_PATTERN = /(^|[^0-9a-fA-F])(?:0x)?[0-9a-fA-F]{64}($|[^0-9a-fA-F])/;
|
|
15
|
+
const RAW_SECRET_BASE64_PATTERN = /(^|[^A-Za-z0-9+/_=-])(?:[A-Za-z0-9+/]{43}=|[A-Za-z0-9+/]{44}|[A-Za-z0-9_-]{43,44})($|[^A-Za-z0-9+/_=-])/;
|
|
16
|
+
const POSITIVE_DECIMAL_DISPLAY_AMOUNT_PATTERN = /^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/;
|
|
17
|
+
const BIP39_WORD_COUNTS = [12, 15, 18, 21, 24];
|
|
18
|
+
function proposalTextSchema(maxLength, fieldName, options = {}) {
|
|
19
|
+
return z.string().min(1).max(maxLength).superRefine((value, ctx) => {
|
|
20
|
+
if (EXECUTABLE_MATERIAL_TEXT_PATTERN.test(value) ||
|
|
21
|
+
LONG_HEX_OR_BASE64LIKE_PAYLOAD_PATTERN.test(value) ||
|
|
22
|
+
containsSuiPrivateKeyMaterial(value) ||
|
|
23
|
+
containsValidEnglishBip39Mnemonic(value) ||
|
|
24
|
+
(!options.allowRawSecretLikeText && containsRawSecretLikeText(value))) {
|
|
25
|
+
ctx.addIssue({
|
|
26
|
+
code: z.ZodIssueCode.custom,
|
|
27
|
+
message: `${fieldName} must not contain executable, signing, private-key, mnemonic, route-selected, or encoded secret-like material`
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function identifierTextSchema(maxLength, fieldName) {
|
|
33
|
+
return proposalTextSchema(maxLength, fieldName, { allowRawSecretLikeText: true });
|
|
34
|
+
}
|
|
35
|
+
function containsSuiPrivateKeyMaterial(value) {
|
|
36
|
+
const matches = value.match(SUI_PRIVATE_KEY_CANDIDATE_PATTERN) ?? [];
|
|
37
|
+
return matches.some((candidate) => {
|
|
38
|
+
try {
|
|
39
|
+
decodeSuiPrivateKey(candidate.toLowerCase());
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return candidate.toLowerCase().startsWith("suiprivkey1");
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function containsValidEnglishBip39Mnemonic(value) {
|
|
48
|
+
const words = value
|
|
49
|
+
.normalize("NFKD")
|
|
50
|
+
.toLowerCase()
|
|
51
|
+
.replace(/[^a-z]+/g, " ")
|
|
52
|
+
.trim()
|
|
53
|
+
.split(/\s+/)
|
|
54
|
+
.filter(Boolean);
|
|
55
|
+
for (const wordCount of BIP39_WORD_COUNTS) {
|
|
56
|
+
if (words.length < wordCount) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
for (let index = 0; index <= words.length - wordCount; index += 1) {
|
|
60
|
+
if (validateMnemonic(words.slice(index, index + wordCount).join(" "), englishBip39Wordlist)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function containsRawSecretLikeText(value) {
|
|
68
|
+
return RAW_SECRET_HEX_PATTERN.test(value) || RAW_SECRET_BASE64_PATTERN.test(value);
|
|
69
|
+
}
|
|
70
|
+
const proposalDisplayAmountSchema = proposalTextSchema(80, "amountDisplay").refine((value) => POSITIVE_DECIMAL_DISPLAY_AMOUNT_PATTERN.test(value) &&
|
|
71
|
+
/[1-9]/.test(value), {
|
|
72
|
+
message: "Expected a positive decimal display amount"
|
|
73
|
+
});
|
|
74
|
+
const externalProposalSourceSchema = z.object({
|
|
75
|
+
kind: z.enum(["mcp_server", "ai_client", "user", "other"]),
|
|
76
|
+
name: proposalTextSchema(120, "source.name"),
|
|
77
|
+
reference: proposalTextSchema(256, "source.reference").optional()
|
|
78
|
+
}).strict();
|
|
79
|
+
const externalProposalPartySchema = z.object({
|
|
80
|
+
address: suiAddressStringSchema.optional(),
|
|
81
|
+
label: proposalTextSchema(120, "party.label").optional()
|
|
82
|
+
}).strict().refine((party) => party.address !== undefined || party.label !== undefined, {
|
|
83
|
+
message: "Expected address or label"
|
|
84
|
+
});
|
|
85
|
+
const externalProposalAssetAmountSchema = z.object({
|
|
86
|
+
amountDisplay: proposalDisplayAmountSchema,
|
|
87
|
+
amountKind: z.literal("display_proposal").default("display_proposal"),
|
|
88
|
+
symbol: proposalTextSchema(64, "amount.symbol").optional(),
|
|
89
|
+
coinType: identifierTextSchema(512, "amount.coinType").optional(),
|
|
90
|
+
denomination: proposalTextSchema(64, "amount.denomination").optional()
|
|
91
|
+
}).strict();
|
|
92
|
+
const externalProposalActionTargetSchema = z.object({
|
|
93
|
+
packageId: identifierTextSchema(128, "action.target.packageId").optional(),
|
|
94
|
+
module: proposalTextSchema(128, "action.target.module").optional(),
|
|
95
|
+
function: proposalTextSchema(128, "action.target.function").optional(),
|
|
96
|
+
objectId: identifierTextSchema(128, "action.target.objectId").optional(),
|
|
97
|
+
label: proposalTextSchema(120, "action.target.label").optional()
|
|
98
|
+
}).strict().refine((target) => target.packageId !== undefined ||
|
|
99
|
+
target.module !== undefined ||
|
|
100
|
+
target.function !== undefined ||
|
|
101
|
+
target.objectId !== undefined ||
|
|
102
|
+
target.label !== undefined, { message: "Expected at least one action target field" });
|
|
103
|
+
const externalProposalAssetFlowItemSchema = z.object({
|
|
104
|
+
direction: z.enum(["outgoing", "expected_incoming", "fee"]),
|
|
105
|
+
amount: externalProposalAssetAmountSchema,
|
|
106
|
+
recipient: externalProposalPartySchema.optional(),
|
|
107
|
+
description: proposalTextSchema(512, "assetFlow.description").optional()
|
|
108
|
+
}).strict();
|
|
109
|
+
const externalProposalBaseSchema = z.object({
|
|
110
|
+
id: proposalTextSchema(120, "proposal.id"),
|
|
111
|
+
source: externalProposalSourceSchema,
|
|
112
|
+
network: z.literal("sui:mainnet"),
|
|
113
|
+
createdAt: isoUtcStringSchema,
|
|
114
|
+
expiresAt: isoUtcStringSchema.optional(),
|
|
115
|
+
purpose: proposalTextSchema(512, "purpose"),
|
|
116
|
+
assumptions: z.array(proposalTextSchema(512, "assumptions[]")).max(20).optional(),
|
|
117
|
+
requiredUserChoices: z.array(proposalTextSchema(512, "requiredUserChoices[]")).max(20).optional()
|
|
118
|
+
}).strict();
|
|
119
|
+
const externalPaymentProposalSchema = externalProposalBaseSchema.extend({
|
|
120
|
+
type: z.literal("payment"),
|
|
121
|
+
payment: z.object({
|
|
122
|
+
amount: externalProposalAssetAmountSchema,
|
|
123
|
+
recipient: externalProposalPartySchema,
|
|
124
|
+
target: proposalTextSchema(512, "payment.target").optional()
|
|
125
|
+
}).strict()
|
|
126
|
+
}).strict();
|
|
127
|
+
const externalSuiActionProposalSchema = externalProposalBaseSchema.extend({
|
|
128
|
+
type: z.literal("sui_action"),
|
|
129
|
+
action: z.object({
|
|
130
|
+
actionKind: proposalTextSchema(120, "action.actionKind"),
|
|
131
|
+
target: externalProposalActionTargetSchema,
|
|
132
|
+
recipient: externalProposalPartySchema.optional(),
|
|
133
|
+
assetFlow: z.array(externalProposalAssetFlowItemSchema).max(20).optional()
|
|
134
|
+
}).strict()
|
|
135
|
+
}).strict();
|
|
136
|
+
export const externalProposalSchema = z.discriminatedUnion("type", [
|
|
137
|
+
externalPaymentProposalSchema,
|
|
138
|
+
externalSuiActionProposalSchema
|
|
139
|
+
]);
|
|
140
|
+
const proposalReviewCheckSchema = z.object({
|
|
141
|
+
id: z.string(),
|
|
142
|
+
label: z.string(),
|
|
143
|
+
status: z.enum(["pass", "warning", "fail"]),
|
|
144
|
+
message: z.string(),
|
|
145
|
+
source: z.enum(["proposal", "adapter", "registry", "quote", "wallet", "simulation", "network"])
|
|
146
|
+
}).strict();
|
|
147
|
+
const proposalReviewGapSchema = z.object({
|
|
148
|
+
id: z.string(),
|
|
149
|
+
label: z.string(),
|
|
150
|
+
reason: z.string()
|
|
151
|
+
}).strict();
|
|
152
|
+
export const proposalReviewModelSchema = z.object({
|
|
153
|
+
modelVersion: z.literal(PROPOSAL_REVIEW_MODEL_VERSION),
|
|
154
|
+
contractVersion: z.literal(EXTERNAL_PROPOSAL_CONTRACT_VERSION),
|
|
155
|
+
proposalId: z.string(),
|
|
156
|
+
proposalType: z.enum(["payment", "sui_action"]),
|
|
157
|
+
proposalSource: externalProposalSourceSchema,
|
|
158
|
+
proposedAction: z.object({
|
|
159
|
+
kind: z.enum(["payment", "sui_action"]),
|
|
160
|
+
title: z.string(),
|
|
161
|
+
purpose: z.string(),
|
|
162
|
+
network: z.literal("sui:mainnet"),
|
|
163
|
+
recipient: externalProposalPartySchema.optional(),
|
|
164
|
+
target: z.union([z.string(), externalProposalActionTargetSchema]).optional()
|
|
165
|
+
}).strict(),
|
|
166
|
+
assetFlow: z.object({
|
|
167
|
+
outgoing: z.array(externalProposalAssetAmountSchema),
|
|
168
|
+
expectedIncoming: z.array(externalProposalAssetAmountSchema),
|
|
169
|
+
fees: z.array(externalProposalAssetAmountSchema)
|
|
170
|
+
}).strict(),
|
|
171
|
+
recipients: z.array(externalProposalPartySchema),
|
|
172
|
+
targets: z.array(z.union([z.string(), externalProposalActionTargetSchema])),
|
|
173
|
+
evidenceUsed: z.array(z.object({
|
|
174
|
+
id: z.string(),
|
|
175
|
+
label: z.string(),
|
|
176
|
+
source: z.enum(["external_proposal", "local_schema"]),
|
|
177
|
+
summary: z.string()
|
|
178
|
+
}).strict()),
|
|
179
|
+
missingEvidence: z.array(proposalReviewGapSchema),
|
|
180
|
+
requiredUserChoices: z.array(proposalReviewGapSchema),
|
|
181
|
+
unsupportedClaims: z.array(z.object({
|
|
182
|
+
id: z.string(),
|
|
183
|
+
label: z.string(),
|
|
184
|
+
reason: z.string()
|
|
185
|
+
}).strict()),
|
|
186
|
+
rejectedExecutableFields: z.array(z.object({
|
|
187
|
+
fieldName: z.string(),
|
|
188
|
+
reason: z.string()
|
|
189
|
+
}).strict()),
|
|
190
|
+
freshness: z.object({
|
|
191
|
+
proposalCreatedAt: isoUtcStringSchema,
|
|
192
|
+
proposalExpiresAt: isoUtcStringSchema.optional(),
|
|
193
|
+
evaluatedAt: isoUtcStringSchema,
|
|
194
|
+
status: z.enum(["current", "expired", "created_in_future", "expiry_not_provided"]),
|
|
195
|
+
reason: z.string()
|
|
196
|
+
}).strict(),
|
|
197
|
+
blockingChecks: z.array(proposalReviewCheckSchema),
|
|
198
|
+
nonSignableReason: z.object({
|
|
199
|
+
code: z.literal("external_proposal_review_only"),
|
|
200
|
+
message: z.string(),
|
|
201
|
+
blockedCapabilities: z.array(z.string())
|
|
202
|
+
}).strict()
|
|
203
|
+
}).strict();
|
|
204
|
+
export const externalProposalActionPlanDataSchema = z.object({
|
|
205
|
+
requestedIntent: externalProposalSchema,
|
|
206
|
+
implementationStatus: z.literal("read_only_review_only"),
|
|
207
|
+
contractVersion: z.literal(EXTERNAL_PROPOSAL_CONTRACT_VERSION)
|
|
208
|
+
}).strict();
|