@zktx.io/sui-mcp 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/LICENSES/@mysten-bcs-2.0.5-Apache-2.0.txt +205 -0
- package/LICENSES/@mysten-sui-2.17.0-Apache-2.0.txt +201 -0
- package/LICENSES/@mysten-utils-0.3.3-Apache-2.0.txt +205 -0
- package/LICENSES/fancy-canvas-2.1.0-MIT.txt +7 -0
- package/LICENSES/lightweight-charts-5.2.0-NOTICE.txt +2 -0
- package/README.md +288 -0
- package/dist/adapters/adapterLifecycleValidators.js +5 -0
- package/dist/adapters/adapterPromptSurfaces.js +60 -0
- package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +178 -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 +254 -0
- package/dist/adapters/intentPlanFactories.js +51 -0
- package/dist/adapters/reviewAdapters.js +47 -0
- package/dist/core/action/adapterLifecycleValidation.js +12 -0
- package/dist/core/action/contractNameRegistry.js +151 -0
- package/dist/core/action/forbiddenFields.js +43 -0
- package/dist/core/action/humanReadableReviewEvidence.js +193 -0
- package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
- package/dist/core/action/ptbVisualizationProducer.js +71 -0
- package/dist/core/action/receiptPtbGraph.js +29 -0
- package/dist/core/action/reviewCheckResults.js +6 -0
- package/dist/core/action/reviewStateValidation.js +11 -0
- package/dist/core/action/reviewTimeSimulationEvidence.js +470 -0
- package/dist/core/action/schemas.js +491 -0
- package/dist/core/action/signableAdapterContract.js +998 -0
- package/dist/core/action/suiChainReceiptEvidence.js +106 -0
- package/dist/core/action/suiChainReceiptMapping.js +107 -0
- package/dist/core/action/suiChainReceiptReader.js +211 -0
- package/dist/core/action/suiChainReceiptVerifier.js +178 -0
- package/dist/core/action/swapHumanReadableReviewProjection.js +130 -0
- package/dist/core/action/swapQuotePolicyEvidence.js +271 -0
- package/dist/core/action/transactionFunding.js +244 -0
- package/dist/core/action/transactionObjectOwnershipEvidence.js +256 -0
- package/dist/core/action/transactionObjectOwnershipProducer.js +323 -0
- package/dist/core/action/types.js +33 -0
- package/dist/core/action/walletReviewContractAssembler.js +286 -0
- package/dist/core/activity/accountAssetTimeline.js +157 -0
- package/dist/core/activity/accountAssetTimelineUsdcReferences.js +120 -0
- package/dist/core/activity/activityStore.js +16 -0
- package/dist/core/activity/externalActivityCoverage.js +76 -0
- package/dist/core/activity/externalActivityTransactionStream.js +82 -0
- package/dist/core/activity/localDataService.js +296 -0
- package/dist/core/activity/localDataTypes.js +11 -0
- package/dist/core/activity/localDataValidation.js +439 -0
- package/dist/core/activity/schemaVersion.js +2 -0
- package/dist/core/activity/sqliteActivityStore.js +1068 -0
- package/dist/core/activity/sqliteActivityStoreRows.js +389 -0
- package/dist/core/activity/sqliteActivityStoreSchema.js +367 -0
- package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
- package/dist/core/activity/suiFunctionTarget.js +43 -0
- package/dist/core/activity/transactionActivityAccountEffects.js +186 -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 +85 -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/deepbookOfficialIndexerSource.js +373 -0
- package/dist/core/read/deepbookRawQuoteClient.js +86 -0
- package/dist/core/read/deepbookReadHelpers.js +321 -0
- package/dist/core/read/deepbookRegistry.js +157 -0
- package/dist/core/read/deepbookSourceOwners.js +159 -0
- package/dist/core/read/deepbookUsdcChartService.js +342 -0
- package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
- package/dist/core/read/readCardInputs.js +19 -0
- package/dist/core/read/readCardResult.js +40 -0
- package/dist/core/read/readResponseGuidance.js +402 -0
- package/dist/core/read/readService.js +1639 -0
- package/dist/core/read/readServiceTypes.js +88 -0
- package/dist/core/read/settlementParityFormatting.js +82 -0
- package/dist/core/read/walletReadHelpers.js +99 -0
- package/dist/core/review/reviewChecks.js +45 -0
- package/dist/core/review/reviewComputation.js +38 -0
- package/dist/core/review/reviewComputationResult.js +87 -0
- package/dist/core/session/cardSession.js +31 -0
- package/dist/core/session/cardSessionStore.js +204 -0
- package/dist/core/session/keyedRecordStore.js +18 -0
- package/dist/core/session/liveReviewSessionContract.js +3 -0
- package/dist/core/session/localSession.js +31 -0
- package/dist/core/session/privateReviewArtifacts.js +75 -0
- package/dist/core/session/reviewValidity.js +49 -0
- package/dist/core/session/sessionErrors.js +9 -0
- package/dist/core/session/sessionRecordStore.js +40 -0
- package/dist/core/session/sessionStore.js +655 -0
- package/dist/core/session/settingsSession.js +1 -0
- package/dist/core/session/settingsSessions.js +45 -0
- package/dist/core/session/sqliteCardStore.js +88 -0
- package/dist/core/session/sqliteSessionStore.js +213 -0
- package/dist/core/session/sqliteTransactionMaterialStore.js +64 -0
- package/dist/core/session/sqliteWalletWorkflowStore.js +821 -0
- package/dist/core/session/status.js +60 -0
- package/dist/core/session/transactionMaterialStore.js +221 -0
- package/dist/core/session/transactionRequest.js +72 -0
- package/dist/core/session/wait.js +79 -0
- package/dist/core/session/walletConnection.js +92 -0
- package/dist/core/session/walletRuntime.js +38 -0
- package/dist/core/session/walletWorkflow.js +608 -0
- package/dist/core/session/workflowState.js +80 -0
- package/dist/core/session/workflowView.js +150 -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 +326 -0
- package/dist/mcp/result.js +17 -0
- package/dist/mcp/schemas.js +11 -0
- package/dist/mcp/server.js +32 -0
- package/dist/mcp/serverInfo.js +131 -0
- package/dist/mcp/toolErrors.js +118 -0
- package/dist/mcp/toolNames.js +58 -0
- package/dist/mcp/tools/account/index.js +44 -0
- package/dist/mcp/tools/action/prepareSuiActionReview.js +126 -0
- package/dist/mcp/tools/read/commonSchemas.js +43 -0
- package/dist/mcp/tools/read/deepbookReadTools.js +686 -0
- package/dist/mcp/tools/read/index.js +14 -0
- package/dist/mcp/tools/read/readToolHelpers.js +97 -0
- package/dist/mcp/tools/read/reviewActivityTools.js +179 -0
- package/dist/mcp/tools/read/serverStatusTools.js +100 -0
- package/dist/mcp/tools/read/transactionActivityOutput.js +371 -0
- package/dist/mcp/tools/read/transactionActivityTools.js +858 -0
- package/dist/mcp/tools/read/walletReadTools.js +734 -0
- package/dist/mcp/tools/session/executionResultTools.js +44 -0
- package/dist/mcp/tools/session/index.js +8 -0
- package/dist/mcp/tools/session/shared.js +36 -0
- package/dist/mcp/tools/session/statusTools.js +69 -0
- package/dist/mcp/tools/session/walletConnectionTools.js +69 -0
- package/dist/mcp/tools/settings/index.js +66 -0
- package/dist/mcp-app/account.html +3133 -0
- package/dist/mcp-app/account.notices.txt +973 -0
- package/dist/mcp-app/chart.html +3354 -0
- package/dist/mcp-app/chart.notices.txt +1194 -0
- package/dist/mcp-app/connect.html +3179 -0
- package/dist/mcp-app/connect.notices.txt +1012 -0
- package/dist/mcp-app/receipt.html +8430 -0
- package/dist/mcp-app/receipt.notices.txt +3549 -0
- package/dist/mcp-app/review.html +8430 -0
- package/dist/mcp-app/review.notices.txt +3549 -0
- package/dist/mcp-ui/contracts.js +31 -0
- package/dist/mcp-ui/readCards.js +28 -0
- package/dist/mcp-ui/tools.js +134 -0
- package/dist/review-app/brand-dark.svg +1 -0
- package/dist/review-app/brand-light.svg +1 -0
- package/dist/review-app/favicon.svg +1 -0
- package/dist/review-app/settings.css +1 -0
- package/dist/review-app/settings.js +1 -0
- package/dist/review-app/ui.css +809 -0
- package/dist/review-server/assets.js +48 -0
- package/dist/review-server/html.js +45 -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 +1 -0
- package/dist/review-server/server.js +72 -0
- package/dist/review-server/settingsApi.js +158 -0
- package/dist/runtime/application.js +203 -0
- package/dist/runtime/config.js +97 -0
- package/dist/runtime/localSettingsService.js +198 -0
- package/dist/runtime/logger.js +66 -0
- package/dist/runtime/reviewDependencies.js +58 -0
- package/dist/runtime/reviewServerAcquire.js +93 -0
- package/dist/runtime/runtimeTermination.js +60 -0
- package/dist/runtime/shared/authenticatedFetch.js +127 -0
- package/dist/runtime/shared/control.js +93 -0
- package/dist/runtime/shared/dataAccess.js +66 -0
- package/dist/runtime/shared/mcpHttp.js +84 -0
- package/dist/runtime/shared/ownerLease.js +50 -0
- package/dist/runtime/shared/server.js +98 -0
- package/dist/runtime/shared/stdio.js +113 -0
- package/dist/runtime/smokeMainnetRead.js +391 -0
- package/dist/runtime/smokeMainnetReadAssertions.js +306 -0
- package/dist/runtime/smokeReview.js +40 -0
- package/dist/runtime/start.js +90 -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/dist/runtime/walletConnectConfig.js +3 -0
- package/dist/runtime/walletConnectStorage.js +99 -0
- package/dist/runtime/walletConnectTransport.js +128 -0
- package/dist/runtime/walletSdkChild.js +3 -0
- package/dist/runtime/walletSdkChildRuntime.js +160 -0
- package/dist/runtime/walletSdkIpc.js +26 -0
- package/dist/runtime/walletSdkProcess.js +358 -0
- package/docs/AGENT_BEHAVIOR.md +524 -0
- package/docs/AGENT_DEVELOPMENT_POLICY.md +815 -0
- package/docs/FRONTEND_POLICY.md +534 -0
- package/docs/LOCAL_DB_ARCHITECTURE.md +381 -0
- package/docs/MCP_SETUP.md +742 -0
- package/docs/MCP_TOOLS.md +1318 -0
- package/docs/SDK_API.md +206 -0
- package/docs/SIGNABLE_ADAPTER_CONTRACT.md +396 -0
- package/docs/TRANSACTION_ACTIVITY_LOG.md +194 -0
- package/docs/UTILITY_INDEX.md +275 -0
- package/docs/WALLET_CONNECTION.md +238 -0
- package/docs/golden-scenarios/BEHAVIOR_MATRIX.md +166 -0
- package/docs/golden-scenarios/INTENT_EVIDENCE_GOLDEN_ANSWERS.md +161 -0
- package/docs/golden-scenarios/INTENT_EVIDENCE_MATRIX.md +259 -0
- package/package.json +79 -0
- package/protocols/deepbook-margin.md +15 -0
- package/protocols/deepbook-v3.md +24 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { createRuntimeReviewDependencies } from "./reviewDependencies.js";
|
|
2
|
+
import { computeSmokeReview, SmokeReviewConfigError } from "./smokeReview.js";
|
|
3
|
+
import { parseSuiAddress } from "../core/suiAddress.js";
|
|
4
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { randomInt } from "node:crypto";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
|
+
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
10
|
+
import { validateSupportedAdapterLifecycle } from "../adapters/adapterLifecycleValidators.js";
|
|
11
|
+
import { SqliteActivityStore } from "../core/activity/sqliteActivityStore.js";
|
|
12
|
+
import { TransactionActivityService } from "../core/activity/transactionActivityService.js";
|
|
13
|
+
import { createSuiReadService } from "../core/read/readService.js";
|
|
14
|
+
import { DeepbookOfficialIndexerSource } from "../core/read/deepbookOfficialIndexerSource.js";
|
|
15
|
+
import { LocalSessionStore } from "../core/session/sessionStore.js";
|
|
16
|
+
import { createMcpServer } from "../mcp/server.js";
|
|
17
|
+
import { TOOL_NAMES } from "../mcp/toolNames.js";
|
|
18
|
+
import { DEFAULT_SUI_GRAPHQL_URL, DEFAULT_SUI_GRPC_URL, composeRuntimeConfig, loadBootConfig } from "./config.js";
|
|
19
|
+
import { RuntimeLocalSettingsService } from "./localSettingsService.js";
|
|
20
|
+
import { createStderrLogger } from "./logger.js";
|
|
21
|
+
import { SmokeResponseShapeError, assertSmokeOkStatus, summarizeActivitySmokePayload } from "./smokeMainnetReadAssertions.js";
|
|
22
|
+
import { SuiEndpointError, verifyMainnetGraphqlEndpoint, verifyMainnetGrpcEndpoint } from "./suiEndpoint.js";
|
|
23
|
+
import { GraphqlSuiTransactionActivitySource } from "./suiTransactionGraphqlSource.js";
|
|
24
|
+
const startedAt = new Date();
|
|
25
|
+
const smokeFunctionTarget = process.env.SMOKE_FUNCTION_TARGET;
|
|
26
|
+
const plannedTools = [
|
|
27
|
+
TOOL_NAMES.readSummarizeWalletAssets,
|
|
28
|
+
TOOL_NAMES.readInspectDeepbookOrderbook,
|
|
29
|
+
TOOL_NAMES.readQuoteDeepbookAction,
|
|
30
|
+
TOOL_NAMES.readScanSuiAccountActivity,
|
|
31
|
+
TOOL_NAMES.readSummarizeSuiActivityScan,
|
|
32
|
+
...(smokeFunctionTarget
|
|
33
|
+
? [
|
|
34
|
+
TOOL_NAMES.readScanSuiFunctionActivity,
|
|
35
|
+
TOOL_NAMES.readSummarizeSuiFunctionActivityScan
|
|
36
|
+
]
|
|
37
|
+
: [])
|
|
38
|
+
];
|
|
39
|
+
const attemptedTools = [];
|
|
40
|
+
const completedTools = [];
|
|
41
|
+
const activitySmoke = {};
|
|
42
|
+
const functionActivitySmoke = smokeFunctionTarget
|
|
43
|
+
? {
|
|
44
|
+
tools: [
|
|
45
|
+
TOOL_NAMES.readScanSuiFunctionActivity,
|
|
46
|
+
TOOL_NAMES.readSummarizeSuiFunctionActivityScan
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
: {
|
|
50
|
+
status: "not_run",
|
|
51
|
+
tools: [
|
|
52
|
+
TOOL_NAMES.readScanSuiFunctionActivity,
|
|
53
|
+
TOOL_NAMES.readSummarizeSuiFunctionActivityScan
|
|
54
|
+
],
|
|
55
|
+
notRunReason: "missing_env"
|
|
56
|
+
};
|
|
57
|
+
const ACTIVITY_SMOKE_LIMIT = 5;
|
|
58
|
+
class SmokeMainnetError extends Error {
|
|
59
|
+
category;
|
|
60
|
+
constructor(category, message) {
|
|
61
|
+
super(message);
|
|
62
|
+
this.category = category;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function main() {
|
|
66
|
+
const logger = createStderrLogger("smoke-mainnet");
|
|
67
|
+
const bootConfig = loadSmokeBootConfig();
|
|
68
|
+
const smokeAddress = parseSuiAddress(requiredEnv("SMOKE_SUI_ADDRESS")) ?? fail("config_error", "SMOKE_SUI_ADDRESS must be a Sui address.");
|
|
69
|
+
const poolKey = requiredEnv("SMOKE_DEEPBOOK_POOL_KEY");
|
|
70
|
+
const quoteAmount = requiredEnv("SMOKE_QUOTE_AMOUNT");
|
|
71
|
+
const inspectDigest = process.env.SMOKE_INSPECT_DIGEST;
|
|
72
|
+
const inspectRandomLatest = truthyEnv("SMOKE_INSPECT_RANDOM_LATEST");
|
|
73
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
74
|
+
const client = new Client({ name: "sui-mcp-smoke", version: "0.0.0" });
|
|
75
|
+
let smokeDbDir;
|
|
76
|
+
let activityStore;
|
|
77
|
+
let server;
|
|
78
|
+
try {
|
|
79
|
+
smokeDbDir = mkdtempSync(join(tmpdir(), "sui-mcp-smoke-db-"));
|
|
80
|
+
activityStore = new SqliteActivityStore({
|
|
81
|
+
databasePath: join(smokeDbDir, "sui-mcp.sqlite"),
|
|
82
|
+
validateAdapterLifecycle: validateSupportedAdapterLifecycle
|
|
83
|
+
});
|
|
84
|
+
const preferencesRepository = activityStore.createPreferencesRepository();
|
|
85
|
+
await preferencesRepository.ensureDefaultLocalSettings({
|
|
86
|
+
suiGrpcUrl: DEFAULT_SUI_GRPC_URL,
|
|
87
|
+
suiGraphqlUrl: DEFAULT_SUI_GRAPHQL_URL
|
|
88
|
+
});
|
|
89
|
+
const storedSuiGrpcUrl = await preferencesRepository.getSuiGrpcUrl();
|
|
90
|
+
const storedSuiGraphqlUrl = await preferencesRepository.getSuiGraphqlUrl();
|
|
91
|
+
const config = composeRuntimeConfig({
|
|
92
|
+
bootConfig,
|
|
93
|
+
env: process.env,
|
|
94
|
+
storedSuiGrpcUrl: storedSuiGrpcUrl?.value,
|
|
95
|
+
storedSuiGraphqlUrl: storedSuiGraphqlUrl?.value,
|
|
96
|
+
defaultSuiGrpcUrl: DEFAULT_SUI_GRPC_URL,
|
|
97
|
+
defaultSuiGraphqlUrl: DEFAULT_SUI_GRAPHQL_URL
|
|
98
|
+
});
|
|
99
|
+
const { client: suiClient, chainIdentifier } = await verifyMainnetGrpcEndpoint({
|
|
100
|
+
url: config.grpcUrl,
|
|
101
|
+
expectedChainIdentifier: config.expectedChainIdentifier
|
|
102
|
+
});
|
|
103
|
+
const localSettings = new RuntimeLocalSettingsService({
|
|
104
|
+
preferencesRepository,
|
|
105
|
+
env: process.env,
|
|
106
|
+
defaultSuiGrpcUrl: DEFAULT_SUI_GRPC_URL,
|
|
107
|
+
defaultSuiGraphqlUrl: DEFAULT_SUI_GRAPHQL_URL,
|
|
108
|
+
bootSuiGrpcUrl: config.suiGrpcUrl,
|
|
109
|
+
bootSuiGraphqlUrl: config.suiGraphqlUrl
|
|
110
|
+
});
|
|
111
|
+
const readService = createSuiReadService({
|
|
112
|
+
client: suiClient,
|
|
113
|
+
network: config.network,
|
|
114
|
+
chainIdentifier,
|
|
115
|
+
coinMetadataCache: activityStore.createCoinMetadataCache(),
|
|
116
|
+
deepbookOfficialIndexerSource: new DeepbookOfficialIndexerSource()
|
|
117
|
+
});
|
|
118
|
+
const transactionMaterialStore = activityStore.createTransactionMaterialStore();
|
|
119
|
+
const sessions = new LocalSessionStore({
|
|
120
|
+
activityStore,
|
|
121
|
+
logger,
|
|
122
|
+
validateAdapterLifecycle: validateSupportedAdapterLifecycle,
|
|
123
|
+
sessions: activityStore.createSessionRecordStore(),
|
|
124
|
+
artifacts: activityStore.createPrivateReviewArtifactStore(),
|
|
125
|
+
settingsStore: activityStore.createSettingsRecordStore()
|
|
126
|
+
});
|
|
127
|
+
const reviewDependencies = createRuntimeReviewDependencies({ client: suiClient, chainIdentifier,
|
|
128
|
+
expectedChainIdentifier: config.expectedChainIdentifier, materialStore: transactionMaterialStore, readService });
|
|
129
|
+
// Utility-only read context in this script's temporary DB. This does not
|
|
130
|
+
// create a live wallet session or prove address ownership.
|
|
131
|
+
await activityStore.setActiveAccount(smokeAddress, "wallet_connection", new Date(), { name: "Explicit smoke read fixture" });
|
|
132
|
+
server = createMcpServer({
|
|
133
|
+
sessions,
|
|
134
|
+
activityStore,
|
|
135
|
+
localSettings,
|
|
136
|
+
readService,
|
|
137
|
+
transactionActivityService: new TransactionActivityService({
|
|
138
|
+
activityStore,
|
|
139
|
+
source: new GraphqlSuiTransactionActivitySource({
|
|
140
|
+
url: config.graphqlUrl,
|
|
141
|
+
expectedChainIdentifier: config.expectedChainIdentifier
|
|
142
|
+
})
|
|
143
|
+
}),
|
|
144
|
+
logger
|
|
145
|
+
});
|
|
146
|
+
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
|
147
|
+
const accountBoundSwapReview = await computeSmokeReview({ env: process.env, account: smokeAddress, sessions, computation: reviewDependencies });
|
|
148
|
+
if (accountBoundSwapReview.status === "ok")
|
|
149
|
+
markCompleted("account_bound_swap_review");
|
|
150
|
+
const wallet = await callSmokeTool(client, TOOL_NAMES.readSummarizeWalletAssets, {});
|
|
151
|
+
const orderbook = await callSmokeTool(client, TOOL_NAMES.readInspectDeepbookOrderbook, {
|
|
152
|
+
poolKey,
|
|
153
|
+
ticks: 5
|
|
154
|
+
});
|
|
155
|
+
const quote = await callSmokeTool(client, TOOL_NAMES.readQuoteDeepbookAction, {
|
|
156
|
+
poolKey,
|
|
157
|
+
direction: "base_to_quote",
|
|
158
|
+
amountRaw: quoteAmount
|
|
159
|
+
});
|
|
160
|
+
const activityScan = await callSmokeTool(client, TOOL_NAMES.readScanSuiAccountActivity, {
|
|
161
|
+
account: smokeAddress,
|
|
162
|
+
limit: ACTIVITY_SMOKE_LIMIT
|
|
163
|
+
});
|
|
164
|
+
const activitySummary = await callSmokeTool(client, TOOL_NAMES.readSummarizeSuiActivityScan, {
|
|
165
|
+
limit: ACTIVITY_SMOKE_LIMIT
|
|
166
|
+
});
|
|
167
|
+
assertSmokeOkStatus(wallet, TOOL_NAMES.readSummarizeWalletAssets);
|
|
168
|
+
markCompleted(TOOL_NAMES.readSummarizeWalletAssets);
|
|
169
|
+
assertSmokeOkStatus(orderbook, TOOL_NAMES.readInspectDeepbookOrderbook);
|
|
170
|
+
markCompleted(TOOL_NAMES.readInspectDeepbookOrderbook);
|
|
171
|
+
assertSmokeOkStatus(quote, TOOL_NAMES.readQuoteDeepbookAction);
|
|
172
|
+
markCompleted(TOOL_NAMES.readQuoteDeepbookAction);
|
|
173
|
+
activitySmoke.scan = summarizeActivitySmokePayload(activityScan, TOOL_NAMES.readScanSuiAccountActivity, {
|
|
174
|
+
expectedAccountSource: "explicit_filter",
|
|
175
|
+
requireAnalysis: false,
|
|
176
|
+
expectNoDetails: true
|
|
177
|
+
});
|
|
178
|
+
markCompleted(TOOL_NAMES.readScanSuiAccountActivity);
|
|
179
|
+
activitySmoke.summary = summarizeActivitySmokePayload(activitySummary, TOOL_NAMES.readSummarizeSuiActivityScan, {
|
|
180
|
+
expectedAccountSource: "active_account_context",
|
|
181
|
+
requireAnalysis: true,
|
|
182
|
+
expectNoDetails: true
|
|
183
|
+
});
|
|
184
|
+
markCompleted(TOOL_NAMES.readSummarizeSuiActivityScan);
|
|
185
|
+
if (smokeFunctionTarget) {
|
|
186
|
+
const functionActivityScan = await callSmokeTool(client, TOOL_NAMES.readScanSuiFunctionActivity, {
|
|
187
|
+
function: smokeFunctionTarget,
|
|
188
|
+
account: smokeAddress,
|
|
189
|
+
limit: ACTIVITY_SMOKE_LIMIT
|
|
190
|
+
});
|
|
191
|
+
const functionActivitySummary = await callSmokeTool(client, TOOL_NAMES.readSummarizeSuiFunctionActivityScan, {
|
|
192
|
+
function: smokeFunctionTarget,
|
|
193
|
+
limit: ACTIVITY_SMOKE_LIMIT
|
|
194
|
+
});
|
|
195
|
+
functionActivitySmoke.scan = summarizeActivitySmokePayload(functionActivityScan, TOOL_NAMES.readScanSuiFunctionActivity, {
|
|
196
|
+
expectedAccountSource: "explicit_filter",
|
|
197
|
+
expectedRelationship: "sent",
|
|
198
|
+
requireFunction: true,
|
|
199
|
+
requireAnalysis: false,
|
|
200
|
+
expectNoDetails: true
|
|
201
|
+
});
|
|
202
|
+
markCompleted(TOOL_NAMES.readScanSuiFunctionActivity);
|
|
203
|
+
functionActivitySmoke.summary = summarizeActivitySmokePayload(functionActivitySummary, TOOL_NAMES.readSummarizeSuiFunctionActivityScan, {
|
|
204
|
+
expectedAccountSource: "active_account_context",
|
|
205
|
+
expectedRelationship: "sent",
|
|
206
|
+
requireFunction: true,
|
|
207
|
+
requireAnalysis: true,
|
|
208
|
+
expectNoDetails: true
|
|
209
|
+
});
|
|
210
|
+
markCompleted(TOOL_NAMES.readSummarizeSuiFunctionActivityScan);
|
|
211
|
+
}
|
|
212
|
+
if (inspectDigest) {
|
|
213
|
+
const inspected = await callSmokeTool(client, TOOL_NAMES.readInspectSuiTransaction, {
|
|
214
|
+
digest: inspectDigest,
|
|
215
|
+
account: smokeAddress
|
|
216
|
+
});
|
|
217
|
+
assertSmokeOkStatus(inspected, TOOL_NAMES.readInspectSuiTransaction);
|
|
218
|
+
markCompleted(TOOL_NAMES.readInspectSuiTransaction);
|
|
219
|
+
}
|
|
220
|
+
else if (inspectRandomLatest) {
|
|
221
|
+
const randomLatestDigest = await pickRandomLatestTransactionDigest({
|
|
222
|
+
url: config.graphqlUrl,
|
|
223
|
+
expectedChainIdentifier: config.expectedChainIdentifier
|
|
224
|
+
});
|
|
225
|
+
const inspected = await callSmokeTool(client, TOOL_NAMES.readInspectSuiTransaction, {
|
|
226
|
+
digest: randomLatestDigest
|
|
227
|
+
});
|
|
228
|
+
assertSmokeOkStatus(inspected, TOOL_NAMES.readInspectSuiTransaction);
|
|
229
|
+
markCompleted(TOOL_NAMES.readInspectSuiTransaction);
|
|
230
|
+
}
|
|
231
|
+
tryWriteSmokeResult({
|
|
232
|
+
accountBoundSwapReview,
|
|
233
|
+
ok: true,
|
|
234
|
+
startedAt: startedAt.toISOString(),
|
|
235
|
+
completedAt: new Date().toISOString(),
|
|
236
|
+
chainIdentifier,
|
|
237
|
+
env: smokeEnvPresence(),
|
|
238
|
+
plannedTools: [...plannedTools],
|
|
239
|
+
attemptedTools,
|
|
240
|
+
tools: completedTools,
|
|
241
|
+
activitySmoke,
|
|
242
|
+
functionActivitySmoke
|
|
243
|
+
});
|
|
244
|
+
process.stdout.write(`${JSON.stringify({
|
|
245
|
+
ok: true,
|
|
246
|
+
plannedTools: [...plannedTools],
|
|
247
|
+
attemptedTools,
|
|
248
|
+
tools: completedTools,
|
|
249
|
+
activitySmoke,
|
|
250
|
+
functionActivitySmoke
|
|
251
|
+
}, null, 2)}\n`);
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
await Promise.allSettled([
|
|
255
|
+
...(server ? [server.close()] : []),
|
|
256
|
+
client.close(),
|
|
257
|
+
]);
|
|
258
|
+
activityStore?.close();
|
|
259
|
+
if (smokeDbDir)
|
|
260
|
+
rmSync(smokeDbDir, { recursive: true, force: true });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async function callSmokeTool(client, name, args) {
|
|
264
|
+
attemptedTools.push(name);
|
|
265
|
+
return callTool(client, name, args);
|
|
266
|
+
}
|
|
267
|
+
async function callTool(client, name, args) {
|
|
268
|
+
const result = await client.callTool({ name, arguments: args });
|
|
269
|
+
const content = result.content;
|
|
270
|
+
const text = content[0]?.type === "text" ? content[0].text : undefined;
|
|
271
|
+
if (!text) {
|
|
272
|
+
fail("tool_failure", `Tool ${name} did not return text JSON content`);
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
return JSON.parse(text);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
throw new SmokeResponseShapeError(`Tool ${name} did not return valid text JSON content: ${error instanceof Error ? error.message : String(error)}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function markCompleted(name) {
|
|
282
|
+
if (!completedTools.includes(name)) {
|
|
283
|
+
completedTools.push(name);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function requiredEnv(name) {
|
|
287
|
+
const value = process.env[name];
|
|
288
|
+
if (!value) {
|
|
289
|
+
fail("missing_env", `${name} is required for npm run smoke:mainnet`);
|
|
290
|
+
}
|
|
291
|
+
return value;
|
|
292
|
+
}
|
|
293
|
+
function truthyEnv(name) {
|
|
294
|
+
const value = process.env[name];
|
|
295
|
+
return value === "1" || value === "true" || value === "TRUE" || value === "yes" || value === "YES";
|
|
296
|
+
}
|
|
297
|
+
async function pickRandomLatestTransactionDigest(input) {
|
|
298
|
+
const { client } = await verifyMainnetGraphqlEndpoint({
|
|
299
|
+
url: input.url,
|
|
300
|
+
expectedChainIdentifier: input.expectedChainIdentifier
|
|
301
|
+
});
|
|
302
|
+
const result = await client.query({
|
|
303
|
+
query: `
|
|
304
|
+
query SuiMcpSmokeLatestTransactionSample($last: Int!) {
|
|
305
|
+
transactions(last: $last) {
|
|
306
|
+
nodes { digest }
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
`,
|
|
310
|
+
variables: { last: 20 }
|
|
311
|
+
});
|
|
312
|
+
if (result.errors && result.errors.length > 0) {
|
|
313
|
+
fail("tool_failure", `Latest transaction sample query failed: ${result.errors.map((error) => error.message).join("; ")}`);
|
|
314
|
+
}
|
|
315
|
+
const digests = result.data?.transactions?.nodes
|
|
316
|
+
?.flatMap((node) => typeof node.digest === "string" && node.digest.length > 0 ? [node.digest] : []) ?? [];
|
|
317
|
+
if (digests.length === 0) {
|
|
318
|
+
fail("tool_failure", "Latest transaction sample query returned no transaction digests");
|
|
319
|
+
}
|
|
320
|
+
return digests[randomInt(digests.length)] ?? fail("tool_failure", "Latest transaction sample selection failed");
|
|
321
|
+
}
|
|
322
|
+
function loadSmokeBootConfig() {
|
|
323
|
+
try {
|
|
324
|
+
return loadBootConfig();
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
throw new SmokeMainnetError("config_error", error instanceof Error ? error.message : String(error));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function fail(category, message) {
|
|
331
|
+
throw new SmokeMainnetError(category, message);
|
|
332
|
+
}
|
|
333
|
+
function smokeEnvPresence() {
|
|
334
|
+
return {
|
|
335
|
+
SUI_GRPC_URL: process.env.SUI_GRPC_URL !== undefined,
|
|
336
|
+
SUI_GRAPHQL_URL: process.env.SUI_GRAPHQL_URL !== undefined,
|
|
337
|
+
SMOKE_SUI_ADDRESS: process.env.SMOKE_SUI_ADDRESS !== undefined,
|
|
338
|
+
SMOKE_DEEPBOOK_POOL_KEY: process.env.SMOKE_DEEPBOOK_POOL_KEY !== undefined,
|
|
339
|
+
SMOKE_QUOTE_AMOUNT: process.env.SMOKE_QUOTE_AMOUNT !== undefined,
|
|
340
|
+
SMOKE_INSPECT_DIGEST: process.env.SMOKE_INSPECT_DIGEST !== undefined,
|
|
341
|
+
SMOKE_INSPECT_RANDOM_LATEST: process.env.SMOKE_INSPECT_RANDOM_LATEST !== undefined,
|
|
342
|
+
SMOKE_FUNCTION_TARGET: process.env.SMOKE_FUNCTION_TARGET !== undefined,
|
|
343
|
+
SMOKE_SWAP_PROTOCOL: process.env.SMOKE_SWAP_PROTOCOL !== undefined,
|
|
344
|
+
SMOKE_SWAP_FROM_SYMBOL: process.env.SMOKE_SWAP_FROM_SYMBOL !== undefined,
|
|
345
|
+
SMOKE_SWAP_TO_SYMBOL: process.env.SMOKE_SWAP_TO_SYMBOL !== undefined,
|
|
346
|
+
SMOKE_SWAP_AMOUNT_DISPLAY: process.env.SMOKE_SWAP_AMOUNT_DISPLAY !== undefined
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function tryWriteSmokeResult(record) {
|
|
350
|
+
try {
|
|
351
|
+
writeSmokeResult(record);
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
process.stderr.write(`smoke:mainnet result recording failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function writeSmokeResult(record) {
|
|
358
|
+
const directory = join(process.cwd(), ".WORK", "smoke-results");
|
|
359
|
+
mkdirSync(directory, { recursive: true });
|
|
360
|
+
writeFileSync(join(directory, `${record.completedAt ?? new Date().toISOString()}.json`.replace(/:/g, "-")), `${JSON.stringify(record, null, 2)}\n`);
|
|
361
|
+
}
|
|
362
|
+
function smokeErrorCategory(error) {
|
|
363
|
+
if (error instanceof SuiEndpointError) {
|
|
364
|
+
return error.kind;
|
|
365
|
+
}
|
|
366
|
+
if (error instanceof SmokeResponseShapeError) {
|
|
367
|
+
return "tool_failure";
|
|
368
|
+
}
|
|
369
|
+
if (error instanceof SmokeReviewConfigError)
|
|
370
|
+
return "config_error";
|
|
371
|
+
if (error instanceof SmokeMainnetError) {
|
|
372
|
+
return error.category;
|
|
373
|
+
}
|
|
374
|
+
return "runtime_error";
|
|
375
|
+
}
|
|
376
|
+
main().catch((error) => {
|
|
377
|
+
tryWriteSmokeResult({
|
|
378
|
+
ok: false,
|
|
379
|
+
startedAt: startedAt.toISOString(),
|
|
380
|
+
completedAt: new Date().toISOString(),
|
|
381
|
+
env: smokeEnvPresence(),
|
|
382
|
+
attemptedTools,
|
|
383
|
+
tools: completedTools,
|
|
384
|
+
plannedTools: [...plannedTools],
|
|
385
|
+
activitySmoke,
|
|
386
|
+
functionActivitySmoke,
|
|
387
|
+
errorCategory: smokeErrorCategory(error)
|
|
388
|
+
});
|
|
389
|
+
process.stderr.write(`smoke:mainnet failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
390
|
+
process.exit(1);
|
|
391
|
+
});
|