@truecarry/mcp 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +654 -1579
- package/dist/factory.d.ts +35 -21
- package/dist/factory.d.ts.map +1 -1
- package/dist/index.cjs +781 -4180
- package/dist/index.d.ts +5 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +781 -4167
- package/dist/services/McpWalletService.d.ts +74 -133
- package/dist/services/McpWalletService.d.ts.map +1 -1
- package/dist/tools/balance-tools.d.ts +61 -0
- package/dist/tools/balance-tools.d.ts.map +1 -0
- package/dist/tools/index.d.ts +5 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/known-jettons-tools.d.ts +44 -0
- package/dist/tools/known-jettons-tools.d.ts.map +1 -0
- package/dist/tools/nft-tools.d.ts +85 -0
- package/dist/tools/nft-tools.d.ts.map +1 -0
- package/dist/tools/swap-tools.d.ts +49 -0
- package/dist/tools/swap-tools.d.ts.map +1 -0
- package/dist/tools/transfer-tools.d.ts +159 -0
- package/dist/tools/transfer-tools.d.ts.map +1 -0
- package/dist/tools/types.d.ts +21 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/types/config.d.ts +12 -36
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -4
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/adapters/InMemoryStorageAdapter.d.ts +0 -49
- package/dist/adapters/InMemoryStorageAdapter.d.ts.map +0 -1
- package/dist/adapters/LocalSignerAdapter.d.ts +0 -107
- package/dist/adapters/LocalSignerAdapter.d.ts.map +0 -1
- package/dist/adapters/SqliteSignerAdapter.d.ts +0 -119
- package/dist/adapters/SqliteSignerAdapter.d.ts.map +0 -1
- package/dist/adapters/SqliteStorageAdapter.d.ts +0 -81
- package/dist/adapters/SqliteStorageAdapter.d.ts.map +0 -1
- package/dist/adapters/TelegramUserContextProvider.d.ts +0 -70
- package/dist/adapters/TelegramUserContextProvider.d.ts.map +0 -1
- package/dist/adapters/index.d.ts +0 -19
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/core/LimitsManager.d.ts +0 -59
- package/dist/core/LimitsManager.d.ts.map +0 -1
- package/dist/core/PendingTransactionManager.d.ts +0 -122
- package/dist/core/PendingTransactionManager.d.ts.map +0 -1
- package/dist/core/UserScopedSigner.d.ts +0 -96
- package/dist/core/UserScopedSigner.d.ts.map +0 -1
- package/dist/core/UserScopedStorage.d.ts +0 -59
- package/dist/core/UserScopedStorage.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -15
- package/dist/core/index.d.ts.map +0 -1
- package/dist/services/WalletService.d.ts +0 -144
- package/dist/services/WalletService.d.ts.map +0 -1
- package/dist/storage/SecureStorage.d.ts +0 -79
- package/dist/storage/SecureStorage.d.ts.map +0 -1
- package/dist/tools/balance.d.ts +0 -167
- package/dist/tools/balance.d.ts.map +0 -1
- package/dist/tools/mcp-tools.d.ts +0 -439
- package/dist/tools/mcp-tools.d.ts.map +0 -1
- package/dist/tools/swap.d.ts +0 -110
- package/dist/tools/swap.d.ts.map +0 -1
- package/dist/tools/transfer.d.ts +0 -146
- package/dist/tools/transfer.d.ts.map +0 -1
- package/dist/tools/wallet.d.ts +0 -138
- package/dist/tools/wallet.d.ts.map +0 -1
- package/dist/types/signer.d.ts +0 -120
- package/dist/types/signer.d.ts.map +0 -1
- package/dist/types/storage.d.ts +0 -41
- package/dist/types/storage.d.ts.map +0 -1
- package/dist/types/user-context.d.ts +0 -48
- package/dist/types/user-context.d.ts.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -21893,7 +21893,7 @@ var WalletKitError = class WalletKitError extends Error {
|
|
|
21893
21893
|
function asBase64(data) {
|
|
21894
21894
|
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(data)) throw new Error("Not a valid base64");
|
|
21895
21895
|
try {
|
|
21896
|
-
|
|
21896
|
+
ParseBase64(data);
|
|
21897
21897
|
} catch (_e) {
|
|
21898
21898
|
throw new Error("Not a valid base64");
|
|
21899
21899
|
}
|
|
@@ -23814,36 +23814,22 @@ var TONConnectStoredSessionManager = class {
|
|
|
23814
23814
|
async getSession(sessionId) {
|
|
23815
23815
|
return this.sessions.get(sessionId);
|
|
23816
23816
|
}
|
|
23817
|
-
async
|
|
23818
|
-
let
|
|
23819
|
-
|
|
23820
|
-
|
|
23817
|
+
async getSessions(filter) {
|
|
23818
|
+
let sessions = Array.from(this.sessions.values());
|
|
23819
|
+
if (!filter) return sessions;
|
|
23820
|
+
let domain;
|
|
23821
|
+
if (filter.domain) try {
|
|
23822
|
+
domain = new URL(filter.domain).host;
|
|
23821
23823
|
} catch {
|
|
23822
|
-
|
|
23823
|
-
}
|
|
23824
|
-
|
|
23825
|
-
|
|
23826
|
-
|
|
23827
|
-
|
|
23828
|
-
|
|
23829
|
-
|
|
23830
|
-
|
|
23831
|
-
}
|
|
23832
|
-
/**
|
|
23833
|
-
* Get sessions for specific wallet by wallet ID
|
|
23834
|
-
*/
|
|
23835
|
-
async getSessionsForWallet(walletId) {
|
|
23836
|
-
return (await this.getSessions()).filter((session) => session.walletId === walletId);
|
|
23837
|
-
}
|
|
23838
|
-
/**
|
|
23839
|
-
* Update session activity timestamp
|
|
23840
|
-
*/
|
|
23841
|
-
async updateSessionActivity(sessionId) {
|
|
23842
|
-
const session = this.sessions.get(sessionId);
|
|
23843
|
-
if (session) {
|
|
23844
|
-
session.lastActivityAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23845
|
-
await this.persistSessions();
|
|
23846
|
-
}
|
|
23824
|
+
domain = filter.domain;
|
|
23825
|
+
}
|
|
23826
|
+
return sessions.filter((session) => {
|
|
23827
|
+
let isIncluded = true;
|
|
23828
|
+
if (filter.walletId) isIncluded = isIncluded && session.walletId === filter.walletId;
|
|
23829
|
+
if (filter.domain) isIncluded = isIncluded && session.domain === domain;
|
|
23830
|
+
if (filter.isJsBridge !== void 0) isIncluded = isIncluded && session.isJsBridge === filter.isJsBridge;
|
|
23831
|
+
return isIncluded;
|
|
23832
|
+
});
|
|
23847
23833
|
}
|
|
23848
23834
|
/**
|
|
23849
23835
|
* Remove session by ID
|
|
@@ -23851,11 +23837,8 @@ var TONConnectStoredSessionManager = class {
|
|
|
23851
23837
|
async removeSession(sessionId) {
|
|
23852
23838
|
if (this.sessions.delete(sessionId)) await this.persistSessions();
|
|
23853
23839
|
}
|
|
23854
|
-
|
|
23855
|
-
|
|
23856
|
-
*/
|
|
23857
|
-
async removeSessionsForWallet(walletId) {
|
|
23858
|
-
const sessionsToRemove = await this.getSessionsForWallet(walletId);
|
|
23840
|
+
async removeSessions(filter) {
|
|
23841
|
+
const sessionsToRemove = await this.getSessions(filter);
|
|
23859
23842
|
let removedCount = 0;
|
|
23860
23843
|
for (const session of sessionsToRemove) if (this.sessions.delete(session.sessionId)) removedCount++;
|
|
23861
23844
|
if (removedCount > 0) await this.persistSessions();
|
|
@@ -64265,13 +64248,15 @@ var BridgeManager = class {
|
|
|
64265
64248
|
isJsBridge: true,
|
|
64266
64249
|
tabId: messageInfo.tabId,
|
|
64267
64250
|
domain: messageInfo.domain,
|
|
64268
|
-
messageId: messageInfo.messageId
|
|
64251
|
+
messageId: messageInfo.messageId,
|
|
64252
|
+
walletId: messageInfo.walletId
|
|
64269
64253
|
});
|
|
64270
64254
|
else if (event.method == "restoreConnection") this.eventEmitter?.emit("restoreConnection", {
|
|
64271
64255
|
...event,
|
|
64272
64256
|
tabId: messageInfo.tabId,
|
|
64273
64257
|
domain: messageInfo.domain,
|
|
64274
|
-
messageId: messageInfo.messageId
|
|
64258
|
+
messageId: messageInfo.messageId,
|
|
64259
|
+
walletId: messageInfo.walletId
|
|
64275
64260
|
});
|
|
64276
64261
|
else if (event.method == "send" && event?.params?.length === 1) this.eventQueue.push({
|
|
64277
64262
|
...event,
|
|
@@ -64279,7 +64264,8 @@ var BridgeManager = class {
|
|
|
64279
64264
|
isJsBridge: true,
|
|
64280
64265
|
tabId: messageInfo.tabId,
|
|
64281
64266
|
domain: messageInfo.domain,
|
|
64282
|
-
messageId: messageInfo.messageId
|
|
64267
|
+
messageId: messageInfo.messageId,
|
|
64268
|
+
walletId: messageInfo.walletId
|
|
64283
64269
|
});
|
|
64284
64270
|
this.processBridgeEvents().catch((error) => {
|
|
64285
64271
|
log$21.error("Error in background event processing", { error });
|
|
@@ -64331,7 +64317,8 @@ var BridgeManager = class {
|
|
|
64331
64317
|
isJsBridge: event?.isJsBridge,
|
|
64332
64318
|
tabId: event?.tabId,
|
|
64333
64319
|
messageId: event?.messageId,
|
|
64334
|
-
traceId: event?.traceId
|
|
64320
|
+
traceId: event?.traceId,
|
|
64321
|
+
walletId: event?.walletId
|
|
64335
64322
|
};
|
|
64336
64323
|
if (!rawEvent.traceId) rawEvent.traceId = v7_default();
|
|
64337
64324
|
await this.sessionManager.initialize();
|
|
@@ -64349,7 +64336,12 @@ var BridgeManager = class {
|
|
|
64349
64336
|
};
|
|
64350
64337
|
}
|
|
64351
64338
|
} else if (rawEvent.domain) {
|
|
64352
|
-
const
|
|
64339
|
+
const sessions = await this.sessionManager.getSessions({
|
|
64340
|
+
walletId: event.walletId,
|
|
64341
|
+
domain: rawEvent.domain,
|
|
64342
|
+
isJsBridge: rawEvent.isJsBridge
|
|
64343
|
+
});
|
|
64344
|
+
const session = sessions.length > 0 ? sessions[0] : void 0;
|
|
64353
64345
|
if (session?.walletId) rawEvent.walletId = session.walletId;
|
|
64354
64346
|
if (session?.walletAddress) rawEvent.walletAddress = session.walletAddress;
|
|
64355
64347
|
if (session?.sessionId) rawEvent.from = session.sessionId;
|
|
@@ -68159,9 +68151,6 @@ async function MnemonicToKeyPair(mnemonic, mnemonicType = "ton") {
|
|
|
68159
68151
|
supportedTypes: ["ton", "bip39"]
|
|
68160
68152
|
});
|
|
68161
68153
|
}
|
|
68162
|
-
async function CreateTonMnemonic() {
|
|
68163
|
-
return (0, import_dist$1.mnemonicNew)(24);
|
|
68164
|
-
}
|
|
68165
68154
|
|
|
68166
68155
|
//#endregion
|
|
68167
68156
|
//#region ../walletkit/dist/esm/utils/sign.js
|
|
@@ -70109,6 +70098,7 @@ var DefiManagerError = class extends Error {
|
|
|
70109
70098
|
static NO_DEFAULT_PROVIDER = "NO_DEFAULT_PROVIDER";
|
|
70110
70099
|
static NETWORK_ERROR = "NETWORK_ERROR";
|
|
70111
70100
|
static INVALID_PARAMS = "INVALID_PARAMS";
|
|
70101
|
+
static INVALID_PROVIDER = "INVALID_PROVIDER";
|
|
70112
70102
|
code;
|
|
70113
70103
|
details;
|
|
70114
70104
|
constructor(message, code, details) {
|
|
@@ -70150,36 +70140,42 @@ var SwapError = class extends DefiManagerError {
|
|
|
70150
70140
|
*/
|
|
70151
70141
|
var DefiManager = class {
|
|
70152
70142
|
providers = /* @__PURE__ */ new Map();
|
|
70153
|
-
|
|
70143
|
+
defaultProviderId;
|
|
70154
70144
|
/**
|
|
70155
70145
|
* Register a swap provider
|
|
70156
70146
|
* @param name - Unique name for the provider
|
|
70157
70147
|
* @param provider - Provider instance
|
|
70158
70148
|
*/
|
|
70159
|
-
|
|
70160
|
-
|
|
70161
|
-
|
|
70149
|
+
/**
|
|
70150
|
+
* Register a swap provider
|
|
70151
|
+
* @param provider - Provider instance
|
|
70152
|
+
*/
|
|
70153
|
+
registerProvider(provider) {
|
|
70154
|
+
const providerId = provider.providerId;
|
|
70155
|
+
if (!providerId) throw this.createError("Provider must have a providerId", DefiManagerError.INVALID_PROVIDER);
|
|
70156
|
+
this.providers.set(providerId, provider);
|
|
70157
|
+
if (!this.defaultProviderId) this.defaultProviderId = providerId;
|
|
70162
70158
|
}
|
|
70163
70159
|
/**
|
|
70164
70160
|
* Set the default provider to use when none is specified
|
|
70165
|
-
* @param
|
|
70161
|
+
* @param providerId - Provider name
|
|
70166
70162
|
* @throws DefiManagerError if provider not found
|
|
70167
70163
|
*/
|
|
70168
|
-
setDefaultProvider(
|
|
70169
|
-
if (!this.providers.has(
|
|
70170
|
-
provider:
|
|
70164
|
+
setDefaultProvider(providerId) {
|
|
70165
|
+
if (!this.providers.has(providerId)) throw this.createError(`Provider '${providerId}' not registered`, DefiManagerError.PROVIDER_NOT_FOUND, {
|
|
70166
|
+
provider: providerId,
|
|
70171
70167
|
registered: Array.from(this.providers.keys())
|
|
70172
70168
|
});
|
|
70173
|
-
this.
|
|
70169
|
+
this.defaultProviderId = providerId;
|
|
70174
70170
|
}
|
|
70175
70171
|
/**
|
|
70176
70172
|
* Get a provider by name, or the default provider
|
|
70177
|
-
* @param
|
|
70173
|
+
* @param providerId - Optional provider name
|
|
70178
70174
|
* @returns Provider instance
|
|
70179
70175
|
* @throws DefiManagerError if provider not found or no default set
|
|
70180
70176
|
*/
|
|
70181
|
-
getProvider(
|
|
70182
|
-
const providerName =
|
|
70177
|
+
getProvider(providerId) {
|
|
70178
|
+
const providerName = providerId || this.defaultProviderId;
|
|
70183
70179
|
if (!providerName) throw this.createError("No default provider set. Register a provider first.", DefiManagerError.NO_DEFAULT_PROVIDER);
|
|
70184
70180
|
const provider = this.providers.get(providerName);
|
|
70185
70181
|
if (!provider) throw this.createError(`Provider '${providerName}' not found`, DefiManagerError.PROVIDER_NOT_FOUND, {
|
|
@@ -70197,11 +70193,11 @@ var DefiManager = class {
|
|
|
70197
70193
|
}
|
|
70198
70194
|
/**
|
|
70199
70195
|
* Check if a provider is registered
|
|
70200
|
-
* @param
|
|
70196
|
+
* @param providerId - Provider id
|
|
70201
70197
|
* @returns True if provider exists
|
|
70202
70198
|
*/
|
|
70203
|
-
hasProvider(
|
|
70204
|
-
return this.providers.has(
|
|
70199
|
+
hasProvider(providerId) {
|
|
70200
|
+
return this.providers.has(providerId);
|
|
70205
70201
|
}
|
|
70206
70202
|
};
|
|
70207
70203
|
|
|
@@ -70229,14 +70225,12 @@ var SwapManager = class extends DefiManager {
|
|
|
70229
70225
|
* @returns Promise resolving to swap quote
|
|
70230
70226
|
*/
|
|
70231
70227
|
async getQuote(params, provider) {
|
|
70232
|
-
if (params.amountFrom && params.amountTo) throw new SwapError("Cannot specify both amountFrom and amountTo", SwapError.INVALID_PARAMS);
|
|
70233
|
-
if (!params.amountFrom && !params.amountTo) throw new SwapError("Must specify either amountFrom or amountTo", SwapError.INVALID_PARAMS);
|
|
70234
70228
|
log$10.debug("Getting swap quote", {
|
|
70235
70229
|
fromToken: params.fromToken,
|
|
70236
70230
|
toToken: params.toToken,
|
|
70237
|
-
|
|
70238
|
-
|
|
70239
|
-
provider: provider || this.
|
|
70231
|
+
amount: params.amount,
|
|
70232
|
+
isReverseSwap: params.isReverseSwap,
|
|
70233
|
+
provider: provider || this.defaultProviderId
|
|
70240
70234
|
});
|
|
70241
70235
|
try {
|
|
70242
70236
|
const quote = await this.getProvider(provider).getQuote(params);
|
|
@@ -70263,7 +70257,7 @@ var SwapManager = class extends DefiManager {
|
|
|
70263
70257
|
async buildSwapTransaction(params, provider) {
|
|
70264
70258
|
log$10.debug("Building swap transaction", {
|
|
70265
70259
|
userAddress: params.userAddress,
|
|
70266
|
-
provider: provider || this.
|
|
70260
|
+
provider: provider || this.defaultProviderId
|
|
70267
70261
|
});
|
|
70268
70262
|
try {
|
|
70269
70263
|
const transaction = await this.getProvider(provider).buildSwapTransaction(params);
|
|
@@ -71530,23 +71524,28 @@ var TonWalletKit = class {
|
|
|
71530
71524
|
this.eventEmitter.on("restoreConnection", async (event) => {
|
|
71531
71525
|
if (!event.domain) {
|
|
71532
71526
|
log$5.error("Domain is required for restore connection");
|
|
71533
|
-
return;
|
|
71527
|
+
return this.sendErrorConnectResponse(event);
|
|
71534
71528
|
}
|
|
71535
|
-
const
|
|
71529
|
+
const sessions = await this.sessionManager.getSessions({
|
|
71530
|
+
walletId: event.walletId,
|
|
71531
|
+
domain: event.domain,
|
|
71532
|
+
isJsBridge: true
|
|
71533
|
+
});
|
|
71534
|
+
const session = sessions.length > 0 ? sessions[0] : void 0;
|
|
71536
71535
|
if (!session) {
|
|
71537
71536
|
log$5.error("Session not found for domain", { domain: event.domain });
|
|
71538
|
-
return;
|
|
71537
|
+
return this.sendErrorConnectResponse(event);
|
|
71539
71538
|
}
|
|
71540
71539
|
const wallet = session.walletId ? this.walletManager?.getWallet(session.walletId) : void 0;
|
|
71541
71540
|
if (!wallet) {
|
|
71542
71541
|
log$5.error("Wallet not found for session", { walletId: session.walletId });
|
|
71543
|
-
return;
|
|
71542
|
+
return this.sendErrorConnectResponse(event);
|
|
71544
71543
|
}
|
|
71545
71544
|
const walletAddress = wallet.getAddress();
|
|
71546
71545
|
const walletStateInit = await wallet.getStateInit();
|
|
71547
71546
|
const publicKey = wallet.getPublicKey().replace("0x", "");
|
|
71548
71547
|
const deviceInfo = getDeviceInfoForWallet(wallet, this.config.deviceInfo);
|
|
71549
|
-
const
|
|
71548
|
+
const tonConnectEvent = {
|
|
71550
71549
|
event: "connect",
|
|
71551
71550
|
id: Date.now(),
|
|
71552
71551
|
payload: {
|
|
@@ -71560,9 +71559,20 @@ var TonWalletKit = class {
|
|
|
71560
71559
|
}]
|
|
71561
71560
|
}
|
|
71562
71561
|
};
|
|
71563
|
-
this.bridgeManager.sendJsBridgeResponse(event?.tabId?.toString() || "", true, event?.id ?? event?.messageId,
|
|
71562
|
+
this.bridgeManager.sendJsBridgeResponse(event?.tabId?.toString() || "", true, event?.id ?? event?.messageId, tonConnectEvent);
|
|
71564
71563
|
});
|
|
71565
71564
|
}
|
|
71565
|
+
async sendErrorConnectResponse(event) {
|
|
71566
|
+
const tonConnectEvent = {
|
|
71567
|
+
event: "connect_error",
|
|
71568
|
+
id: Date.now(),
|
|
71569
|
+
payload: {
|
|
71570
|
+
code: CONNECT_EVENT_ERROR_CODES.UNKNOWN_APP_ERROR,
|
|
71571
|
+
message: ""
|
|
71572
|
+
}
|
|
71573
|
+
};
|
|
71574
|
+
await this.bridgeManager.sendJsBridgeResponse(event?.tabId?.toString() || "", true, event?.id ?? event?.messageId, tonConnectEvent);
|
|
71575
|
+
}
|
|
71566
71576
|
/**
|
|
71567
71577
|
* Initialize all components
|
|
71568
71578
|
*/
|
|
@@ -71667,7 +71677,7 @@ var TonWalletKit = class {
|
|
|
71667
71677
|
if (!wallet) throw new WalletKitError(ERROR_CODES.WALLET_NOT_FOUND, "Wallet not found for removal", void 0, { walletId });
|
|
71668
71678
|
await this.eventProcessor.stopProcessing(wallet.getAddress());
|
|
71669
71679
|
await this.walletManager.removeWallet(walletId);
|
|
71670
|
-
await this.sessionManager.
|
|
71680
|
+
await this.sessionManager.removeSessions({ walletId });
|
|
71671
71681
|
}
|
|
71672
71682
|
async clearWallets() {
|
|
71673
71683
|
await this.ensureInitialized();
|
|
@@ -87854,15 +87864,21 @@ function unwrapObservable(originalMethod) {
|
|
|
87854
87864
|
*
|
|
87855
87865
|
*/
|
|
87856
87866
|
const tokenToAddress = (token) => {
|
|
87857
|
-
if (token === "
|
|
87858
|
-
return import_dist$2.Address.parse(token).toRawString();
|
|
87867
|
+
if (token.type === "ton") return "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c";
|
|
87868
|
+
return import_dist$2.Address.parse(token.value).toRawString();
|
|
87859
87869
|
};
|
|
87860
87870
|
const addressToToken = (address) => {
|
|
87861
|
-
if (address === "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c") return "
|
|
87871
|
+
if (address === "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c") return { type: "ton" };
|
|
87862
87872
|
try {
|
|
87863
|
-
return
|
|
87873
|
+
return {
|
|
87874
|
+
type: "jetton",
|
|
87875
|
+
value: import_dist$2.Address.parseRaw(address).toString()
|
|
87876
|
+
};
|
|
87864
87877
|
} catch {
|
|
87865
|
-
return
|
|
87878
|
+
return {
|
|
87879
|
+
type: "jetton",
|
|
87880
|
+
value: address
|
|
87881
|
+
};
|
|
87866
87882
|
}
|
|
87867
87883
|
};
|
|
87868
87884
|
const toOmnistonAddress = (address, network) => {
|
|
@@ -87929,8 +87945,10 @@ var OmnistonSwapProvider = class extends SwapProvider {
|
|
|
87929
87945
|
referrerFeeBps;
|
|
87930
87946
|
flexibleReferrerFee;
|
|
87931
87947
|
omniston$;
|
|
87948
|
+
providerId;
|
|
87932
87949
|
constructor(config) {
|
|
87933
87950
|
super();
|
|
87951
|
+
this.providerId = config?.providerId ?? "omniston";
|
|
87934
87952
|
this.apiUrl = config?.apiUrl ?? "wss://omni-ws.ston.fi";
|
|
87935
87953
|
this.defaultSlippageBps = config?.defaultSlippageBps ?? 100;
|
|
87936
87954
|
this.quoteTimeoutMs = config?.quoteTimeoutMs ?? 1e4;
|
|
@@ -87950,8 +87968,8 @@ var OmnistonSwapProvider = class extends SwapProvider {
|
|
|
87950
87968
|
log$1.debug("Getting Omniston quote", {
|
|
87951
87969
|
fromToken: params.fromToken,
|
|
87952
87970
|
toToken: params.toToken,
|
|
87953
|
-
|
|
87954
|
-
|
|
87971
|
+
amount: params.amount,
|
|
87972
|
+
isReverseSwap: params.isReverseSwap
|
|
87955
87973
|
});
|
|
87956
87974
|
try {
|
|
87957
87975
|
const bidAssetAddress = tokenToAddress(params.fromToken);
|
|
@@ -87961,7 +87979,7 @@ var OmnistonSwapProvider = class extends SwapProvider {
|
|
|
87961
87979
|
const referrerFeeBps = params.providerOptions?.referrerFeeBps ?? this.referrerFeeBps;
|
|
87962
87980
|
const flexibleReferrerFee = params.providerOptions?.flexibleReferrerFee ?? this.flexibleReferrerFee;
|
|
87963
87981
|
const quoteRequest = {
|
|
87964
|
-
amount: params.
|
|
87982
|
+
amount: params.isReverseSwap ? { askUnits: params.amount } : { bidUnits: params.amount },
|
|
87965
87983
|
settlementMethods: [SettlementMethod.SETTLEMENT_METHOD_SWAP],
|
|
87966
87984
|
bidAssetAddress: toOmnistonAddress(bidAssetAddress, params.network),
|
|
87967
87985
|
askAssetAddress: toOmnistonAddress(askAssetAddress, params.network),
|
|
@@ -88095,7 +88113,7 @@ var OmnistonSwapProvider = class extends SwapProvider {
|
|
|
88095
88113
|
});
|
|
88096
88114
|
return {
|
|
88097
88115
|
metadata,
|
|
88098
|
-
|
|
88116
|
+
providerId: this.providerId,
|
|
88099
88117
|
fromToken: params.fromToken,
|
|
88100
88118
|
toToken: params.toToken,
|
|
88101
88119
|
fromAmount: quote.bidUnits,
|
|
@@ -88108,388 +88126,6 @@ var OmnistonSwapProvider = class extends SwapProvider {
|
|
|
88108
88126
|
}
|
|
88109
88127
|
};
|
|
88110
88128
|
|
|
88111
|
-
//#endregion
|
|
88112
|
-
//#region src/core/UserScopedStorage.ts
|
|
88113
|
-
/**
|
|
88114
|
-
* User-scoped storage wrapper.
|
|
88115
|
-
* Automatically prefixes all keys with user namespace.
|
|
88116
|
-
*/
|
|
88117
|
-
var UserScopedStorage = class {
|
|
88118
|
-
storage;
|
|
88119
|
-
userId;
|
|
88120
|
-
prefix;
|
|
88121
|
-
constructor(storage, userId) {
|
|
88122
|
-
this.storage = storage;
|
|
88123
|
-
this.userId = userId;
|
|
88124
|
-
this.prefix = `user:${userId}:`;
|
|
88125
|
-
}
|
|
88126
|
-
/**
|
|
88127
|
-
* Get the user ID this storage is scoped to
|
|
88128
|
-
*/
|
|
88129
|
-
getUserId() {
|
|
88130
|
-
return this.userId;
|
|
88131
|
-
}
|
|
88132
|
-
/**
|
|
88133
|
-
* Build full key with user prefix
|
|
88134
|
-
*/
|
|
88135
|
-
buildKey(key) {
|
|
88136
|
-
return `${this.prefix}${key}`;
|
|
88137
|
-
}
|
|
88138
|
-
/**
|
|
88139
|
-
* Strip user prefix from a key
|
|
88140
|
-
*/
|
|
88141
|
-
stripPrefix(fullKey) {
|
|
88142
|
-
if (fullKey.startsWith(this.prefix)) return fullKey.slice(this.prefix.length);
|
|
88143
|
-
return fullKey;
|
|
88144
|
-
}
|
|
88145
|
-
/**
|
|
88146
|
-
* Get a value by key (user-scoped)
|
|
88147
|
-
*/
|
|
88148
|
-
async get(key) {
|
|
88149
|
-
return this.storage.get(this.buildKey(key));
|
|
88150
|
-
}
|
|
88151
|
-
/**
|
|
88152
|
-
* Set a value (user-scoped)
|
|
88153
|
-
*/
|
|
88154
|
-
async set(key, value, ttlSeconds) {
|
|
88155
|
-
return this.storage.set(this.buildKey(key), value, ttlSeconds);
|
|
88156
|
-
}
|
|
88157
|
-
/**
|
|
88158
|
-
* Delete a key (user-scoped)
|
|
88159
|
-
*/
|
|
88160
|
-
async delete(key) {
|
|
88161
|
-
return this.storage.delete(this.buildKey(key));
|
|
88162
|
-
}
|
|
88163
|
-
/**
|
|
88164
|
-
* List keys matching prefix (user-scoped)
|
|
88165
|
-
* Returns keys with user prefix stripped.
|
|
88166
|
-
*/
|
|
88167
|
-
async list(subPrefix) {
|
|
88168
|
-
const fullPrefix = this.buildKey(subPrefix);
|
|
88169
|
-
return (await this.storage.list(fullPrefix)).map((k) => this.stripPrefix(k));
|
|
88170
|
-
}
|
|
88171
|
-
/**
|
|
88172
|
-
* Get the underlying storage adapter.
|
|
88173
|
-
* Use with caution - bypasses user isolation.
|
|
88174
|
-
*/
|
|
88175
|
-
getUnderlyingStorage() {
|
|
88176
|
-
return this.storage;
|
|
88177
|
-
}
|
|
88178
|
-
};
|
|
88179
|
-
|
|
88180
|
-
//#endregion
|
|
88181
|
-
//#region src/core/UserScopedSigner.ts
|
|
88182
|
-
/**
|
|
88183
|
-
* User-scoped signer wrapper.
|
|
88184
|
-
* Ensures all operations are scoped to the authenticated user.
|
|
88185
|
-
*/
|
|
88186
|
-
var UserScopedSigner = class {
|
|
88187
|
-
signer;
|
|
88188
|
-
userId;
|
|
88189
|
-
userPrefix;
|
|
88190
|
-
constructor(signer, userId) {
|
|
88191
|
-
this.signer = signer;
|
|
88192
|
-
this.userId = userId;
|
|
88193
|
-
this.userPrefix = `${userId}:`;
|
|
88194
|
-
}
|
|
88195
|
-
/**
|
|
88196
|
-
* Get the user ID this signer is scoped to
|
|
88197
|
-
*/
|
|
88198
|
-
getUserId() {
|
|
88199
|
-
return this.userId;
|
|
88200
|
-
}
|
|
88201
|
-
/**
|
|
88202
|
-
* Build user-scoped wallet ID from wallet name
|
|
88203
|
-
*/
|
|
88204
|
-
scopedId(walletName) {
|
|
88205
|
-
return `${this.userPrefix}${walletName}`;
|
|
88206
|
-
}
|
|
88207
|
-
/**
|
|
88208
|
-
* Extract wallet name from scoped ID
|
|
88209
|
-
*/
|
|
88210
|
-
extractName(scopedId) {
|
|
88211
|
-
if (scopedId.startsWith(this.userPrefix)) return scopedId.slice(this.userPrefix.length);
|
|
88212
|
-
return scopedId;
|
|
88213
|
-
}
|
|
88214
|
-
/**
|
|
88215
|
-
* Check if a wallet ID belongs to this user
|
|
88216
|
-
*/
|
|
88217
|
-
isOwnedByUser(walletId) {
|
|
88218
|
-
return walletId.startsWith(this.userPrefix);
|
|
88219
|
-
}
|
|
88220
|
-
/**
|
|
88221
|
-
* Transform wallet info to expose wallet name instead of internal ID
|
|
88222
|
-
*/
|
|
88223
|
-
transformWalletInfo(info) {
|
|
88224
|
-
return {
|
|
88225
|
-
...info,
|
|
88226
|
-
name: this.extractName(info.walletId)
|
|
88227
|
-
};
|
|
88228
|
-
}
|
|
88229
|
-
/**
|
|
88230
|
-
* Create a new wallet (user-scoped)
|
|
88231
|
-
*/
|
|
88232
|
-
async createWallet(params) {
|
|
88233
|
-
const result = await this.signer.createWallet({
|
|
88234
|
-
walletId: this.scopedId(params.name),
|
|
88235
|
-
version: params.version,
|
|
88236
|
-
network: params.network
|
|
88237
|
-
});
|
|
88238
|
-
return this.transformWalletInfo(result);
|
|
88239
|
-
}
|
|
88240
|
-
/**
|
|
88241
|
-
* Import a wallet from mnemonic (user-scoped)
|
|
88242
|
-
* Note: Mnemonic is passed to signer and stored securely, never returned
|
|
88243
|
-
*/
|
|
88244
|
-
async importWallet(params) {
|
|
88245
|
-
const result = await this.signer.importWallet({
|
|
88246
|
-
walletId: this.scopedId(params.name),
|
|
88247
|
-
mnemonic: params.mnemonic,
|
|
88248
|
-
version: params.version,
|
|
88249
|
-
network: params.network
|
|
88250
|
-
});
|
|
88251
|
-
return this.transformWalletInfo(result);
|
|
88252
|
-
}
|
|
88253
|
-
/**
|
|
88254
|
-
* Get wallet by name (user-scoped)
|
|
88255
|
-
* Returns null for both "not found" and "not owned" to prevent enumeration
|
|
88256
|
-
*/
|
|
88257
|
-
async getWallet(walletName) {
|
|
88258
|
-
const walletId = this.scopedId(walletName);
|
|
88259
|
-
const wallet = await this.signer.getWallet(walletId);
|
|
88260
|
-
if (!wallet) return null;
|
|
88261
|
-
if (!this.isOwnedByUser(wallet.walletId)) return null;
|
|
88262
|
-
return this.transformWalletInfo(wallet);
|
|
88263
|
-
}
|
|
88264
|
-
/**
|
|
88265
|
-
* List all wallets for this user
|
|
88266
|
-
*/
|
|
88267
|
-
async listWallets() {
|
|
88268
|
-
const userIds = (await this.signer.listWalletIds()).filter((id) => this.isOwnedByUser(id));
|
|
88269
|
-
return (await Promise.all(userIds.map(async (id) => {
|
|
88270
|
-
const wallet = await this.signer.getWallet(id);
|
|
88271
|
-
return wallet ? this.transformWalletInfo(wallet) : null;
|
|
88272
|
-
}))).filter((w) => w !== null);
|
|
88273
|
-
}
|
|
88274
|
-
/**
|
|
88275
|
-
* Delete a wallet (user-scoped)
|
|
88276
|
-
* Returns false for both "not found" and "not owned"
|
|
88277
|
-
*/
|
|
88278
|
-
async deleteWallet(walletName) {
|
|
88279
|
-
const walletId = this.scopedId(walletName);
|
|
88280
|
-
const wallet = await this.signer.getWallet(walletId);
|
|
88281
|
-
if (!wallet || !this.isOwnedByUser(wallet.walletId)) return false;
|
|
88282
|
-
return this.signer.deleteWallet(walletId);
|
|
88283
|
-
}
|
|
88284
|
-
/**
|
|
88285
|
-
* Sign a transaction (user-scoped)
|
|
88286
|
-
* Verifies ownership before signing
|
|
88287
|
-
*/
|
|
88288
|
-
async signTransaction(walletName, unsignedBoc) {
|
|
88289
|
-
const walletId = this.scopedId(walletName);
|
|
88290
|
-
const wallet = await this.signer.getWallet(walletId);
|
|
88291
|
-
if (!wallet || !this.isOwnedByUser(wallet.walletId)) throw new Error("Wallet not found");
|
|
88292
|
-
return this.signer.signTransaction(walletId, unsignedBoc);
|
|
88293
|
-
}
|
|
88294
|
-
/**
|
|
88295
|
-
* Sign a message (user-scoped)
|
|
88296
|
-
* Verifies ownership before signing
|
|
88297
|
-
*/
|
|
88298
|
-
async signMessage(walletName, message) {
|
|
88299
|
-
const walletId = this.scopedId(walletName);
|
|
88300
|
-
const wallet = await this.signer.getWallet(walletId);
|
|
88301
|
-
if (!wallet || !this.isOwnedByUser(wallet.walletId)) throw new Error("Wallet not found");
|
|
88302
|
-
return this.signer.signMessage(walletId, message);
|
|
88303
|
-
}
|
|
88304
|
-
/**
|
|
88305
|
-
* Get the underlying signer adapter.
|
|
88306
|
-
* Use with caution - bypasses user isolation.
|
|
88307
|
-
*/
|
|
88308
|
-
getUnderlyingSigner() {
|
|
88309
|
-
return this.signer;
|
|
88310
|
-
}
|
|
88311
|
-
};
|
|
88312
|
-
|
|
88313
|
-
//#endregion
|
|
88314
|
-
//#region src/core/LimitsManager.ts
|
|
88315
|
-
/** TON has 9 decimal places */
|
|
88316
|
-
const TON_DECIMALS$1 = 9;
|
|
88317
|
-
/**
|
|
88318
|
-
* LimitsManager enforces safety limits on transactions and wallet counts.
|
|
88319
|
-
*/
|
|
88320
|
-
var LimitsManager = class {
|
|
88321
|
-
limits;
|
|
88322
|
-
constructor(limits) {
|
|
88323
|
-
this.limits = {
|
|
88324
|
-
maxTransactionTon: limits?.maxTransactionTon ?? Infinity,
|
|
88325
|
-
dailyLimitTon: limits?.dailyLimitTon ?? Infinity,
|
|
88326
|
-
maxWalletsPerUser: limits?.maxWalletsPerUser ?? Infinity
|
|
88327
|
-
};
|
|
88328
|
-
}
|
|
88329
|
-
/**
|
|
88330
|
-
* Check if a transaction amount is within limits
|
|
88331
|
-
*/
|
|
88332
|
-
async checkTransactionLimit(storage, amountTon) {
|
|
88333
|
-
if (amountTon > this.limits.maxTransactionTon) return {
|
|
88334
|
-
allowed: false,
|
|
88335
|
-
reason: `Transaction amount ${amountTon} TON exceeds maximum allowed ${this.limits.maxTransactionTon} TON per transaction`
|
|
88336
|
-
};
|
|
88337
|
-
const today = this.getTodayDate();
|
|
88338
|
-
const usage = await this.getDailyUsage(storage, today);
|
|
88339
|
-
const currentSpentTon = this.nanoToTon(usage.totalSpentNano);
|
|
88340
|
-
if (currentSpentTon + amountTon > this.limits.dailyLimitTon) {
|
|
88341
|
-
const remainingTon = Math.max(0, this.limits.dailyLimitTon - currentSpentTon);
|
|
88342
|
-
return {
|
|
88343
|
-
allowed: false,
|
|
88344
|
-
reason: `Transaction would exceed daily limit of ${this.limits.dailyLimitTon} TON. Already spent: ${currentSpentTon.toFixed(2)} TON. Remaining: ${remainingTon.toFixed(2)} TON`
|
|
88345
|
-
};
|
|
88346
|
-
}
|
|
88347
|
-
return { allowed: true };
|
|
88348
|
-
}
|
|
88349
|
-
/**
|
|
88350
|
-
* Record a transaction for daily limit tracking
|
|
88351
|
-
*/
|
|
88352
|
-
async recordTransaction(storage, amountTon) {
|
|
88353
|
-
const today = this.getTodayDate();
|
|
88354
|
-
const usage = await this.getDailyUsage(storage, today);
|
|
88355
|
-
const newUsage = {
|
|
88356
|
-
date: today,
|
|
88357
|
-
totalSpentNano: (BigInt(usage.totalSpentNano) + BigInt(this.tonToNano(amountTon))).toString()
|
|
88358
|
-
};
|
|
88359
|
-
await storage.set(`daily:${today}`, newUsage, 9e4);
|
|
88360
|
-
}
|
|
88361
|
-
/**
|
|
88362
|
-
* Check if user can create another wallet
|
|
88363
|
-
*/
|
|
88364
|
-
async checkWalletCountLimit(currentWalletCount) {
|
|
88365
|
-
if (currentWalletCount >= this.limits.maxWalletsPerUser) return {
|
|
88366
|
-
allowed: false,
|
|
88367
|
-
reason: `Maximum wallet limit of ${this.limits.maxWalletsPerUser} reached`
|
|
88368
|
-
};
|
|
88369
|
-
return { allowed: true };
|
|
88370
|
-
}
|
|
88371
|
-
/**
|
|
88372
|
-
* Get the configured limits
|
|
88373
|
-
*/
|
|
88374
|
-
getLimits() {
|
|
88375
|
-
return { ...this.limits };
|
|
88376
|
-
}
|
|
88377
|
-
/**
|
|
88378
|
-
* Get today's date as ISO string (YYYY-MM-DD)
|
|
88379
|
-
*/
|
|
88380
|
-
getTodayDate() {
|
|
88381
|
-
return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
88382
|
-
}
|
|
88383
|
-
/**
|
|
88384
|
-
* Get daily usage for a specific date
|
|
88385
|
-
*/
|
|
88386
|
-
async getDailyUsage(storage, date) {
|
|
88387
|
-
return await storage.get(`daily:${date}`) ?? {
|
|
88388
|
-
date,
|
|
88389
|
-
totalSpentNano: "0"
|
|
88390
|
-
};
|
|
88391
|
-
}
|
|
88392
|
-
/**
|
|
88393
|
-
* Convert TON to nanoTON string
|
|
88394
|
-
*/
|
|
88395
|
-
tonToNano(ton) {
|
|
88396
|
-
return BigInt(Math.floor(ton * Math.pow(10, TON_DECIMALS$1))).toString();
|
|
88397
|
-
}
|
|
88398
|
-
/**
|
|
88399
|
-
* Convert nanoTON string to TON
|
|
88400
|
-
*/
|
|
88401
|
-
nanoToTon(nano) {
|
|
88402
|
-
return Number(BigInt(nano)) / Math.pow(10, TON_DECIMALS$1);
|
|
88403
|
-
}
|
|
88404
|
-
};
|
|
88405
|
-
|
|
88406
|
-
//#endregion
|
|
88407
|
-
//#region src/core/PendingTransactionManager.ts
|
|
88408
|
-
/** Default pending transaction TTL in seconds (5 minutes) */
|
|
88409
|
-
const DEFAULT_PENDING_TTL_SECONDS = 300;
|
|
88410
|
-
/**
|
|
88411
|
-
* PendingTransactionManager handles the confirmation flow for transactions.
|
|
88412
|
-
*/
|
|
88413
|
-
var PendingTransactionManager = class {
|
|
88414
|
-
ttlSeconds;
|
|
88415
|
-
constructor(ttlSeconds = DEFAULT_PENDING_TTL_SECONDS) {
|
|
88416
|
-
this.ttlSeconds = ttlSeconds;
|
|
88417
|
-
}
|
|
88418
|
-
/**
|
|
88419
|
-
* Generate a unique transaction ID
|
|
88420
|
-
*/
|
|
88421
|
-
generateId() {
|
|
88422
|
-
return `tx_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
88423
|
-
}
|
|
88424
|
-
/**
|
|
88425
|
-
* Create a pending transaction
|
|
88426
|
-
*/
|
|
88427
|
-
async createPending(storage, params) {
|
|
88428
|
-
const id = this.generateId();
|
|
88429
|
-
const now = /* @__PURE__ */ new Date();
|
|
88430
|
-
const expiresAt = new Date(now.getTime() + this.ttlSeconds * 1e3);
|
|
88431
|
-
const pending = {
|
|
88432
|
-
id,
|
|
88433
|
-
type: params.type,
|
|
88434
|
-
walletName: params.walletName,
|
|
88435
|
-
createdAt: now.toISOString(),
|
|
88436
|
-
expiresAt: expiresAt.toISOString(),
|
|
88437
|
-
description: params.description,
|
|
88438
|
-
data: params.data
|
|
88439
|
-
};
|
|
88440
|
-
await storage.set(`pending:${id}`, pending, this.ttlSeconds);
|
|
88441
|
-
return pending;
|
|
88442
|
-
}
|
|
88443
|
-
/**
|
|
88444
|
-
* Get a pending transaction by ID
|
|
88445
|
-
*/
|
|
88446
|
-
async getPending(storage, transactionId) {
|
|
88447
|
-
const pending = await storage.get(`pending:${transactionId}`);
|
|
88448
|
-
if (!pending) return null;
|
|
88449
|
-
if (new Date(pending.expiresAt) < /* @__PURE__ */ new Date()) {
|
|
88450
|
-
await this.deletePending(storage, transactionId);
|
|
88451
|
-
return null;
|
|
88452
|
-
}
|
|
88453
|
-
return pending;
|
|
88454
|
-
}
|
|
88455
|
-
/**
|
|
88456
|
-
* List all pending transactions for the user
|
|
88457
|
-
*/
|
|
88458
|
-
async listPending(storage) {
|
|
88459
|
-
const keys = await storage.list("pending:");
|
|
88460
|
-
const now = /* @__PURE__ */ new Date();
|
|
88461
|
-
const transactions = [];
|
|
88462
|
-
for (const key of keys) {
|
|
88463
|
-
const pending = await storage.get(key);
|
|
88464
|
-
if (pending && new Date(pending.expiresAt) >= now) transactions.push(pending);
|
|
88465
|
-
}
|
|
88466
|
-
return transactions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
88467
|
-
}
|
|
88468
|
-
/**
|
|
88469
|
-
* Delete a pending transaction
|
|
88470
|
-
*/
|
|
88471
|
-
async deletePending(storage, transactionId) {
|
|
88472
|
-
return storage.delete(`pending:${transactionId}`);
|
|
88473
|
-
}
|
|
88474
|
-
/**
|
|
88475
|
-
* Mark a pending transaction as confirmed (delete it)
|
|
88476
|
-
* The actual execution is handled by the caller
|
|
88477
|
-
*/
|
|
88478
|
-
async confirmPending(storage, transactionId) {
|
|
88479
|
-
const pending = await this.getPending(storage, transactionId);
|
|
88480
|
-
if (!pending) return null;
|
|
88481
|
-
await this.deletePending(storage, transactionId);
|
|
88482
|
-
return pending;
|
|
88483
|
-
}
|
|
88484
|
-
/**
|
|
88485
|
-
* Cancel a pending transaction
|
|
88486
|
-
*/
|
|
88487
|
-
async cancelPending(storage, transactionId) {
|
|
88488
|
-
if (!await this.getPending(storage, transactionId)) return false;
|
|
88489
|
-
return this.deletePending(storage, transactionId);
|
|
88490
|
-
}
|
|
88491
|
-
};
|
|
88492
|
-
|
|
88493
88129
|
//#endregion
|
|
88494
88130
|
//#region src/services/McpWalletService.ts
|
|
88495
88131
|
/**
|
|
@@ -88500,38 +88136,46 @@ var PendingTransactionManager = class {
|
|
|
88500
88136
|
*
|
|
88501
88137
|
*/
|
|
88502
88138
|
/**
|
|
88503
|
-
* McpWalletService -
|
|
88139
|
+
* McpWalletService - Simplified wallet service for MCP server
|
|
88504
88140
|
*
|
|
88505
|
-
* This service wraps
|
|
88506
|
-
*
|
|
88507
|
-
* - Transaction limits via LimitsManager
|
|
88508
|
-
* - Confirmation flow via PendingTransactionManager
|
|
88141
|
+
* This service wraps a single Wallet instance for operations.
|
|
88142
|
+
* Wallet management (create/import/list/remove) is handled externally.
|
|
88509
88143
|
*
|
|
88510
|
-
*
|
|
88511
|
-
*
|
|
88144
|
+
* For multi-user scenarios (e.g., Telegram bots), use this service
|
|
88145
|
+
* with user-specific wallet instances.
|
|
88512
88146
|
*/
|
|
88513
88147
|
/**
|
|
88514
|
-
* McpWalletService manages wallet operations for
|
|
88148
|
+
* McpWalletService manages wallet operations for a single wallet.
|
|
88515
88149
|
*/
|
|
88516
|
-
var McpWalletService = class {
|
|
88150
|
+
var McpWalletService = class McpWalletService {
|
|
88517
88151
|
config;
|
|
88518
|
-
|
|
88519
|
-
pendingManager;
|
|
88152
|
+
wallet;
|
|
88520
88153
|
kit = null;
|
|
88521
|
-
loadedWallets = /* @__PURE__ */ new Map();
|
|
88522
88154
|
constructor(config) {
|
|
88523
88155
|
this.config = config;
|
|
88524
|
-
this.
|
|
88525
|
-
|
|
88156
|
+
this.wallet = config.wallet;
|
|
88157
|
+
}
|
|
88158
|
+
static async create(config) {
|
|
88159
|
+
const wallet = await wrapWalletInterface(config.wallet);
|
|
88160
|
+
return new McpWalletService({
|
|
88161
|
+
...config,
|
|
88162
|
+
wallet
|
|
88163
|
+
});
|
|
88526
88164
|
}
|
|
88527
88165
|
/**
|
|
88528
|
-
* Get
|
|
88166
|
+
* Get wallet address
|
|
88529
88167
|
*/
|
|
88530
|
-
|
|
88531
|
-
return
|
|
88168
|
+
getAddress() {
|
|
88169
|
+
return this.wallet.getAddress();
|
|
88532
88170
|
}
|
|
88533
88171
|
/**
|
|
88534
|
-
*
|
|
88172
|
+
* Get wallet network
|
|
88173
|
+
*/
|
|
88174
|
+
getNetwork() {
|
|
88175
|
+
return this.wallet.getNetwork().chainId === Network.mainnet().chainId ? "mainnet" : "testnet";
|
|
88176
|
+
}
|
|
88177
|
+
/**
|
|
88178
|
+
* Initialize TonWalletKit (for swap operations)
|
|
88535
88179
|
*/
|
|
88536
88180
|
async getKit() {
|
|
88537
88181
|
if (!this.kit) {
|
|
@@ -88554,169 +88198,27 @@ var McpWalletService = class {
|
|
|
88554
88198
|
});
|
|
88555
88199
|
await this.kit.waitForReady();
|
|
88556
88200
|
const omnistonProvider = new OmnistonSwapProvider({ defaultSlippageBps: 100 });
|
|
88557
|
-
this.kit.swap.registerProvider(
|
|
88558
|
-
this.kit.swap.setDefaultProvider("omniston");
|
|
88201
|
+
this.kit.swap.registerProvider(omnistonProvider);
|
|
88559
88202
|
}
|
|
88560
88203
|
return this.kit;
|
|
88561
88204
|
}
|
|
88562
88205
|
/**
|
|
88563
|
-
* Create user-scoped storage wrapper
|
|
88564
|
-
*/
|
|
88565
|
-
createUserStorage(userId) {
|
|
88566
|
-
return new UserScopedStorage(this.config.storage, userId);
|
|
88567
|
-
}
|
|
88568
|
-
/**
|
|
88569
|
-
* Create user-scoped signer wrapper
|
|
88570
|
-
*/
|
|
88571
|
-
createUserSigner(userId) {
|
|
88572
|
-
return new UserScopedSigner(this.config.signer, userId);
|
|
88573
|
-
}
|
|
88574
|
-
/**
|
|
88575
|
-
* Get limits manager
|
|
88576
|
-
*/
|
|
88577
|
-
getLimitsManager() {
|
|
88578
|
-
return this.limitsManager;
|
|
88579
|
-
}
|
|
88580
|
-
/**
|
|
88581
|
-
* Get pending transaction manager
|
|
88582
|
-
*/
|
|
88583
|
-
getPendingManager() {
|
|
88584
|
-
return this.pendingManager;
|
|
88585
|
-
}
|
|
88586
|
-
/**
|
|
88587
|
-
* Check if confirmation is required
|
|
88588
|
-
*/
|
|
88589
|
-
requiresConfirmation() {
|
|
88590
|
-
return this.config.requireConfirmation ?? false;
|
|
88591
|
-
}
|
|
88592
|
-
/**
|
|
88593
|
-
* Create a new wallet for a user
|
|
88594
|
-
*/
|
|
88595
|
-
async createWallet(userSigner, userStorage, name, version = "v5r1", networkName = this.config.defaultNetwork ?? "mainnet") {
|
|
88596
|
-
const existingWallets = await userSigner.listWallets();
|
|
88597
|
-
const limitCheck = await this.limitsManager.checkWalletCountLimit(existingWallets.length);
|
|
88598
|
-
if (!limitCheck.allowed) throw new Error(limitCheck.reason);
|
|
88599
|
-
const walletInfo = await userSigner.createWallet({
|
|
88600
|
-
name,
|
|
88601
|
-
version,
|
|
88602
|
-
network: networkName
|
|
88603
|
-
});
|
|
88604
|
-
const metadata = {
|
|
88605
|
-
name: walletInfo.name,
|
|
88606
|
-
address: walletInfo.address,
|
|
88607
|
-
network: walletInfo.network,
|
|
88608
|
-
version: walletInfo.version,
|
|
88609
|
-
createdAt: walletInfo.createdAt
|
|
88610
|
-
};
|
|
88611
|
-
await userStorage.set(`wallet:${name}`, metadata);
|
|
88612
|
-
return {
|
|
88613
|
-
name: walletInfo.name,
|
|
88614
|
-
address: walletInfo.address,
|
|
88615
|
-
network: walletInfo.network
|
|
88616
|
-
};
|
|
88617
|
-
}
|
|
88618
|
-
/**
|
|
88619
|
-
* Import a wallet for a user
|
|
88620
|
-
*/
|
|
88621
|
-
async importWallet(userSigner, userStorage, name, mnemonic, version = "v5r1", networkName = this.config.defaultNetwork ?? "mainnet") {
|
|
88622
|
-
const existingWallets = await userSigner.listWallets();
|
|
88623
|
-
const limitCheck = await this.limitsManager.checkWalletCountLimit(existingWallets.length);
|
|
88624
|
-
if (!limitCheck.allowed) throw new Error(limitCheck.reason);
|
|
88625
|
-
const walletInfo = await userSigner.importWallet({
|
|
88626
|
-
name,
|
|
88627
|
-
mnemonic,
|
|
88628
|
-
version,
|
|
88629
|
-
network: networkName
|
|
88630
|
-
});
|
|
88631
|
-
const metadata = {
|
|
88632
|
-
name: walletInfo.name,
|
|
88633
|
-
address: walletInfo.address,
|
|
88634
|
-
network: walletInfo.network,
|
|
88635
|
-
version: walletInfo.version,
|
|
88636
|
-
createdAt: walletInfo.createdAt
|
|
88637
|
-
};
|
|
88638
|
-
await userStorage.set(`wallet:${name}`, metadata);
|
|
88639
|
-
return {
|
|
88640
|
-
name: walletInfo.name,
|
|
88641
|
-
address: walletInfo.address,
|
|
88642
|
-
network: walletInfo.network
|
|
88643
|
-
};
|
|
88644
|
-
}
|
|
88645
|
-
/**
|
|
88646
|
-
* List all wallets for a user
|
|
88647
|
-
*/
|
|
88648
|
-
async listWallets(userSigner) {
|
|
88649
|
-
return (await userSigner.listWallets()).map((w) => ({
|
|
88650
|
-
name: w.name,
|
|
88651
|
-
address: w.address,
|
|
88652
|
-
network: w.network,
|
|
88653
|
-
version: w.version,
|
|
88654
|
-
createdAt: w.createdAt
|
|
88655
|
-
}));
|
|
88656
|
-
}
|
|
88657
|
-
/**
|
|
88658
|
-
* Remove a wallet for a user
|
|
88659
|
-
*/
|
|
88660
|
-
async removeWallet(userSigner, userStorage, name) {
|
|
88661
|
-
const deleted = await userSigner.deleteWallet(name);
|
|
88662
|
-
if (deleted) await userStorage.delete(`wallet:${name}`);
|
|
88663
|
-
return deleted;
|
|
88664
|
-
}
|
|
88665
|
-
/**
|
|
88666
|
-
* Get or load a wallet for balance/transfer operations
|
|
88667
|
-
*/
|
|
88668
|
-
async getWalletForOperations(userSigner, name) {
|
|
88669
|
-
const walletInfo = await userSigner.getWallet(name);
|
|
88670
|
-
if (!walletInfo) throw new Error("Wallet not found");
|
|
88671
|
-
const network = this.getNetwork(walletInfo.network);
|
|
88672
|
-
const walletId = createWalletId(network, walletInfo.address);
|
|
88673
|
-
if (this.loadedWallets.has(walletId)) return this.loadedWallets.get(walletId);
|
|
88674
|
-
const signer = userSigner.getUnderlyingSigner();
|
|
88675
|
-
if (typeof signer.getLoadedWallet === "function") {
|
|
88676
|
-
const scopedId = `${userSigner.getUserId()}:${name}`;
|
|
88677
|
-
const wallet = await signer.getLoadedWallet(scopedId);
|
|
88678
|
-
this.loadedWallets.set(walletId, wallet);
|
|
88679
|
-
return wallet;
|
|
88680
|
-
}
|
|
88681
|
-
if (typeof signer.getStoredWallet === "function") {
|
|
88682
|
-
const scopedId = `${userSigner.getUserId()}:${name}`;
|
|
88683
|
-
const storedWallet = signer.getStoredWallet(scopedId);
|
|
88684
|
-
if (storedWallet) {
|
|
88685
|
-
const kit = await this.getKit();
|
|
88686
|
-
const signerInstance = await Signer.fromMnemonic(storedWallet.mnemonic, { type: "ton" });
|
|
88687
|
-
const walletAdapter = storedWallet.version === "v5r1" ? await WalletV5R1Adapter.create(signerInstance, {
|
|
88688
|
-
client: kit.getApiClient(network),
|
|
88689
|
-
network
|
|
88690
|
-
}) : await WalletV4R2Adapter.create(signerInstance, {
|
|
88691
|
-
client: kit.getApiClient(network),
|
|
88692
|
-
network
|
|
88693
|
-
});
|
|
88694
|
-
let wallet = await kit.addWallet(walletAdapter);
|
|
88695
|
-
if (!wallet) wallet = kit.getWallet(walletId);
|
|
88696
|
-
if (!wallet) throw new Error("Failed to load wallet");
|
|
88697
|
-
this.loadedWallets.set(walletId, wallet);
|
|
88698
|
-
return wallet;
|
|
88699
|
-
}
|
|
88700
|
-
}
|
|
88701
|
-
throw new Error("Unable to load wallet for operations");
|
|
88702
|
-
}
|
|
88703
|
-
/**
|
|
88704
88206
|
* Get TON balance
|
|
88705
88207
|
*/
|
|
88706
|
-
async getBalance(
|
|
88707
|
-
return
|
|
88208
|
+
async getBalance() {
|
|
88209
|
+
return this.wallet.getBalance();
|
|
88708
88210
|
}
|
|
88709
88211
|
/**
|
|
88710
88212
|
* Get Jetton balance
|
|
88711
88213
|
*/
|
|
88712
|
-
async getJettonBalance(
|
|
88713
|
-
return
|
|
88214
|
+
async getJettonBalance(jettonAddress) {
|
|
88215
|
+
return this.wallet.getJettonBalance(jettonAddress);
|
|
88714
88216
|
}
|
|
88715
88217
|
/**
|
|
88716
88218
|
* Get all Jettons
|
|
88717
88219
|
*/
|
|
88718
|
-
async getJettons(
|
|
88719
|
-
return (await
|
|
88220
|
+
async getJettons() {
|
|
88221
|
+
return (await this.wallet.getJettons({ pagination: {
|
|
88720
88222
|
limit: 100,
|
|
88721
88223
|
offset: 0
|
|
88722
88224
|
} })).jettons.map((j) => ({
|
|
@@ -88728,15 +88230,11 @@ var McpWalletService = class {
|
|
|
88728
88230
|
}));
|
|
88729
88231
|
}
|
|
88730
88232
|
/**
|
|
88731
|
-
* Get transaction history
|
|
88732
|
-
*/
|
|
88733
|
-
/**
|
|
88734
|
-
* Get transaction history using events API (like demo wallet)
|
|
88233
|
+
* Get transaction history using events API
|
|
88735
88234
|
*/
|
|
88736
|
-
async getTransactions(
|
|
88737
|
-
const
|
|
88738
|
-
const
|
|
88739
|
-
const response = await wallet.getClient().getEvents({
|
|
88235
|
+
async getTransactions(limit = 20) {
|
|
88236
|
+
const address = this.wallet.getAddress();
|
|
88237
|
+
const response = await this.wallet.getClient().getEvents({
|
|
88740
88238
|
account: address,
|
|
88741
88239
|
limit
|
|
88742
88240
|
});
|
|
@@ -88781,49 +88279,16 @@ var McpWalletService = class {
|
|
|
88781
88279
|
return results;
|
|
88782
88280
|
}
|
|
88783
88281
|
/**
|
|
88784
|
-
* Send TON
|
|
88785
|
-
*/
|
|
88786
|
-
async sendTon(userSigner, userStorage, walletName, toAddress, amountNano, amountTon, comment) {
|
|
88787
|
-
const limitCheck = await this.limitsManager.checkTransactionLimit(userStorage, parseFloat(amountTon));
|
|
88788
|
-
if (!limitCheck.allowed) return {
|
|
88789
|
-
success: false,
|
|
88790
|
-
message: limitCheck.reason
|
|
88791
|
-
};
|
|
88792
|
-
if (this.requiresConfirmation()) {
|
|
88793
|
-
const pending = await this.pendingManager.createPending(userStorage, {
|
|
88794
|
-
type: "send_ton",
|
|
88795
|
-
walletName,
|
|
88796
|
-
description: `Send ${amountTon} TON to ${toAddress}${comment ? ` (${comment})` : ""}`,
|
|
88797
|
-
data: {
|
|
88798
|
-
type: "send_ton",
|
|
88799
|
-
toAddress,
|
|
88800
|
-
amountNano,
|
|
88801
|
-
amountTon,
|
|
88802
|
-
comment
|
|
88803
|
-
}
|
|
88804
|
-
});
|
|
88805
|
-
return {
|
|
88806
|
-
success: true,
|
|
88807
|
-
message: `Transaction pending confirmation. ID: ${pending.id}`,
|
|
88808
|
-
pendingTransactionId: pending.id
|
|
88809
|
-
};
|
|
88810
|
-
}
|
|
88811
|
-
return this.executeTonTransfer(userSigner, userStorage, walletName, toAddress, amountNano, comment);
|
|
88812
|
-
}
|
|
88813
|
-
/**
|
|
88814
|
-
* Execute TON transfer (internal)
|
|
88282
|
+
* Send TON
|
|
88815
88283
|
*/
|
|
88816
|
-
async
|
|
88284
|
+
async sendTon(toAddress, amountNano, comment) {
|
|
88817
88285
|
try {
|
|
88818
|
-
const
|
|
88819
|
-
const tx = await wallet.createTransferTonTransaction({
|
|
88286
|
+
const tx = await this.wallet.createTransferTonTransaction({
|
|
88820
88287
|
recipientAddress: toAddress,
|
|
88821
88288
|
transferAmount: amountNano,
|
|
88822
88289
|
comment
|
|
88823
88290
|
});
|
|
88824
|
-
await wallet.sendTransaction(tx);
|
|
88825
|
-
const amountTon = Number(BigInt(amountNano)) / 1e9;
|
|
88826
|
-
await this.limitsManager.recordTransaction(userStorage, amountTon);
|
|
88291
|
+
await this.wallet.sendTransaction(tx);
|
|
88827
88292
|
return {
|
|
88828
88293
|
success: true,
|
|
88829
88294
|
message: `Successfully sent ${amountNano} nanoTON to ${toAddress}`
|
|
@@ -88836,49 +88301,37 @@ var McpWalletService = class {
|
|
|
88836
88301
|
}
|
|
88837
88302
|
}
|
|
88838
88303
|
/**
|
|
88839
|
-
* Send Jetton
|
|
88304
|
+
* Send Jetton
|
|
88840
88305
|
*/
|
|
88841
|
-
async sendJetton(
|
|
88842
|
-
|
|
88843
|
-
const
|
|
88844
|
-
|
|
88845
|
-
|
|
88846
|
-
|
|
88847
|
-
|
|
88848
|
-
type: "send_jetton",
|
|
88849
|
-
toAddress,
|
|
88850
|
-
jettonAddress,
|
|
88851
|
-
amountRaw,
|
|
88852
|
-
amountHuman,
|
|
88853
|
-
symbol,
|
|
88854
|
-
decimals,
|
|
88855
|
-
comment
|
|
88856
|
-
}
|
|
88306
|
+
async sendJetton(toAddress, jettonAddress, amountRaw, comment) {
|
|
88307
|
+
try {
|
|
88308
|
+
const tx = await this.wallet.createTransferJettonTransaction({
|
|
88309
|
+
recipientAddress: toAddress,
|
|
88310
|
+
jettonAddress,
|
|
88311
|
+
transferAmount: amountRaw,
|
|
88312
|
+
comment
|
|
88857
88313
|
});
|
|
88314
|
+
await this.wallet.sendTransaction(tx);
|
|
88858
88315
|
return {
|
|
88859
88316
|
success: true,
|
|
88860
|
-
message: `
|
|
88861
|
-
|
|
88317
|
+
message: `Successfully sent jettons to ${toAddress}`
|
|
88318
|
+
};
|
|
88319
|
+
} catch (error) {
|
|
88320
|
+
return {
|
|
88321
|
+
success: false,
|
|
88322
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
88862
88323
|
};
|
|
88863
88324
|
}
|
|
88864
|
-
return this.executeJettonTransfer(userSigner, walletName, toAddress, jettonAddress, amountRaw, comment);
|
|
88865
88325
|
}
|
|
88866
88326
|
/**
|
|
88867
|
-
*
|
|
88327
|
+
* Send a raw transaction request directly
|
|
88868
88328
|
*/
|
|
88869
|
-
async
|
|
88329
|
+
async sendRawTransaction(request) {
|
|
88870
88330
|
try {
|
|
88871
|
-
|
|
88872
|
-
const tx = await wallet.createTransferJettonTransaction({
|
|
88873
|
-
recipientAddress: toAddress,
|
|
88874
|
-
jettonAddress,
|
|
88875
|
-
transferAmount: amountRaw,
|
|
88876
|
-
comment
|
|
88877
|
-
});
|
|
88878
|
-
await wallet.sendTransaction(tx);
|
|
88331
|
+
await this.wallet.sendTransaction(request);
|
|
88879
88332
|
return {
|
|
88880
88333
|
success: true,
|
|
88881
|
-
message: `Successfully sent
|
|
88334
|
+
message: `Successfully sent transaction with ${request.messages.length} message(s)`
|
|
88882
88335
|
};
|
|
88883
88336
|
} catch (error) {
|
|
88884
88337
|
return {
|
|
@@ -88888,80 +88341,114 @@ var McpWalletService = class {
|
|
|
88888
88341
|
}
|
|
88889
88342
|
}
|
|
88890
88343
|
/**
|
|
88891
|
-
* Get swap quote
|
|
88344
|
+
* Get swap quote with transaction params ready to execute
|
|
88892
88345
|
*/
|
|
88893
|
-
async getSwapQuote(
|
|
88894
|
-
const
|
|
88895
|
-
if (!walletInfo) throw new Error("Wallet not found");
|
|
88896
|
-
const network = this.getNetwork(walletInfo.network);
|
|
88346
|
+
async getSwapQuote(fromToken, toToken, amount, slippageBps) {
|
|
88347
|
+
const network = this.wallet.getNetwork();
|
|
88897
88348
|
const kit = await this.getKit();
|
|
88898
88349
|
const params = {
|
|
88899
|
-
fromToken: fromToken === "TON" ? "
|
|
88900
|
-
|
|
88901
|
-
|
|
88350
|
+
fromToken: fromToken === "TON" ? { type: "ton" } : {
|
|
88351
|
+
type: "jetton",
|
|
88352
|
+
value: fromToken
|
|
88353
|
+
},
|
|
88354
|
+
toToken: toToken === "TON" ? { type: "ton" } : {
|
|
88355
|
+
type: "jetton",
|
|
88356
|
+
value: toToken
|
|
88357
|
+
},
|
|
88358
|
+
amount,
|
|
88902
88359
|
network,
|
|
88903
88360
|
slippageBps
|
|
88904
88361
|
};
|
|
88905
88362
|
const quote = await kit.swap.getQuote(params);
|
|
88906
|
-
|
|
88363
|
+
const swapParams = {
|
|
88907
88364
|
quote,
|
|
88908
|
-
|
|
88909
|
-
|
|
88365
|
+
userAddress: this.wallet.getAddress()
|
|
88366
|
+
};
|
|
88367
|
+
const tx = await kit.swap.buildSwapTransaction(swapParams);
|
|
88368
|
+
return {
|
|
88369
|
+
fromToken: quote.fromToken.type === "ton" ? "TON" : quote.fromToken.value,
|
|
88370
|
+
toToken: quote.toToken.type === "ton" ? "TON" : quote.toToken.value,
|
|
88910
88371
|
fromAmount: quote.fromAmount,
|
|
88911
88372
|
toAmount: quote.toAmount,
|
|
88912
88373
|
minReceived: quote.minReceived,
|
|
88913
|
-
provider: quote.
|
|
88914
|
-
expiresAt: quote.expiresAt
|
|
88374
|
+
provider: quote.providerId,
|
|
88375
|
+
expiresAt: quote.expiresAt,
|
|
88376
|
+
transaction: {
|
|
88377
|
+
messages: tx.messages.map((m) => ({
|
|
88378
|
+
address: m.address,
|
|
88379
|
+
amount: m.amount.toString(),
|
|
88380
|
+
stateInit: m.stateInit,
|
|
88381
|
+
payload: m.payload
|
|
88382
|
+
})),
|
|
88383
|
+
validUntil: tx.validUntil
|
|
88384
|
+
}
|
|
88915
88385
|
};
|
|
88916
88386
|
}
|
|
88917
88387
|
/**
|
|
88918
|
-
*
|
|
88388
|
+
* Get all NFTs
|
|
88919
88389
|
*/
|
|
88920
|
-
async
|
|
88921
|
-
|
|
88922
|
-
|
|
88923
|
-
|
|
88924
|
-
|
|
88925
|
-
|
|
88926
|
-
|
|
88927
|
-
|
|
88928
|
-
|
|
88929
|
-
|
|
88930
|
-
|
|
88931
|
-
|
|
88932
|
-
|
|
88933
|
-
|
|
88934
|
-
|
|
88935
|
-
|
|
88936
|
-
})
|
|
88937
|
-
|
|
88938
|
-
|
|
88939
|
-
|
|
88940
|
-
|
|
88941
|
-
|
|
88942
|
-
}
|
|
88943
|
-
return this.executeSwapInternal(userSigner, walletName, quote);
|
|
88390
|
+
async getNfts(limit = 20, offset = 0) {
|
|
88391
|
+
return (await this.wallet.getNfts({ pagination: {
|
|
88392
|
+
limit,
|
|
88393
|
+
offset
|
|
88394
|
+
} })).nfts.map((nft) => ({
|
|
88395
|
+
address: nft.address,
|
|
88396
|
+
name: nft.info?.name,
|
|
88397
|
+
description: nft.info?.description,
|
|
88398
|
+
image: typeof nft.info?.image === "string" ? nft.info.image : nft.info?.image?.url,
|
|
88399
|
+
collection: nft.collection ? {
|
|
88400
|
+
address: nft.collection.address,
|
|
88401
|
+
name: nft.collection.name
|
|
88402
|
+
} : void 0,
|
|
88403
|
+
attributes: nft.attributes?.map((attr) => ({
|
|
88404
|
+
trait_type: attr.traitType,
|
|
88405
|
+
value: attr.value
|
|
88406
|
+
})),
|
|
88407
|
+
ownerAddress: nft.ownerAddress,
|
|
88408
|
+
isOnSale: nft.isOnSale,
|
|
88409
|
+
isSoulbound: nft.isSoulbound,
|
|
88410
|
+
saleContractAddress: nft.saleContractAddress
|
|
88411
|
+
}));
|
|
88944
88412
|
}
|
|
88945
88413
|
/**
|
|
88946
|
-
*
|
|
88414
|
+
* Get a specific NFT by address
|
|
88947
88415
|
*/
|
|
88948
|
-
async
|
|
88416
|
+
async getNft(nftAddress) {
|
|
88417
|
+
const nft = await this.wallet.getNft(nftAddress);
|
|
88418
|
+
if (!nft) return null;
|
|
88419
|
+
return {
|
|
88420
|
+
address: nft.address,
|
|
88421
|
+
name: nft.info?.name,
|
|
88422
|
+
description: nft.info?.description,
|
|
88423
|
+
image: typeof nft.info?.image === "string" ? nft.info.image : nft.info?.image?.url,
|
|
88424
|
+
collection: nft.collection ? {
|
|
88425
|
+
address: nft.collection.address,
|
|
88426
|
+
name: nft.collection.name
|
|
88427
|
+
} : void 0,
|
|
88428
|
+
attributes: nft.attributes?.map((attr) => ({
|
|
88429
|
+
trait_type: attr.traitType,
|
|
88430
|
+
value: attr.value
|
|
88431
|
+
})),
|
|
88432
|
+
ownerAddress: nft.ownerAddress,
|
|
88433
|
+
isOnSale: nft.isOnSale,
|
|
88434
|
+
isSoulbound: nft.isSoulbound,
|
|
88435
|
+
saleContractAddress: nft.saleContractAddress
|
|
88436
|
+
};
|
|
88437
|
+
}
|
|
88438
|
+
/**
|
|
88439
|
+
* Send NFT
|
|
88440
|
+
*/
|
|
88441
|
+
async sendNft(nftAddress, toAddress, comment) {
|
|
88949
88442
|
try {
|
|
88950
|
-
const
|
|
88951
|
-
|
|
88952
|
-
|
|
88953
|
-
|
|
88954
|
-
|
|
88955
|
-
|
|
88956
|
-
const params = {
|
|
88957
|
-
quote,
|
|
88958
|
-
userAddress: walletInfo.address
|
|
88959
|
-
};
|
|
88960
|
-
const tx = await kit.swap.buildSwapTransaction(params);
|
|
88961
|
-
await wallet.sendTransaction(tx);
|
|
88443
|
+
const tx = await this.wallet.createTransferNftTransaction({
|
|
88444
|
+
nftAddress,
|
|
88445
|
+
recipientAddress: toAddress,
|
|
88446
|
+
comment
|
|
88447
|
+
});
|
|
88448
|
+
await this.wallet.sendTransaction(tx);
|
|
88962
88449
|
return {
|
|
88963
88450
|
success: true,
|
|
88964
|
-
message: `Successfully
|
|
88451
|
+
message: `Successfully sent NFT ${nftAddress} to ${toAddress}`
|
|
88965
88452
|
};
|
|
88966
88453
|
} catch (error) {
|
|
88967
88454
|
return {
|
|
@@ -88971,52 +88458,11 @@ var McpWalletService = class {
|
|
|
88971
88458
|
}
|
|
88972
88459
|
}
|
|
88973
88460
|
/**
|
|
88974
|
-
* Confirm a pending transaction
|
|
88975
|
-
*/
|
|
88976
|
-
async confirmTransaction(userSigner, userStorage, transactionId) {
|
|
88977
|
-
const pending = await this.pendingManager.confirmPending(userStorage, transactionId);
|
|
88978
|
-
if (!pending) return {
|
|
88979
|
-
success: false,
|
|
88980
|
-
message: "Transaction not found or expired"
|
|
88981
|
-
};
|
|
88982
|
-
switch (pending.data.type) {
|
|
88983
|
-
case "send_ton": {
|
|
88984
|
-
const data = pending.data;
|
|
88985
|
-
return this.executeTonTransfer(userSigner, userStorage, pending.walletName, data.toAddress, data.amountNano, data.comment);
|
|
88986
|
-
}
|
|
88987
|
-
case "send_jetton": {
|
|
88988
|
-
const data = pending.data;
|
|
88989
|
-
return this.executeJettonTransfer(userSigner, pending.walletName, data.toAddress, data.jettonAddress, data.amountRaw, data.comment);
|
|
88990
|
-
}
|
|
88991
|
-
case "swap": {
|
|
88992
|
-
const data = pending.data;
|
|
88993
|
-
const quote = JSON.parse(data.quoteJson);
|
|
88994
|
-
return this.executeSwapInternal(userSigner, pending.walletName, quote);
|
|
88995
|
-
}
|
|
88996
|
-
default: return {
|
|
88997
|
-
success: false,
|
|
88998
|
-
message: "Unknown transaction type"
|
|
88999
|
-
};
|
|
89000
|
-
}
|
|
89001
|
-
}
|
|
89002
|
-
/**
|
|
89003
|
-
* Cancel a pending transaction
|
|
89004
|
-
*/
|
|
89005
|
-
async cancelTransaction(userStorage, transactionId) {
|
|
89006
|
-
return this.pendingManager.cancelPending(userStorage, transactionId);
|
|
89007
|
-
}
|
|
89008
|
-
/**
|
|
89009
|
-
* List pending transactions
|
|
89010
|
-
*/
|
|
89011
|
-
async listPendingTransactions(userStorage) {
|
|
89012
|
-
return this.pendingManager.listPending(userStorage);
|
|
89013
|
-
}
|
|
89014
|
-
/**
|
|
89015
88461
|
* Resolve contact name to address
|
|
89016
88462
|
*/
|
|
89017
|
-
async resolveContact(
|
|
88463
|
+
async resolveContact(name) {
|
|
89018
88464
|
if (!this.config.contacts) return null;
|
|
89019
|
-
return this.config.contacts.resolve(
|
|
88465
|
+
return this.config.contacts.resolve("default", name);
|
|
89020
88466
|
}
|
|
89021
88467
|
/**
|
|
89022
88468
|
* Close and cleanup
|
|
@@ -89026,12 +88472,11 @@ var McpWalletService = class {
|
|
|
89026
88472
|
await this.kit.close();
|
|
89027
88473
|
this.kit = null;
|
|
89028
88474
|
}
|
|
89029
|
-
this.loadedWallets.clear();
|
|
89030
88475
|
}
|
|
89031
88476
|
};
|
|
89032
88477
|
|
|
89033
88478
|
//#endregion
|
|
89034
|
-
//#region src/tools/
|
|
88479
|
+
//#region src/tools/balance-tools.ts
|
|
89035
88480
|
/**
|
|
89036
88481
|
* Copyright (c) TonTech.
|
|
89037
88482
|
*
|
|
@@ -89039,185 +88484,24 @@ var McpWalletService = class {
|
|
|
89039
88484
|
* LICENSE file in the root directory of this source tree.
|
|
89040
88485
|
*
|
|
89041
88486
|
*/
|
|
89042
|
-
|
|
89043
|
-
|
|
89044
|
-
|
|
89045
|
-
|
|
89046
|
-
|
|
89047
|
-
*/
|
|
89048
|
-
/**
|
|
89049
|
-
* Converts a human-readable amount to raw units.
|
|
89050
|
-
*/
|
|
89051
|
-
function toRawAmount(amount, decimals) {
|
|
89052
|
-
const [intPart, fracPart = ""] = amount.split(".");
|
|
89053
|
-
return (intPart + fracPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
|
|
89054
|
-
}
|
|
89055
|
-
const TON_DECIMALS = 9;
|
|
89056
|
-
const createWalletSchema = z.object({
|
|
89057
|
-
name: z.string().min(1).describe("Unique name for the wallet"),
|
|
89058
|
-
version: z.enum(["v5r1", "v4r2"]).optional().describe("Wallet version (v5r1 recommended, v4r2 for legacy compatibility). Defaults to v5r1."),
|
|
89059
|
-
network: z.enum(["mainnet", "testnet"]).optional().describe("Network to create the wallet on. Defaults to the server configured network.")
|
|
89060
|
-
});
|
|
89061
|
-
const importWalletSchema = z.object({
|
|
89062
|
-
name: z.string().min(1).describe("Unique name for the wallet"),
|
|
89063
|
-
mnemonic: z.string().describe("24-word mnemonic phrase separated by spaces"),
|
|
89064
|
-
version: z.enum(["v5r1", "v4r2"]).optional().describe("Wallet version (v5r1 recommended, v4r2 for legacy compatibility). Defaults to v5r1."),
|
|
89065
|
-
network: z.enum(["mainnet", "testnet"]).optional().describe("Network to import the wallet on. Defaults to the server configured network.")
|
|
89066
|
-
});
|
|
89067
|
-
const removeWalletSchema = z.object({ name: z.string().min(1).describe("Name of the wallet to remove") });
|
|
89068
|
-
function createMcpWalletTools(_walletService, wrapHandler) {
|
|
89069
|
-
return {
|
|
89070
|
-
create_wallet: {
|
|
89071
|
-
description: "Create a new TON wallet. The wallet is created securely and you will receive the address. No seed phrase is exposed.",
|
|
89072
|
-
inputSchema: createWalletSchema,
|
|
89073
|
-
handler: wrapHandler(async (args, userId, service) => {
|
|
89074
|
-
const userSigner = service.createUserSigner(userId);
|
|
89075
|
-
const userStorage = service.createUserStorage(userId);
|
|
89076
|
-
try {
|
|
89077
|
-
const result = await service.createWallet(userSigner, userStorage, args.name, args.version, args.network);
|
|
89078
|
-
return { content: [{
|
|
89079
|
-
type: "text",
|
|
89080
|
-
text: JSON.stringify({
|
|
89081
|
-
success: true,
|
|
89082
|
-
wallet: {
|
|
89083
|
-
name: result.name,
|
|
89084
|
-
address: result.address,
|
|
89085
|
-
network: result.network
|
|
89086
|
-
}
|
|
89087
|
-
}, null, 2)
|
|
89088
|
-
}] };
|
|
89089
|
-
} catch (error) {
|
|
89090
|
-
return {
|
|
89091
|
-
content: [{
|
|
89092
|
-
type: "text",
|
|
89093
|
-
text: JSON.stringify({
|
|
89094
|
-
success: false,
|
|
89095
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
89096
|
-
})
|
|
89097
|
-
}],
|
|
89098
|
-
isError: true
|
|
89099
|
-
};
|
|
89100
|
-
}
|
|
89101
|
-
})
|
|
89102
|
-
},
|
|
89103
|
-
import_wallet: {
|
|
89104
|
-
description: "Import an existing TON wallet using a 24-word mnemonic phrase. The mnemonic is stored securely and never exposed.",
|
|
89105
|
-
inputSchema: importWalletSchema,
|
|
89106
|
-
handler: wrapHandler(async (args, userId, service) => {
|
|
89107
|
-
const mnemonicWords = args.mnemonic.trim().split(/\s+/);
|
|
89108
|
-
if (mnemonicWords.length !== 24) return {
|
|
89109
|
-
content: [{
|
|
89110
|
-
type: "text",
|
|
89111
|
-
text: JSON.stringify({
|
|
89112
|
-
success: false,
|
|
89113
|
-
error: `Invalid mnemonic: expected 24 words, got ${mnemonicWords.length}`
|
|
89114
|
-
})
|
|
89115
|
-
}],
|
|
89116
|
-
isError: true
|
|
89117
|
-
};
|
|
89118
|
-
const userSigner = service.createUserSigner(userId);
|
|
89119
|
-
const userStorage = service.createUserStorage(userId);
|
|
89120
|
-
try {
|
|
89121
|
-
const result = await service.importWallet(userSigner, userStorage, args.name, mnemonicWords, args.version, args.network);
|
|
89122
|
-
return { content: [{
|
|
89123
|
-
type: "text",
|
|
89124
|
-
text: JSON.stringify({
|
|
89125
|
-
success: true,
|
|
89126
|
-
wallet: {
|
|
89127
|
-
name: result.name,
|
|
89128
|
-
address: result.address,
|
|
89129
|
-
network: result.network
|
|
89130
|
-
}
|
|
89131
|
-
}, null, 2)
|
|
89132
|
-
}] };
|
|
89133
|
-
} catch (error) {
|
|
89134
|
-
return {
|
|
89135
|
-
content: [{
|
|
89136
|
-
type: "text",
|
|
89137
|
-
text: JSON.stringify({
|
|
89138
|
-
success: false,
|
|
89139
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
89140
|
-
})
|
|
89141
|
-
}],
|
|
89142
|
-
isError: true
|
|
89143
|
-
};
|
|
89144
|
-
}
|
|
89145
|
-
})
|
|
89146
|
-
},
|
|
89147
|
-
list_wallets: {
|
|
89148
|
-
description: "List all your stored TON wallets with their addresses and metadata.",
|
|
89149
|
-
inputSchema: z.object({}),
|
|
89150
|
-
handler: wrapHandler(async (_args, userId, service) => {
|
|
89151
|
-
const userSigner = service.createUserSigner(userId);
|
|
89152
|
-
const wallets = await service.listWallets(userSigner);
|
|
89153
|
-
return { content: [{
|
|
89154
|
-
type: "text",
|
|
89155
|
-
text: JSON.stringify({
|
|
89156
|
-
success: true,
|
|
89157
|
-
wallets: wallets.map((w) => ({
|
|
89158
|
-
name: w.name,
|
|
89159
|
-
address: w.address,
|
|
89160
|
-
network: w.network,
|
|
89161
|
-
version: w.version,
|
|
89162
|
-
createdAt: w.createdAt
|
|
89163
|
-
})),
|
|
89164
|
-
count: wallets.length
|
|
89165
|
-
}, null, 2)
|
|
89166
|
-
}] };
|
|
89167
|
-
})
|
|
89168
|
-
},
|
|
89169
|
-
remove_wallet: {
|
|
89170
|
-
description: "Remove a wallet from storage. This action cannot be undone!",
|
|
89171
|
-
inputSchema: removeWalletSchema,
|
|
89172
|
-
handler: wrapHandler(async (args, userId, service) => {
|
|
89173
|
-
const userSigner = service.createUserSigner(userId);
|
|
89174
|
-
const userStorage = service.createUserStorage(userId);
|
|
89175
|
-
if (!await service.removeWallet(userSigner, userStorage, args.name)) return {
|
|
89176
|
-
content: [{
|
|
89177
|
-
type: "text",
|
|
89178
|
-
text: JSON.stringify({
|
|
89179
|
-
success: false,
|
|
89180
|
-
error: "Wallet not found"
|
|
89181
|
-
})
|
|
89182
|
-
}],
|
|
89183
|
-
isError: true
|
|
89184
|
-
};
|
|
89185
|
-
return { content: [{
|
|
89186
|
-
type: "text",
|
|
89187
|
-
text: JSON.stringify({
|
|
89188
|
-
success: true,
|
|
89189
|
-
message: `Wallet "${args.name}" has been removed`
|
|
89190
|
-
})
|
|
89191
|
-
}] };
|
|
89192
|
-
})
|
|
89193
|
-
}
|
|
89194
|
-
};
|
|
89195
|
-
}
|
|
89196
|
-
const getBalanceSchema = z.object({ wallet: z.string().min(1).describe("Name of the wallet to check balance") });
|
|
89197
|
-
const getJettonBalanceSchema = z.object({
|
|
89198
|
-
wallet: z.string().min(1).describe("Name of the wallet"),
|
|
89199
|
-
jettonAddress: z.string().min(1).describe("Jetton master contract address")
|
|
89200
|
-
});
|
|
89201
|
-
const getJettonsSchema = z.object({ wallet: z.string().min(1).describe("Name of the wallet") });
|
|
89202
|
-
const getTransactionsSchema = z.object({
|
|
89203
|
-
wallet: z.string().min(1).describe("Name of the wallet to get transactions for"),
|
|
89204
|
-
limit: z.number().min(1).max(100).optional().describe("Maximum number of transactions to return (default: 20, max: 100)")
|
|
89205
|
-
});
|
|
89206
|
-
function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
88487
|
+
const getBalanceSchema = z.object({});
|
|
88488
|
+
const getJettonBalanceSchema = z.object({ jettonAddress: z.string().min(1).describe("Jetton master contract address") });
|
|
88489
|
+
const getJettonsSchema = z.object({});
|
|
88490
|
+
const getTransactionsSchema = z.object({ limit: z.number().min(1).max(100).optional().describe("Maximum number of transactions to return (default: 20, max: 100)") });
|
|
88491
|
+
function createMcpBalanceTools(service) {
|
|
89207
88492
|
return {
|
|
89208
88493
|
get_balance: {
|
|
89209
|
-
description: "Get the TON balance of
|
|
88494
|
+
description: "Get the TON balance of the wallet. Returns both human-readable and raw (nanoTON) amounts.",
|
|
89210
88495
|
inputSchema: getBalanceSchema,
|
|
89211
|
-
handler:
|
|
89212
|
-
const userSigner = service.createUserSigner(userId);
|
|
88496
|
+
handler: async () => {
|
|
89213
88497
|
try {
|
|
89214
|
-
const balance = await service.getBalance(
|
|
88498
|
+
const balance = await service.getBalance();
|
|
89215
88499
|
const balanceTon = Number(BigInt(balance)) / 1e9;
|
|
89216
88500
|
return { content: [{
|
|
89217
88501
|
type: "text",
|
|
89218
88502
|
text: JSON.stringify({
|
|
89219
88503
|
success: true,
|
|
89220
|
-
|
|
88504
|
+
address: service.getAddress(),
|
|
89221
88505
|
balance: `${balanceTon} TON`,
|
|
89222
88506
|
balanceNano: balance
|
|
89223
88507
|
}, null, 2)
|
|
@@ -89234,20 +88518,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89234
88518
|
isError: true
|
|
89235
88519
|
};
|
|
89236
88520
|
}
|
|
89237
|
-
}
|
|
88521
|
+
}
|
|
89238
88522
|
},
|
|
89239
88523
|
get_jetton_balance: {
|
|
89240
|
-
description: "Get the balance of a specific Jetton (token) in
|
|
88524
|
+
description: "Get the balance of a specific Jetton (token) in the wallet.",
|
|
89241
88525
|
inputSchema: getJettonBalanceSchema,
|
|
89242
|
-
handler:
|
|
89243
|
-
const userSigner = service.createUserSigner(userId);
|
|
88526
|
+
handler: async (args) => {
|
|
89244
88527
|
try {
|
|
89245
|
-
const balance = await service.getJettonBalance(
|
|
88528
|
+
const balance = await service.getJettonBalance(args.jettonAddress);
|
|
89246
88529
|
return { content: [{
|
|
89247
88530
|
type: "text",
|
|
89248
88531
|
text: JSON.stringify({
|
|
89249
88532
|
success: true,
|
|
89250
|
-
wallet: args.wallet,
|
|
89251
88533
|
jettonAddress: args.jettonAddress,
|
|
89252
88534
|
balance
|
|
89253
88535
|
}, null, 2)
|
|
@@ -89264,20 +88546,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89264
88546
|
isError: true
|
|
89265
88547
|
};
|
|
89266
88548
|
}
|
|
89267
|
-
}
|
|
88549
|
+
}
|
|
89268
88550
|
},
|
|
89269
88551
|
get_jettons: {
|
|
89270
|
-
description: "List all Jettons (tokens) in
|
|
88552
|
+
description: "List all Jettons (tokens) in the wallet with their balances and metadata.",
|
|
89271
88553
|
inputSchema: getJettonsSchema,
|
|
89272
|
-
handler:
|
|
89273
|
-
const userSigner = service.createUserSigner(userId);
|
|
88554
|
+
handler: async () => {
|
|
89274
88555
|
try {
|
|
89275
|
-
const jettons = await service.getJettons(
|
|
88556
|
+
const jettons = await service.getJettons();
|
|
89276
88557
|
return { content: [{
|
|
89277
88558
|
type: "text",
|
|
89278
88559
|
text: JSON.stringify({
|
|
89279
88560
|
success: true,
|
|
89280
|
-
wallet: args.wallet,
|
|
89281
88561
|
jettons,
|
|
89282
88562
|
count: jettons.length
|
|
89283
88563
|
}, null, 2)
|
|
@@ -89294,20 +88574,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89294
88574
|
isError: true
|
|
89295
88575
|
};
|
|
89296
88576
|
}
|
|
89297
|
-
}
|
|
88577
|
+
}
|
|
89298
88578
|
},
|
|
89299
88579
|
get_transactions: {
|
|
89300
|
-
description: "Get recent transaction history for
|
|
88580
|
+
description: "Get recent transaction history for the wallet. Returns events with actions like TON transfers, Jetton transfers, swaps, and more.",
|
|
89301
88581
|
inputSchema: getTransactionsSchema,
|
|
89302
|
-
handler:
|
|
89303
|
-
const userSigner = service.createUserSigner(userId);
|
|
88582
|
+
handler: async (args) => {
|
|
89304
88583
|
try {
|
|
89305
|
-
const transactions = await service.getTransactions(
|
|
88584
|
+
const transactions = await service.getTransactions(args.limit ?? 20);
|
|
89306
88585
|
return { content: [{
|
|
89307
88586
|
type: "text",
|
|
89308
88587
|
text: JSON.stringify({
|
|
89309
88588
|
success: true,
|
|
89310
|
-
wallet: args.wallet,
|
|
89311
88589
|
transactions: transactions.map((tx) => ({
|
|
89312
88590
|
eventId: tx.eventId,
|
|
89313
88591
|
timestamp: tx.timestamp,
|
|
@@ -89355,33 +88633,61 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89355
88633
|
isError: true
|
|
89356
88634
|
};
|
|
89357
88635
|
}
|
|
89358
|
-
}
|
|
88636
|
+
}
|
|
89359
88637
|
}
|
|
89360
88638
|
};
|
|
89361
88639
|
}
|
|
88640
|
+
|
|
88641
|
+
//#endregion
|
|
88642
|
+
//#region src/tools/types.ts
|
|
88643
|
+
/**
|
|
88644
|
+
* Converts a human-readable amount to raw units.
|
|
88645
|
+
*/
|
|
88646
|
+
function toRawAmount(amount, decimals) {
|
|
88647
|
+
const [intPart, fracPart = ""] = amount.split(".");
|
|
88648
|
+
return (intPart + fracPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
|
|
88649
|
+
}
|
|
88650
|
+
const TON_DECIMALS = 9;
|
|
88651
|
+
|
|
88652
|
+
//#endregion
|
|
88653
|
+
//#region src/tools/transfer-tools.ts
|
|
88654
|
+
/**
|
|
88655
|
+
* Copyright (c) TonTech.
|
|
88656
|
+
*
|
|
88657
|
+
* This source code is licensed under the MIT license found in the
|
|
88658
|
+
* LICENSE file in the root directory of this source tree.
|
|
88659
|
+
*
|
|
88660
|
+
*/
|
|
89362
88661
|
const sendTonSchema = z.object({
|
|
89363
|
-
wallet: z.string().min(1).describe("Name of the wallet to send from"),
|
|
89364
88662
|
toAddress: z.string().min(1).describe("Recipient TON address"),
|
|
89365
88663
|
amount: z.string().min(1).describe("Amount of TON to send (e.g., \"1.5\" for 1.5 TON)"),
|
|
89366
88664
|
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
89367
88665
|
});
|
|
89368
88666
|
const sendJettonSchema = z.object({
|
|
89369
|
-
wallet: z.string().min(1).describe("Name of the wallet to send from"),
|
|
89370
88667
|
toAddress: z.string().min(1).describe("Recipient TON address"),
|
|
89371
88668
|
jettonAddress: z.string().min(1).describe("Jetton master contract address"),
|
|
89372
88669
|
amount: z.string().min(1).describe("Amount of tokens to send in human-readable format"),
|
|
89373
88670
|
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
89374
88671
|
});
|
|
89375
|
-
|
|
88672
|
+
const transactionMessageSchema = z.object({
|
|
88673
|
+
address: z.string().min(1).describe("Recipient wallet address"),
|
|
88674
|
+
amount: z.string().min(1).describe("Amount to transfer in nanotons"),
|
|
88675
|
+
stateInit: z.string().optional().describe("Initial state for deploying a new contract (Base64)"),
|
|
88676
|
+
payload: z.string().optional().describe("Message payload data (Base64)")
|
|
88677
|
+
});
|
|
88678
|
+
const sendRawTransactionSchema = z.object({
|
|
88679
|
+
messages: z.array(transactionMessageSchema).min(1).describe("Array of messages to include in the transaction"),
|
|
88680
|
+
validUntil: z.number().optional().describe("Unix timestamp after which the transaction becomes invalid"),
|
|
88681
|
+
fromAddress: z.string().optional().describe("Sender wallet address")
|
|
88682
|
+
});
|
|
88683
|
+
function createMcpTransferTools(service) {
|
|
89376
88684
|
return {
|
|
89377
88685
|
send_ton: {
|
|
89378
|
-
description: "Send TON from
|
|
88686
|
+
description: "Send TON from the wallet to an address. Amount is in TON (e.g., \"1.5\" means 1.5 TON).",
|
|
89379
88687
|
inputSchema: sendTonSchema,
|
|
89380
|
-
handler:
|
|
89381
|
-
const userSigner = service.createUserSigner(userId);
|
|
89382
|
-
const userStorage = service.createUserStorage(userId);
|
|
88688
|
+
handler: async (args) => {
|
|
89383
88689
|
const rawAmount = toRawAmount(args.amount, TON_DECIMALS);
|
|
89384
|
-
const result = await service.sendTon(
|
|
88690
|
+
const result = await service.sendTon(args.toAddress, rawAmount, args.comment);
|
|
89385
88691
|
if (!result.success) return {
|
|
89386
88692
|
content: [{
|
|
89387
88693
|
type: "text",
|
|
@@ -89398,26 +88704,22 @@ function createMcpTransferTools(_walletService, wrapHandler) {
|
|
|
89398
88704
|
success: true,
|
|
89399
88705
|
message: result.message,
|
|
89400
88706
|
details: {
|
|
89401
|
-
from: args.wallet,
|
|
89402
88707
|
to: args.toAddress,
|
|
89403
88708
|
amount: `${args.amount} TON`,
|
|
89404
|
-
comment: args.comment || null
|
|
89405
|
-
pendingTransactionId: result.pendingTransactionId || null
|
|
88709
|
+
comment: args.comment || null
|
|
89406
88710
|
}
|
|
89407
88711
|
}, null, 2)
|
|
89408
88712
|
}] };
|
|
89409
|
-
}
|
|
88713
|
+
}
|
|
89410
88714
|
},
|
|
89411
88715
|
send_jetton: {
|
|
89412
|
-
description: "Send Jettons (tokens) from
|
|
88716
|
+
description: "Send Jettons (tokens) from the wallet to an address. Amount is in human-readable format.",
|
|
89413
88717
|
inputSchema: sendJettonSchema,
|
|
89414
|
-
handler:
|
|
89415
|
-
const userSigner = service.createUserSigner(userId);
|
|
89416
|
-
const userStorage = service.createUserStorage(userId);
|
|
88718
|
+
handler: async (args) => {
|
|
89417
88719
|
let decimals;
|
|
89418
88720
|
let symbol;
|
|
89419
88721
|
try {
|
|
89420
|
-
const jetton = (await service.getJettons(
|
|
88722
|
+
const jetton = (await service.getJettons()).find((j) => j.address.toLowerCase() === args.jettonAddress.toLowerCase());
|
|
89421
88723
|
if (jetton) {
|
|
89422
88724
|
decimals = jetton.decimals;
|
|
89423
88725
|
symbol = jetton.symbol;
|
|
@@ -89445,7 +88747,7 @@ function createMcpTransferTools(_walletService, wrapHandler) {
|
|
|
89445
88747
|
isError: true
|
|
89446
88748
|
};
|
|
89447
88749
|
const rawAmount = toRawAmount(args.amount, decimals);
|
|
89448
|
-
const result = await service.sendJetton(
|
|
88750
|
+
const result = await service.sendJetton(args.toAddress, args.jettonAddress, rawAmount, args.comment);
|
|
89449
88751
|
if (!result.success) return {
|
|
89450
88752
|
content: [{
|
|
89451
88753
|
type: "text",
|
|
@@ -89462,68 +88764,209 @@ function createMcpTransferTools(_walletService, wrapHandler) {
|
|
|
89462
88764
|
success: true,
|
|
89463
88765
|
message: result.message,
|
|
89464
88766
|
details: {
|
|
89465
|
-
from: args.wallet,
|
|
89466
88767
|
to: args.toAddress,
|
|
89467
88768
|
jettonAddress: args.jettonAddress,
|
|
89468
88769
|
amount: `${args.amount} ${symbol || "tokens"}`,
|
|
89469
|
-
comment: args.comment || null
|
|
89470
|
-
pendingTransactionId: result.pendingTransactionId || null
|
|
88770
|
+
comment: args.comment || null
|
|
89471
88771
|
}
|
|
89472
88772
|
}, null, 2)
|
|
89473
88773
|
}] };
|
|
89474
|
-
}
|
|
88774
|
+
}
|
|
88775
|
+
},
|
|
88776
|
+
send_raw_transaction: {
|
|
88777
|
+
description: "Send a raw transaction with full control over messages. Amounts are in nanotons. Supports multiple messages in a single transaction.",
|
|
88778
|
+
inputSchema: sendRawTransactionSchema,
|
|
88779
|
+
handler: async (args) => {
|
|
88780
|
+
const result = await service.sendRawTransaction({
|
|
88781
|
+
messages: args.messages,
|
|
88782
|
+
validUntil: args.validUntil,
|
|
88783
|
+
fromAddress: args.fromAddress
|
|
88784
|
+
});
|
|
88785
|
+
if (!result.success) return {
|
|
88786
|
+
content: [{
|
|
88787
|
+
type: "text",
|
|
88788
|
+
text: JSON.stringify({
|
|
88789
|
+
success: false,
|
|
88790
|
+
error: result.message
|
|
88791
|
+
})
|
|
88792
|
+
}],
|
|
88793
|
+
isError: true
|
|
88794
|
+
};
|
|
88795
|
+
return { content: [{
|
|
88796
|
+
type: "text",
|
|
88797
|
+
text: JSON.stringify({
|
|
88798
|
+
success: true,
|
|
88799
|
+
message: result.message,
|
|
88800
|
+
details: {
|
|
88801
|
+
messageCount: args.messages.length,
|
|
88802
|
+
messages: args.messages.map((m) => ({
|
|
88803
|
+
to: m.address,
|
|
88804
|
+
amount: `${m.amount} nanoTON`
|
|
88805
|
+
}))
|
|
88806
|
+
}
|
|
88807
|
+
}, null, 2)
|
|
88808
|
+
}] };
|
|
88809
|
+
}
|
|
89475
88810
|
}
|
|
89476
88811
|
};
|
|
89477
88812
|
}
|
|
89478
|
-
|
|
89479
|
-
|
|
89480
|
-
|
|
89481
|
-
|
|
89482
|
-
|
|
89483
|
-
|
|
89484
|
-
|
|
89485
|
-
|
|
88813
|
+
|
|
88814
|
+
//#endregion
|
|
88815
|
+
//#region src/tools/swap-tools.ts
|
|
88816
|
+
/**
|
|
88817
|
+
* Copyright (c) TonTech.
|
|
88818
|
+
*
|
|
88819
|
+
* This source code is licensed under the MIT license found in the
|
|
88820
|
+
* LICENSE file in the root directory of this source tree.
|
|
88821
|
+
*
|
|
88822
|
+
*/
|
|
89486
88823
|
const getSwapQuoteSchema = z.object({
|
|
89487
|
-
wallet: z.string().min(1).describe("Name of the wallet to swap from"),
|
|
89488
88824
|
fromToken: z.string().min(1).describe("Token to swap from (\"TON\" or jetton address)"),
|
|
89489
88825
|
toToken: z.string().min(1).describe("Token to swap to (\"TON\" or jetton address)"),
|
|
89490
88826
|
amount: z.string().min(1).describe("Amount to swap in raw units"),
|
|
89491
88827
|
slippageBps: z.number().optional().describe("Slippage tolerance in basis points (default 100 = 1%)")
|
|
89492
88828
|
});
|
|
89493
|
-
|
|
89494
|
-
|
|
89495
|
-
|
|
88829
|
+
function createMcpSwapTools(service) {
|
|
88830
|
+
return { get_swap_quote: {
|
|
88831
|
+
description: "Get a quote for swapping tokens. Returns quote details and transaction params. If user confirms, use send_raw_transaction to execute.",
|
|
88832
|
+
inputSchema: getSwapQuoteSchema,
|
|
88833
|
+
handler: async (args) => {
|
|
88834
|
+
try {
|
|
88835
|
+
const result = await service.getSwapQuote(args.fromToken, args.toToken, args.amount, args.slippageBps);
|
|
88836
|
+
return { content: [{
|
|
88837
|
+
type: "text",
|
|
88838
|
+
text: JSON.stringify({
|
|
88839
|
+
success: true,
|
|
88840
|
+
quote: {
|
|
88841
|
+
fromToken: result.fromToken,
|
|
88842
|
+
toToken: result.toToken,
|
|
88843
|
+
fromAmount: result.fromAmount,
|
|
88844
|
+
toAmount: result.toAmount,
|
|
88845
|
+
minReceived: result.minReceived,
|
|
88846
|
+
provider: result.provider,
|
|
88847
|
+
expiresAt: result.expiresAt ? (/* @__PURE__ */ new Date(result.expiresAt * 1e3)).toISOString() : null
|
|
88848
|
+
},
|
|
88849
|
+
transaction: result.transaction,
|
|
88850
|
+
note: "If user confirms, use send_raw_transaction with the transaction params to execute the swap."
|
|
88851
|
+
}, null, 2)
|
|
88852
|
+
}] };
|
|
88853
|
+
} catch (error) {
|
|
88854
|
+
return {
|
|
88855
|
+
content: [{
|
|
88856
|
+
type: "text",
|
|
88857
|
+
text: JSON.stringify({
|
|
88858
|
+
success: false,
|
|
88859
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
88860
|
+
})
|
|
88861
|
+
}],
|
|
88862
|
+
isError: true
|
|
88863
|
+
};
|
|
88864
|
+
}
|
|
88865
|
+
}
|
|
88866
|
+
} };
|
|
88867
|
+
}
|
|
88868
|
+
|
|
88869
|
+
//#endregion
|
|
88870
|
+
//#region src/tools/known-jettons-tools.ts
|
|
88871
|
+
/**
|
|
88872
|
+
* Copyright (c) TonTech.
|
|
88873
|
+
*
|
|
88874
|
+
* This source code is licensed under the MIT license found in the
|
|
88875
|
+
* LICENSE file in the root directory of this source tree.
|
|
88876
|
+
*
|
|
88877
|
+
*/
|
|
88878
|
+
const getKnownJettonsSchema = z.object({});
|
|
88879
|
+
const KNOWN_JETTONS = [
|
|
88880
|
+
{
|
|
88881
|
+
symbol: "USD₮",
|
|
88882
|
+
name: "Tether USD",
|
|
88883
|
+
address: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
|
|
88884
|
+
decimals: 6
|
|
88885
|
+
},
|
|
88886
|
+
{
|
|
88887
|
+
symbol: "NOT",
|
|
88888
|
+
name: "Notcoin",
|
|
88889
|
+
address: "EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT",
|
|
88890
|
+
decimals: 9
|
|
88891
|
+
},
|
|
88892
|
+
{
|
|
88893
|
+
symbol: "DOGS",
|
|
88894
|
+
name: "Dogs",
|
|
88895
|
+
address: "EQCvxJy4eG8hyHBFsZ7eePxrRsUQSFE_jpptRAYBmcG_DOGS",
|
|
88896
|
+
decimals: 9
|
|
88897
|
+
},
|
|
88898
|
+
{
|
|
88899
|
+
symbol: "DUST",
|
|
88900
|
+
name: "DeDust",
|
|
88901
|
+
address: "EQBlqsm144Dq6SjbPI4jjZvA1hqTIP3CvHovbIfW_t-SCALE",
|
|
88902
|
+
decimals: 9
|
|
88903
|
+
},
|
|
88904
|
+
{
|
|
88905
|
+
symbol: "GRAM",
|
|
88906
|
+
name: "Gram",
|
|
88907
|
+
address: "EQC47093oX5Xhb0xuk2lCr2RhS8rj-vul61u4W2UH5ORmG_O",
|
|
88908
|
+
decimals: 9
|
|
88909
|
+
}
|
|
88910
|
+
];
|
|
88911
|
+
function createMcpKnownJettonsTools() {
|
|
88912
|
+
return { get_known_jettons: {
|
|
88913
|
+
description: "Get a list of known/popular Jettons (tokens) on TON with their addresses and metadata. Useful for looking up token addresses for swaps or transfers.",
|
|
88914
|
+
inputSchema: getKnownJettonsSchema,
|
|
88915
|
+
handler: async () => {
|
|
88916
|
+
return { content: [{
|
|
88917
|
+
type: "text",
|
|
88918
|
+
text: JSON.stringify({
|
|
88919
|
+
success: true,
|
|
88920
|
+
jettons: KNOWN_JETTONS,
|
|
88921
|
+
count: KNOWN_JETTONS.length
|
|
88922
|
+
}, null, 2)
|
|
88923
|
+
}] };
|
|
88924
|
+
}
|
|
88925
|
+
} };
|
|
88926
|
+
}
|
|
88927
|
+
|
|
88928
|
+
//#endregion
|
|
88929
|
+
//#region src/tools/nft-tools.ts
|
|
88930
|
+
/**
|
|
88931
|
+
* Copyright (c) TonTech.
|
|
88932
|
+
*
|
|
88933
|
+
* This source code is licensed under the MIT license found in the
|
|
88934
|
+
* LICENSE file in the root directory of this source tree.
|
|
88935
|
+
*
|
|
88936
|
+
*/
|
|
88937
|
+
const getNftsSchema = z.object({
|
|
88938
|
+
limit: z.number().min(1).max(100).optional().describe("Maximum number of NFTs to return (default: 20, max: 100)"),
|
|
88939
|
+
offset: z.number().min(0).optional().describe("Offset for pagination (default: 0)")
|
|
88940
|
+
});
|
|
88941
|
+
const getNftSchema = z.object({ nftAddress: z.string().min(1).describe("NFT item contract address") });
|
|
88942
|
+
const sendNftSchema = z.object({
|
|
88943
|
+
nftAddress: z.string().min(1).describe("NFT item contract address to transfer"),
|
|
88944
|
+
toAddress: z.string().min(1).describe("Recipient TON address"),
|
|
88945
|
+
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
89496
88946
|
});
|
|
89497
|
-
function
|
|
88947
|
+
function createMcpNftTools(service) {
|
|
89498
88948
|
return {
|
|
89499
|
-
|
|
89500
|
-
description: "
|
|
89501
|
-
inputSchema:
|
|
89502
|
-
handler:
|
|
89503
|
-
const userSigner = service.createUserSigner(userId);
|
|
88949
|
+
get_nfts: {
|
|
88950
|
+
description: "List all NFTs (non-fungible tokens) in the wallet with their metadata, collection info, and attributes.",
|
|
88951
|
+
inputSchema: getNftsSchema,
|
|
88952
|
+
handler: async (args) => {
|
|
89504
88953
|
try {
|
|
89505
|
-
|
|
89506
|
-
const result = await service.getSwapQuote(userSigner, args.wallet, args.fromToken, args.toToken, args.amount, args.slippageBps);
|
|
89507
|
-
const quoteId = generateQuoteId();
|
|
89508
|
-
const expiresAt = result.expiresAt ? result.expiresAt * 1e3 : Date.now() + 6e4;
|
|
89509
|
-
quoteCache.set(quoteId, {
|
|
89510
|
-
quote: result.quote,
|
|
89511
|
-
expiresAt,
|
|
89512
|
-
userId
|
|
89513
|
-
});
|
|
88954
|
+
const nfts = await service.getNfts(args.limit ?? 20, args.offset ?? 0);
|
|
89514
88955
|
return { content: [{
|
|
89515
88956
|
type: "text",
|
|
89516
88957
|
text: JSON.stringify({
|
|
89517
88958
|
success: true,
|
|
89518
|
-
|
|
89519
|
-
|
|
89520
|
-
|
|
89521
|
-
|
|
89522
|
-
|
|
89523
|
-
|
|
89524
|
-
|
|
89525
|
-
|
|
89526
|
-
|
|
88959
|
+
nfts: nfts.map((nft) => ({
|
|
88960
|
+
address: nft.address,
|
|
88961
|
+
name: nft.name,
|
|
88962
|
+
description: nft.description,
|
|
88963
|
+
image: nft.image,
|
|
88964
|
+
collection: nft.collection,
|
|
88965
|
+
attributes: nft.attributes,
|
|
88966
|
+
isOnSale: nft.isOnSale,
|
|
88967
|
+
isSoulbound: nft.isSoulbound
|
|
88968
|
+
})),
|
|
88969
|
+
count: nfts.length
|
|
89527
88970
|
}, null, 2)
|
|
89528
88971
|
}] };
|
|
89529
88972
|
} catch (error) {
|
|
@@ -89538,156 +88981,87 @@ function createMcpSwapTools(_walletService, wrapHandler) {
|
|
|
89538
88981
|
isError: true
|
|
89539
88982
|
};
|
|
89540
88983
|
}
|
|
89541
|
-
}
|
|
88984
|
+
}
|
|
89542
88985
|
},
|
|
89543
|
-
|
|
89544
|
-
description: "
|
|
89545
|
-
inputSchema:
|
|
89546
|
-
handler:
|
|
89547
|
-
|
|
89548
|
-
|
|
89549
|
-
|
|
89550
|
-
|
|
89551
|
-
|
|
89552
|
-
|
|
89553
|
-
|
|
89554
|
-
|
|
89555
|
-
|
|
89556
|
-
|
|
89557
|
-
|
|
89558
|
-
}
|
|
89559
|
-
|
|
89560
|
-
};
|
|
89561
|
-
if (cachedQuote.userId !== userId) return {
|
|
89562
|
-
content: [{
|
|
88986
|
+
get_nft: {
|
|
88987
|
+
description: "Get detailed information about a specific NFT by its address.",
|
|
88988
|
+
inputSchema: getNftSchema,
|
|
88989
|
+
handler: async (args) => {
|
|
88990
|
+
try {
|
|
88991
|
+
const nft = await service.getNft(args.nftAddress);
|
|
88992
|
+
if (!nft) return {
|
|
88993
|
+
content: [{
|
|
88994
|
+
type: "text",
|
|
88995
|
+
text: JSON.stringify({
|
|
88996
|
+
success: false,
|
|
88997
|
+
error: "NFT not found"
|
|
88998
|
+
})
|
|
88999
|
+
}],
|
|
89000
|
+
isError: true
|
|
89001
|
+
};
|
|
89002
|
+
return { content: [{
|
|
89563
89003
|
type: "text",
|
|
89564
89004
|
text: JSON.stringify({
|
|
89565
|
-
success:
|
|
89566
|
-
|
|
89567
|
-
|
|
89568
|
-
|
|
89569
|
-
|
|
89570
|
-
|
|
89571
|
-
|
|
89572
|
-
|
|
89005
|
+
success: true,
|
|
89006
|
+
nft: {
|
|
89007
|
+
address: nft.address,
|
|
89008
|
+
name: nft.name,
|
|
89009
|
+
description: nft.description,
|
|
89010
|
+
image: nft.image,
|
|
89011
|
+
collection: nft.collection,
|
|
89012
|
+
attributes: nft.attributes,
|
|
89013
|
+
ownerAddress: nft.ownerAddress,
|
|
89014
|
+
isOnSale: nft.isOnSale,
|
|
89015
|
+
isSoulbound: nft.isSoulbound,
|
|
89016
|
+
saleContractAddress: nft.saleContractAddress
|
|
89017
|
+
}
|
|
89018
|
+
}, null, 2)
|
|
89019
|
+
}] };
|
|
89020
|
+
} catch (error) {
|
|
89573
89021
|
return {
|
|
89574
89022
|
content: [{
|
|
89575
89023
|
type: "text",
|
|
89576
89024
|
text: JSON.stringify({
|
|
89577
89025
|
success: false,
|
|
89578
|
-
error:
|
|
89026
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
89579
89027
|
})
|
|
89580
89028
|
}],
|
|
89581
89029
|
isError: true
|
|
89582
89030
|
};
|
|
89583
89031
|
}
|
|
89584
|
-
|
|
89585
|
-
quoteCache.delete(args.quoteId);
|
|
89586
|
-
if (!result.success) return {
|
|
89587
|
-
content: [{
|
|
89588
|
-
type: "text",
|
|
89589
|
-
text: JSON.stringify({
|
|
89590
|
-
success: false,
|
|
89591
|
-
error: result.message
|
|
89592
|
-
})
|
|
89593
|
-
}],
|
|
89594
|
-
isError: true
|
|
89595
|
-
};
|
|
89596
|
-
return { content: [{
|
|
89597
|
-
type: "text",
|
|
89598
|
-
text: JSON.stringify({
|
|
89599
|
-
success: true,
|
|
89600
|
-
message: result.message,
|
|
89601
|
-
details: {
|
|
89602
|
-
fromToken: cachedQuote.quote.fromToken,
|
|
89603
|
-
toToken: cachedQuote.quote.toToken,
|
|
89604
|
-
fromAmount: cachedQuote.quote.fromAmount,
|
|
89605
|
-
toAmount: cachedQuote.quote.toAmount,
|
|
89606
|
-
provider: cachedQuote.quote.provider,
|
|
89607
|
-
pendingTransactionId: result.pendingTransactionId || null
|
|
89608
|
-
}
|
|
89609
|
-
}, null, 2)
|
|
89610
|
-
}] };
|
|
89611
|
-
})
|
|
89612
|
-
}
|
|
89613
|
-
};
|
|
89614
|
-
}
|
|
89615
|
-
const confirmTransactionSchema = z.object({ transactionId: z.string().min(1).describe("ID of the pending transaction to confirm") });
|
|
89616
|
-
const cancelTransactionSchema = z.object({ transactionId: z.string().min(1).describe("ID of the pending transaction to cancel") });
|
|
89617
|
-
function createMcpPendingTools(_walletService, wrapHandler) {
|
|
89618
|
-
return {
|
|
89619
|
-
confirm_transaction: {
|
|
89620
|
-
description: "Confirm and execute a pending transaction.",
|
|
89621
|
-
inputSchema: confirmTransactionSchema,
|
|
89622
|
-
handler: wrapHandler(async (args, userId, service) => {
|
|
89623
|
-
const userSigner = service.createUserSigner(userId);
|
|
89624
|
-
const userStorage = service.createUserStorage(userId);
|
|
89625
|
-
const result = await service.confirmTransaction(userSigner, userStorage, args.transactionId);
|
|
89626
|
-
if (!result.success) return {
|
|
89627
|
-
content: [{
|
|
89628
|
-
type: "text",
|
|
89629
|
-
text: JSON.stringify({
|
|
89630
|
-
success: false,
|
|
89631
|
-
error: result.message
|
|
89632
|
-
})
|
|
89633
|
-
}],
|
|
89634
|
-
isError: true
|
|
89635
|
-
};
|
|
89636
|
-
return { content: [{
|
|
89637
|
-
type: "text",
|
|
89638
|
-
text: JSON.stringify({
|
|
89639
|
-
success: true,
|
|
89640
|
-
message: result.message
|
|
89641
|
-
}, null, 2)
|
|
89642
|
-
}] };
|
|
89643
|
-
})
|
|
89644
|
-
},
|
|
89645
|
-
cancel_transaction: {
|
|
89646
|
-
description: "Cancel a pending transaction.",
|
|
89647
|
-
inputSchema: cancelTransactionSchema,
|
|
89648
|
-
handler: wrapHandler(async (args, userId, service) => {
|
|
89649
|
-
const userStorage = service.createUserStorage(userId);
|
|
89650
|
-
if (!await service.cancelTransaction(userStorage, args.transactionId)) return {
|
|
89651
|
-
content: [{
|
|
89652
|
-
type: "text",
|
|
89653
|
-
text: JSON.stringify({
|
|
89654
|
-
success: false,
|
|
89655
|
-
error: "Transaction not found or already processed"
|
|
89656
|
-
})
|
|
89657
|
-
}],
|
|
89658
|
-
isError: true
|
|
89659
|
-
};
|
|
89660
|
-
return { content: [{
|
|
89661
|
-
type: "text",
|
|
89662
|
-
text: JSON.stringify({
|
|
89663
|
-
success: true,
|
|
89664
|
-
message: "Transaction cancelled"
|
|
89665
|
-
})
|
|
89666
|
-
}] };
|
|
89667
|
-
})
|
|
89032
|
+
}
|
|
89668
89033
|
},
|
|
89669
|
-
|
|
89670
|
-
description: "
|
|
89671
|
-
inputSchema:
|
|
89672
|
-
handler:
|
|
89673
|
-
|
|
89674
|
-
|
|
89675
|
-
|
|
89676
|
-
|
|
89677
|
-
|
|
89678
|
-
|
|
89679
|
-
|
|
89680
|
-
|
|
89681
|
-
|
|
89682
|
-
|
|
89683
|
-
|
|
89684
|
-
|
|
89685
|
-
|
|
89686
|
-
|
|
89687
|
-
|
|
89688
|
-
|
|
89689
|
-
|
|
89690
|
-
|
|
89034
|
+
send_nft: {
|
|
89035
|
+
description: "Transfer an NFT from the wallet to another address.",
|
|
89036
|
+
inputSchema: sendNftSchema,
|
|
89037
|
+
handler: async (args) => {
|
|
89038
|
+
try {
|
|
89039
|
+
const result = await service.sendNft(args.nftAddress, args.toAddress, args.comment);
|
|
89040
|
+
return {
|
|
89041
|
+
content: [{
|
|
89042
|
+
type: "text",
|
|
89043
|
+
text: JSON.stringify({
|
|
89044
|
+
success: result.success,
|
|
89045
|
+
message: result.message,
|
|
89046
|
+
nftAddress: args.nftAddress,
|
|
89047
|
+
recipient: args.toAddress
|
|
89048
|
+
}, null, 2)
|
|
89049
|
+
}],
|
|
89050
|
+
isError: !result.success
|
|
89051
|
+
};
|
|
89052
|
+
} catch (error) {
|
|
89053
|
+
return {
|
|
89054
|
+
content: [{
|
|
89055
|
+
type: "text",
|
|
89056
|
+
text: JSON.stringify({
|
|
89057
|
+
success: false,
|
|
89058
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
89059
|
+
})
|
|
89060
|
+
}],
|
|
89061
|
+
isError: true
|
|
89062
|
+
};
|
|
89063
|
+
}
|
|
89064
|
+
}
|
|
89691
89065
|
}
|
|
89692
89066
|
};
|
|
89693
89067
|
}
|
|
@@ -89709,403 +89083,63 @@ const SERVER_VERSION = "0.1.0";
|
|
|
89709
89083
|
/**
|
|
89710
89084
|
* Create a configured TON Wallet MCP server
|
|
89711
89085
|
*
|
|
89712
|
-
* @param config - Configuration with
|
|
89086
|
+
* @param config - Configuration with wallet instance
|
|
89713
89087
|
* @returns Configured McpServer instance
|
|
89714
89088
|
*
|
|
89715
89089
|
* @example
|
|
89716
89090
|
* ```typescript
|
|
89717
|
-
* import { createTonWalletMCP
|
|
89091
|
+
* import { createTonWalletMCP } from '@ton/mcp';
|
|
89092
|
+
* import { Signer, WalletV5R1Adapter, TonWalletKit, Network } from '@ton/walletkit';
|
|
89718
89093
|
*
|
|
89719
|
-
*
|
|
89720
|
-
*
|
|
89721
|
-
*
|
|
89722
|
-
*
|
|
89723
|
-
*
|
|
89724
|
-
*
|
|
89725
|
-
* limits: {
|
|
89726
|
-
* maxTransactionTon: 100,
|
|
89727
|
-
* dailyLimitTon: 1000,
|
|
89728
|
-
* maxWalletsPerUser: 10,
|
|
89729
|
-
* },
|
|
89730
|
-
* requireConfirmation: true,
|
|
89094
|
+
* // Create wallet adapter
|
|
89095
|
+
* const kit = new TonWalletKit({ ... });
|
|
89096
|
+
* const signer = await Signer.fromMnemonic(mnemonic, { type: 'ton' });
|
|
89097
|
+
* const walletAdapter = await WalletV5R1Adapter.create(signer, {
|
|
89098
|
+
* client: kit.getApiClient(Network.mainnet()),
|
|
89099
|
+
* network: Network.mainnet(),
|
|
89731
89100
|
* });
|
|
89101
|
+
* const wallet = await kit.addWallet(walletAdapter);
|
|
89102
|
+
*
|
|
89103
|
+
* // Create MCP server
|
|
89104
|
+
* const server = createTonWalletMCP({ wallet });
|
|
89732
89105
|
* ```
|
|
89733
89106
|
*/
|
|
89734
|
-
function createTonWalletMCP(config) {
|
|
89735
|
-
const walletService =
|
|
89736
|
-
|
|
89737
|
-
signer: config.signer,
|
|
89107
|
+
async function createTonWalletMCP(config) {
|
|
89108
|
+
const walletService = await McpWalletService.create({
|
|
89109
|
+
wallet: config.wallet,
|
|
89738
89110
|
contacts: config.contacts,
|
|
89739
|
-
|
|
89740
|
-
limits: config.limits,
|
|
89741
|
-
requireConfirmation: config.requireConfirmation
|
|
89111
|
+
networks: config.networks
|
|
89742
89112
|
});
|
|
89743
89113
|
const server = new McpServer({
|
|
89744
89114
|
name: SERVER_NAME$1,
|
|
89745
89115
|
version: SERVER_VERSION
|
|
89746
89116
|
});
|
|
89747
|
-
const
|
|
89748
|
-
|
|
89749
|
-
|
|
89750
|
-
|
|
89751
|
-
|
|
89752
|
-
const createAuthenticatedHandler = (handler) => {
|
|
89753
|
-
return async (args, extra) => {
|
|
89754
|
-
const extraObj = extra;
|
|
89755
|
-
return handler(args, await authenticateUser({
|
|
89756
|
-
headers: extraObj?.headers,
|
|
89757
|
-
metadata: extraObj?.meta
|
|
89758
|
-
}), walletService);
|
|
89759
|
-
};
|
|
89760
|
-
};
|
|
89761
|
-
const walletTools = createMcpWalletTools(walletService, createAuthenticatedHandler);
|
|
89762
|
-
const balanceTools = createMcpBalanceTools(walletService, createAuthenticatedHandler);
|
|
89763
|
-
const transferTools = createMcpTransferTools(walletService, createAuthenticatedHandler);
|
|
89764
|
-
const swapTools = createMcpSwapTools(walletService, createAuthenticatedHandler);
|
|
89765
|
-
const pendingTools = createMcpPendingTools(walletService, createAuthenticatedHandler);
|
|
89117
|
+
const balanceTools = createMcpBalanceTools(walletService);
|
|
89118
|
+
const transferTools = createMcpTransferTools(walletService);
|
|
89119
|
+
const swapTools = createMcpSwapTools(walletService);
|
|
89120
|
+
const knownJettonsTools = createMcpKnownJettonsTools();
|
|
89121
|
+
const nftTools = createMcpNftTools(walletService);
|
|
89766
89122
|
const registerTool = (name, tool) => {
|
|
89767
89123
|
server.registerTool(name, {
|
|
89768
89124
|
description: tool.description,
|
|
89769
89125
|
inputSchema: tool.inputSchema
|
|
89770
89126
|
}, tool.handler);
|
|
89771
89127
|
};
|
|
89772
|
-
registerTool("create_wallet", walletTools.create_wallet);
|
|
89773
|
-
registerTool("import_wallet", walletTools.import_wallet);
|
|
89774
|
-
registerTool("list_wallets", walletTools.list_wallets);
|
|
89775
|
-
registerTool("remove_wallet", walletTools.remove_wallet);
|
|
89776
89128
|
registerTool("get_balance", balanceTools.get_balance);
|
|
89777
89129
|
registerTool("get_jetton_balance", balanceTools.get_jetton_balance);
|
|
89778
89130
|
registerTool("get_jettons", balanceTools.get_jettons);
|
|
89779
89131
|
registerTool("get_transactions", balanceTools.get_transactions);
|
|
89780
89132
|
registerTool("send_ton", transferTools.send_ton);
|
|
89781
89133
|
registerTool("send_jetton", transferTools.send_jetton);
|
|
89134
|
+
registerTool("send_raw_transaction", transferTools.send_raw_transaction);
|
|
89782
89135
|
registerTool("get_swap_quote", swapTools.get_swap_quote);
|
|
89783
|
-
registerTool("
|
|
89784
|
-
|
|
89785
|
-
|
|
89786
|
-
|
|
89787
|
-
registerTool("list_pending_transactions", pendingTools.list_pending_transactions);
|
|
89788
|
-
}
|
|
89136
|
+
registerTool("get_known_jettons", knownJettonsTools.get_known_jettons);
|
|
89137
|
+
registerTool("get_nfts", nftTools.get_nfts);
|
|
89138
|
+
registerTool("get_nft", nftTools.get_nft);
|
|
89139
|
+
registerTool("send_nft", nftTools.send_nft);
|
|
89789
89140
|
return server;
|
|
89790
89141
|
}
|
|
89791
89142
|
|
|
89792
|
-
//#endregion
|
|
89793
|
-
//#region src/adapters/InMemoryStorageAdapter.ts
|
|
89794
|
-
/**
|
|
89795
|
-
* In-memory storage adapter for testing and development.
|
|
89796
|
-
* Data is not persistent and will be lost on process restart.
|
|
89797
|
-
*/
|
|
89798
|
-
var InMemoryStorageAdapter = class {
|
|
89799
|
-
data = /* @__PURE__ */ new Map();
|
|
89800
|
-
timers = /* @__PURE__ */ new Map();
|
|
89801
|
-
/**
|
|
89802
|
-
* Get a value by key
|
|
89803
|
-
*/
|
|
89804
|
-
async get(key) {
|
|
89805
|
-
return this.data.get(key) ?? null;
|
|
89806
|
-
}
|
|
89807
|
-
/**
|
|
89808
|
-
* Set a value with optional TTL
|
|
89809
|
-
*/
|
|
89810
|
-
async set(key, value, ttlSeconds) {
|
|
89811
|
-
const existingTimer = this.timers.get(key);
|
|
89812
|
-
if (existingTimer) {
|
|
89813
|
-
clearTimeout(existingTimer);
|
|
89814
|
-
this.timers.delete(key);
|
|
89815
|
-
}
|
|
89816
|
-
this.data.set(key, value);
|
|
89817
|
-
if (ttlSeconds !== void 0 && ttlSeconds > 0) {
|
|
89818
|
-
const timer = setTimeout(() => {
|
|
89819
|
-
this.data.delete(key);
|
|
89820
|
-
this.timers.delete(key);
|
|
89821
|
-
}, ttlSeconds * 1e3);
|
|
89822
|
-
this.timers.set(key, timer);
|
|
89823
|
-
}
|
|
89824
|
-
}
|
|
89825
|
-
/**
|
|
89826
|
-
* Delete a key
|
|
89827
|
-
*/
|
|
89828
|
-
async delete(key) {
|
|
89829
|
-
const timer = this.timers.get(key);
|
|
89830
|
-
if (timer) {
|
|
89831
|
-
clearTimeout(timer);
|
|
89832
|
-
this.timers.delete(key);
|
|
89833
|
-
}
|
|
89834
|
-
return this.data.delete(key);
|
|
89835
|
-
}
|
|
89836
|
-
/**
|
|
89837
|
-
* List keys matching prefix
|
|
89838
|
-
*/
|
|
89839
|
-
async list(prefix) {
|
|
89840
|
-
const keys = [];
|
|
89841
|
-
for (const key of this.data.keys()) if (key.startsWith(prefix)) keys.push(key);
|
|
89842
|
-
return keys;
|
|
89843
|
-
}
|
|
89844
|
-
/**
|
|
89845
|
-
* Clear all data (useful for testing)
|
|
89846
|
-
*/
|
|
89847
|
-
clear() {
|
|
89848
|
-
for (const timer of this.timers.values()) clearTimeout(timer);
|
|
89849
|
-
this.timers.clear();
|
|
89850
|
-
this.data.clear();
|
|
89851
|
-
}
|
|
89852
|
-
/**
|
|
89853
|
-
* Get the number of stored items (useful for testing)
|
|
89854
|
-
*/
|
|
89855
|
-
size() {
|
|
89856
|
-
return this.data.size;
|
|
89857
|
-
}
|
|
89858
|
-
};
|
|
89859
|
-
|
|
89860
|
-
//#endregion
|
|
89861
|
-
//#region src/adapters/LocalSignerAdapter.ts
|
|
89862
|
-
/**
|
|
89863
|
-
* Copyright (c) TonTech.
|
|
89864
|
-
*
|
|
89865
|
-
* This source code is licensed under the MIT license found in the
|
|
89866
|
-
* LICENSE file in the root directory of this source tree.
|
|
89867
|
-
*
|
|
89868
|
-
*/
|
|
89869
|
-
/**
|
|
89870
|
-
* LocalSignerAdapter - Local signer using @ton/walletkit
|
|
89871
|
-
*
|
|
89872
|
-
* This adapter uses TonWalletKit for wallet operations.
|
|
89873
|
-
* For production use with encryption, extend this class or implement
|
|
89874
|
-
* your own ISignerAdapter with proper key encryption.
|
|
89875
|
-
*
|
|
89876
|
-
* Note: This is a reference implementation. For production custody,
|
|
89877
|
-
* consider using HSM, KMS, or Vault-based signers.
|
|
89878
|
-
*/
|
|
89879
|
-
/**
|
|
89880
|
-
* Local signer adapter using TonWalletKit.
|
|
89881
|
-
*
|
|
89882
|
-
* This implementation stores mnemonics in memory. For production use,
|
|
89883
|
-
* implement encryption or use a secure key management system.
|
|
89884
|
-
*/
|
|
89885
|
-
var LocalSignerAdapter = class {
|
|
89886
|
-
wallets = /* @__PURE__ */ new Map();
|
|
89887
|
-
kit = null;
|
|
89888
|
-
loadedWallets = /* @__PURE__ */ new Map();
|
|
89889
|
-
/**
|
|
89890
|
-
* Get Network instance from network name
|
|
89891
|
-
*/
|
|
89892
|
-
getNetwork(networkName) {
|
|
89893
|
-
return networkName === "mainnet" ? Network.mainnet() : Network.testnet();
|
|
89894
|
-
}
|
|
89895
|
-
/**
|
|
89896
|
-
* Initialize or get TonWalletKit instance
|
|
89897
|
-
*/
|
|
89898
|
-
async getKit() {
|
|
89899
|
-
if (!this.kit) {
|
|
89900
|
-
this.kit = new TonWalletKit({
|
|
89901
|
-
networks: {
|
|
89902
|
-
[Network.mainnet().chainId]: {},
|
|
89903
|
-
[Network.testnet().chainId]: {}
|
|
89904
|
-
},
|
|
89905
|
-
storage: new MemoryStorageAdapter()
|
|
89906
|
-
});
|
|
89907
|
-
await this.kit.waitForReady();
|
|
89908
|
-
}
|
|
89909
|
-
return this.kit;
|
|
89910
|
-
}
|
|
89911
|
-
/**
|
|
89912
|
-
* Create wallet adapter from mnemonic
|
|
89913
|
-
*/
|
|
89914
|
-
async createWalletAdapter(mnemonic, version, network) {
|
|
89915
|
-
const kit = await this.getKit();
|
|
89916
|
-
const signer = await Signer.fromMnemonic(mnemonic, { type: "ton" });
|
|
89917
|
-
return {
|
|
89918
|
-
adapter: version === "v5r1" ? await WalletV5R1Adapter.create(signer, {
|
|
89919
|
-
client: kit.getApiClient(network),
|
|
89920
|
-
network
|
|
89921
|
-
}) : await WalletV4R2Adapter.create(signer, {
|
|
89922
|
-
client: kit.getApiClient(network),
|
|
89923
|
-
network
|
|
89924
|
-
}),
|
|
89925
|
-
publicKey: Buffer.from(signer.publicKey).toString("hex")
|
|
89926
|
-
};
|
|
89927
|
-
}
|
|
89928
|
-
/**
|
|
89929
|
-
* Create a new wallet with generated mnemonic
|
|
89930
|
-
*/
|
|
89931
|
-
async createWallet(params) {
|
|
89932
|
-
const { walletId, version, network: networkName } = params;
|
|
89933
|
-
if (this.wallets.has(walletId)) throw new Error(`Wallet "${walletId}" already exists`);
|
|
89934
|
-
const network = this.getNetwork(networkName);
|
|
89935
|
-
const mnemonic = await CreateTonMnemonic();
|
|
89936
|
-
const { adapter, publicKey } = await this.createWalletAdapter(mnemonic, version, network);
|
|
89937
|
-
const address = adapter.getAddress();
|
|
89938
|
-
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
89939
|
-
const storedWallet = {
|
|
89940
|
-
walletId,
|
|
89941
|
-
mnemonic,
|
|
89942
|
-
publicKey,
|
|
89943
|
-
address,
|
|
89944
|
-
network: networkName,
|
|
89945
|
-
version,
|
|
89946
|
-
createdAt
|
|
89947
|
-
};
|
|
89948
|
-
this.wallets.set(walletId, storedWallet);
|
|
89949
|
-
const wallet = await (await this.getKit()).addWallet(adapter);
|
|
89950
|
-
if (wallet) this.loadedWallets.set(walletId, wallet);
|
|
89951
|
-
return {
|
|
89952
|
-
walletId,
|
|
89953
|
-
publicKey,
|
|
89954
|
-
address,
|
|
89955
|
-
network: networkName,
|
|
89956
|
-
version,
|
|
89957
|
-
createdAt
|
|
89958
|
-
};
|
|
89959
|
-
}
|
|
89960
|
-
/**
|
|
89961
|
-
* Import a wallet from mnemonic
|
|
89962
|
-
*/
|
|
89963
|
-
async importWallet(params) {
|
|
89964
|
-
const { walletId, mnemonic, version, network: networkName } = params;
|
|
89965
|
-
if (this.wallets.has(walletId)) throw new Error(`Wallet "${walletId}" already exists`);
|
|
89966
|
-
if (mnemonic.length !== 24) throw new Error(`Invalid mnemonic: expected 24 words, got ${mnemonic.length}`);
|
|
89967
|
-
const network = this.getNetwork(networkName);
|
|
89968
|
-
const { adapter, publicKey } = await this.createWalletAdapter(mnemonic, version, network);
|
|
89969
|
-
const address = adapter.getAddress();
|
|
89970
|
-
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
89971
|
-
const storedWallet = {
|
|
89972
|
-
walletId,
|
|
89973
|
-
mnemonic,
|
|
89974
|
-
publicKey,
|
|
89975
|
-
address,
|
|
89976
|
-
network: networkName,
|
|
89977
|
-
version,
|
|
89978
|
-
createdAt
|
|
89979
|
-
};
|
|
89980
|
-
this.wallets.set(walletId, storedWallet);
|
|
89981
|
-
const wallet = await (await this.getKit()).addWallet(adapter);
|
|
89982
|
-
if (wallet) this.loadedWallets.set(walletId, wallet);
|
|
89983
|
-
return {
|
|
89984
|
-
walletId,
|
|
89985
|
-
publicKey,
|
|
89986
|
-
address,
|
|
89987
|
-
network: networkName,
|
|
89988
|
-
version,
|
|
89989
|
-
createdAt
|
|
89990
|
-
};
|
|
89991
|
-
}
|
|
89992
|
-
/**
|
|
89993
|
-
* Get wallet info by ID
|
|
89994
|
-
*/
|
|
89995
|
-
async getWallet(walletId) {
|
|
89996
|
-
const stored = this.wallets.get(walletId);
|
|
89997
|
-
if (!stored) return null;
|
|
89998
|
-
return {
|
|
89999
|
-
walletId: stored.walletId,
|
|
90000
|
-
publicKey: stored.publicKey,
|
|
90001
|
-
address: stored.address,
|
|
90002
|
-
network: stored.network,
|
|
90003
|
-
version: stored.version,
|
|
90004
|
-
createdAt: stored.createdAt
|
|
90005
|
-
};
|
|
90006
|
-
}
|
|
90007
|
-
/**
|
|
90008
|
-
* List all wallet IDs
|
|
90009
|
-
*/
|
|
90010
|
-
async listWalletIds() {
|
|
90011
|
-
return Array.from(this.wallets.keys());
|
|
90012
|
-
}
|
|
90013
|
-
/**
|
|
90014
|
-
* Delete a wallet
|
|
90015
|
-
*/
|
|
90016
|
-
async deleteWallet(walletId) {
|
|
90017
|
-
if (!this.wallets.get(walletId)) return false;
|
|
90018
|
-
this.loadedWallets.delete(walletId);
|
|
90019
|
-
return this.wallets.delete(walletId);
|
|
90020
|
-
}
|
|
90021
|
-
/**
|
|
90022
|
-
* Get or load a wallet for signing
|
|
90023
|
-
*/
|
|
90024
|
-
async getWalletForSigning(walletId) {
|
|
90025
|
-
if (this.loadedWallets.has(walletId)) return this.loadedWallets.get(walletId);
|
|
90026
|
-
const stored = this.wallets.get(walletId);
|
|
90027
|
-
if (!stored) throw new Error("Wallet not found");
|
|
90028
|
-
const network = this.getNetwork(stored.network);
|
|
90029
|
-
const { adapter } = await this.createWalletAdapter(stored.mnemonic, stored.version, network);
|
|
90030
|
-
const kit = await this.getKit();
|
|
90031
|
-
let wallet = await kit.addWallet(adapter);
|
|
90032
|
-
if (!wallet) {
|
|
90033
|
-
const kitWalletId = `${network.chainId}:${stored.address}`;
|
|
90034
|
-
wallet = kit.getWallet(kitWalletId);
|
|
90035
|
-
if (!wallet) throw new Error("Failed to load wallet");
|
|
90036
|
-
}
|
|
90037
|
-
this.loadedWallets.set(walletId, wallet);
|
|
90038
|
-
return wallet;
|
|
90039
|
-
}
|
|
90040
|
-
/**
|
|
90041
|
-
* Sign a transaction
|
|
90042
|
-
*/
|
|
90043
|
-
async signTransaction(_walletId, _unsignedBoc) {
|
|
90044
|
-
throw new Error("signTransaction with BOC not implemented. Use the wallet service for transaction signing.");
|
|
90045
|
-
}
|
|
90046
|
-
/**
|
|
90047
|
-
* Sign a message
|
|
90048
|
-
*/
|
|
90049
|
-
async signMessage(walletId, message) {
|
|
90050
|
-
const stored = this.wallets.get(walletId);
|
|
90051
|
-
if (!stored) throw new Error("Wallet not found");
|
|
90052
|
-
const signature = await (await Signer.fromMnemonic(stored.mnemonic, { type: "ton" })).sign(message);
|
|
90053
|
-
return Buffer.from(signature, "hex");
|
|
90054
|
-
}
|
|
90055
|
-
/**
|
|
90056
|
-
* Close and cleanup
|
|
90057
|
-
*/
|
|
90058
|
-
async close() {
|
|
90059
|
-
if (this.kit) {
|
|
90060
|
-
await this.kit.close();
|
|
90061
|
-
this.kit = null;
|
|
90062
|
-
}
|
|
90063
|
-
this.loadedWallets.clear();
|
|
90064
|
-
}
|
|
90065
|
-
/**
|
|
90066
|
-
* Get TonWalletKit instance for direct wallet operations
|
|
90067
|
-
* Used by WalletService for balance/transfer operations
|
|
90068
|
-
*/
|
|
90069
|
-
async getKitInstance() {
|
|
90070
|
-
return this.getKit();
|
|
90071
|
-
}
|
|
90072
|
-
/**
|
|
90073
|
-
* Get a loaded wallet by ID for direct operations
|
|
90074
|
-
* Used by WalletService for balance/transfer operations
|
|
90075
|
-
*/
|
|
90076
|
-
async getLoadedWallet(walletId) {
|
|
90077
|
-
return this.getWalletForSigning(walletId);
|
|
90078
|
-
}
|
|
90079
|
-
/**
|
|
90080
|
-
* Get stored wallet data (internal use only)
|
|
90081
|
-
*/
|
|
90082
|
-
getStoredWallet(walletId) {
|
|
90083
|
-
return this.wallets.get(walletId);
|
|
90084
|
-
}
|
|
90085
|
-
};
|
|
90086
|
-
|
|
90087
|
-
//#endregion
|
|
90088
|
-
//#region src/adapters/TelegramUserContextProvider.ts
|
|
90089
|
-
/**
|
|
90090
|
-
* Simple user context provider that always returns a fixed user ID.
|
|
90091
|
-
* Useful for single-user CLI applications or testing.
|
|
90092
|
-
*/
|
|
90093
|
-
var StaticUserContextProvider = class {
|
|
90094
|
-
userId;
|
|
90095
|
-
constructor(userId) {
|
|
90096
|
-
this.userId = userId;
|
|
90097
|
-
}
|
|
90098
|
-
async getUserId() {
|
|
90099
|
-
return this.userId;
|
|
90100
|
-
}
|
|
90101
|
-
async getUserMetadata() {
|
|
90102
|
-
return {
|
|
90103
|
-
provider: "static",
|
|
90104
|
-
userId: this.userId
|
|
90105
|
-
};
|
|
90106
|
-
}
|
|
90107
|
-
};
|
|
90108
|
-
|
|
90109
89143
|
//#endregion
|
|
90110
89144
|
//#region src/cli.ts
|
|
90111
89145
|
/**
|
|
@@ -90122,12 +89156,21 @@ var StaticUserContextProvider = class {
|
|
|
90122
89156
|
* TON wallet management tools for use with Claude Desktop or other MCP clients.
|
|
90123
89157
|
*
|
|
90124
89158
|
* Usage:
|
|
90125
|
-
* npx @ton/mcp
|
|
90126
|
-
* npx @ton/mcp --http
|
|
90127
|
-
* npx @ton/mcp --http 8080
|
|
89159
|
+
* npx @ton/mcp # stdio mode (default)
|
|
89160
|
+
* npx @ton/mcp --http # HTTP server on 0.0.0.0:3000
|
|
89161
|
+
* npx @ton/mcp --http 8080 # HTTP server on custom port
|
|
89162
|
+
* npx @ton/mcp --http --host 127.0.0.1 # HTTP server on custom host
|
|
89163
|
+
*
|
|
89164
|
+
* Environment variables:
|
|
89165
|
+
* NETWORK - Network to use (mainnet or testnet, default: mainnet)
|
|
89166
|
+
* MNEMONIC - 24-word mnemonic phrase for wallet (if not provided, a new wallet is created)
|
|
89167
|
+
* WALLET_VERSION - Wallet version (v5r1 or v4r2, default: v5r1)
|
|
90128
89168
|
*/
|
|
90129
89169
|
const SERVER_NAME = "ton-mcp";
|
|
90130
89170
|
const NETWORK = process.env.NETWORK || "mainnet";
|
|
89171
|
+
const MNEMONIC = process.env.MNEMONIC;
|
|
89172
|
+
const WALLET_VERSION = process.env.WALLET_VERSION || "v5r1";
|
|
89173
|
+
const TONCENTER_API_KEY = process.env.TONCENTER_API_KEY;
|
|
90131
89174
|
function log(message) {
|
|
90132
89175
|
console.error(`[${SERVER_NAME}] ${message}`);
|
|
90133
89176
|
}
|
|
@@ -90136,33 +89179,66 @@ function parseArgs() {
|
|
|
90136
89179
|
const httpIndex = args.indexOf("--http");
|
|
90137
89180
|
if (httpIndex === -1) return { mode: "stdio" };
|
|
90138
89181
|
const nextArg = args[httpIndex + 1];
|
|
89182
|
+
const port = nextArg && !nextArg.startsWith("-") ? parseInt(nextArg, 10) : 3e3;
|
|
89183
|
+
const hostIndex = args.indexOf("--host");
|
|
89184
|
+
const hostArg = hostIndex !== -1 ? args[hostIndex + 1] : void 0;
|
|
90139
89185
|
return {
|
|
90140
89186
|
mode: "http",
|
|
90141
|
-
port
|
|
89187
|
+
port,
|
|
89188
|
+
host: hostArg && !hostArg.startsWith("-") ? hostArg : "0.0.0.0"
|
|
90142
89189
|
};
|
|
90143
89190
|
}
|
|
90144
|
-
function
|
|
90145
|
-
const
|
|
90146
|
-
const
|
|
89191
|
+
async function createWalletAndServer() {
|
|
89192
|
+
const network = NETWORK === "mainnet" ? Network.mainnet() : Network.testnet();
|
|
89193
|
+
const apiConfig = {};
|
|
89194
|
+
if (TONCENTER_API_KEY) {
|
|
89195
|
+
apiConfig.url = NETWORK === "mainnet" ? "https://toncenter.com" : "https://testnet.toncenter.com";
|
|
89196
|
+
apiConfig.key = TONCENTER_API_KEY;
|
|
89197
|
+
}
|
|
89198
|
+
const kit = new TonWalletKit({
|
|
89199
|
+
networks: { [network.chainId]: { apiClient: apiConfig } },
|
|
89200
|
+
storage: new MemoryStorageAdapter()
|
|
89201
|
+
});
|
|
89202
|
+
await kit.waitForReady();
|
|
89203
|
+
let mnemonic;
|
|
89204
|
+
if (MNEMONIC) {
|
|
89205
|
+
mnemonic = MNEMONIC.trim().split(/\s+/);
|
|
89206
|
+
if (mnemonic.length !== 24) throw new Error(`Invalid mnemonic: expected 24 words, got ${mnemonic.length}`);
|
|
89207
|
+
log("Using provided mnemonic");
|
|
89208
|
+
} else throw new Error("MNEMONIC is required");
|
|
89209
|
+
const signer = await Signer.fromMnemonic(mnemonic, { type: "ton" });
|
|
89210
|
+
const walletAdapter = WALLET_VERSION === "v5r1" ? await WalletV5R1Adapter.create(signer, {
|
|
89211
|
+
client: kit.getApiClient(network),
|
|
89212
|
+
network
|
|
89213
|
+
}) : await WalletV4R2Adapter.create(signer, {
|
|
89214
|
+
client: kit.getApiClient(network),
|
|
89215
|
+
network
|
|
89216
|
+
});
|
|
89217
|
+
let wallet = await kit.addWallet(walletAdapter);
|
|
89218
|
+
if (!wallet) wallet = kit.getWallet(walletAdapter.getWalletId());
|
|
89219
|
+
if (!wallet) throw new Error("Failed to create wallet");
|
|
89220
|
+
log(`Wallet address: ${wallet.getAddress()}`);
|
|
89221
|
+
log(`Network: ${NETWORK}`);
|
|
89222
|
+
log(`Version: ${WALLET_VERSION}`);
|
|
90147
89223
|
return {
|
|
90148
|
-
server: createTonWalletMCP({
|
|
90149
|
-
|
|
90150
|
-
|
|
90151
|
-
|
|
90152
|
-
|
|
90153
|
-
|
|
89224
|
+
server: await createTonWalletMCP({
|
|
89225
|
+
wallet,
|
|
89226
|
+
networks: {
|
|
89227
|
+
mainnet: TONCENTER_API_KEY && NETWORK === "mainnet" ? { apiKey: TONCENTER_API_KEY } : void 0,
|
|
89228
|
+
testnet: TONCENTER_API_KEY && NETWORK === "testnet" ? { apiKey: TONCENTER_API_KEY } : void 0
|
|
89229
|
+
}
|
|
90154
89230
|
}),
|
|
90155
|
-
|
|
89231
|
+
kit,
|
|
89232
|
+
wallet
|
|
90156
89233
|
};
|
|
90157
89234
|
}
|
|
90158
89235
|
async function startStdio() {
|
|
90159
89236
|
log("Starting in stdio mode...");
|
|
90160
|
-
|
|
90161
|
-
const { server, signer } = createAdaptersAndServer();
|
|
89237
|
+
const { server, kit } = await createWalletAndServer();
|
|
90162
89238
|
const transport = new StdioServerTransport();
|
|
90163
89239
|
const shutdown = async () => {
|
|
90164
89240
|
log("Shutting down...");
|
|
90165
|
-
await
|
|
89241
|
+
await kit.close();
|
|
90166
89242
|
log("Shutdown complete");
|
|
90167
89243
|
process.exit(0);
|
|
90168
89244
|
};
|
|
@@ -90171,32 +89247,31 @@ async function startStdio() {
|
|
|
90171
89247
|
await server.connect(transport);
|
|
90172
89248
|
log("Server connected and ready to accept requests");
|
|
90173
89249
|
}
|
|
90174
|
-
async function startHttp(port) {
|
|
90175
|
-
log(`Starting in HTTP mode on
|
|
90176
|
-
|
|
90177
|
-
const { server, signer } = createAdaptersAndServer();
|
|
89250
|
+
async function startHttp(port, host) {
|
|
89251
|
+
log(`Starting in HTTP mode on ${host}:${port}...`);
|
|
89252
|
+
const { server, kit } = await createWalletAndServer();
|
|
90178
89253
|
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
|
|
90179
89254
|
await server.connect(transport);
|
|
90180
89255
|
const httpServer = createServer(async (req, res) => {
|
|
90181
|
-
if (new URL(req.url ?? "/", `http
|
|
89256
|
+
if (new URL(req.url ?? "/", `http://${host}:${port}`).pathname === "/mcp") await transport.handleRequest(req, res);
|
|
90182
89257
|
else res.writeHead(404).end("Not Found");
|
|
90183
89258
|
});
|
|
90184
89259
|
const shutdown = async () => {
|
|
90185
89260
|
log("Shutting down...");
|
|
90186
89261
|
httpServer.close();
|
|
90187
89262
|
await transport.close();
|
|
90188
|
-
await
|
|
89263
|
+
await kit.close();
|
|
90189
89264
|
log("Shutdown complete");
|
|
90190
89265
|
process.exit(0);
|
|
90191
89266
|
};
|
|
90192
89267
|
process.on("SIGINT", shutdown);
|
|
90193
89268
|
process.on("SIGTERM", shutdown);
|
|
90194
|
-
httpServer.listen(port, () => {
|
|
90195
|
-
log(`HTTP server listening on http
|
|
89269
|
+
httpServer.listen(port, host, () => {
|
|
89270
|
+
log(`HTTP server listening on http://${host}:${port}/mcp`);
|
|
90196
89271
|
});
|
|
90197
89272
|
}
|
|
90198
89273
|
const config = parseArgs();
|
|
90199
|
-
if (config.mode === "http") startHttp(config.port).catch((error) => {
|
|
89274
|
+
if (config.mode === "http") startHttp(config.port, config.host).catch((error) => {
|
|
90200
89275
|
console.error(`[${SERVER_NAME}] Fatal error:`, error);
|
|
90201
89276
|
process.exit(1);
|
|
90202
89277
|
});
|