moltspay 1.5.0 → 1.6.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.
@@ -17,11 +17,11 @@ import { join as join3 } from "path";
17
17
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
18
18
  import { z } from "zod";
19
19
 
20
- // src/client/index.ts
20
+ // src/client/node/index.ts
21
21
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, statSync, chmodSync } from "fs";
22
22
  import { homedir as homedir2 } from "os";
23
23
  import { join as join2 } from "path";
24
- import { Wallet, ethers } from "ethers";
24
+ import { Wallet as Wallet2, ethers as ethers2 } from "ethers";
25
25
 
26
26
  // src/chains/index.ts
27
27
  var CHAINS = {
@@ -272,16 +272,16 @@ import {
272
272
  getAccount as getAccount2,
273
273
  createAssociatedTokenAccountInstruction
274
274
  } from "@solana/spl-token";
275
- async function createSolanaPaymentTransaction(senderPubkey, recipientPubkey, amount, chain, feePayerPubkey) {
275
+ async function createSolanaPaymentTransaction(senderPubkey, recipientPubkey, amount, chain, feePayerPubkey, connection) {
276
276
  const chainConfig = SOLANA_CHAINS[chain];
277
- const connection = new Connection3(chainConfig.rpc, "confirmed");
277
+ const conn = connection ?? new Connection3(chainConfig.rpc, "confirmed");
278
278
  const mint = new PublicKey3(chainConfig.tokens.USDC.mint);
279
279
  const actualFeePayer = feePayerPubkey || senderPubkey;
280
280
  const senderATA = await getAssociatedTokenAddress2(mint, senderPubkey);
281
281
  const recipientATA = await getAssociatedTokenAddress2(mint, recipientPubkey);
282
282
  const transaction = new Transaction();
283
283
  try {
284
- await getAccount2(connection, recipientATA);
284
+ await getAccount2(conn, recipientATA);
285
285
  } catch {
286
286
  transaction.add(
287
287
  createAssociatedTokenAccountInstruction(
@@ -312,17 +312,178 @@ async function createSolanaPaymentTransaction(senderPubkey, recipientPubkey, amo
312
312
  // decimals
313
313
  )
314
314
  );
315
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
315
+ const { blockhash, lastValidBlockHeight } = await conn.getLatestBlockhash();
316
316
  transaction.recentBlockhash = blockhash;
317
317
  transaction.feePayer = actualFeePayer;
318
318
  return transaction;
319
319
  }
320
320
 
321
- // src/client/index.ts
321
+ // src/client/node/index.ts
322
322
  import { PublicKey as PublicKey4 } from "@solana/web3.js";
323
+
324
+ // src/client/core/types.ts
323
325
  var X402_VERSION = 2;
324
326
  var PAYMENT_REQUIRED_HEADER = "x-payment-required";
325
327
  var PAYMENT_HEADER = "x-payment";
328
+
329
+ // src/client/core/chain-map.ts
330
+ var NETWORK_TO_CHAIN = {
331
+ "eip155:8453": "base",
332
+ "eip155:137": "polygon",
333
+ "eip155:84532": "base_sepolia",
334
+ "eip155:42431": "tempo_moderato",
335
+ "eip155:56": "bnb",
336
+ "eip155:97": "bnb_testnet",
337
+ "solana:mainnet": "solana",
338
+ "solana:devnet": "solana_devnet"
339
+ };
340
+ var CHAIN_TO_NETWORK = Object.fromEntries(
341
+ Object.entries(NETWORK_TO_CHAIN).map(([network, chain]) => [chain, network])
342
+ );
343
+ function networkToChainName(network) {
344
+ return NETWORK_TO_CHAIN[network] ?? null;
345
+ }
346
+
347
+ // src/client/core/base64.ts
348
+ var BufferCtor = globalThis.Buffer;
349
+
350
+ // src/client/core/eip3009.ts
351
+ var EIP3009_TYPES = {
352
+ TransferWithAuthorization: [
353
+ { name: "from", type: "address" },
354
+ { name: "to", type: "address" },
355
+ { name: "value", type: "uint256" },
356
+ { name: "validAfter", type: "uint256" },
357
+ { name: "validBefore", type: "uint256" },
358
+ { name: "nonce", type: "bytes32" }
359
+ ]
360
+ };
361
+ function buildEIP3009TypedData(args) {
362
+ const validAfter = args.validAfter ?? "0";
363
+ const validBefore = args.validBefore ?? (Math.floor(Date.now() / 1e3) + 3600).toString();
364
+ const authorization = {
365
+ from: args.from,
366
+ to: args.to,
367
+ value: args.value,
368
+ validAfter,
369
+ validBefore,
370
+ nonce: args.nonce
371
+ };
372
+ return {
373
+ domain: {
374
+ name: args.tokenName,
375
+ version: args.tokenVersion,
376
+ chainId: args.chainId,
377
+ verifyingContract: args.tokenAddress
378
+ },
379
+ types: EIP3009_TYPES,
380
+ primaryType: "TransferWithAuthorization",
381
+ message: authorization
382
+ };
383
+ }
384
+
385
+ // src/client/core/bnb-intent.ts
386
+ var BNB_INTENT_TYPES = {
387
+ PaymentIntent: [
388
+ { name: "from", type: "address" },
389
+ { name: "to", type: "address" },
390
+ { name: "amount", type: "uint256" },
391
+ { name: "token", type: "address" },
392
+ { name: "service", type: "string" },
393
+ { name: "nonce", type: "uint256" },
394
+ { name: "deadline", type: "uint256" }
395
+ ]
396
+ };
397
+ var BNB_DOMAIN_NAME = "MoltsPay";
398
+ var BNB_DOMAIN_VERSION = "1";
399
+ function buildBnbIntentTypedData(args) {
400
+ const intent = {
401
+ from: args.from,
402
+ to: args.to,
403
+ amount: args.amount,
404
+ token: args.tokenAddress,
405
+ service: args.service,
406
+ nonce: args.nonce,
407
+ deadline: args.deadline
408
+ };
409
+ return {
410
+ domain: {
411
+ name: BNB_DOMAIN_NAME,
412
+ version: BNB_DOMAIN_VERSION,
413
+ chainId: args.chainId
414
+ },
415
+ types: BNB_INTENT_TYPES,
416
+ primaryType: "PaymentIntent",
417
+ message: intent
418
+ };
419
+ }
420
+
421
+ // src/client/node/signer.ts
422
+ import { ethers } from "ethers";
423
+ import { Transaction as Transaction2 } from "@solana/web3.js";
424
+ var NodeSigner = class {
425
+ evmWallet;
426
+ getSolanaKeypair;
427
+ constructor(evmWallet, options = {}) {
428
+ this.evmWallet = evmWallet;
429
+ this.getSolanaKeypair = options.getSolanaKeypair ?? (() => null);
430
+ }
431
+ async getEvmAddress() {
432
+ return this.evmWallet.address;
433
+ }
434
+ async getSolanaAddress() {
435
+ const kp = this.getSolanaKeypair();
436
+ return kp ? kp.publicKey.toBase58() : null;
437
+ }
438
+ async signTypedData(envelope) {
439
+ const mutableTypes = {};
440
+ for (const [key, fields] of Object.entries(envelope.types)) {
441
+ mutableTypes[key] = [...fields];
442
+ }
443
+ return this.evmWallet.signTypedData(
444
+ envelope.domain,
445
+ mutableTypes,
446
+ envelope.message
447
+ );
448
+ }
449
+ async sendEvmTransaction(args) {
450
+ const chain = findChainByChainId(args.chainId);
451
+ if (!chain) {
452
+ throw new Error(`sendEvmTransaction: unknown chainId ${args.chainId}`);
453
+ }
454
+ const provider = new ethers.JsonRpcProvider(chain.rpc);
455
+ const connected = this.evmWallet.connect(provider);
456
+ const tx = await connected.sendTransaction({
457
+ to: args.to,
458
+ data: args.data,
459
+ value: args.value ? BigInt(args.value) : 0n
460
+ });
461
+ return tx.hash;
462
+ }
463
+ async signSolanaTransaction(args) {
464
+ const kp = this.getSolanaKeypair();
465
+ if (!kp) {
466
+ throw new Error("signSolanaTransaction: no Solana wallet configured");
467
+ }
468
+ const tx = Transaction2.from(Buffer.from(args.transactionBase64, "base64"));
469
+ if (args.partialSign) {
470
+ tx.partialSign(kp);
471
+ } else {
472
+ tx.sign(kp);
473
+ }
474
+ return tx.serialize({ requireAllSignatures: false }).toString("base64");
475
+ }
476
+ };
477
+ function findChainByChainId(chainId) {
478
+ for (const cfg of Object.values(CHAINS)) {
479
+ if (cfg.chainId === chainId) {
480
+ return cfg;
481
+ }
482
+ }
483
+ return void 0;
484
+ }
485
+
486
+ // src/client/node/index.ts
326
487
  var DEFAULT_CONFIG = {
327
488
  chain: "base",
328
489
  limits: {
@@ -335,6 +496,7 @@ var MoltsPayClient = class {
335
496
  config;
336
497
  walletData = null;
337
498
  wallet = null;
499
+ signer = null;
338
500
  todaySpending = 0;
339
501
  lastSpendingReset = 0;
340
502
  constructor(options = {}) {
@@ -343,7 +505,11 @@ var MoltsPayClient = class {
343
505
  this.walletData = this.loadWallet();
344
506
  this.loadSpending();
345
507
  if (this.walletData) {
346
- this.wallet = new Wallet(this.walletData.privateKey);
508
+ this.wallet = new Wallet2(this.walletData.privateKey);
509
+ const configDir = this.configDir;
510
+ this.signer = new NodeSigner(this.wallet, {
511
+ getSolanaKeypair: () => loadSolanaWallet(configDir)
512
+ });
347
513
  }
348
514
  }
349
515
  /**
@@ -471,20 +637,6 @@ var MoltsPayClient = class {
471
637
  } catch {
472
638
  throw new Error("Invalid x-payment-required header");
473
639
  }
474
- const networkToChainName = (network2) => {
475
- if (network2 === "solana:mainnet") return "solana";
476
- if (network2 === "solana:devnet") return "solana_devnet";
477
- const match = network2.match(/^eip155:(\d+)$/);
478
- if (!match) return null;
479
- const chainId = parseInt(match[1]);
480
- if (chainId === 8453) return "base";
481
- if (chainId === 137) return "polygon";
482
- if (chainId === 84532) return "base_sepolia";
483
- if (chainId === 42431) return "tempo_moderato";
484
- if (chainId === 56) return "bnb";
485
- if (chainId === 97) return "bnb_testnet";
486
- return null;
487
- };
488
640
  const serverChains = requirements.map((r) => networkToChainName(r.network)).filter((c) => c !== null);
489
641
  const userSpecifiedChain = options.chain;
490
642
  let selectedChain;
@@ -713,14 +865,14 @@ Please specify: --chain <chain_name>`
713
865
  async handleBNBPayment(executeUrl, service, params, paymentDetails, options = {}) {
714
866
  const { to, amount, token, chainName, chain, spender } = paymentDetails;
715
867
  const tokenConfig = chain.tokens[token];
716
- const provider = new ethers.JsonRpcProvider(chain.rpc);
868
+ const provider = new ethers2.JsonRpcProvider(chain.rpc);
717
869
  const allowance = await this.checkAllowance(tokenConfig.address, spender, provider);
718
870
  const amountWeiCheck = BigInt(Math.floor(amount * 10 ** tokenConfig.decimals));
719
871
  if (allowance < amountWeiCheck) {
720
872
  const nativeBalance = await provider.getBalance(this.wallet.address);
721
- const minGasBalance = ethers.parseEther("0.0005");
873
+ const minGasBalance = ethers2.parseEther("0.0005");
722
874
  if (nativeBalance < minGasBalance) {
723
- const nativeBNB = parseFloat(ethers.formatEther(nativeBalance)).toFixed(4);
875
+ const nativeBNB = parseFloat(ethers2.formatEther(nativeBalance)).toFixed(4);
724
876
  const isTestnet = chainName === "bnb_testnet";
725
877
  if (isTestnet) {
726
878
  throw new Error(
@@ -754,35 +906,21 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
754
906
  );
755
907
  }
756
908
  const amountWei = BigInt(Math.floor(amount * 10 ** tokenConfig.decimals)).toString();
757
- const intent = {
909
+ const intentNonce = Date.now();
910
+ const intentDeadline = Date.now() + 36e5;
911
+ const envelope = buildBnbIntentTypedData({
758
912
  from: this.wallet.address,
759
913
  to,
760
914
  amount: amountWei,
761
- token: tokenConfig.address,
915
+ tokenAddress: tokenConfig.address,
762
916
  service,
763
- nonce: Date.now(),
764
- // Use timestamp as nonce for simplicity
765
- deadline: Date.now() + 36e5
766
- // 1 hour
767
- };
768
- const domain = {
769
- name: "MoltsPay",
770
- version: "1",
917
+ nonce: intentNonce,
918
+ deadline: intentDeadline,
771
919
  chainId: chain.chainId
772
- };
773
- const types = {
774
- PaymentIntent: [
775
- { name: "from", type: "address" },
776
- { name: "to", type: "address" },
777
- { name: "amount", type: "uint256" },
778
- { name: "token", type: "address" },
779
- { name: "service", type: "string" },
780
- { name: "nonce", type: "uint256" },
781
- { name: "deadline", type: "uint256" }
782
- ]
783
- };
920
+ });
784
921
  console.log(`[MoltsPay] Signing BNB payment intent...`);
785
- const signature = await this.wallet.signTypedData(domain, types, intent);
922
+ const signature = await this.signer.signTypedData(envelope);
923
+ const intent = envelope.message;
786
924
  const network = `eip155:${chain.chainId}`;
787
925
  const payload = {
788
926
  x402Version: 2,
@@ -856,12 +994,11 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
856
994
  feePayerPubkey
857
995
  // Optional fee payer for gasless mode
858
996
  );
859
- if (feePayerPubkey) {
860
- transaction.partialSign(solanaWallet);
861
- } else {
862
- transaction.sign(solanaWallet);
863
- }
864
- const signedTx = transaction.serialize({ requireAllSignatures: false }).toString("base64");
997
+ const unsignedBase64 = transaction.serialize({ requireAllSignatures: false, verifySignatures: false }).toString("base64");
998
+ const signedTx = await this.signer.signSolanaTransaction({
999
+ transactionBase64: unsignedBase64,
1000
+ partialSign: !!feePayerPubkey
1001
+ });
865
1002
  console.log(`[MoltsPay] Transaction signed, sending to server...`);
866
1003
  const network = chain === "solana" ? "solana:mainnet" : "solana:devnet";
867
1004
  const payload = {
@@ -908,7 +1045,7 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
908
1045
  * Check ERC20 allowance for a spender
909
1046
  */
910
1047
  async checkAllowance(tokenAddress, spender, provider) {
911
- const contract = new ethers.Contract(
1048
+ const contract = new ethers2.Contract(
912
1049
  tokenAddress,
913
1050
  ["function allowance(address owner, address spender) view returns (uint256)"],
914
1051
  provider
@@ -919,41 +1056,29 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
919
1056
  * Sign EIP-3009 transferWithAuthorization (GASLESS)
920
1057
  * This only signs - no on-chain transaction, no gas needed.
921
1058
  * Supports both USDC and USDT.
1059
+ *
1060
+ * Delegates typed-data construction to `core/eip3009.ts` and the signature
1061
+ * itself to `this.signer`. That way Web Client (Phase 4) can reuse the same
1062
+ * flow with an EIP-1193 signer without duplicating typed-data layout.
922
1063
  */
923
1064
  async signEIP3009(to, amount, chain, token = "USDC", domainOverride) {
924
- const validAfter = 0;
925
- const validBefore = Math.floor(Date.now() / 1e3) + 3600;
926
- const nonce = ethers.hexlify(ethers.randomBytes(32));
927
1065
  const tokenConfig = chain.tokens[token];
928
1066
  const value = BigInt(Math.floor(amount * 10 ** tokenConfig.decimals)).toString();
929
- const authorization = {
1067
+ const nonce = ethers2.hexlify(ethers2.randomBytes(32));
1068
+ const tokenName = domainOverride?.name || tokenConfig.eip712Name || (token === "USDC" ? "USD Coin" : "Tether USD");
1069
+ const tokenVersion = domainOverride?.version || "2";
1070
+ const envelope = buildEIP3009TypedData({
930
1071
  from: this.wallet.address,
931
1072
  to,
932
1073
  value,
933
- validAfter: validAfter.toString(),
934
- validBefore: validBefore.toString(),
935
- nonce
936
- };
937
- const tokenName = domainOverride?.name || tokenConfig.eip712Name || (token === "USDC" ? "USD Coin" : "Tether USD");
938
- const tokenVersion = domainOverride?.version || "2";
939
- const domain = {
940
- name: tokenName,
941
- version: tokenVersion,
1074
+ nonce,
942
1075
  chainId: chain.chainId,
943
- verifyingContract: tokenConfig.address
944
- };
945
- const types = {
946
- TransferWithAuthorization: [
947
- { name: "from", type: "address" },
948
- { name: "to", type: "address" },
949
- { name: "value", type: "uint256" },
950
- { name: "validAfter", type: "uint256" },
951
- { name: "validBefore", type: "uint256" },
952
- { name: "nonce", type: "bytes32" }
953
- ]
954
- };
955
- const signature = await this.wallet.signTypedData(domain, types, authorization);
956
- return { authorization, signature };
1076
+ tokenAddress: tokenConfig.address,
1077
+ tokenName,
1078
+ tokenVersion
1079
+ });
1080
+ const signature = await this.signer.signTypedData(envelope);
1081
+ return { authorization: envelope.message, signature };
957
1082
  }
958
1083
  /**
959
1084
  * Check spending limits
@@ -1057,7 +1182,7 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
1057
1182
  */
1058
1183
  static init(configDir, options) {
1059
1184
  mkdirSync2(configDir, { recursive: true });
1060
- const wallet = Wallet.createRandom();
1185
+ const wallet = Wallet2.createRandom();
1061
1186
  const walletData = {
1062
1187
  address: wallet.address,
1063
1188
  privateKey: wallet.privateKey,
@@ -1089,17 +1214,17 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
1089
1214
  } catch {
1090
1215
  throw new Error(`Unknown chain: ${this.config.chain}`);
1091
1216
  }
1092
- const provider = new ethers.JsonRpcProvider(chain.rpc);
1217
+ const provider = new ethers2.JsonRpcProvider(chain.rpc);
1093
1218
  const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
1094
1219
  const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
1095
1220
  provider.getBalance(this.wallet.address),
1096
- new ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
1097
- new ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
1221
+ new ethers2.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
1222
+ new ethers2.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
1098
1223
  ]);
1099
1224
  return {
1100
- usdc: parseFloat(ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
1101
- usdt: parseFloat(ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
1102
- native: parseFloat(ethers.formatEther(nativeBalance))
1225
+ usdc: parseFloat(ethers2.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
1226
+ usdt: parseFloat(ethers2.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
1227
+ native: parseFloat(ethers2.formatEther(nativeBalance))
1103
1228
  };
1104
1229
  }
1105
1230
  /**
@@ -1122,38 +1247,38 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
1122
1247
  supportedChains.map(async (chainName) => {
1123
1248
  try {
1124
1249
  const chain = getChain(chainName);
1125
- const provider = new ethers.JsonRpcProvider(chain.rpc);
1250
+ const provider = new ethers2.JsonRpcProvider(chain.rpc);
1126
1251
  if (chainName === "tempo_moderato") {
1127
1252
  const [nativeBalance, pathUSD, alphaUSD, betaUSD, thetaUSD] = await Promise.all([
1128
1253
  provider.getBalance(this.wallet.address),
1129
- new ethers.Contract(tempoTokens.pathUSD, tokenAbi, provider).balanceOf(this.wallet.address),
1130
- new ethers.Contract(tempoTokens.alphaUSD, tokenAbi, provider).balanceOf(this.wallet.address),
1131
- new ethers.Contract(tempoTokens.betaUSD, tokenAbi, provider).balanceOf(this.wallet.address),
1132
- new ethers.Contract(tempoTokens.thetaUSD, tokenAbi, provider).balanceOf(this.wallet.address)
1254
+ new ethers2.Contract(tempoTokens.pathUSD, tokenAbi, provider).balanceOf(this.wallet.address),
1255
+ new ethers2.Contract(tempoTokens.alphaUSD, tokenAbi, provider).balanceOf(this.wallet.address),
1256
+ new ethers2.Contract(tempoTokens.betaUSD, tokenAbi, provider).balanceOf(this.wallet.address),
1257
+ new ethers2.Contract(tempoTokens.thetaUSD, tokenAbi, provider).balanceOf(this.wallet.address)
1133
1258
  ]);
1134
1259
  results[chainName] = {
1135
- usdc: parseFloat(ethers.formatUnits(pathUSD, 6)),
1260
+ usdc: parseFloat(ethers2.formatUnits(pathUSD, 6)),
1136
1261
  // pathUSD as default USDC
1137
- usdt: parseFloat(ethers.formatUnits(alphaUSD, 6)),
1262
+ usdt: parseFloat(ethers2.formatUnits(alphaUSD, 6)),
1138
1263
  // alphaUSD as default USDT
1139
- native: parseFloat(ethers.formatEther(nativeBalance)),
1264
+ native: parseFloat(ethers2.formatEther(nativeBalance)),
1140
1265
  tempo: {
1141
- pathUSD: parseFloat(ethers.formatUnits(pathUSD, 6)),
1142
- alphaUSD: parseFloat(ethers.formatUnits(alphaUSD, 6)),
1143
- betaUSD: parseFloat(ethers.formatUnits(betaUSD, 6)),
1144
- thetaUSD: parseFloat(ethers.formatUnits(thetaUSD, 6))
1266
+ pathUSD: parseFloat(ethers2.formatUnits(pathUSD, 6)),
1267
+ alphaUSD: parseFloat(ethers2.formatUnits(alphaUSD, 6)),
1268
+ betaUSD: parseFloat(ethers2.formatUnits(betaUSD, 6)),
1269
+ thetaUSD: parseFloat(ethers2.formatUnits(thetaUSD, 6))
1145
1270
  }
1146
1271
  };
1147
1272
  } else {
1148
1273
  const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
1149
1274
  provider.getBalance(this.wallet.address),
1150
- new ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
1151
- new ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
1275
+ new ethers2.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
1276
+ new ethers2.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
1152
1277
  ]);
1153
1278
  results[chainName] = {
1154
- usdc: parseFloat(ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
1155
- usdt: parseFloat(ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
1156
- native: parseFloat(ethers.formatEther(nativeBalance))
1279
+ usdc: parseFloat(ethers2.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
1280
+ usdt: parseFloat(ethers2.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
1281
+ native: parseFloat(ethers2.formatEther(nativeBalance))
1157
1282
  };
1158
1283
  }
1159
1284
  } catch (err2) {