@truecarry/mcp 0.1.3 → 0.1.4
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 +328 -1512
- package/dist/factory.d.ts +35 -21
- package/dist/factory.d.ts.map +1 -1
- package/dist/index.cjs +455 -4113
- package/dist/index.d.ts +5 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +455 -4100
- package/dist/services/McpWalletService.d.ts +25 -129
- 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 +3 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/{swap.d.ts → swap-tools.d.ts} +6 -49
- package/dist/tools/swap-tools.d.ts.map +1 -0
- package/dist/tools/transfer-tools.d.ts +79 -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.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
|
+
});
|
|
88164
|
+
}
|
|
88165
|
+
/**
|
|
88166
|
+
* Get wallet address
|
|
88167
|
+
*/
|
|
88168
|
+
getAddress() {
|
|
88169
|
+
return this.wallet.getAddress();
|
|
88526
88170
|
}
|
|
88527
88171
|
/**
|
|
88528
|
-
* Get
|
|
88172
|
+
* Get wallet network
|
|
88529
88173
|
*/
|
|
88530
|
-
getNetwork(
|
|
88531
|
-
return
|
|
88174
|
+
getNetwork() {
|
|
88175
|
+
return this.wallet.getNetwork().chainId === Network.mainnet().chainId ? "mainnet" : "testnet";
|
|
88532
88176
|
}
|
|
88533
88177
|
/**
|
|
88534
|
-
* Initialize TonWalletKit
|
|
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
|
|
88233
|
+
* Get transaction history using events API
|
|
88732
88234
|
*/
|
|
88733
|
-
|
|
88734
|
-
|
|
88735
|
-
|
|
88736
|
-
async getTransactions(userSigner, walletName, limit = 20) {
|
|
88737
|
-
const wallet = await this.getWalletForOperations(userSigner, walletName);
|
|
88738
|
-
const address = wallet.getAddress();
|
|
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,46 +88301,17 @@ var McpWalletService = class {
|
|
|
88836
88301
|
}
|
|
88837
88302
|
}
|
|
88838
88303
|
/**
|
|
88839
|
-
* Send Jetton
|
|
88304
|
+
* Send Jetton
|
|
88840
88305
|
*/
|
|
88841
|
-
async sendJetton(
|
|
88842
|
-
if (this.requiresConfirmation()) {
|
|
88843
|
-
const pending = await this.pendingManager.createPending(userStorage, {
|
|
88844
|
-
type: "send_jetton",
|
|
88845
|
-
walletName,
|
|
88846
|
-
description: `Send ${amountHuman} ${symbol ?? "tokens"} to ${toAddress}${comment ? ` (${comment})` : ""}`,
|
|
88847
|
-
data: {
|
|
88848
|
-
type: "send_jetton",
|
|
88849
|
-
toAddress,
|
|
88850
|
-
jettonAddress,
|
|
88851
|
-
amountRaw,
|
|
88852
|
-
amountHuman,
|
|
88853
|
-
symbol,
|
|
88854
|
-
decimals,
|
|
88855
|
-
comment
|
|
88856
|
-
}
|
|
88857
|
-
});
|
|
88858
|
-
return {
|
|
88859
|
-
success: true,
|
|
88860
|
-
message: `Transaction pending confirmation. ID: ${pending.id}`,
|
|
88861
|
-
pendingTransactionId: pending.id
|
|
88862
|
-
};
|
|
88863
|
-
}
|
|
88864
|
-
return this.executeJettonTransfer(userSigner, walletName, toAddress, jettonAddress, amountRaw, comment);
|
|
88865
|
-
}
|
|
88866
|
-
/**
|
|
88867
|
-
* Execute Jetton transfer (internal)
|
|
88868
|
-
*/
|
|
88869
|
-
async executeJettonTransfer(userSigner, walletName, toAddress, jettonAddress, amountRaw, comment) {
|
|
88306
|
+
async sendJetton(toAddress, jettonAddress, amountRaw, comment) {
|
|
88870
88307
|
try {
|
|
88871
|
-
const
|
|
88872
|
-
const tx = await wallet.createTransferJettonTransaction({
|
|
88308
|
+
const tx = await this.wallet.createTransferJettonTransaction({
|
|
88873
88309
|
recipientAddress: toAddress,
|
|
88874
88310
|
jettonAddress,
|
|
88875
88311
|
transferAmount: amountRaw,
|
|
88876
88312
|
comment
|
|
88877
88313
|
});
|
|
88878
|
-
await wallet.sendTransaction(tx);
|
|
88314
|
+
await this.wallet.sendTransaction(tx);
|
|
88879
88315
|
return {
|
|
88880
88316
|
success: true,
|
|
88881
88317
|
message: `Successfully sent jettons to ${toAddress}`
|
|
@@ -88890,75 +88326,46 @@ var McpWalletService = class {
|
|
|
88890
88326
|
/**
|
|
88891
88327
|
* Get swap quote
|
|
88892
88328
|
*/
|
|
88893
|
-
async getSwapQuote(
|
|
88894
|
-
const
|
|
88895
|
-
if (!walletInfo) throw new Error("Wallet not found");
|
|
88896
|
-
const network = this.getNetwork(walletInfo.network);
|
|
88329
|
+
async getSwapQuote(fromToken, toToken, amount, slippageBps) {
|
|
88330
|
+
const network = this.wallet.getNetwork();
|
|
88897
88331
|
const kit = await this.getKit();
|
|
88898
88332
|
const params = {
|
|
88899
|
-
fromToken: fromToken === "TON" ? "
|
|
88900
|
-
|
|
88901
|
-
|
|
88333
|
+
fromToken: fromToken === "TON" ? { type: "ton" } : {
|
|
88334
|
+
type: "jetton",
|
|
88335
|
+
value: fromToken
|
|
88336
|
+
},
|
|
88337
|
+
toToken: toToken === "TON" ? { type: "ton" } : {
|
|
88338
|
+
type: "jetton",
|
|
88339
|
+
value: toToken
|
|
88340
|
+
},
|
|
88341
|
+
amount,
|
|
88902
88342
|
network,
|
|
88903
88343
|
slippageBps
|
|
88904
88344
|
};
|
|
88905
88345
|
const quote = await kit.swap.getQuote(params);
|
|
88906
88346
|
return {
|
|
88907
88347
|
quote,
|
|
88908
|
-
fromToken:
|
|
88909
|
-
toToken:
|
|
88348
|
+
fromToken: quote.fromToken.type === "ton" ? "TON" : quote.fromToken.value,
|
|
88349
|
+
toToken: quote.toToken.type === "ton" ? "TON" : quote.toToken.value,
|
|
88910
88350
|
fromAmount: quote.fromAmount,
|
|
88911
88351
|
toAmount: quote.toAmount,
|
|
88912
88352
|
minReceived: quote.minReceived,
|
|
88913
|
-
provider: quote.
|
|
88353
|
+
provider: quote.providerId,
|
|
88914
88354
|
expiresAt: quote.expiresAt
|
|
88915
88355
|
};
|
|
88916
88356
|
}
|
|
88917
88357
|
/**
|
|
88918
|
-
* Execute swap
|
|
88919
|
-
*/
|
|
88920
|
-
async executeSwap(userSigner, userStorage, walletName, quote) {
|
|
88921
|
-
if (this.requiresConfirmation()) {
|
|
88922
|
-
const pending = await this.pendingManager.createPending(userStorage, {
|
|
88923
|
-
type: "swap",
|
|
88924
|
-
walletName,
|
|
88925
|
-
description: `Swap ${quote.fromAmount} ${quote.fromToken} for ${quote.toAmount} ${quote.toToken}`,
|
|
88926
|
-
data: {
|
|
88927
|
-
type: "swap",
|
|
88928
|
-
fromToken: String(quote.fromToken),
|
|
88929
|
-
toToken: String(quote.toToken),
|
|
88930
|
-
fromAmount: quote.fromAmount,
|
|
88931
|
-
toAmount: quote.toAmount,
|
|
88932
|
-
minReceived: quote.minReceived,
|
|
88933
|
-
provider: quote.provider,
|
|
88934
|
-
quoteJson: JSON.stringify(quote)
|
|
88935
|
-
}
|
|
88936
|
-
});
|
|
88937
|
-
return {
|
|
88938
|
-
success: true,
|
|
88939
|
-
message: `Swap pending confirmation. ID: ${pending.id}`,
|
|
88940
|
-
pendingTransactionId: pending.id
|
|
88941
|
-
};
|
|
88942
|
-
}
|
|
88943
|
-
return this.executeSwapInternal(userSigner, walletName, quote);
|
|
88944
|
-
}
|
|
88945
|
-
/**
|
|
88946
|
-
* Execute swap (internal)
|
|
88358
|
+
* Execute swap
|
|
88947
88359
|
*/
|
|
88948
|
-
async
|
|
88360
|
+
async executeSwap(quote) {
|
|
88949
88361
|
try {
|
|
88950
|
-
const
|
|
88951
|
-
this.getWalletForOperations(userSigner, walletName),
|
|
88952
|
-
this.getKit(),
|
|
88953
|
-
userSigner.getWallet(walletName)
|
|
88954
|
-
]);
|
|
88955
|
-
if (!walletInfo) throw new Error("Wallet not found");
|
|
88362
|
+
const kit = await this.getKit();
|
|
88956
88363
|
const params = {
|
|
88957
88364
|
quote,
|
|
88958
|
-
userAddress:
|
|
88365
|
+
userAddress: this.wallet.getAddress()
|
|
88959
88366
|
};
|
|
88960
88367
|
const tx = await kit.swap.buildSwapTransaction(params);
|
|
88961
|
-
await wallet.sendTransaction(tx);
|
|
88368
|
+
await this.wallet.sendTransaction(tx);
|
|
88962
88369
|
return {
|
|
88963
88370
|
success: true,
|
|
88964
88371
|
message: `Successfully swapped ${quote.fromAmount} ${quote.fromToken} for ${quote.toAmount} ${quote.toToken}`
|
|
@@ -88971,52 +88378,11 @@ var McpWalletService = class {
|
|
|
88971
88378
|
}
|
|
88972
88379
|
}
|
|
88973
88380
|
/**
|
|
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
88381
|
* Resolve contact name to address
|
|
89016
88382
|
*/
|
|
89017
|
-
async resolveContact(
|
|
88383
|
+
async resolveContact(name) {
|
|
89018
88384
|
if (!this.config.contacts) return null;
|
|
89019
|
-
return this.config.contacts.resolve(
|
|
88385
|
+
return this.config.contacts.resolve("default", name);
|
|
89020
88386
|
}
|
|
89021
88387
|
/**
|
|
89022
88388
|
* Close and cleanup
|
|
@@ -89026,12 +88392,11 @@ var McpWalletService = class {
|
|
|
89026
88392
|
await this.kit.close();
|
|
89027
88393
|
this.kit = null;
|
|
89028
88394
|
}
|
|
89029
|
-
this.loadedWallets.clear();
|
|
89030
88395
|
}
|
|
89031
88396
|
};
|
|
89032
88397
|
|
|
89033
88398
|
//#endregion
|
|
89034
|
-
//#region src/tools/
|
|
88399
|
+
//#region src/tools/balance-tools.ts
|
|
89035
88400
|
/**
|
|
89036
88401
|
* Copyright (c) TonTech.
|
|
89037
88402
|
*
|
|
@@ -89039,185 +88404,24 @@ var McpWalletService = class {
|
|
|
89039
88404
|
* LICENSE file in the root directory of this source tree.
|
|
89040
88405
|
*
|
|
89041
88406
|
*/
|
|
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) {
|
|
88407
|
+
const getBalanceSchema = z.object({});
|
|
88408
|
+
const getJettonBalanceSchema = z.object({ jettonAddress: z.string().min(1).describe("Jetton master contract address") });
|
|
88409
|
+
const getJettonsSchema = z.object({});
|
|
88410
|
+
const getTransactionsSchema = z.object({ limit: z.number().min(1).max(100).optional().describe("Maximum number of transactions to return (default: 20, max: 100)") });
|
|
88411
|
+
function createMcpBalanceTools(service) {
|
|
89207
88412
|
return {
|
|
89208
88413
|
get_balance: {
|
|
89209
|
-
description: "Get the TON balance of
|
|
88414
|
+
description: "Get the TON balance of the wallet. Returns both human-readable and raw (nanoTON) amounts.",
|
|
89210
88415
|
inputSchema: getBalanceSchema,
|
|
89211
|
-
handler:
|
|
89212
|
-
const userSigner = service.createUserSigner(userId);
|
|
88416
|
+
handler: async () => {
|
|
89213
88417
|
try {
|
|
89214
|
-
const balance = await service.getBalance(
|
|
88418
|
+
const balance = await service.getBalance();
|
|
89215
88419
|
const balanceTon = Number(BigInt(balance)) / 1e9;
|
|
89216
88420
|
return { content: [{
|
|
89217
88421
|
type: "text",
|
|
89218
88422
|
text: JSON.stringify({
|
|
89219
88423
|
success: true,
|
|
89220
|
-
|
|
88424
|
+
address: service.getAddress(),
|
|
89221
88425
|
balance: `${balanceTon} TON`,
|
|
89222
88426
|
balanceNano: balance
|
|
89223
88427
|
}, null, 2)
|
|
@@ -89234,20 +88438,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89234
88438
|
isError: true
|
|
89235
88439
|
};
|
|
89236
88440
|
}
|
|
89237
|
-
}
|
|
88441
|
+
}
|
|
89238
88442
|
},
|
|
89239
88443
|
get_jetton_balance: {
|
|
89240
|
-
description: "Get the balance of a specific Jetton (token) in
|
|
88444
|
+
description: "Get the balance of a specific Jetton (token) in the wallet.",
|
|
89241
88445
|
inputSchema: getJettonBalanceSchema,
|
|
89242
|
-
handler:
|
|
89243
|
-
const userSigner = service.createUserSigner(userId);
|
|
88446
|
+
handler: async (args) => {
|
|
89244
88447
|
try {
|
|
89245
|
-
const balance = await service.getJettonBalance(
|
|
88448
|
+
const balance = await service.getJettonBalance(args.jettonAddress);
|
|
89246
88449
|
return { content: [{
|
|
89247
88450
|
type: "text",
|
|
89248
88451
|
text: JSON.stringify({
|
|
89249
88452
|
success: true,
|
|
89250
|
-
wallet: args.wallet,
|
|
89251
88453
|
jettonAddress: args.jettonAddress,
|
|
89252
88454
|
balance
|
|
89253
88455
|
}, null, 2)
|
|
@@ -89264,20 +88466,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89264
88466
|
isError: true
|
|
89265
88467
|
};
|
|
89266
88468
|
}
|
|
89267
|
-
}
|
|
88469
|
+
}
|
|
89268
88470
|
},
|
|
89269
88471
|
get_jettons: {
|
|
89270
|
-
description: "List all Jettons (tokens) in
|
|
88472
|
+
description: "List all Jettons (tokens) in the wallet with their balances and metadata.",
|
|
89271
88473
|
inputSchema: getJettonsSchema,
|
|
89272
|
-
handler:
|
|
89273
|
-
const userSigner = service.createUserSigner(userId);
|
|
88474
|
+
handler: async () => {
|
|
89274
88475
|
try {
|
|
89275
|
-
const jettons = await service.getJettons(
|
|
88476
|
+
const jettons = await service.getJettons();
|
|
89276
88477
|
return { content: [{
|
|
89277
88478
|
type: "text",
|
|
89278
88479
|
text: JSON.stringify({
|
|
89279
88480
|
success: true,
|
|
89280
|
-
wallet: args.wallet,
|
|
89281
88481
|
jettons,
|
|
89282
88482
|
count: jettons.length
|
|
89283
88483
|
}, null, 2)
|
|
@@ -89294,20 +88494,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89294
88494
|
isError: true
|
|
89295
88495
|
};
|
|
89296
88496
|
}
|
|
89297
|
-
}
|
|
88497
|
+
}
|
|
89298
88498
|
},
|
|
89299
88499
|
get_transactions: {
|
|
89300
|
-
description: "Get recent transaction history for
|
|
88500
|
+
description: "Get recent transaction history for the wallet. Returns events with actions like TON transfers, Jetton transfers, swaps, and more.",
|
|
89301
88501
|
inputSchema: getTransactionsSchema,
|
|
89302
|
-
handler:
|
|
89303
|
-
const userSigner = service.createUserSigner(userId);
|
|
88502
|
+
handler: async (args) => {
|
|
89304
88503
|
try {
|
|
89305
|
-
const transactions = await service.getTransactions(
|
|
88504
|
+
const transactions = await service.getTransactions(args.limit ?? 20);
|
|
89306
88505
|
return { content: [{
|
|
89307
88506
|
type: "text",
|
|
89308
88507
|
text: JSON.stringify({
|
|
89309
88508
|
success: true,
|
|
89310
|
-
wallet: args.wallet,
|
|
89311
88509
|
transactions: transactions.map((tx) => ({
|
|
89312
88510
|
eventId: tx.eventId,
|
|
89313
88511
|
timestamp: tx.timestamp,
|
|
@@ -89355,33 +88553,50 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
|
|
|
89355
88553
|
isError: true
|
|
89356
88554
|
};
|
|
89357
88555
|
}
|
|
89358
|
-
}
|
|
88556
|
+
}
|
|
89359
88557
|
}
|
|
89360
88558
|
};
|
|
89361
88559
|
}
|
|
88560
|
+
|
|
88561
|
+
//#endregion
|
|
88562
|
+
//#region src/tools/types.ts
|
|
88563
|
+
/**
|
|
88564
|
+
* Converts a human-readable amount to raw units.
|
|
88565
|
+
*/
|
|
88566
|
+
function toRawAmount(amount, decimals) {
|
|
88567
|
+
const [intPart, fracPart = ""] = amount.split(".");
|
|
88568
|
+
return (intPart + fracPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
|
|
88569
|
+
}
|
|
88570
|
+
const TON_DECIMALS = 9;
|
|
88571
|
+
|
|
88572
|
+
//#endregion
|
|
88573
|
+
//#region src/tools/transfer-tools.ts
|
|
88574
|
+
/**
|
|
88575
|
+
* Copyright (c) TonTech.
|
|
88576
|
+
*
|
|
88577
|
+
* This source code is licensed under the MIT license found in the
|
|
88578
|
+
* LICENSE file in the root directory of this source tree.
|
|
88579
|
+
*
|
|
88580
|
+
*/
|
|
89362
88581
|
const sendTonSchema = z.object({
|
|
89363
|
-
wallet: z.string().min(1).describe("Name of the wallet to send from"),
|
|
89364
88582
|
toAddress: z.string().min(1).describe("Recipient TON address"),
|
|
89365
88583
|
amount: z.string().min(1).describe("Amount of TON to send (e.g., \"1.5\" for 1.5 TON)"),
|
|
89366
88584
|
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
89367
88585
|
});
|
|
89368
88586
|
const sendJettonSchema = z.object({
|
|
89369
|
-
wallet: z.string().min(1).describe("Name of the wallet to send from"),
|
|
89370
88587
|
toAddress: z.string().min(1).describe("Recipient TON address"),
|
|
89371
88588
|
jettonAddress: z.string().min(1).describe("Jetton master contract address"),
|
|
89372
88589
|
amount: z.string().min(1).describe("Amount of tokens to send in human-readable format"),
|
|
89373
88590
|
comment: z.string().optional().describe("Optional comment/memo for the transaction")
|
|
89374
88591
|
});
|
|
89375
|
-
function createMcpTransferTools(
|
|
88592
|
+
function createMcpTransferTools(service) {
|
|
89376
88593
|
return {
|
|
89377
88594
|
send_ton: {
|
|
89378
|
-
description: "Send TON from
|
|
88595
|
+
description: "Send TON from the wallet to an address. Amount is in TON (e.g., \"1.5\" means 1.5 TON).",
|
|
89379
88596
|
inputSchema: sendTonSchema,
|
|
89380
|
-
handler:
|
|
89381
|
-
const userSigner = service.createUserSigner(userId);
|
|
89382
|
-
const userStorage = service.createUserStorage(userId);
|
|
88597
|
+
handler: async (args) => {
|
|
89383
88598
|
const rawAmount = toRawAmount(args.amount, TON_DECIMALS);
|
|
89384
|
-
const result = await service.sendTon(
|
|
88599
|
+
const result = await service.sendTon(args.toAddress, rawAmount, args.comment);
|
|
89385
88600
|
if (!result.success) return {
|
|
89386
88601
|
content: [{
|
|
89387
88602
|
type: "text",
|
|
@@ -89398,26 +88613,22 @@ function createMcpTransferTools(_walletService, wrapHandler) {
|
|
|
89398
88613
|
success: true,
|
|
89399
88614
|
message: result.message,
|
|
89400
88615
|
details: {
|
|
89401
|
-
from: args.wallet,
|
|
89402
88616
|
to: args.toAddress,
|
|
89403
88617
|
amount: `${args.amount} TON`,
|
|
89404
|
-
comment: args.comment || null
|
|
89405
|
-
pendingTransactionId: result.pendingTransactionId || null
|
|
88618
|
+
comment: args.comment || null
|
|
89406
88619
|
}
|
|
89407
88620
|
}, null, 2)
|
|
89408
88621
|
}] };
|
|
89409
|
-
}
|
|
88622
|
+
}
|
|
89410
88623
|
},
|
|
89411
88624
|
send_jetton: {
|
|
89412
|
-
description: "Send Jettons (tokens) from
|
|
88625
|
+
description: "Send Jettons (tokens) from the wallet to an address. Amount is in human-readable format.",
|
|
89413
88626
|
inputSchema: sendJettonSchema,
|
|
89414
|
-
handler:
|
|
89415
|
-
const userSigner = service.createUserSigner(userId);
|
|
89416
|
-
const userStorage = service.createUserStorage(userId);
|
|
88627
|
+
handler: async (args) => {
|
|
89417
88628
|
let decimals;
|
|
89418
88629
|
let symbol;
|
|
89419
88630
|
try {
|
|
89420
|
-
const jetton = (await service.getJettons(
|
|
88631
|
+
const jetton = (await service.getJettons()).find((j) => j.address.toLowerCase() === args.jettonAddress.toLowerCase());
|
|
89421
88632
|
if (jetton) {
|
|
89422
88633
|
decimals = jetton.decimals;
|
|
89423
88634
|
symbol = jetton.symbol;
|
|
@@ -89445,7 +88656,7 @@ function createMcpTransferTools(_walletService, wrapHandler) {
|
|
|
89445
88656
|
isError: true
|
|
89446
88657
|
};
|
|
89447
88658
|
const rawAmount = toRawAmount(args.amount, decimals);
|
|
89448
|
-
const result = await service.sendJetton(
|
|
88659
|
+
const result = await service.sendJetton(args.toAddress, args.jettonAddress, rawAmount, args.comment);
|
|
89449
88660
|
if (!result.success) return {
|
|
89450
88661
|
content: [{
|
|
89451
88662
|
type: "text",
|
|
@@ -89462,19 +88673,27 @@ function createMcpTransferTools(_walletService, wrapHandler) {
|
|
|
89462
88673
|
success: true,
|
|
89463
88674
|
message: result.message,
|
|
89464
88675
|
details: {
|
|
89465
|
-
from: args.wallet,
|
|
89466
88676
|
to: args.toAddress,
|
|
89467
88677
|
jettonAddress: args.jettonAddress,
|
|
89468
88678
|
amount: `${args.amount} ${symbol || "tokens"}`,
|
|
89469
|
-
comment: args.comment || null
|
|
89470
|
-
pendingTransactionId: result.pendingTransactionId || null
|
|
88679
|
+
comment: args.comment || null
|
|
89471
88680
|
}
|
|
89472
88681
|
}, null, 2)
|
|
89473
88682
|
}] };
|
|
89474
|
-
}
|
|
88683
|
+
}
|
|
89475
88684
|
}
|
|
89476
88685
|
};
|
|
89477
88686
|
}
|
|
88687
|
+
|
|
88688
|
+
//#endregion
|
|
88689
|
+
//#region src/tools/swap-tools.ts
|
|
88690
|
+
/**
|
|
88691
|
+
* Copyright (c) TonTech.
|
|
88692
|
+
*
|
|
88693
|
+
* This source code is licensed under the MIT license found in the
|
|
88694
|
+
* LICENSE file in the root directory of this source tree.
|
|
88695
|
+
*
|
|
88696
|
+
*/
|
|
89478
88697
|
const quoteCache = /* @__PURE__ */ new Map();
|
|
89479
88698
|
function generateQuoteId() {
|
|
89480
88699
|
return `quote_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
@@ -89484,32 +88703,26 @@ function cleanExpiredQuotes() {
|
|
|
89484
88703
|
for (const [id, data] of quoteCache.entries()) if (data.expiresAt < now) quoteCache.delete(id);
|
|
89485
88704
|
}
|
|
89486
88705
|
const getSwapQuoteSchema = z.object({
|
|
89487
|
-
wallet: z.string().min(1).describe("Name of the wallet to swap from"),
|
|
89488
88706
|
fromToken: z.string().min(1).describe("Token to swap from (\"TON\" or jetton address)"),
|
|
89489
88707
|
toToken: z.string().min(1).describe("Token to swap to (\"TON\" or jetton address)"),
|
|
89490
88708
|
amount: z.string().min(1).describe("Amount to swap in raw units"),
|
|
89491
88709
|
slippageBps: z.number().optional().describe("Slippage tolerance in basis points (default 100 = 1%)")
|
|
89492
88710
|
});
|
|
89493
|
-
const executeSwapSchema = z.object({
|
|
89494
|
-
|
|
89495
|
-
quoteId: z.string().min(1).describe("Quote ID returned from get_swap_quote")
|
|
89496
|
-
});
|
|
89497
|
-
function createMcpSwapTools(_walletService, wrapHandler) {
|
|
88711
|
+
const executeSwapSchema = z.object({ quoteId: z.string().min(1).describe("Quote ID returned from get_swap_quote") });
|
|
88712
|
+
function createMcpSwapTools(service) {
|
|
89498
88713
|
return {
|
|
89499
88714
|
get_swap_quote: {
|
|
89500
88715
|
description: "Get a quote for swapping tokens. Returns a quote ID to use with execute_swap.",
|
|
89501
88716
|
inputSchema: getSwapQuoteSchema,
|
|
89502
|
-
handler:
|
|
89503
|
-
const userSigner = service.createUserSigner(userId);
|
|
88717
|
+
handler: async (args) => {
|
|
89504
88718
|
try {
|
|
89505
88719
|
cleanExpiredQuotes();
|
|
89506
|
-
const result = await service.getSwapQuote(
|
|
88720
|
+
const result = await service.getSwapQuote(args.fromToken, args.toToken, args.amount, args.slippageBps);
|
|
89507
88721
|
const quoteId = generateQuoteId();
|
|
89508
88722
|
const expiresAt = result.expiresAt ? result.expiresAt * 1e3 : Date.now() + 6e4;
|
|
89509
88723
|
quoteCache.set(quoteId, {
|
|
89510
88724
|
quote: result.quote,
|
|
89511
|
-
expiresAt
|
|
89512
|
-
userId
|
|
88725
|
+
expiresAt
|
|
89513
88726
|
});
|
|
89514
88727
|
return { content: [{
|
|
89515
88728
|
type: "text",
|
|
@@ -89538,14 +88751,12 @@ function createMcpSwapTools(_walletService, wrapHandler) {
|
|
|
89538
88751
|
isError: true
|
|
89539
88752
|
};
|
|
89540
88753
|
}
|
|
89541
|
-
}
|
|
88754
|
+
}
|
|
89542
88755
|
},
|
|
89543
88756
|
execute_swap: {
|
|
89544
|
-
description: "Execute a token swap using a quote.
|
|
88757
|
+
description: "Execute a token swap using a quote.",
|
|
89545
88758
|
inputSchema: executeSwapSchema,
|
|
89546
|
-
handler:
|
|
89547
|
-
const userSigner = service.createUserSigner(userId);
|
|
89548
|
-
const userStorage = service.createUserStorage(userId);
|
|
88759
|
+
handler: async (args) => {
|
|
89549
88760
|
cleanExpiredQuotes();
|
|
89550
88761
|
const cachedQuote = quoteCache.get(args.quoteId);
|
|
89551
88762
|
if (!cachedQuote) return {
|
|
@@ -89558,16 +88769,6 @@ function createMcpSwapTools(_walletService, wrapHandler) {
|
|
|
89558
88769
|
}],
|
|
89559
88770
|
isError: true
|
|
89560
88771
|
};
|
|
89561
|
-
if (cachedQuote.userId !== userId) return {
|
|
89562
|
-
content: [{
|
|
89563
|
-
type: "text",
|
|
89564
|
-
text: JSON.stringify({
|
|
89565
|
-
success: false,
|
|
89566
|
-
error: "Quote not found or expired. Please get a new quote."
|
|
89567
|
-
})
|
|
89568
|
-
}],
|
|
89569
|
-
isError: true
|
|
89570
|
-
};
|
|
89571
88772
|
if (cachedQuote.expiresAt < Date.now()) {
|
|
89572
88773
|
quoteCache.delete(args.quoteId);
|
|
89573
88774
|
return {
|
|
@@ -89581,7 +88782,7 @@ function createMcpSwapTools(_walletService, wrapHandler) {
|
|
|
89581
88782
|
isError: true
|
|
89582
88783
|
};
|
|
89583
88784
|
}
|
|
89584
|
-
const result = await service.executeSwap(
|
|
88785
|
+
const result = await service.executeSwap(cachedQuote.quote);
|
|
89585
88786
|
quoteCache.delete(args.quoteId);
|
|
89586
88787
|
if (!result.success) return {
|
|
89587
88788
|
content: [{
|
|
@@ -89603,91 +88804,11 @@ function createMcpSwapTools(_walletService, wrapHandler) {
|
|
|
89603
88804
|
toToken: cachedQuote.quote.toToken,
|
|
89604
88805
|
fromAmount: cachedQuote.quote.fromAmount,
|
|
89605
88806
|
toAmount: cachedQuote.quote.toAmount,
|
|
89606
|
-
provider: cachedQuote.quote.
|
|
89607
|
-
pendingTransactionId: result.pendingTransactionId || null
|
|
88807
|
+
provider: cachedQuote.quote.providerId
|
|
89608
88808
|
}
|
|
89609
88809
|
}, null, 2)
|
|
89610
88810
|
}] };
|
|
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
|
-
})
|
|
89668
|
-
},
|
|
89669
|
-
list_pending_transactions: {
|
|
89670
|
-
description: "List all pending transactions awaiting confirmation.",
|
|
89671
|
-
inputSchema: z.object({}),
|
|
89672
|
-
handler: wrapHandler(async (_args, userId, service) => {
|
|
89673
|
-
const userStorage = service.createUserStorage(userId);
|
|
89674
|
-
const pending = await service.listPendingTransactions(userStorage);
|
|
89675
|
-
return { content: [{
|
|
89676
|
-
type: "text",
|
|
89677
|
-
text: JSON.stringify({
|
|
89678
|
-
success: true,
|
|
89679
|
-
transactions: pending.map((tx) => ({
|
|
89680
|
-
id: tx.id,
|
|
89681
|
-
type: tx.type,
|
|
89682
|
-
wallet: tx.walletName,
|
|
89683
|
-
description: tx.description,
|
|
89684
|
-
createdAt: tx.createdAt,
|
|
89685
|
-
expiresAt: tx.expiresAt
|
|
89686
|
-
})),
|
|
89687
|
-
count: pending.length
|
|
89688
|
-
}, null, 2)
|
|
89689
|
-
}] };
|
|
89690
|
-
})
|
|
88811
|
+
}
|
|
89691
88812
|
}
|
|
89692
88813
|
};
|
|
89693
88814
|
}
|
|
@@ -89709,70 +88830,46 @@ const SERVER_VERSION = "0.1.0";
|
|
|
89709
88830
|
/**
|
|
89710
88831
|
* Create a configured TON Wallet MCP server
|
|
89711
88832
|
*
|
|
89712
|
-
* @param config - Configuration with
|
|
88833
|
+
* @param config - Configuration with wallet instance
|
|
89713
88834
|
* @returns Configured McpServer instance
|
|
89714
88835
|
*
|
|
89715
88836
|
* @example
|
|
89716
88837
|
* ```typescript
|
|
89717
|
-
* import { createTonWalletMCP
|
|
88838
|
+
* import { createTonWalletMCP } from '@ton/mcp';
|
|
88839
|
+
* import { Signer, WalletV5R1Adapter, TonWalletKit, Network } from '@ton/walletkit';
|
|
89718
88840
|
*
|
|
89719
|
-
*
|
|
89720
|
-
*
|
|
89721
|
-
*
|
|
89722
|
-
*
|
|
89723
|
-
*
|
|
89724
|
-
*
|
|
89725
|
-
* limits: {
|
|
89726
|
-
* maxTransactionTon: 100,
|
|
89727
|
-
* dailyLimitTon: 1000,
|
|
89728
|
-
* maxWalletsPerUser: 10,
|
|
89729
|
-
* },
|
|
89730
|
-
* requireConfirmation: true,
|
|
88841
|
+
* // Create wallet adapter
|
|
88842
|
+
* const kit = new TonWalletKit({ ... });
|
|
88843
|
+
* const signer = await Signer.fromMnemonic(mnemonic, { type: 'ton' });
|
|
88844
|
+
* const walletAdapter = await WalletV5R1Adapter.create(signer, {
|
|
88845
|
+
* client: kit.getApiClient(Network.mainnet()),
|
|
88846
|
+
* network: Network.mainnet(),
|
|
89731
88847
|
* });
|
|
88848
|
+
* const wallet = await kit.addWallet(walletAdapter);
|
|
88849
|
+
*
|
|
88850
|
+
* // Create MCP server
|
|
88851
|
+
* const server = createTonWalletMCP({ wallet });
|
|
89732
88852
|
* ```
|
|
89733
88853
|
*/
|
|
89734
|
-
function createTonWalletMCP(config) {
|
|
89735
|
-
const walletService =
|
|
89736
|
-
|
|
89737
|
-
signer: config.signer,
|
|
88854
|
+
async function createTonWalletMCP(config) {
|
|
88855
|
+
const walletService = await McpWalletService.create({
|
|
88856
|
+
wallet: config.wallet,
|
|
89738
88857
|
contacts: config.contacts,
|
|
89739
|
-
|
|
89740
|
-
limits: config.limits,
|
|
89741
|
-
requireConfirmation: config.requireConfirmation
|
|
88858
|
+
networks: config.networks
|
|
89742
88859
|
});
|
|
89743
88860
|
const server = new McpServer({
|
|
89744
88861
|
name: SERVER_NAME$1,
|
|
89745
88862
|
version: SERVER_VERSION
|
|
89746
88863
|
});
|
|
89747
|
-
const
|
|
89748
|
-
|
|
89749
|
-
|
|
89750
|
-
return userId;
|
|
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);
|
|
88864
|
+
const balanceTools = createMcpBalanceTools(walletService);
|
|
88865
|
+
const transferTools = createMcpTransferTools(walletService);
|
|
88866
|
+
const swapTools = createMcpSwapTools(walletService);
|
|
89766
88867
|
const registerTool = (name, tool) => {
|
|
89767
88868
|
server.registerTool(name, {
|
|
89768
88869
|
description: tool.description,
|
|
89769
88870
|
inputSchema: tool.inputSchema
|
|
89770
88871
|
}, tool.handler);
|
|
89771
88872
|
};
|
|
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
88873
|
registerTool("get_balance", balanceTools.get_balance);
|
|
89777
88874
|
registerTool("get_jetton_balance", balanceTools.get_jetton_balance);
|
|
89778
88875
|
registerTool("get_jettons", balanceTools.get_jettons);
|
|
@@ -89781,331 +88878,9 @@ function createTonWalletMCP(config) {
|
|
|
89781
88878
|
registerTool("send_jetton", transferTools.send_jetton);
|
|
89782
88879
|
registerTool("get_swap_quote", swapTools.get_swap_quote);
|
|
89783
88880
|
registerTool("execute_swap", swapTools.execute_swap);
|
|
89784
|
-
if (config.requireConfirmation) {
|
|
89785
|
-
registerTool("confirm_transaction", pendingTools.confirm_transaction);
|
|
89786
|
-
registerTool("cancel_transaction", pendingTools.cancel_transaction);
|
|
89787
|
-
registerTool("list_pending_transactions", pendingTools.list_pending_transactions);
|
|
89788
|
-
}
|
|
89789
88881
|
return server;
|
|
89790
88882
|
}
|
|
89791
88883
|
|
|
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
88884
|
//#endregion
|
|
90110
88885
|
//#region src/cli.ts
|
|
90111
88886
|
/**
|
|
@@ -90122,12 +88897,21 @@ var StaticUserContextProvider = class {
|
|
|
90122
88897
|
* TON wallet management tools for use with Claude Desktop or other MCP clients.
|
|
90123
88898
|
*
|
|
90124
88899
|
* Usage:
|
|
90125
|
-
* npx @ton/mcp
|
|
90126
|
-
* npx @ton/mcp --http
|
|
90127
|
-
* npx @ton/mcp --http 8080
|
|
88900
|
+
* npx @ton/mcp # stdio mode (default)
|
|
88901
|
+
* npx @ton/mcp --http # HTTP server on 0.0.0.0:3000
|
|
88902
|
+
* npx @ton/mcp --http 8080 # HTTP server on custom port
|
|
88903
|
+
* npx @ton/mcp --http --host 127.0.0.1 # HTTP server on custom host
|
|
88904
|
+
*
|
|
88905
|
+
* Environment variables:
|
|
88906
|
+
* NETWORK - Network to use (mainnet or testnet, default: mainnet)
|
|
88907
|
+
* MNEMONIC - 24-word mnemonic phrase for wallet (if not provided, a new wallet is created)
|
|
88908
|
+
* WALLET_VERSION - Wallet version (v5r1 or v4r2, default: v5r1)
|
|
90128
88909
|
*/
|
|
90129
88910
|
const SERVER_NAME = "ton-mcp";
|
|
90130
88911
|
const NETWORK = process.env.NETWORK || "mainnet";
|
|
88912
|
+
const MNEMONIC = process.env.MNEMONIC;
|
|
88913
|
+
const WALLET_VERSION = process.env.WALLET_VERSION || "v5r1";
|
|
88914
|
+
const TONCENTER_API_KEY = process.env.TONCENTER_API_KEY;
|
|
90131
88915
|
function log(message) {
|
|
90132
88916
|
console.error(`[${SERVER_NAME}] ${message}`);
|
|
90133
88917
|
}
|
|
@@ -90136,33 +88920,66 @@ function parseArgs() {
|
|
|
90136
88920
|
const httpIndex = args.indexOf("--http");
|
|
90137
88921
|
if (httpIndex === -1) return { mode: "stdio" };
|
|
90138
88922
|
const nextArg = args[httpIndex + 1];
|
|
88923
|
+
const port = nextArg && !nextArg.startsWith("-") ? parseInt(nextArg, 10) : 3e3;
|
|
88924
|
+
const hostIndex = args.indexOf("--host");
|
|
88925
|
+
const hostArg = hostIndex !== -1 ? args[hostIndex + 1] : void 0;
|
|
90139
88926
|
return {
|
|
90140
88927
|
mode: "http",
|
|
90141
|
-
port
|
|
88928
|
+
port,
|
|
88929
|
+
host: hostArg && !hostArg.startsWith("-") ? hostArg : "0.0.0.0"
|
|
90142
88930
|
};
|
|
90143
88931
|
}
|
|
90144
|
-
function
|
|
90145
|
-
const
|
|
90146
|
-
const
|
|
88932
|
+
async function createWalletAndServer() {
|
|
88933
|
+
const network = NETWORK === "mainnet" ? Network.mainnet() : Network.testnet();
|
|
88934
|
+
const apiConfig = {};
|
|
88935
|
+
if (TONCENTER_API_KEY) {
|
|
88936
|
+
apiConfig.url = NETWORK === "mainnet" ? "https://toncenter.com" : "https://testnet.toncenter.com";
|
|
88937
|
+
apiConfig.key = TONCENTER_API_KEY;
|
|
88938
|
+
}
|
|
88939
|
+
const kit = new TonWalletKit({
|
|
88940
|
+
networks: { [network.chainId]: { apiClient: apiConfig } },
|
|
88941
|
+
storage: new MemoryStorageAdapter()
|
|
88942
|
+
});
|
|
88943
|
+
await kit.waitForReady();
|
|
88944
|
+
let mnemonic;
|
|
88945
|
+
if (MNEMONIC) {
|
|
88946
|
+
mnemonic = MNEMONIC.trim().split(/\s+/);
|
|
88947
|
+
if (mnemonic.length !== 24) throw new Error(`Invalid mnemonic: expected 24 words, got ${mnemonic.length}`);
|
|
88948
|
+
log("Using provided mnemonic");
|
|
88949
|
+
} else throw new Error("MNEMONIC is required");
|
|
88950
|
+
const signer = await Signer.fromMnemonic(mnemonic, { type: "ton" });
|
|
88951
|
+
const walletAdapter = WALLET_VERSION === "v5r1" ? await WalletV5R1Adapter.create(signer, {
|
|
88952
|
+
client: kit.getApiClient(network),
|
|
88953
|
+
network
|
|
88954
|
+
}) : await WalletV4R2Adapter.create(signer, {
|
|
88955
|
+
client: kit.getApiClient(network),
|
|
88956
|
+
network
|
|
88957
|
+
});
|
|
88958
|
+
let wallet = await kit.addWallet(walletAdapter);
|
|
88959
|
+
if (!wallet) wallet = kit.getWallet(walletAdapter.getWalletId());
|
|
88960
|
+
if (!wallet) throw new Error("Failed to create wallet");
|
|
88961
|
+
log(`Wallet address: ${wallet.getAddress()}`);
|
|
88962
|
+
log(`Network: ${NETWORK}`);
|
|
88963
|
+
log(`Version: ${WALLET_VERSION}`);
|
|
90147
88964
|
return {
|
|
90148
|
-
server: createTonWalletMCP({
|
|
90149
|
-
|
|
90150
|
-
|
|
90151
|
-
|
|
90152
|
-
|
|
90153
|
-
|
|
88965
|
+
server: await createTonWalletMCP({
|
|
88966
|
+
wallet,
|
|
88967
|
+
networks: {
|
|
88968
|
+
mainnet: TONCENTER_API_KEY && NETWORK === "mainnet" ? { apiKey: TONCENTER_API_KEY } : void 0,
|
|
88969
|
+
testnet: TONCENTER_API_KEY && NETWORK === "testnet" ? { apiKey: TONCENTER_API_KEY } : void 0
|
|
88970
|
+
}
|
|
90154
88971
|
}),
|
|
90155
|
-
|
|
88972
|
+
kit,
|
|
88973
|
+
wallet
|
|
90156
88974
|
};
|
|
90157
88975
|
}
|
|
90158
88976
|
async function startStdio() {
|
|
90159
88977
|
log("Starting in stdio mode...");
|
|
90160
|
-
|
|
90161
|
-
const { server, signer } = createAdaptersAndServer();
|
|
88978
|
+
const { server, kit } = await createWalletAndServer();
|
|
90162
88979
|
const transport = new StdioServerTransport();
|
|
90163
88980
|
const shutdown = async () => {
|
|
90164
88981
|
log("Shutting down...");
|
|
90165
|
-
await
|
|
88982
|
+
await kit.close();
|
|
90166
88983
|
log("Shutdown complete");
|
|
90167
88984
|
process.exit(0);
|
|
90168
88985
|
};
|
|
@@ -90171,32 +88988,31 @@ async function startStdio() {
|
|
|
90171
88988
|
await server.connect(transport);
|
|
90172
88989
|
log("Server connected and ready to accept requests");
|
|
90173
88990
|
}
|
|
90174
|
-
async function startHttp(port) {
|
|
90175
|
-
log(`Starting in HTTP mode on
|
|
90176
|
-
|
|
90177
|
-
const { server, signer } = createAdaptersAndServer();
|
|
88991
|
+
async function startHttp(port, host) {
|
|
88992
|
+
log(`Starting in HTTP mode on ${host}:${port}...`);
|
|
88993
|
+
const { server, kit } = await createWalletAndServer();
|
|
90178
88994
|
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
|
|
90179
88995
|
await server.connect(transport);
|
|
90180
88996
|
const httpServer = createServer(async (req, res) => {
|
|
90181
|
-
if (new URL(req.url ?? "/", `http
|
|
88997
|
+
if (new URL(req.url ?? "/", `http://${host}:${port}`).pathname === "/mcp") await transport.handleRequest(req, res);
|
|
90182
88998
|
else res.writeHead(404).end("Not Found");
|
|
90183
88999
|
});
|
|
90184
89000
|
const shutdown = async () => {
|
|
90185
89001
|
log("Shutting down...");
|
|
90186
89002
|
httpServer.close();
|
|
90187
89003
|
await transport.close();
|
|
90188
|
-
await
|
|
89004
|
+
await kit.close();
|
|
90189
89005
|
log("Shutdown complete");
|
|
90190
89006
|
process.exit(0);
|
|
90191
89007
|
};
|
|
90192
89008
|
process.on("SIGINT", shutdown);
|
|
90193
89009
|
process.on("SIGTERM", shutdown);
|
|
90194
|
-
httpServer.listen(port, () => {
|
|
90195
|
-
log(`HTTP server listening on http
|
|
89010
|
+
httpServer.listen(port, host, () => {
|
|
89011
|
+
log(`HTTP server listening on http://${host}:${port}/mcp`);
|
|
90196
89012
|
});
|
|
90197
89013
|
}
|
|
90198
89014
|
const config = parseArgs();
|
|
90199
|
-
if (config.mode === "http") startHttp(config.port).catch((error) => {
|
|
89015
|
+
if (config.mode === "http") startHttp(config.port, config.host).catch((error) => {
|
|
90200
89016
|
console.error(`[${SERVER_NAME}] Fatal error:`, error);
|
|
90201
89017
|
process.exit(1);
|
|
90202
89018
|
});
|