@t402/mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1399 @@
1
+ // src/tools/getBalance.ts
2
+ import { z } from "zod";
3
+ import {
4
+ createPublicClient,
5
+ http,
6
+ formatEther,
7
+ formatUnits
8
+ } from "viem";
9
+ import * as chains from "viem/chains";
10
+
11
+ // src/constants.ts
12
+ var CHAIN_IDS = {
13
+ ethereum: 1,
14
+ base: 8453,
15
+ arbitrum: 42161,
16
+ optimism: 10,
17
+ polygon: 137,
18
+ avalanche: 43114,
19
+ ink: 57073,
20
+ berachain: 80094,
21
+ unichain: 130
22
+ };
23
+ var NATIVE_SYMBOLS = {
24
+ ethereum: "ETH",
25
+ base: "ETH",
26
+ arbitrum: "ETH",
27
+ optimism: "ETH",
28
+ polygon: "MATIC",
29
+ avalanche: "AVAX",
30
+ ink: "ETH",
31
+ berachain: "BERA",
32
+ unichain: "ETH"
33
+ };
34
+ var EXPLORER_URLS = {
35
+ ethereum: "https://etherscan.io",
36
+ base: "https://basescan.org",
37
+ arbitrum: "https://arbiscan.io",
38
+ optimism: "https://optimistic.etherscan.io",
39
+ polygon: "https://polygonscan.com",
40
+ avalanche: "https://snowtrace.io",
41
+ ink: "https://explorer.inkonchain.com",
42
+ berachain: "https://berascan.com",
43
+ unichain: "https://unichain.blockscout.com"
44
+ };
45
+ var DEFAULT_RPC_URLS = {
46
+ ethereum: "https://eth.llamarpc.com",
47
+ base: "https://mainnet.base.org",
48
+ arbitrum: "https://arb1.arbitrum.io/rpc",
49
+ optimism: "https://mainnet.optimism.io",
50
+ polygon: "https://polygon-rpc.com",
51
+ avalanche: "https://api.avax.network/ext/bc/C/rpc",
52
+ ink: "https://rpc-gel.inkonchain.com",
53
+ berachain: "https://rpc.berachain.com",
54
+ unichain: "https://mainnet.unichain.org"
55
+ };
56
+ var USDC_ADDRESSES = {
57
+ ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
58
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
59
+ arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
60
+ optimism: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
61
+ polygon: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
62
+ avalanche: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"
63
+ };
64
+ var USDT_ADDRESSES = {
65
+ ethereum: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
66
+ arbitrum: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
67
+ polygon: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
68
+ avalanche: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7",
69
+ optimism: "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58"
70
+ };
71
+ var USDT0_ADDRESSES = {
72
+ ethereum: "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee",
73
+ arbitrum: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
74
+ ink: "0x0200C29006150606B650577BBE7B6248F58470c1",
75
+ berachain: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
76
+ unichain: "0x588ce4F028D8e7B53B687865d6A67b3A54C75518"
77
+ };
78
+ var BRIDGEABLE_CHAINS = [
79
+ "ethereum",
80
+ "arbitrum",
81
+ "ink",
82
+ "berachain",
83
+ "unichain"
84
+ ];
85
+ var ERC20_ABI = [
86
+ {
87
+ name: "balanceOf",
88
+ type: "function",
89
+ stateMutability: "view",
90
+ inputs: [{ name: "account", type: "address" }],
91
+ outputs: [{ name: "", type: "uint256" }]
92
+ },
93
+ {
94
+ name: "decimals",
95
+ type: "function",
96
+ stateMutability: "view",
97
+ inputs: [],
98
+ outputs: [{ name: "", type: "uint8" }]
99
+ },
100
+ {
101
+ name: "symbol",
102
+ type: "function",
103
+ stateMutability: "view",
104
+ inputs: [],
105
+ outputs: [{ name: "", type: "string" }]
106
+ },
107
+ {
108
+ name: "transfer",
109
+ type: "function",
110
+ stateMutability: "nonpayable",
111
+ inputs: [
112
+ { name: "to", type: "address" },
113
+ { name: "amount", type: "uint256" }
114
+ ],
115
+ outputs: [{ name: "", type: "bool" }]
116
+ },
117
+ {
118
+ name: "approve",
119
+ type: "function",
120
+ stateMutability: "nonpayable",
121
+ inputs: [
122
+ { name: "spender", type: "address" },
123
+ { name: "amount", type: "uint256" }
124
+ ],
125
+ outputs: [{ name: "", type: "bool" }]
126
+ },
127
+ {
128
+ name: "allowance",
129
+ type: "function",
130
+ stateMutability: "view",
131
+ inputs: [
132
+ { name: "owner", type: "address" },
133
+ { name: "spender", type: "address" }
134
+ ],
135
+ outputs: [{ name: "", type: "uint256" }]
136
+ }
137
+ ];
138
+ function getExplorerTxUrl(network, txHash) {
139
+ return `${EXPLORER_URLS[network]}/tx/${txHash}`;
140
+ }
141
+ function getLayerZeroScanUrl(messageGuid) {
142
+ return `https://layerzeroscan.com/tx/${messageGuid}`;
143
+ }
144
+ function supportsToken(network, token) {
145
+ switch (token) {
146
+ case "USDC":
147
+ return network in USDC_ADDRESSES;
148
+ case "USDT":
149
+ return network in USDT_ADDRESSES;
150
+ case "USDT0":
151
+ return network in USDT0_ADDRESSES;
152
+ default:
153
+ return false;
154
+ }
155
+ }
156
+ function getTokenAddress(network, token) {
157
+ switch (token) {
158
+ case "USDC":
159
+ return USDC_ADDRESSES[network];
160
+ case "USDT":
161
+ return USDT_ADDRESSES[network];
162
+ case "USDT0":
163
+ return USDT0_ADDRESSES[network];
164
+ default:
165
+ return void 0;
166
+ }
167
+ }
168
+ function formatTokenAmount(amount, decimals, symbol) {
169
+ const divisor = BigInt(10 ** decimals);
170
+ const wholePart = amount / divisor;
171
+ const fractionalPart = amount % divisor;
172
+ const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
173
+ const trimmedFractional = fractionalStr.replace(/0+$/, "") || "0";
174
+ if (trimmedFractional === "0") {
175
+ return `${wholePart} ${symbol}`;
176
+ }
177
+ return `${wholePart}.${trimmedFractional} ${symbol}`;
178
+ }
179
+ function parseTokenAmount(amount, decimals) {
180
+ const [wholePart, fractionalPart = ""] = amount.split(".");
181
+ const paddedFractional = fractionalPart.padEnd(decimals, "0").slice(0, decimals);
182
+ return BigInt(wholePart + paddedFractional);
183
+ }
184
+
185
+ // src/tools/getBalance.ts
186
+ var getBalanceInputSchema = z.object({
187
+ network: z.enum([
188
+ "ethereum",
189
+ "base",
190
+ "arbitrum",
191
+ "optimism",
192
+ "polygon",
193
+ "avalanche",
194
+ "ink",
195
+ "berachain",
196
+ "unichain"
197
+ ]).describe("Blockchain network to check balance on"),
198
+ address: z.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Wallet address to check balance for")
199
+ });
200
+ function getViemChain(network) {
201
+ switch (network) {
202
+ case "ethereum":
203
+ return chains.mainnet;
204
+ case "base":
205
+ return chains.base;
206
+ case "arbitrum":
207
+ return chains.arbitrum;
208
+ case "optimism":
209
+ return chains.optimism;
210
+ case "polygon":
211
+ return chains.polygon;
212
+ case "avalanche":
213
+ return chains.avalanche;
214
+ case "ink":
215
+ return chains.ink;
216
+ case "berachain":
217
+ return chains.berachain;
218
+ case "unichain":
219
+ return chains.unichain;
220
+ default:
221
+ return chains.mainnet;
222
+ }
223
+ }
224
+ async function getTokenBalance(client, tokenAddress, walletAddress) {
225
+ try {
226
+ const [balance, decimals, symbol] = await Promise.all([
227
+ client.readContract({
228
+ address: tokenAddress,
229
+ abi: ERC20_ABI,
230
+ functionName: "balanceOf",
231
+ args: [walletAddress]
232
+ }),
233
+ client.readContract({
234
+ address: tokenAddress,
235
+ abi: ERC20_ABI,
236
+ functionName: "decimals"
237
+ }),
238
+ client.readContract({
239
+ address: tokenAddress,
240
+ abi: ERC20_ABI,
241
+ functionName: "symbol"
242
+ })
243
+ ]);
244
+ return {
245
+ symbol,
246
+ address: tokenAddress,
247
+ balance: balance.toString(),
248
+ formatted: formatUnits(balance, decimals),
249
+ decimals
250
+ };
251
+ } catch {
252
+ return null;
253
+ }
254
+ }
255
+ async function executeGetBalance(input, rpcUrls) {
256
+ const { network, address } = input;
257
+ const walletAddress = address;
258
+ const rpcUrl = rpcUrls?.[network] || DEFAULT_RPC_URLS[network];
259
+ const chain = getViemChain(network);
260
+ const client = createPublicClient({
261
+ chain,
262
+ transport: http(rpcUrl)
263
+ });
264
+ const nativeBalance = await client.getBalance({ address: walletAddress });
265
+ const tokenAddresses = [];
266
+ if (USDC_ADDRESSES[network]) {
267
+ tokenAddresses.push({ token: USDC_ADDRESSES[network], expected: "USDC" });
268
+ }
269
+ if (USDT_ADDRESSES[network]) {
270
+ tokenAddresses.push({ token: USDT_ADDRESSES[network], expected: "USDT" });
271
+ }
272
+ if (USDT0_ADDRESSES[network]) {
273
+ tokenAddresses.push({ token: USDT0_ADDRESSES[network], expected: "USDT0" });
274
+ }
275
+ const tokenBalances = await Promise.all(
276
+ tokenAddresses.map(
277
+ ({ token }) => getTokenBalance(client, token, walletAddress)
278
+ )
279
+ );
280
+ const tokens = tokenBalances.filter(
281
+ (t) => t !== null
282
+ );
283
+ return {
284
+ network,
285
+ chainId: CHAIN_IDS[network],
286
+ native: {
287
+ symbol: NATIVE_SYMBOLS[network],
288
+ balance: nativeBalance.toString(),
289
+ formatted: formatEther(nativeBalance)
290
+ },
291
+ tokens
292
+ };
293
+ }
294
+ function formatBalanceResult(balance) {
295
+ const lines = [
296
+ `## Balance on ${balance.network} (Chain ID: ${balance.chainId})`,
297
+ "",
298
+ `### Native Token`,
299
+ `- ${balance.native.symbol}: ${balance.native.formatted}`,
300
+ ""
301
+ ];
302
+ if (balance.tokens.length > 0) {
303
+ lines.push("### Stablecoins");
304
+ for (const token of balance.tokens) {
305
+ lines.push(`- ${token.symbol}: ${token.formatted}`);
306
+ }
307
+ } else {
308
+ lines.push("_No stablecoin balances found_");
309
+ }
310
+ return lines.join("\n");
311
+ }
312
+
313
+ // src/tools/getAllBalances.ts
314
+ import { z as z2 } from "zod";
315
+ var getAllBalancesInputSchema = z2.object({
316
+ address: z2.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Wallet address to check balances for"),
317
+ networks: z2.array(
318
+ z2.enum([
319
+ "ethereum",
320
+ "base",
321
+ "arbitrum",
322
+ "optimism",
323
+ "polygon",
324
+ "avalanche",
325
+ "ink",
326
+ "berachain",
327
+ "unichain"
328
+ ])
329
+ ).optional().describe(
330
+ "Optional list of networks to check. If not provided, checks all supported networks."
331
+ )
332
+ });
333
+ var ALL_NETWORKS = [
334
+ "ethereum",
335
+ "base",
336
+ "arbitrum",
337
+ "optimism",
338
+ "polygon",
339
+ "avalanche",
340
+ "ink",
341
+ "berachain",
342
+ "unichain"
343
+ ];
344
+ async function executeGetAllBalances(input, rpcUrls) {
345
+ const { address, networks = ALL_NETWORKS } = input;
346
+ const balancePromises = networks.map(
347
+ (network) => executeGetBalance({ network, address }, rpcUrls).catch((error) => {
348
+ console.error(`Failed to fetch balance for ${network}:`, error);
349
+ return null;
350
+ })
351
+ );
352
+ const results = await Promise.all(balancePromises);
353
+ const balances = results.filter((b) => b !== null);
354
+ let totalUsdc = 0n;
355
+ let totalUsdt = 0n;
356
+ for (const balance of balances) {
357
+ for (const token of balance.tokens) {
358
+ if (token.symbol === "USDC") {
359
+ totalUsdc += BigInt(token.balance);
360
+ } else if (token.symbol === "USDT" || token.symbol === "USDT0") {
361
+ totalUsdt += BigInt(token.balance);
362
+ }
363
+ }
364
+ }
365
+ const formatTotal = (amount) => {
366
+ const divisor = BigInt(10 ** 6);
367
+ const whole = amount / divisor;
368
+ const fraction = amount % divisor;
369
+ const fractionStr = fraction.toString().padStart(6, "0").replace(/0+$/, "");
370
+ return fractionStr ? `${whole}.${fractionStr}` : whole.toString();
371
+ };
372
+ const totalUsdcFormatted = formatTotal(totalUsdc);
373
+ const totalUsdtFormatted = formatTotal(totalUsdt);
374
+ const chainsWithBalance = balances.filter(
375
+ (b) => b.tokens.some((t) => BigInt(t.balance) > 0n) || BigInt(b.native.balance) > 0n
376
+ );
377
+ const summary = [
378
+ `Found balances on ${chainsWithBalance.length} of ${balances.length} networks checked.`,
379
+ `Total USDC: ${totalUsdcFormatted}`,
380
+ `Total USDT: ${totalUsdtFormatted}`
381
+ ].join(" ");
382
+ return {
383
+ address,
384
+ balances,
385
+ totalUsdcBalance: totalUsdcFormatted,
386
+ totalUsdtBalance: totalUsdtFormatted,
387
+ summary
388
+ };
389
+ }
390
+ function formatAllBalancesResult(result) {
391
+ const lines = [
392
+ `## Multi-Chain Balance Summary`,
393
+ `**Address:** \`${result.address}\``,
394
+ "",
395
+ `### Totals`,
396
+ `- **Total USDC:** ${result.totalUsdcBalance}`,
397
+ `- **Total USDT:** ${result.totalUsdtBalance}`,
398
+ "",
399
+ `### By Network`,
400
+ ""
401
+ ];
402
+ for (const balance of result.balances) {
403
+ const hasBalance = balance.tokens.some((t) => BigInt(t.balance) > 0n) || BigInt(balance.native.balance) > 0n;
404
+ if (!hasBalance) continue;
405
+ lines.push(`#### ${balance.network}`);
406
+ lines.push(`- ${balance.native.symbol}: ${balance.native.formatted}`);
407
+ for (const token of balance.tokens) {
408
+ if (BigInt(token.balance) > 0n) {
409
+ lines.push(`- ${token.symbol}: ${token.formatted}`);
410
+ }
411
+ }
412
+ lines.push("");
413
+ }
414
+ const emptyNetworks = result.balances.filter(
415
+ (b) => !b.tokens.some((t) => BigInt(t.balance) > 0n) && BigInt(b.native.balance) === 0n
416
+ );
417
+ if (emptyNetworks.length > 0) {
418
+ lines.push(`_No balance on: ${emptyNetworks.map((n) => n.network).join(", ")}_`);
419
+ }
420
+ return lines.join("\n");
421
+ }
422
+
423
+ // src/tools/pay.ts
424
+ import { z as z3 } from "zod";
425
+ import {
426
+ createPublicClient as createPublicClient2,
427
+ createWalletClient,
428
+ http as http2,
429
+ parseUnits
430
+ } from "viem";
431
+ import { privateKeyToAccount } from "viem/accounts";
432
+ import * as chains2 from "viem/chains";
433
+ var payInputSchema = z3.object({
434
+ to: z3.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Recipient address"),
435
+ amount: z3.string().regex(/^\d+(\.\d+)?$/).describe("Amount to pay (e.g., '10.50' for 10.50 USDC)"),
436
+ token: z3.enum(["USDC", "USDT", "USDT0"]).describe("Token to use for payment"),
437
+ network: z3.enum([
438
+ "ethereum",
439
+ "base",
440
+ "arbitrum",
441
+ "optimism",
442
+ "polygon",
443
+ "avalanche",
444
+ "ink",
445
+ "berachain",
446
+ "unichain"
447
+ ]).describe("Network to execute payment on"),
448
+ memo: z3.string().optional().describe("Optional memo/reference for the payment")
449
+ });
450
+ function getViemChain2(network) {
451
+ switch (network) {
452
+ case "ethereum":
453
+ return chains2.mainnet;
454
+ case "base":
455
+ return chains2.base;
456
+ case "arbitrum":
457
+ return chains2.arbitrum;
458
+ case "optimism":
459
+ return chains2.optimism;
460
+ case "polygon":
461
+ return chains2.polygon;
462
+ case "avalanche":
463
+ return chains2.avalanche;
464
+ case "ink":
465
+ return chains2.ink;
466
+ case "berachain":
467
+ return chains2.berachain;
468
+ case "unichain":
469
+ return chains2.unichain;
470
+ default:
471
+ return chains2.mainnet;
472
+ }
473
+ }
474
+ async function executePay(input, options) {
475
+ const { to, amount, token, network, memo } = input;
476
+ const { privateKey, rpcUrl, demoMode } = options;
477
+ if (!supportsToken(network, token)) {
478
+ throw new Error(`Token ${token} is not supported on ${network}`);
479
+ }
480
+ const tokenAddress = getTokenAddress(network, token);
481
+ if (!tokenAddress) {
482
+ throw new Error(`Could not find ${token} address for ${network}`);
483
+ }
484
+ const decimals = 6;
485
+ const amountBigInt = parseUnits(amount, decimals);
486
+ if (demoMode) {
487
+ const fakeTxHash = `0x${"0".repeat(64)}`;
488
+ return {
489
+ txHash: fakeTxHash,
490
+ network,
491
+ amount,
492
+ token,
493
+ to,
494
+ explorerUrl: getExplorerTxUrl(network, fakeTxHash)
495
+ };
496
+ }
497
+ const chain = getViemChain2(network);
498
+ const transport = http2(rpcUrl || DEFAULT_RPC_URLS[network]);
499
+ const account = privateKeyToAccount(privateKey);
500
+ const publicClient = createPublicClient2({
501
+ chain,
502
+ transport
503
+ });
504
+ const walletClient = createWalletClient({
505
+ account,
506
+ chain,
507
+ transport
508
+ });
509
+ const balance = await publicClient.readContract({
510
+ address: tokenAddress,
511
+ abi: ERC20_ABI,
512
+ functionName: "balanceOf",
513
+ args: [account.address]
514
+ });
515
+ if (balance < amountBigInt) {
516
+ throw new Error(
517
+ `Insufficient ${token} balance. Have: ${balance.toString()}, Need: ${amountBigInt.toString()}`
518
+ );
519
+ }
520
+ const hash = await walletClient.writeContract({
521
+ address: tokenAddress,
522
+ abi: ERC20_ABI,
523
+ functionName: "transfer",
524
+ args: [to, amountBigInt]
525
+ });
526
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
527
+ if (receipt.status !== "success") {
528
+ throw new Error(`Transaction failed: ${hash}`);
529
+ }
530
+ return {
531
+ txHash: hash,
532
+ network,
533
+ amount,
534
+ token,
535
+ to,
536
+ explorerUrl: getExplorerTxUrl(network, hash)
537
+ };
538
+ }
539
+ function formatPaymentResult(result) {
540
+ return [
541
+ `## Payment Successful`,
542
+ "",
543
+ `- **Amount:** ${result.amount} ${result.token}`,
544
+ `- **To:** \`${result.to}\``,
545
+ `- **Network:** ${result.network}`,
546
+ `- **Transaction:** \`${result.txHash}\``,
547
+ "",
548
+ `[View on Explorer](${result.explorerUrl})`
549
+ ].join("\n");
550
+ }
551
+
552
+ // src/tools/payGasless.ts
553
+ import { z as z4 } from "zod";
554
+ import {
555
+ createPublicClient as createPublicClient3,
556
+ http as http3,
557
+ parseUnits as parseUnits2,
558
+ encodeFunctionData
559
+ } from "viem";
560
+ import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
561
+ import * as chains3 from "viem/chains";
562
+ var payGaslessInputSchema = z4.object({
563
+ to: z4.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Recipient address"),
564
+ amount: z4.string().regex(/^\d+(\.\d+)?$/).describe("Amount to pay (e.g., '10.50' for 10.50 USDC)"),
565
+ token: z4.enum(["USDC", "USDT", "USDT0"]).describe("Token to use for payment"),
566
+ network: z4.enum([
567
+ "ethereum",
568
+ "base",
569
+ "arbitrum",
570
+ "optimism",
571
+ "polygon",
572
+ "avalanche"
573
+ ]).describe("Network to execute gasless payment on (must support ERC-4337)")
574
+ });
575
+ var GASLESS_SUPPORTED_NETWORKS = [
576
+ "ethereum",
577
+ "base",
578
+ "arbitrum",
579
+ "optimism",
580
+ "polygon",
581
+ "avalanche"
582
+ ];
583
+ function getViemChain3(network) {
584
+ switch (network) {
585
+ case "ethereum":
586
+ return chains3.mainnet;
587
+ case "base":
588
+ return chains3.base;
589
+ case "arbitrum":
590
+ return chains3.arbitrum;
591
+ case "optimism":
592
+ return chains3.optimism;
593
+ case "polygon":
594
+ return chains3.polygon;
595
+ case "avalanche":
596
+ return chains3.avalanche;
597
+ case "ink":
598
+ return chains3.ink;
599
+ case "berachain":
600
+ return chains3.berachain;
601
+ case "unichain":
602
+ return chains3.unichain;
603
+ default:
604
+ return chains3.mainnet;
605
+ }
606
+ }
607
+ async function executePayGasless(input, options) {
608
+ const { to, amount, token, network } = input;
609
+ const { privateKey, bundlerUrl, paymasterUrl, rpcUrl, demoMode } = options;
610
+ if (!GASLESS_SUPPORTED_NETWORKS.includes(network)) {
611
+ throw new Error(
612
+ `Network ${network} does not support ERC-4337 gasless transactions. Supported: ${GASLESS_SUPPORTED_NETWORKS.join(", ")}`
613
+ );
614
+ }
615
+ if (!supportsToken(network, token)) {
616
+ throw new Error(`Token ${token} is not supported on ${network}`);
617
+ }
618
+ const tokenAddress = getTokenAddress(network, token);
619
+ if (!tokenAddress) {
620
+ throw new Error(`Could not find ${token} address for ${network}`);
621
+ }
622
+ const decimals = 6;
623
+ const amountBigInt = parseUnits2(amount, decimals);
624
+ if (demoMode) {
625
+ const fakeTxHash = `0x${"1".repeat(64)}`;
626
+ const fakeUserOpHash = `0x${"2".repeat(64)}`;
627
+ return {
628
+ txHash: fakeTxHash,
629
+ userOpHash: fakeUserOpHash,
630
+ network,
631
+ amount,
632
+ token,
633
+ to,
634
+ explorerUrl: getExplorerTxUrl(network, fakeTxHash),
635
+ paymaster: "demo-paymaster"
636
+ };
637
+ }
638
+ const chain = getViemChain3(network);
639
+ const transport = http3(rpcUrl || DEFAULT_RPC_URLS[network]);
640
+ const account = privateKeyToAccount2(privateKey);
641
+ const publicClient = createPublicClient3({
642
+ chain,
643
+ transport
644
+ });
645
+ const callData = encodeFunctionData({
646
+ abi: ERC20_ABI,
647
+ functionName: "transfer",
648
+ args: [to, amountBigInt]
649
+ });
650
+ const nonce = await publicClient.getTransactionCount({
651
+ address: account.address
652
+ });
653
+ const gasPrice = await publicClient.getGasPrice();
654
+ const userOp = {
655
+ sender: account.address,
656
+ nonce: BigInt(nonce),
657
+ initCode: "0x",
658
+ callData,
659
+ callGasLimit: 100000n,
660
+ verificationGasLimit: 100000n,
661
+ preVerificationGas: 50000n,
662
+ maxFeePerGas: gasPrice,
663
+ maxPriorityFeePerGas: gasPrice / 10n,
664
+ paymasterAndData: "0x",
665
+ // Would be filled by paymaster
666
+ signature: "0x"
667
+ };
668
+ const response = await fetch(bundlerUrl, {
669
+ method: "POST",
670
+ headers: { "Content-Type": "application/json" },
671
+ body: JSON.stringify({
672
+ jsonrpc: "2.0",
673
+ id: 1,
674
+ method: "eth_sendUserOperation",
675
+ params: [userOp, chain.id]
676
+ })
677
+ });
678
+ if (!response.ok) {
679
+ throw new Error(`Bundler request failed: ${response.statusText}`);
680
+ }
681
+ const result = await response.json();
682
+ if (result.error) {
683
+ throw new Error(`Bundler error: ${result.error.message}`);
684
+ }
685
+ const userOpHash = result.result;
686
+ let receipt = null;
687
+ for (let i = 0; i < 30; i++) {
688
+ const receiptResponse = await fetch(bundlerUrl, {
689
+ method: "POST",
690
+ headers: { "Content-Type": "application/json" },
691
+ body: JSON.stringify({
692
+ jsonrpc: "2.0",
693
+ id: 1,
694
+ method: "eth_getUserOperationReceipt",
695
+ params: [userOpHash]
696
+ })
697
+ });
698
+ const receiptResult = await receiptResponse.json();
699
+ if (receiptResult.result) {
700
+ receipt = receiptResult.result;
701
+ break;
702
+ }
703
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
704
+ }
705
+ if (!receipt) {
706
+ throw new Error("Timeout waiting for user operation receipt");
707
+ }
708
+ return {
709
+ txHash: receipt.transactionHash,
710
+ userOpHash,
711
+ network,
712
+ amount,
713
+ token,
714
+ to,
715
+ explorerUrl: getExplorerTxUrl(network, receipt.transactionHash)
716
+ };
717
+ }
718
+ function formatGaslessPaymentResult(result) {
719
+ const lines = [
720
+ `## Gasless Payment Successful`,
721
+ "",
722
+ `- **Amount:** ${result.amount} ${result.token}`,
723
+ `- **To:** \`${result.to}\``,
724
+ `- **Network:** ${result.network}`,
725
+ `- **Transaction:** \`${result.txHash}\``,
726
+ `- **UserOp Hash:** \`${result.userOpHash}\``
727
+ ];
728
+ if (result.paymaster) {
729
+ lines.push(`- **Paymaster:** ${result.paymaster}`);
730
+ }
731
+ lines.push("");
732
+ lines.push(`[View on Explorer](${result.explorerUrl})`);
733
+ lines.push("");
734
+ lines.push("_Gas fees were sponsored - no ETH was deducted from your wallet._");
735
+ return lines.join("\n");
736
+ }
737
+
738
+ // src/tools/getBridgeFee.ts
739
+ import { z as z5 } from "zod";
740
+ import {
741
+ createPublicClient as createPublicClient4,
742
+ http as http4,
743
+ formatEther as formatEther2
744
+ } from "viem";
745
+ import * as chains4 from "viem/chains";
746
+ var getBridgeFeeInputSchema = z5.object({
747
+ fromChain: z5.enum(["ethereum", "arbitrum", "ink", "berachain", "unichain"]).describe("Source chain to bridge from"),
748
+ toChain: z5.enum(["ethereum", "arbitrum", "ink", "berachain", "unichain"]).describe("Destination chain to bridge to"),
749
+ amount: z5.string().regex(/^\d+(\.\d+)?$/).describe("Amount of USDT0 to bridge (e.g., '100' for 100 USDT0)"),
750
+ recipient: z5.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Recipient address on destination chain")
751
+ });
752
+ var LAYERZERO_ENDPOINT_IDS = {
753
+ ethereum: 30101,
754
+ arbitrum: 30110,
755
+ ink: 30291,
756
+ berachain: 30362,
757
+ unichain: 30320
758
+ };
759
+ var ESTIMATED_BRIDGE_TIMES = {
760
+ ethereum: 900,
761
+ // 15 minutes
762
+ arbitrum: 300,
763
+ // 5 minutes
764
+ ink: 300,
765
+ // 5 minutes
766
+ berachain: 300,
767
+ // 5 minutes
768
+ unichain: 300
769
+ // 5 minutes
770
+ };
771
+ var OFT_ABI = [
772
+ {
773
+ name: "quoteSend",
774
+ type: "function",
775
+ stateMutability: "view",
776
+ inputs: [
777
+ {
778
+ name: "_sendParam",
779
+ type: "tuple",
780
+ components: [
781
+ { name: "dstEid", type: "uint32" },
782
+ { name: "to", type: "bytes32" },
783
+ { name: "amountLD", type: "uint256" },
784
+ { name: "minAmountLD", type: "uint256" },
785
+ { name: "extraOptions", type: "bytes" },
786
+ { name: "composeMsg", type: "bytes" },
787
+ { name: "oftCmd", type: "bytes" }
788
+ ]
789
+ },
790
+ { name: "_payInLzToken", type: "bool" }
791
+ ],
792
+ outputs: [
793
+ {
794
+ name: "msgFee",
795
+ type: "tuple",
796
+ components: [
797
+ { name: "nativeFee", type: "uint256" },
798
+ { name: "lzTokenFee", type: "uint256" }
799
+ ]
800
+ }
801
+ ]
802
+ }
803
+ ];
804
+ function getViemChain4(network) {
805
+ switch (network) {
806
+ case "ethereum":
807
+ return chains4.mainnet;
808
+ case "arbitrum":
809
+ return chains4.arbitrum;
810
+ case "ink":
811
+ return chains4.ink;
812
+ case "berachain":
813
+ return chains4.berachain;
814
+ case "unichain":
815
+ return chains4.unichain;
816
+ default:
817
+ return void 0;
818
+ }
819
+ }
820
+ function addressToBytes32(address) {
821
+ return `0x${address.slice(2).padStart(64, "0")}`;
822
+ }
823
+ async function executeGetBridgeFee(input, rpcUrls) {
824
+ const { fromChain, toChain, amount, recipient } = input;
825
+ if (fromChain === toChain) {
826
+ throw new Error("Source and destination chains must be different");
827
+ }
828
+ if (!BRIDGEABLE_CHAINS.includes(fromChain)) {
829
+ throw new Error(`Chain ${fromChain} does not support USDT0 bridging`);
830
+ }
831
+ if (!BRIDGEABLE_CHAINS.includes(toChain)) {
832
+ throw new Error(`Chain ${toChain} does not support USDT0 bridging`);
833
+ }
834
+ const usdt0Address = USDT0_ADDRESSES[fromChain];
835
+ if (!usdt0Address) {
836
+ throw new Error(`USDT0 not found on ${fromChain}`);
837
+ }
838
+ const amountBigInt = parseTokenAmount(amount, 6);
839
+ const chain = getViemChain4(fromChain);
840
+ if (!chain) {
841
+ throw new Error(`Unsupported chain: ${fromChain}`);
842
+ }
843
+ const rpcUrl = rpcUrls?.[fromChain] || DEFAULT_RPC_URLS[fromChain];
844
+ const client = createPublicClient4({
845
+ chain,
846
+ transport: http4(rpcUrl)
847
+ });
848
+ const dstEid = LAYERZERO_ENDPOINT_IDS[toChain];
849
+ const sendParam = {
850
+ dstEid,
851
+ to: addressToBytes32(recipient),
852
+ amountLD: amountBigInt,
853
+ minAmountLD: amountBigInt,
854
+ // No slippage for quote
855
+ extraOptions: "0x",
856
+ composeMsg: "0x",
857
+ oftCmd: "0x"
858
+ };
859
+ const quote = await client.readContract({
860
+ address: usdt0Address,
861
+ abi: OFT_ABI,
862
+ functionName: "quoteSend",
863
+ args: [sendParam, false]
864
+ });
865
+ const nativeSymbol = NATIVE_SYMBOLS[fromChain];
866
+ const estimatedTime = ESTIMATED_BRIDGE_TIMES[toChain] || 300;
867
+ return {
868
+ fromChain,
869
+ toChain,
870
+ amount,
871
+ nativeFee: quote.nativeFee.toString(),
872
+ nativeFeeFormatted: `${formatEther2(quote.nativeFee)} ${nativeSymbol}`,
873
+ estimatedTime
874
+ };
875
+ }
876
+ function formatBridgeFeeResult(result) {
877
+ const minutes = Math.ceil(result.estimatedTime / 60);
878
+ return [
879
+ `## Bridge Fee Quote`,
880
+ "",
881
+ `- **Route:** ${result.fromChain} \u2192 ${result.toChain}`,
882
+ `- **Amount:** ${result.amount} USDT0`,
883
+ `- **Native Fee:** ${result.nativeFeeFormatted}`,
884
+ `- **Estimated Time:** ~${minutes} minutes`,
885
+ "",
886
+ "_Note: Actual fees may vary slightly at execution time._"
887
+ ].join("\n");
888
+ }
889
+
890
+ // src/tools/bridge.ts
891
+ import { z as z6 } from "zod";
892
+ import {
893
+ createPublicClient as createPublicClient5,
894
+ createWalletClient as createWalletClient2,
895
+ http as http5,
896
+ keccak256,
897
+ toBytes
898
+ } from "viem";
899
+ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
900
+ import * as chains5 from "viem/chains";
901
+ var bridgeInputSchema = z6.object({
902
+ fromChain: z6.enum(["ethereum", "arbitrum", "ink", "berachain", "unichain"]).describe("Source chain to bridge from"),
903
+ toChain: z6.enum(["ethereum", "arbitrum", "ink", "berachain", "unichain"]).describe("Destination chain to bridge to"),
904
+ amount: z6.string().regex(/^\d+(\.\d+)?$/).describe("Amount of USDT0 to bridge (e.g., '100' for 100 USDT0)"),
905
+ recipient: z6.string().regex(/^0x[a-fA-F0-9]{40}$/).describe("Recipient address on destination chain")
906
+ });
907
+ var LAYERZERO_ENDPOINT_IDS2 = {
908
+ ethereum: 30101,
909
+ arbitrum: 30110,
910
+ ink: 30291,
911
+ berachain: 30362,
912
+ unichain: 30320
913
+ };
914
+ var ESTIMATED_BRIDGE_TIMES2 = {
915
+ ethereum: 900,
916
+ arbitrum: 300,
917
+ ink: 300,
918
+ berachain: 300,
919
+ unichain: 300
920
+ };
921
+ var OFT_ABI2 = [
922
+ {
923
+ name: "quoteSend",
924
+ type: "function",
925
+ stateMutability: "view",
926
+ inputs: [
927
+ {
928
+ name: "_sendParam",
929
+ type: "tuple",
930
+ components: [
931
+ { name: "dstEid", type: "uint32" },
932
+ { name: "to", type: "bytes32" },
933
+ { name: "amountLD", type: "uint256" },
934
+ { name: "minAmountLD", type: "uint256" },
935
+ { name: "extraOptions", type: "bytes" },
936
+ { name: "composeMsg", type: "bytes" },
937
+ { name: "oftCmd", type: "bytes" }
938
+ ]
939
+ },
940
+ { name: "_payInLzToken", type: "bool" }
941
+ ],
942
+ outputs: [
943
+ {
944
+ name: "msgFee",
945
+ type: "tuple",
946
+ components: [
947
+ { name: "nativeFee", type: "uint256" },
948
+ { name: "lzTokenFee", type: "uint256" }
949
+ ]
950
+ }
951
+ ]
952
+ },
953
+ {
954
+ name: "send",
955
+ type: "function",
956
+ stateMutability: "payable",
957
+ inputs: [
958
+ {
959
+ name: "_sendParam",
960
+ type: "tuple",
961
+ components: [
962
+ { name: "dstEid", type: "uint32" },
963
+ { name: "to", type: "bytes32" },
964
+ { name: "amountLD", type: "uint256" },
965
+ { name: "minAmountLD", type: "uint256" },
966
+ { name: "extraOptions", type: "bytes" },
967
+ { name: "composeMsg", type: "bytes" },
968
+ { name: "oftCmd", type: "bytes" }
969
+ ]
970
+ },
971
+ {
972
+ name: "_fee",
973
+ type: "tuple",
974
+ components: [
975
+ { name: "nativeFee", type: "uint256" },
976
+ { name: "lzTokenFee", type: "uint256" }
977
+ ]
978
+ },
979
+ { name: "_refundAddress", type: "address" }
980
+ ],
981
+ outputs: [
982
+ {
983
+ name: "msgReceipt",
984
+ type: "tuple",
985
+ components: [
986
+ { name: "guid", type: "bytes32" },
987
+ { name: "nonce", type: "uint64" },
988
+ {
989
+ name: "fee",
990
+ type: "tuple",
991
+ components: [
992
+ { name: "nativeFee", type: "uint256" },
993
+ { name: "lzTokenFee", type: "uint256" }
994
+ ]
995
+ }
996
+ ]
997
+ },
998
+ {
999
+ name: "oftReceipt",
1000
+ type: "tuple",
1001
+ components: [
1002
+ { name: "amountSentLD", type: "uint256" },
1003
+ { name: "amountReceivedLD", type: "uint256" }
1004
+ ]
1005
+ }
1006
+ ]
1007
+ }
1008
+ ];
1009
+ var OFT_SENT_EVENT_TOPIC = keccak256(
1010
+ toBytes("OFTSent(bytes32,uint32,address,uint256,uint256)")
1011
+ );
1012
+ function getViemChain5(network) {
1013
+ switch (network) {
1014
+ case "ethereum":
1015
+ return chains5.mainnet;
1016
+ case "arbitrum":
1017
+ return chains5.arbitrum;
1018
+ case "ink":
1019
+ return chains5.ink;
1020
+ case "berachain":
1021
+ return chains5.berachain;
1022
+ case "unichain":
1023
+ return chains5.unichain;
1024
+ default:
1025
+ return void 0;
1026
+ }
1027
+ }
1028
+ function addressToBytes322(address) {
1029
+ return `0x${address.slice(2).padStart(64, "0")}`;
1030
+ }
1031
+ async function executeBridge(input, options) {
1032
+ const { fromChain, toChain, amount, recipient } = input;
1033
+ const { privateKey, rpcUrl, demoMode, slippageTolerance = 0.5 } = options;
1034
+ if (fromChain === toChain) {
1035
+ throw new Error("Source and destination chains must be different");
1036
+ }
1037
+ if (!BRIDGEABLE_CHAINS.includes(fromChain)) {
1038
+ throw new Error(`Chain ${fromChain} does not support USDT0 bridging`);
1039
+ }
1040
+ if (!BRIDGEABLE_CHAINS.includes(toChain)) {
1041
+ throw new Error(`Chain ${toChain} does not support USDT0 bridging`);
1042
+ }
1043
+ const usdt0Address = USDT0_ADDRESSES[fromChain];
1044
+ if (!usdt0Address) {
1045
+ throw new Error(`USDT0 not found on ${fromChain}`);
1046
+ }
1047
+ const amountBigInt = parseTokenAmount(amount, 6);
1048
+ const slippageMultiplier = BigInt(Math.floor((100 - slippageTolerance) * 100));
1049
+ const minAmountBigInt = amountBigInt * slippageMultiplier / 10000n;
1050
+ if (demoMode) {
1051
+ const fakeTxHash = `0x${"a".repeat(64)}`;
1052
+ const fakeGuid = `0x${"b".repeat(64)}`;
1053
+ const estimatedTime2 = ESTIMATED_BRIDGE_TIMES2[toChain] || 300;
1054
+ return {
1055
+ txHash: fakeTxHash,
1056
+ messageGuid: fakeGuid,
1057
+ amount,
1058
+ fromChain,
1059
+ toChain,
1060
+ estimatedTime: estimatedTime2,
1061
+ trackingUrl: getLayerZeroScanUrl(fakeGuid)
1062
+ };
1063
+ }
1064
+ const chain = getViemChain5(fromChain);
1065
+ if (!chain) {
1066
+ throw new Error(`Unsupported chain: ${fromChain}`);
1067
+ }
1068
+ const transport = http5(rpcUrl || DEFAULT_RPC_URLS[fromChain]);
1069
+ const account = privateKeyToAccount3(privateKey);
1070
+ const publicClient = createPublicClient5({
1071
+ chain,
1072
+ transport
1073
+ });
1074
+ const walletClient = createWalletClient2({
1075
+ account,
1076
+ chain,
1077
+ transport
1078
+ });
1079
+ const balance = await publicClient.readContract({
1080
+ address: usdt0Address,
1081
+ abi: ERC20_ABI,
1082
+ functionName: "balanceOf",
1083
+ args: [account.address]
1084
+ });
1085
+ if (balance < amountBigInt) {
1086
+ throw new Error(
1087
+ `Insufficient USDT0 balance. Have: ${balance.toString()}, Need: ${amountBigInt.toString()}`
1088
+ );
1089
+ }
1090
+ const dstEid = LAYERZERO_ENDPOINT_IDS2[toChain];
1091
+ const sendParam = {
1092
+ dstEid,
1093
+ to: addressToBytes322(recipient),
1094
+ amountLD: amountBigInt,
1095
+ minAmountLD: minAmountBigInt,
1096
+ extraOptions: "0x",
1097
+ composeMsg: "0x",
1098
+ oftCmd: "0x"
1099
+ };
1100
+ const quote = await publicClient.readContract({
1101
+ address: usdt0Address,
1102
+ abi: OFT_ABI2,
1103
+ functionName: "quoteSend",
1104
+ args: [sendParam, false]
1105
+ });
1106
+ const nativeFeeWithBuffer = quote.nativeFee * 110n / 100n;
1107
+ const hash = await walletClient.writeContract({
1108
+ address: usdt0Address,
1109
+ abi: OFT_ABI2,
1110
+ functionName: "send",
1111
+ args: [
1112
+ sendParam,
1113
+ { nativeFee: nativeFeeWithBuffer, lzTokenFee: 0n },
1114
+ account.address
1115
+ ],
1116
+ value: nativeFeeWithBuffer
1117
+ });
1118
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
1119
+ if (receipt.status !== "success") {
1120
+ throw new Error(`Bridge transaction failed: ${hash}`);
1121
+ }
1122
+ let messageGuid = "0x";
1123
+ for (const log of receipt.logs) {
1124
+ if (log.topics[0] === OFT_SENT_EVENT_TOPIC && log.topics[1]) {
1125
+ messageGuid = log.topics[1];
1126
+ break;
1127
+ }
1128
+ }
1129
+ if (messageGuid === "0x") {
1130
+ throw new Error("Failed to extract message GUID from transaction logs");
1131
+ }
1132
+ const estimatedTime = ESTIMATED_BRIDGE_TIMES2[toChain] || 300;
1133
+ return {
1134
+ txHash: hash,
1135
+ messageGuid,
1136
+ amount,
1137
+ fromChain,
1138
+ toChain,
1139
+ estimatedTime,
1140
+ trackingUrl: getLayerZeroScanUrl(messageGuid)
1141
+ };
1142
+ }
1143
+ function formatBridgeResult(result) {
1144
+ const minutes = Math.ceil(result.estimatedTime / 60);
1145
+ return [
1146
+ `## Bridge Transaction Submitted`,
1147
+ "",
1148
+ `- **Route:** ${result.fromChain} \u2192 ${result.toChain}`,
1149
+ `- **Amount:** ${result.amount} USDT0`,
1150
+ `- **Transaction:** \`${result.txHash}\``,
1151
+ `- **Message GUID:** \`${result.messageGuid}\``,
1152
+ `- **Estimated Delivery:** ~${minutes} minutes`,
1153
+ "",
1154
+ `### Tracking`,
1155
+ `- [View on LayerZero Scan](${result.trackingUrl})`,
1156
+ `- [View Source TX](${getExplorerTxUrl(result.fromChain, result.txHash)})`,
1157
+ "",
1158
+ "_Your USDT0 will arrive on ${result.toChain} once the LayerZero message is delivered._"
1159
+ ].join("\n");
1160
+ }
1161
+
1162
+ // src/tools/index.ts
1163
+ var TOOL_DEFINITIONS = {
1164
+ "t402/getBalance": {
1165
+ name: "t402/getBalance",
1166
+ description: "Get token balances (native + stablecoins) for a wallet on a specific blockchain network. Returns ETH/native token balance plus USDC, USDT, and USDT0 balances where supported.",
1167
+ inputSchema: {
1168
+ type: "object",
1169
+ properties: {
1170
+ network: {
1171
+ type: "string",
1172
+ enum: [
1173
+ "ethereum",
1174
+ "base",
1175
+ "arbitrum",
1176
+ "optimism",
1177
+ "polygon",
1178
+ "avalanche",
1179
+ "ink",
1180
+ "berachain",
1181
+ "unichain"
1182
+ ],
1183
+ description: "Blockchain network to check balance on"
1184
+ },
1185
+ address: {
1186
+ type: "string",
1187
+ pattern: "^0x[a-fA-F0-9]{40}$",
1188
+ description: "Wallet address to check balance for"
1189
+ }
1190
+ },
1191
+ required: ["network", "address"]
1192
+ }
1193
+ },
1194
+ "t402/getAllBalances": {
1195
+ name: "t402/getAllBalances",
1196
+ description: "Get token balances across all supported networks for a wallet. Returns aggregated totals and per-network breakdown of native tokens and stablecoins (USDC, USDT, USDT0).",
1197
+ inputSchema: {
1198
+ type: "object",
1199
+ properties: {
1200
+ address: {
1201
+ type: "string",
1202
+ pattern: "^0x[a-fA-F0-9]{40}$",
1203
+ description: "Wallet address to check balances for"
1204
+ },
1205
+ networks: {
1206
+ type: "array",
1207
+ items: {
1208
+ type: "string",
1209
+ enum: [
1210
+ "ethereum",
1211
+ "base",
1212
+ "arbitrum",
1213
+ "optimism",
1214
+ "polygon",
1215
+ "avalanche",
1216
+ "ink",
1217
+ "berachain",
1218
+ "unichain"
1219
+ ]
1220
+ },
1221
+ description: "Optional list of networks to check. If not provided, checks all supported networks."
1222
+ }
1223
+ },
1224
+ required: ["address"]
1225
+ }
1226
+ },
1227
+ "t402/pay": {
1228
+ name: "t402/pay",
1229
+ description: "Execute a stablecoin payment on a specific blockchain network. Supports USDC, USDT, and USDT0 tokens. Requires a configured wallet with sufficient balance and native token for gas.",
1230
+ inputSchema: {
1231
+ type: "object",
1232
+ properties: {
1233
+ to: {
1234
+ type: "string",
1235
+ pattern: "^0x[a-fA-F0-9]{40}$",
1236
+ description: "Recipient address"
1237
+ },
1238
+ amount: {
1239
+ type: "string",
1240
+ pattern: "^\\d+(\\.\\d+)?$",
1241
+ description: "Amount to pay (e.g., '10.50' for 10.50 USDC)"
1242
+ },
1243
+ token: {
1244
+ type: "string",
1245
+ enum: ["USDC", "USDT", "USDT0"],
1246
+ description: "Token to use for payment"
1247
+ },
1248
+ network: {
1249
+ type: "string",
1250
+ enum: [
1251
+ "ethereum",
1252
+ "base",
1253
+ "arbitrum",
1254
+ "optimism",
1255
+ "polygon",
1256
+ "avalanche",
1257
+ "ink",
1258
+ "berachain",
1259
+ "unichain"
1260
+ ],
1261
+ description: "Network to execute payment on"
1262
+ },
1263
+ memo: {
1264
+ type: "string",
1265
+ description: "Optional memo/reference for the payment"
1266
+ }
1267
+ },
1268
+ required: ["to", "amount", "token", "network"]
1269
+ }
1270
+ },
1271
+ "t402/payGasless": {
1272
+ name: "t402/payGasless",
1273
+ description: "Execute a gasless stablecoin payment using ERC-4337 account abstraction. Gas fees are sponsored by a paymaster, so no ETH is needed for the transaction. Supported on select networks.",
1274
+ inputSchema: {
1275
+ type: "object",
1276
+ properties: {
1277
+ to: {
1278
+ type: "string",
1279
+ pattern: "^0x[a-fA-F0-9]{40}$",
1280
+ description: "Recipient address"
1281
+ },
1282
+ amount: {
1283
+ type: "string",
1284
+ pattern: "^\\d+(\\.\\d+)?$",
1285
+ description: "Amount to pay (e.g., '10.50' for 10.50 USDC)"
1286
+ },
1287
+ token: {
1288
+ type: "string",
1289
+ enum: ["USDC", "USDT", "USDT0"],
1290
+ description: "Token to use for payment"
1291
+ },
1292
+ network: {
1293
+ type: "string",
1294
+ enum: ["ethereum", "base", "arbitrum", "optimism", "polygon", "avalanche"],
1295
+ description: "Network to execute gasless payment on (must support ERC-4337)"
1296
+ }
1297
+ },
1298
+ required: ["to", "amount", "token", "network"]
1299
+ }
1300
+ },
1301
+ "t402/getBridgeFee": {
1302
+ name: "t402/getBridgeFee",
1303
+ description: "Get the fee quote for bridging USDT0 between chains using LayerZero OFT. Returns the native token fee required and estimated delivery time. Supported chains: ethereum, arbitrum, ink, berachain, unichain.",
1304
+ inputSchema: {
1305
+ type: "object",
1306
+ properties: {
1307
+ fromChain: {
1308
+ type: "string",
1309
+ enum: ["ethereum", "arbitrum", "ink", "berachain", "unichain"],
1310
+ description: "Source chain to bridge from"
1311
+ },
1312
+ toChain: {
1313
+ type: "string",
1314
+ enum: ["ethereum", "arbitrum", "ink", "berachain", "unichain"],
1315
+ description: "Destination chain to bridge to"
1316
+ },
1317
+ amount: {
1318
+ type: "string",
1319
+ pattern: "^\\d+(\\.\\d+)?$",
1320
+ description: "Amount of USDT0 to bridge (e.g., '100' for 100 USDT0)"
1321
+ },
1322
+ recipient: {
1323
+ type: "string",
1324
+ pattern: "^0x[a-fA-F0-9]{40}$",
1325
+ description: "Recipient address on destination chain"
1326
+ }
1327
+ },
1328
+ required: ["fromChain", "toChain", "amount", "recipient"]
1329
+ }
1330
+ },
1331
+ "t402/bridge": {
1332
+ name: "t402/bridge",
1333
+ description: "Bridge USDT0 between chains using LayerZero OFT standard. Executes a cross-chain transfer and returns the LayerZero message GUID for tracking. Supported chains: ethereum, arbitrum, ink, berachain, unichain.",
1334
+ inputSchema: {
1335
+ type: "object",
1336
+ properties: {
1337
+ fromChain: {
1338
+ type: "string",
1339
+ enum: ["ethereum", "arbitrum", "ink", "berachain", "unichain"],
1340
+ description: "Source chain to bridge from"
1341
+ },
1342
+ toChain: {
1343
+ type: "string",
1344
+ enum: ["ethereum", "arbitrum", "ink", "berachain", "unichain"],
1345
+ description: "Destination chain to bridge to"
1346
+ },
1347
+ amount: {
1348
+ type: "string",
1349
+ pattern: "^\\d+(\\.\\d+)?$",
1350
+ description: "Amount of USDT0 to bridge (e.g., '100' for 100 USDT0)"
1351
+ },
1352
+ recipient: {
1353
+ type: "string",
1354
+ pattern: "^0x[a-fA-F0-9]{40}$",
1355
+ description: "Recipient address on destination chain"
1356
+ }
1357
+ },
1358
+ required: ["fromChain", "toChain", "amount", "recipient"]
1359
+ }
1360
+ }
1361
+ };
1362
+
1363
+ export {
1364
+ CHAIN_IDS,
1365
+ NATIVE_SYMBOLS,
1366
+ EXPLORER_URLS,
1367
+ DEFAULT_RPC_URLS,
1368
+ USDC_ADDRESSES,
1369
+ USDT_ADDRESSES,
1370
+ USDT0_ADDRESSES,
1371
+ BRIDGEABLE_CHAINS,
1372
+ getExplorerTxUrl,
1373
+ getLayerZeroScanUrl,
1374
+ supportsToken,
1375
+ getTokenAddress,
1376
+ formatTokenAmount,
1377
+ parseTokenAmount,
1378
+ getBalanceInputSchema,
1379
+ executeGetBalance,
1380
+ formatBalanceResult,
1381
+ getAllBalancesInputSchema,
1382
+ executeGetAllBalances,
1383
+ formatAllBalancesResult,
1384
+ payInputSchema,
1385
+ executePay,
1386
+ formatPaymentResult,
1387
+ payGaslessInputSchema,
1388
+ GASLESS_SUPPORTED_NETWORKS,
1389
+ executePayGasless,
1390
+ formatGaslessPaymentResult,
1391
+ getBridgeFeeInputSchema,
1392
+ executeGetBridgeFee,
1393
+ formatBridgeFeeResult,
1394
+ bridgeInputSchema,
1395
+ executeBridge,
1396
+ formatBridgeResult,
1397
+ TOOL_DEFINITIONS
1398
+ };
1399
+ //# sourceMappingURL=chunk-SB4O25HA.mjs.map