@alleyboss/micropay-solana-x402-paywall 3.3.7 → 3.3.8

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/index.cjs CHANGED
@@ -528,6 +528,216 @@ function useFormatPrice(lamports) {
528
528
  isLoading: false
529
529
  };
530
530
  }
531
+ var LocalSvmFacilitator = class {
532
+ scheme = "exact";
533
+ caipFamily = "solana:*";
534
+ connection;
535
+ constructor(rpcUrl) {
536
+ console.log("[LocalSvmFacilitator] Initialized with RPC:", rpcUrl);
537
+ this.connection = new web3_js.Connection(rpcUrl, "confirmed");
538
+ }
539
+ /**
540
+ * Get supported payment kinds
541
+ * Mocking the response of the /supported endpoint
542
+ */
543
+ /**
544
+ * Network Constants - CAIP-2 format for x402 v2
545
+ * These match the official Solana chain IDs used by x402 protocol
546
+ */
547
+ NETWORKS = {
548
+ DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
549
+ MAINNET: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
550
+ };
551
+ /**
552
+ * DUMMY_FEE_PAYER Explanation (for auditors):
553
+ *
554
+ * In a HOSTED facilitator (like x402.org), the `feePayer` field in the
555
+ * SupportedResponse.extra specifies which address will pay transaction fees
556
+ * when the facilitator submits transactions on behalf of users.
557
+ *
558
+ * In LOCAL/SELF-SOVEREIGN mode (this implementation):
559
+ * - The USER pays their own transaction fees directly
560
+ * - The facilitator NEVER submits transactions - it only VERIFIES them
561
+ * - Therefore, no fee payer address is actually used
562
+ *
563
+ * However, the x402 protocol REQUIRES this field in the response schema.
564
+ * We use the System Program address (all 1s) as a placeholder because:
565
+ * 1. It's clearly not a real wallet (obvious placeholder)
566
+ * 2. It cannot receive funds or sign transactions
567
+ * 3. It signals to developers that fee paying is handled differently
568
+ *
569
+ * SECURITY NOTE: This is NOT a security risk because:
570
+ * - The fee payer is never used in verify() or settle() methods
571
+ * - Users sign and pay for their own transactions
572
+ * - The address is just a protocol-required placeholder
573
+ *
574
+ * @see https://docs.x402.org for protocol specification
575
+ */
576
+ DUMMY_FEE_PAYER = "11111111111111111111111111111111";
577
+ /**
578
+ * Get supported payment kinds
579
+ * Returns x402 v2 compatible response with CAIP-2 network identifiers
580
+ *
581
+ * NOTE: The feePayer in extra.feePayer is a placeholder only.
582
+ * In self-sovereign mode, users pay their own transaction fees.
583
+ */
584
+ async getSupported(_extensionKeys = []) {
585
+ const supported = {
586
+ kinds: [
587
+ {
588
+ x402Version: 2,
589
+ scheme: "exact",
590
+ network: this.NETWORKS.DEVNET,
591
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
592
+ },
593
+ {
594
+ x402Version: 2,
595
+ scheme: "exact",
596
+ network: this.NETWORKS.MAINNET,
597
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
598
+ }
599
+ ],
600
+ extensions: [],
601
+ signers: {
602
+ // Placeholder - in self-sovereign mode, users are their own signers
603
+ "solana:*": [this.DUMMY_FEE_PAYER]
604
+ }
605
+ };
606
+ return supported;
607
+ }
608
+ /**
609
+ * Get mechanism-specific extra data
610
+ */
611
+ getExtra(_network) {
612
+ return void 0;
613
+ }
614
+ /**
615
+ * Get default signers (not used for local verification usually, but required by interface)
616
+ */
617
+ getSigners(_network) {
618
+ return [];
619
+ }
620
+ /**
621
+ * Enable debug logging (disable in production)
622
+ */
623
+ debug = process.env.NODE_ENV === "development";
624
+ /**
625
+ * Verify a payment on-chain
626
+ */
627
+ async verify(payload, requirements) {
628
+ try {
629
+ const signature = payload.payload.signature;
630
+ if (!signature) {
631
+ return { isValid: false, invalidReason: "Missing signature in payment payload" };
632
+ }
633
+ const payTo = requirements.payTo;
634
+ const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
635
+ const requiredAmount = BigInt(amountVal);
636
+ if (this.debug) {
637
+ console.log(`[LocalSvmFacilitator] Verifying tx: ${signature.slice(0, 8)}...`);
638
+ }
639
+ const tx = await this.fetchTransactionWithRetry(signature, 3);
640
+ if (!tx) {
641
+ return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
642
+ }
643
+ const instructions = tx.transaction.message.instructions;
644
+ let paidAmount = 0n;
645
+ let payer = void 0;
646
+ for (const ix of instructions) {
647
+ if ("program" in ix && ix.program === "system") {
648
+ const parsed = ix.parsed;
649
+ if (parsed?.type === "transfer" && parsed.info?.destination === payTo) {
650
+ paidAmount += BigInt(parsed.info.lamports);
651
+ if (!payer) payer = parsed.info.source;
652
+ }
653
+ }
654
+ if ("program" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
655
+ const parsed = ix.parsed;
656
+ if (parsed?.type === "transferChecked" || parsed?.type === "transfer") {
657
+ if (this.debug) {
658
+ console.log(`[LocalSvmFacilitator] Found SPL transfer`);
659
+ }
660
+ }
661
+ }
662
+ }
663
+ if (paidAmount >= requiredAmount) {
664
+ if (this.debug) {
665
+ console.log(`[LocalSvmFacilitator] Verification SUCCESS for tx: ${signature.slice(0, 8)}...`);
666
+ }
667
+ return {
668
+ isValid: true,
669
+ payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
670
+ };
671
+ }
672
+ return {
673
+ isValid: false,
674
+ invalidReason: "Insufficient payment amount",
675
+ payer
676
+ };
677
+ } catch (error) {
678
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
679
+ if (this.debug) {
680
+ console.error("[LocalSvmFacilitator] Verify error:", errorMessage);
681
+ }
682
+ throw new types.VerifyError(500, {
683
+ isValid: false,
684
+ invalidReason: errorMessage
685
+ });
686
+ }
687
+ }
688
+ /**
689
+ * Fetch transaction with exponential backoff retry
690
+ */
691
+ async fetchTransactionWithRetry(signature, maxRetries = 3) {
692
+ let lastError;
693
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
694
+ try {
695
+ const tx = await this.connection.getParsedTransaction(signature, {
696
+ maxSupportedTransactionVersion: 0,
697
+ commitment: "confirmed"
698
+ });
699
+ if (tx) return tx;
700
+ if (attempt < maxRetries - 1) {
701
+ await this.sleep(Math.pow(2, attempt) * 1e3);
702
+ }
703
+ } catch (error) {
704
+ lastError = error instanceof Error ? error : new Error("RPC error");
705
+ if (attempt < maxRetries - 1) {
706
+ await this.sleep(Math.pow(2, attempt) * 1e3);
707
+ }
708
+ }
709
+ }
710
+ if (lastError) throw lastError;
711
+ return null;
712
+ }
713
+ /**
714
+ * Sleep helper
715
+ */
716
+ sleep(ms) {
717
+ return new Promise((resolve) => setTimeout(resolve, ms));
718
+ }
719
+ /**
720
+ * Settle a payment (not applicable for direct chain verification, usually)
721
+ * But we must implement it. For 'exact', settlement is just verification + finality.
722
+ */
723
+ async settle(payload, requirements) {
724
+ const verifyResult = await this.verify(payload, requirements);
725
+ if (!verifyResult.isValid) {
726
+ throw new types.SettleError(400, {
727
+ success: false,
728
+ errorReason: verifyResult.invalidReason || "Verification failed",
729
+ transaction: payload.payload.signature,
730
+ network: requirements.network
731
+ });
732
+ }
733
+ return {
734
+ success: true,
735
+ payer: verifyResult.payer,
736
+ transaction: payload.payload.signature,
737
+ network: requirements.network
738
+ };
739
+ }
740
+ };
531
741
  var DEFAULT_COMPUTE_UNITS = 2e5;
532
742
  var DEFAULT_MICRO_LAMPORTS = 1e3;
533
743
  function createPriorityFeeInstructions(config = {}) {
@@ -870,6 +1080,7 @@ async function getRemainingCredits(token, secret) {
870
1080
  };
871
1081
  }
872
1082
 
1083
+ exports.LocalSvmFacilitator = LocalSvmFacilitator;
873
1084
  exports.addCredits = addCredits;
874
1085
  exports.buildSolanaPayUrl = buildSolanaPayUrl;
875
1086
  exports.clearPriceCache = clearPriceCache;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from '@x402/core';
2
+ import { PaymentPayload, PaymentRequirements, VerifyResponse, SettleResponse, SupportedResponse, Network } from '@x402/core/types';
2
3
  export * from '@x402/core/types';
3
4
  export * from '@x402/core/client';
4
5
  export * from '@x402/svm';
@@ -7,3 +8,95 @@ export { AgentPaymentResult, CreditSessionClaims, CreditSessionConfig, CreditSes
7
8
  export { CustomPriceProvider, PriceConfig, PriceData, clearPriceCache, configurePricing, formatPriceDisplay, formatPriceSync, getProviders, getSolPrice, lamportsToSol, lamportsToUsd, usdToLamports } from './pricing/index.cjs';
8
9
  import '@solana/web3.js';
9
10
  import './types-BWYQMw03.cjs';
11
+
12
+ interface FacilitatorClient {
13
+ verify(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements): Promise<VerifyResponse>;
14
+ settle(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements): Promise<SettleResponse>;
15
+ getSupported(extensionKeys?: string[]): Promise<SupportedResponse>;
16
+ }
17
+ /**
18
+ * Local SVM Facilitator
19
+ *
20
+ * Verifies and settles Solana payments locally using a direct RPC connection,
21
+ * bypassing the need for a hosted facilitator service.
22
+ */
23
+ declare class LocalSvmFacilitator implements FacilitatorClient {
24
+ readonly scheme = "exact";
25
+ readonly caipFamily = "solana:*";
26
+ private connection;
27
+ constructor(rpcUrl: string);
28
+ /**
29
+ * Get supported payment kinds
30
+ * Mocking the response of the /supported endpoint
31
+ */
32
+ /**
33
+ * Network Constants - CAIP-2 format for x402 v2
34
+ * These match the official Solana chain IDs used by x402 protocol
35
+ */
36
+ private readonly NETWORKS;
37
+ /**
38
+ * DUMMY_FEE_PAYER Explanation (for auditors):
39
+ *
40
+ * In a HOSTED facilitator (like x402.org), the `feePayer` field in the
41
+ * SupportedResponse.extra specifies which address will pay transaction fees
42
+ * when the facilitator submits transactions on behalf of users.
43
+ *
44
+ * In LOCAL/SELF-SOVEREIGN mode (this implementation):
45
+ * - The USER pays their own transaction fees directly
46
+ * - The facilitator NEVER submits transactions - it only VERIFIES them
47
+ * - Therefore, no fee payer address is actually used
48
+ *
49
+ * However, the x402 protocol REQUIRES this field in the response schema.
50
+ * We use the System Program address (all 1s) as a placeholder because:
51
+ * 1. It's clearly not a real wallet (obvious placeholder)
52
+ * 2. It cannot receive funds or sign transactions
53
+ * 3. It signals to developers that fee paying is handled differently
54
+ *
55
+ * SECURITY NOTE: This is NOT a security risk because:
56
+ * - The fee payer is never used in verify() or settle() methods
57
+ * - Users sign and pay for their own transactions
58
+ * - The address is just a protocol-required placeholder
59
+ *
60
+ * @see https://docs.x402.org for protocol specification
61
+ */
62
+ private readonly DUMMY_FEE_PAYER;
63
+ /**
64
+ * Get supported payment kinds
65
+ * Returns x402 v2 compatible response with CAIP-2 network identifiers
66
+ *
67
+ * NOTE: The feePayer in extra.feePayer is a placeholder only.
68
+ * In self-sovereign mode, users pay their own transaction fees.
69
+ */
70
+ getSupported(_extensionKeys?: string[]): Promise<SupportedResponse>;
71
+ /**
72
+ * Get mechanism-specific extra data
73
+ */
74
+ getExtra(_network: Network): Record<string, unknown> | undefined;
75
+ /**
76
+ * Get default signers (not used for local verification usually, but required by interface)
77
+ */
78
+ getSigners(_network: string): string[];
79
+ /**
80
+ * Enable debug logging (disable in production)
81
+ */
82
+ private debug;
83
+ /**
84
+ * Verify a payment on-chain
85
+ */
86
+ verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
87
+ /**
88
+ * Fetch transaction with exponential backoff retry
89
+ */
90
+ private fetchTransactionWithRetry;
91
+ /**
92
+ * Sleep helper
93
+ */
94
+ private sleep;
95
+ /**
96
+ * Settle a payment (not applicable for direct chain verification, usually)
97
+ * But we must implement it. For 'exact', settlement is just verification + finality.
98
+ */
99
+ settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
100
+ }
101
+
102
+ export { LocalSvmFacilitator };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from '@x402/core';
2
+ import { PaymentPayload, PaymentRequirements, VerifyResponse, SettleResponse, SupportedResponse, Network } from '@x402/core/types';
2
3
  export * from '@x402/core/types';
3
4
  export * from '@x402/core/client';
4
5
  export * from '@x402/svm';
@@ -7,3 +8,95 @@ export { AgentPaymentResult, CreditSessionClaims, CreditSessionConfig, CreditSes
7
8
  export { CustomPriceProvider, PriceConfig, PriceData, clearPriceCache, configurePricing, formatPriceDisplay, formatPriceSync, getProviders, getSolPrice, lamportsToSol, lamportsToUsd, usdToLamports } from './pricing/index.js';
8
9
  import '@solana/web3.js';
9
10
  import './types-BWYQMw03.js';
11
+
12
+ interface FacilitatorClient {
13
+ verify(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements): Promise<VerifyResponse>;
14
+ settle(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements): Promise<SettleResponse>;
15
+ getSupported(extensionKeys?: string[]): Promise<SupportedResponse>;
16
+ }
17
+ /**
18
+ * Local SVM Facilitator
19
+ *
20
+ * Verifies and settles Solana payments locally using a direct RPC connection,
21
+ * bypassing the need for a hosted facilitator service.
22
+ */
23
+ declare class LocalSvmFacilitator implements FacilitatorClient {
24
+ readonly scheme = "exact";
25
+ readonly caipFamily = "solana:*";
26
+ private connection;
27
+ constructor(rpcUrl: string);
28
+ /**
29
+ * Get supported payment kinds
30
+ * Mocking the response of the /supported endpoint
31
+ */
32
+ /**
33
+ * Network Constants - CAIP-2 format for x402 v2
34
+ * These match the official Solana chain IDs used by x402 protocol
35
+ */
36
+ private readonly NETWORKS;
37
+ /**
38
+ * DUMMY_FEE_PAYER Explanation (for auditors):
39
+ *
40
+ * In a HOSTED facilitator (like x402.org), the `feePayer` field in the
41
+ * SupportedResponse.extra specifies which address will pay transaction fees
42
+ * when the facilitator submits transactions on behalf of users.
43
+ *
44
+ * In LOCAL/SELF-SOVEREIGN mode (this implementation):
45
+ * - The USER pays their own transaction fees directly
46
+ * - The facilitator NEVER submits transactions - it only VERIFIES them
47
+ * - Therefore, no fee payer address is actually used
48
+ *
49
+ * However, the x402 protocol REQUIRES this field in the response schema.
50
+ * We use the System Program address (all 1s) as a placeholder because:
51
+ * 1. It's clearly not a real wallet (obvious placeholder)
52
+ * 2. It cannot receive funds or sign transactions
53
+ * 3. It signals to developers that fee paying is handled differently
54
+ *
55
+ * SECURITY NOTE: This is NOT a security risk because:
56
+ * - The fee payer is never used in verify() or settle() methods
57
+ * - Users sign and pay for their own transactions
58
+ * - The address is just a protocol-required placeholder
59
+ *
60
+ * @see https://docs.x402.org for protocol specification
61
+ */
62
+ private readonly DUMMY_FEE_PAYER;
63
+ /**
64
+ * Get supported payment kinds
65
+ * Returns x402 v2 compatible response with CAIP-2 network identifiers
66
+ *
67
+ * NOTE: The feePayer in extra.feePayer is a placeholder only.
68
+ * In self-sovereign mode, users pay their own transaction fees.
69
+ */
70
+ getSupported(_extensionKeys?: string[]): Promise<SupportedResponse>;
71
+ /**
72
+ * Get mechanism-specific extra data
73
+ */
74
+ getExtra(_network: Network): Record<string, unknown> | undefined;
75
+ /**
76
+ * Get default signers (not used for local verification usually, but required by interface)
77
+ */
78
+ getSigners(_network: string): string[];
79
+ /**
80
+ * Enable debug logging (disable in production)
81
+ */
82
+ private debug;
83
+ /**
84
+ * Verify a payment on-chain
85
+ */
86
+ verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
87
+ /**
88
+ * Fetch transaction with exponential backoff retry
89
+ */
90
+ private fetchTransactionWithRetry;
91
+ /**
92
+ * Sleep helper
93
+ */
94
+ private sleep;
95
+ /**
96
+ * Settle a payment (not applicable for direct chain verification, usually)
97
+ * But we must implement it. For 'exact', settlement is just verification + finality.
98
+ */
99
+ settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
100
+ }
101
+
102
+ export { LocalSvmFacilitator };
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  export * from '@x402/core';
2
+ import { VerifyError, SettleError } from '@x402/core/types';
2
3
  export * from '@x402/core/types';
3
4
  export * from '@x402/core/client';
4
5
  export * from '@x402/svm';
5
6
  import { decodePaymentRequiredHeader, encodePaymentSignatureHeader } from '@x402/core/http';
6
- import { PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL, Keypair, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } from '@solana/web3.js';
7
+ import { PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL, Connection, Keypair, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } from '@solana/web3.js';
7
8
  import { useState, useCallback, useEffect, useRef } from 'react';
8
9
  import bs58 from 'bs58';
9
10
  import { SignJWT, jwtVerify } from 'jose';
@@ -522,6 +523,216 @@ function useFormatPrice(lamports) {
522
523
  isLoading: false
523
524
  };
524
525
  }
526
+ var LocalSvmFacilitator = class {
527
+ scheme = "exact";
528
+ caipFamily = "solana:*";
529
+ connection;
530
+ constructor(rpcUrl) {
531
+ console.log("[LocalSvmFacilitator] Initialized with RPC:", rpcUrl);
532
+ this.connection = new Connection(rpcUrl, "confirmed");
533
+ }
534
+ /**
535
+ * Get supported payment kinds
536
+ * Mocking the response of the /supported endpoint
537
+ */
538
+ /**
539
+ * Network Constants - CAIP-2 format for x402 v2
540
+ * These match the official Solana chain IDs used by x402 protocol
541
+ */
542
+ NETWORKS = {
543
+ DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
544
+ MAINNET: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
545
+ };
546
+ /**
547
+ * DUMMY_FEE_PAYER Explanation (for auditors):
548
+ *
549
+ * In a HOSTED facilitator (like x402.org), the `feePayer` field in the
550
+ * SupportedResponse.extra specifies which address will pay transaction fees
551
+ * when the facilitator submits transactions on behalf of users.
552
+ *
553
+ * In LOCAL/SELF-SOVEREIGN mode (this implementation):
554
+ * - The USER pays their own transaction fees directly
555
+ * - The facilitator NEVER submits transactions - it only VERIFIES them
556
+ * - Therefore, no fee payer address is actually used
557
+ *
558
+ * However, the x402 protocol REQUIRES this field in the response schema.
559
+ * We use the System Program address (all 1s) as a placeholder because:
560
+ * 1. It's clearly not a real wallet (obvious placeholder)
561
+ * 2. It cannot receive funds or sign transactions
562
+ * 3. It signals to developers that fee paying is handled differently
563
+ *
564
+ * SECURITY NOTE: This is NOT a security risk because:
565
+ * - The fee payer is never used in verify() or settle() methods
566
+ * - Users sign and pay for their own transactions
567
+ * - The address is just a protocol-required placeholder
568
+ *
569
+ * @see https://docs.x402.org for protocol specification
570
+ */
571
+ DUMMY_FEE_PAYER = "11111111111111111111111111111111";
572
+ /**
573
+ * Get supported payment kinds
574
+ * Returns x402 v2 compatible response with CAIP-2 network identifiers
575
+ *
576
+ * NOTE: The feePayer in extra.feePayer is a placeholder only.
577
+ * In self-sovereign mode, users pay their own transaction fees.
578
+ */
579
+ async getSupported(_extensionKeys = []) {
580
+ const supported = {
581
+ kinds: [
582
+ {
583
+ x402Version: 2,
584
+ scheme: "exact",
585
+ network: this.NETWORKS.DEVNET,
586
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
587
+ },
588
+ {
589
+ x402Version: 2,
590
+ scheme: "exact",
591
+ network: this.NETWORKS.MAINNET,
592
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
593
+ }
594
+ ],
595
+ extensions: [],
596
+ signers: {
597
+ // Placeholder - in self-sovereign mode, users are their own signers
598
+ "solana:*": [this.DUMMY_FEE_PAYER]
599
+ }
600
+ };
601
+ return supported;
602
+ }
603
+ /**
604
+ * Get mechanism-specific extra data
605
+ */
606
+ getExtra(_network) {
607
+ return void 0;
608
+ }
609
+ /**
610
+ * Get default signers (not used for local verification usually, but required by interface)
611
+ */
612
+ getSigners(_network) {
613
+ return [];
614
+ }
615
+ /**
616
+ * Enable debug logging (disable in production)
617
+ */
618
+ debug = process.env.NODE_ENV === "development";
619
+ /**
620
+ * Verify a payment on-chain
621
+ */
622
+ async verify(payload, requirements) {
623
+ try {
624
+ const signature = payload.payload.signature;
625
+ if (!signature) {
626
+ return { isValid: false, invalidReason: "Missing signature in payment payload" };
627
+ }
628
+ const payTo = requirements.payTo;
629
+ const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
630
+ const requiredAmount = BigInt(amountVal);
631
+ if (this.debug) {
632
+ console.log(`[LocalSvmFacilitator] Verifying tx: ${signature.slice(0, 8)}...`);
633
+ }
634
+ const tx = await this.fetchTransactionWithRetry(signature, 3);
635
+ if (!tx) {
636
+ return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
637
+ }
638
+ const instructions = tx.transaction.message.instructions;
639
+ let paidAmount = 0n;
640
+ let payer = void 0;
641
+ for (const ix of instructions) {
642
+ if ("program" in ix && ix.program === "system") {
643
+ const parsed = ix.parsed;
644
+ if (parsed?.type === "transfer" && parsed.info?.destination === payTo) {
645
+ paidAmount += BigInt(parsed.info.lamports);
646
+ if (!payer) payer = parsed.info.source;
647
+ }
648
+ }
649
+ if ("program" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
650
+ const parsed = ix.parsed;
651
+ if (parsed?.type === "transferChecked" || parsed?.type === "transfer") {
652
+ if (this.debug) {
653
+ console.log(`[LocalSvmFacilitator] Found SPL transfer`);
654
+ }
655
+ }
656
+ }
657
+ }
658
+ if (paidAmount >= requiredAmount) {
659
+ if (this.debug) {
660
+ console.log(`[LocalSvmFacilitator] Verification SUCCESS for tx: ${signature.slice(0, 8)}...`);
661
+ }
662
+ return {
663
+ isValid: true,
664
+ payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
665
+ };
666
+ }
667
+ return {
668
+ isValid: false,
669
+ invalidReason: "Insufficient payment amount",
670
+ payer
671
+ };
672
+ } catch (error) {
673
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
674
+ if (this.debug) {
675
+ console.error("[LocalSvmFacilitator] Verify error:", errorMessage);
676
+ }
677
+ throw new VerifyError(500, {
678
+ isValid: false,
679
+ invalidReason: errorMessage
680
+ });
681
+ }
682
+ }
683
+ /**
684
+ * Fetch transaction with exponential backoff retry
685
+ */
686
+ async fetchTransactionWithRetry(signature, maxRetries = 3) {
687
+ let lastError;
688
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
689
+ try {
690
+ const tx = await this.connection.getParsedTransaction(signature, {
691
+ maxSupportedTransactionVersion: 0,
692
+ commitment: "confirmed"
693
+ });
694
+ if (tx) return tx;
695
+ if (attempt < maxRetries - 1) {
696
+ await this.sleep(Math.pow(2, attempt) * 1e3);
697
+ }
698
+ } catch (error) {
699
+ lastError = error instanceof Error ? error : new Error("RPC error");
700
+ if (attempt < maxRetries - 1) {
701
+ await this.sleep(Math.pow(2, attempt) * 1e3);
702
+ }
703
+ }
704
+ }
705
+ if (lastError) throw lastError;
706
+ return null;
707
+ }
708
+ /**
709
+ * Sleep helper
710
+ */
711
+ sleep(ms) {
712
+ return new Promise((resolve) => setTimeout(resolve, ms));
713
+ }
714
+ /**
715
+ * Settle a payment (not applicable for direct chain verification, usually)
716
+ * But we must implement it. For 'exact', settlement is just verification + finality.
717
+ */
718
+ async settle(payload, requirements) {
719
+ const verifyResult = await this.verify(payload, requirements);
720
+ if (!verifyResult.isValid) {
721
+ throw new SettleError(400, {
722
+ success: false,
723
+ errorReason: verifyResult.invalidReason || "Verification failed",
724
+ transaction: payload.payload.signature,
725
+ network: requirements.network
726
+ });
727
+ }
728
+ return {
729
+ success: true,
730
+ payer: verifyResult.payer,
731
+ transaction: payload.payload.signature,
732
+ network: requirements.network
733
+ };
734
+ }
735
+ };
525
736
  var DEFAULT_COMPUTE_UNITS = 2e5;
526
737
  var DEFAULT_MICRO_LAMPORTS = 1e3;
527
738
  function createPriorityFeeInstructions(config = {}) {
@@ -864,4 +1075,4 @@ async function getRemainingCredits(token, secret) {
864
1075
  };
865
1076
  }
866
1077
 
867
- export { addCredits, buildSolanaPayUrl, clearPriceCache, configurePricing, createCreditSession, createPaymentFlow, createPaymentReference, createX402AuthorizationHeader, executeAgentPayment, formatPriceDisplay, formatPriceSync, generateAgentKeypair, getAgentBalance, getProviders, getRemainingCredits, getSolPrice, hasAgentSufficientBalance, keypairFromBase58, lamportsToSol, lamportsToUsd, sendSolanaPayment, usdToLamports, useCredit, useFormatPrice, useLamportsToUsd, useMicropay, usePaywallResource, usePricing, validateCreditSession };
1078
+ export { LocalSvmFacilitator, addCredits, buildSolanaPayUrl, clearPriceCache, configurePricing, createCreditSession, createPaymentFlow, createPaymentReference, createX402AuthorizationHeader, executeAgentPayment, formatPriceDisplay, formatPriceSync, generateAgentKeypair, getAgentBalance, getProviders, getRemainingCredits, getSolPrice, hasAgentSufficientBalance, keypairFromBase58, lamportsToSol, lamportsToUsd, sendSolanaPayment, usdToLamports, useCredit, useFormatPrice, useLamportsToUsd, useMicropay, usePaywallResource, usePricing, validateCreditSession };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alleyboss/micropay-solana-x402-paywall",
3
- "version": "3.3.7",
3
+ "version": "3.3.8",
4
4
  "description": "Production-ready Solana micropayments library wrapper for official x402 SDK",
5
5
  "author": "AlleyBoss",
6
6
  "license": "MIT",