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.
- package/README.md +142 -0
- package/dist/cli/index.js +476 -144
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +473 -141
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +5 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.js +235 -108
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +231 -106
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/web/index.d.mts +418 -0
- package/dist/client/web/index.mjs +1289 -0
- package/dist/client/web/index.mjs.map +1 -0
- package/dist/facilitators/index.d.mts +24 -2
- package/dist/facilitators/index.d.ts +24 -2
- package/dist/facilitators/index.js +127 -13
- package/dist/facilitators/index.js.map +1 -1
- package/dist/facilitators/index.mjs +127 -13
- package/dist/facilitators/index.mjs.map +1 -1
- package/dist/index.js +453 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +450 -138
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/index.js +234 -109
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/index.mjs +231 -106
- package/dist/mcp/index.mjs.map +1 -1
- package/dist/server/index.d.mts +43 -1
- package/dist/server/index.d.ts +43 -1
- package/dist/server/index.js +205 -18
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +205 -18
- package/dist/server/index.mjs.map +1 -1
- package/package.json +9 -2
package/dist/mcp/index.mjs
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
873
|
+
const minGasBalance = ethers2.parseEther("0.0005");
|
|
722
874
|
if (nativeBalance < minGasBalance) {
|
|
723
|
-
const nativeBNB = parseFloat(
|
|
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
|
|
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
|
-
|
|
915
|
+
tokenAddress: tokenConfig.address,
|
|
762
916
|
service,
|
|
763
|
-
nonce:
|
|
764
|
-
|
|
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.
|
|
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
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
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 =
|
|
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
|
|
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
|
|
1097
|
-
new
|
|
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(
|
|
1101
|
-
usdt: parseFloat(
|
|
1102
|
-
native: parseFloat(
|
|
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
|
|
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
|
|
1130
|
-
new
|
|
1131
|
-
new
|
|
1132
|
-
new
|
|
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(
|
|
1260
|
+
usdc: parseFloat(ethers2.formatUnits(pathUSD, 6)),
|
|
1136
1261
|
// pathUSD as default USDC
|
|
1137
|
-
usdt: parseFloat(
|
|
1262
|
+
usdt: parseFloat(ethers2.formatUnits(alphaUSD, 6)),
|
|
1138
1263
|
// alphaUSD as default USDT
|
|
1139
|
-
native: parseFloat(
|
|
1264
|
+
native: parseFloat(ethers2.formatEther(nativeBalance)),
|
|
1140
1265
|
tempo: {
|
|
1141
|
-
pathUSD: parseFloat(
|
|
1142
|
-
alphaUSD: parseFloat(
|
|
1143
|
-
betaUSD: parseFloat(
|
|
1144
|
-
thetaUSD: parseFloat(
|
|
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
|
|
1151
|
-
new
|
|
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(
|
|
1155
|
-
usdt: parseFloat(
|
|
1156
|
-
native: parseFloat(
|
|
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) {
|