@alleyboss/micropay-solana-x402-paywall 3.0.6 → 3.1.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 CHANGED
@@ -106,6 +106,22 @@ import { createSession, validateSession } from '@alleyboss/micropay-solana-x402-
106
106
  import { createPaymentFlow } from '@alleyboss/micropay-solana-x402-paywall/client';
107
107
  ```
108
108
 
109
+ ## 🛡️ Self-Sovereign Verification (New in v3.1)
110
+
111
+ By default, the library uses the `x402.org` hosted facilitator for convenience. However, you can opt for **Self-Sovereign Mode** to verify payments directly against your own Solana RPC node, removing reliance on any external API services.
112
+
113
+ ```typescript
114
+ // app/api/articles/[id]/route.ts
115
+ const withMicropay = createX402Middleware({
116
+ walletAddress: 'YOUR_WALLET',
117
+ network: 'devnet',
118
+ price: '1000000',
119
+ // ⚡️ Enable Self-Sovereign Mode
120
+ // The library will verify transactions locally using this RPC connection.
121
+ rpcUrl: process.env.NEXT_PUBLIC_RPC_URL
122
+ });
123
+ ```
124
+
109
125
  ## 🤖 AI Agent Payments
110
126
 
111
127
  Enable autonomous AI agents to pay for premium API access.
@@ -4,15 +4,146 @@ var next = require('@x402/next');
4
4
  var server = require('@x402/core/server');
5
5
  var http = require('@x402/core/http');
6
6
  var server$1 = require('@x402/svm/exact/server');
7
+ var web3_js = require('@solana/web3.js');
8
+ var types = require('@x402/core/types');
9
+
10
+ // src/next/index.ts
11
+ var LocalSvmFacilitator = class {
12
+ scheme = "exact";
13
+ caipFamily = "solana:*";
14
+ connection;
15
+ constructor(rpcUrl) {
16
+ this.connection = new web3_js.Connection(rpcUrl, "confirmed");
17
+ }
18
+ /**
19
+ * Get supported payment kinds
20
+ * Mocking the response of the /supported endpoint
21
+ */
22
+ async getSupported(extensionKeys = []) {
23
+ return {
24
+ kinds: [
25
+ {
26
+ x402Version: 1,
27
+ scheme: "exact",
28
+ network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
29
+ // Devnet
30
+ extra: {}
31
+ },
32
+ {
33
+ x402Version: 1,
34
+ scheme: "exact",
35
+ network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
36
+ // Mainnet
37
+ extra: {}
38
+ }
39
+ ],
40
+ extensions: [],
41
+ signers: {
42
+ "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": [],
43
+ "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": []
44
+ }
45
+ };
46
+ }
47
+ /**
48
+ * Get mechanism-specific extra data
49
+ */
50
+ getExtra(network) {
51
+ return void 0;
52
+ }
53
+ /**
54
+ * Get default signers (not used for local verification usually, but required by interface)
55
+ */
56
+ getSigners(network) {
57
+ return [];
58
+ }
59
+ /**
60
+ * Verify a payment on-chain
61
+ */
62
+ async verify(payload, requirements) {
63
+ try {
64
+ const signature = payload.payload.signature;
65
+ if (!signature) {
66
+ return { isValid: false, invalidReason: "Missing signature in payment payload" };
67
+ }
68
+ const tx = await this.connection.getParsedTransaction(signature, {
69
+ maxSupportedTransactionVersion: 0,
70
+ commitment: "confirmed"
71
+ });
72
+ if (!tx) {
73
+ return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
74
+ }
75
+ const payTo = requirements.payTo;
76
+ const requiredAmount = BigInt(requirements.amount);
77
+ const instructions = tx.transaction.message.instructions;
78
+ let paidAmount = 0n;
79
+ let payer = void 0;
80
+ for (const ix of instructions) {
81
+ if ("program" in ix && ix.program === "system") {
82
+ const parsed = ix.parsed;
83
+ if (parsed.type === "transfer") {
84
+ const info = parsed.info;
85
+ if (info.destination === payTo) {
86
+ paidAmount += BigInt(info.lamports);
87
+ if (!payer) payer = info.source;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ if (paidAmount >= requiredAmount) {
93
+ return {
94
+ isValid: true,
95
+ payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
96
+ };
97
+ }
98
+ return {
99
+ isValid: false,
100
+ invalidReason: `Insufficient payment. Required: ${requiredAmount}, Found: ${paidAmount}`,
101
+ payer
102
+ };
103
+ } catch (error) {
104
+ console.error("[LocalSvmFacilitator] Verify error:", error);
105
+ throw new types.VerifyError(500, {
106
+ isValid: false,
107
+ invalidReason: error.message
108
+ });
109
+ }
110
+ }
111
+ /**
112
+ * Settle a payment (not applicable for direct chain verification, usually)
113
+ * But we must implement it. For 'exact', settlement is just verification + finality.
114
+ */
115
+ async settle(payload, requirements) {
116
+ const verifyResult = await this.verify(payload, requirements);
117
+ if (!verifyResult.isValid) {
118
+ throw new types.SettleError(400, {
119
+ success: false,
120
+ errorReason: verifyResult.invalidReason || "Verification failed",
121
+ transaction: payload.payload.signature,
122
+ network: requirements.network
123
+ });
124
+ }
125
+ return {
126
+ success: true,
127
+ payer: verifyResult.payer,
128
+ transaction: payload.payload.signature,
129
+ network: requirements.network
130
+ };
131
+ }
132
+ };
7
133
 
8
134
  // src/next/index.ts
9
135
  function createX402Middleware(config) {
10
- const facilitatorUrl = config.facilitatorUrl || "https://x402.org/facilitator";
11
- const client = new http.HTTPFacilitatorClient({
12
- url: facilitatorUrl
13
- });
14
- const server$2 = new server.x402ResourceServer(client);
15
- server$1.registerExactSvmScheme(server$2, {});
136
+ let facilitatorClient;
137
+ if (config.rpcUrl) {
138
+ facilitatorClient = new LocalSvmFacilitator(config.rpcUrl);
139
+ } else {
140
+ const facilitatorUrl = config.facilitatorUrl || "https://x402.org/facilitator";
141
+ facilitatorClient = new http.HTTPFacilitatorClient({
142
+ url: facilitatorUrl
143
+ });
144
+ }
145
+ const server$2 = new server.x402ResourceServer(facilitatorClient);
146
+ server$1.registerExactSvmScheme(server$2);
16
147
  return function withMicropay(handler, routeConfig) {
17
148
  const finalConfig = routeConfig || {
18
149
  accepts: {
@@ -14,6 +14,8 @@ interface X402Config {
14
14
  price?: string | number;
15
15
  /** Network (mainnet-beta or devnet) */
16
16
  network?: 'mainnet-beta' | 'devnet';
17
+ /** RPC URL for local verification (optional, enables self-contained validation) */
18
+ rpcUrl?: string;
17
19
  }
18
20
  /**
19
21
  * Create a specialized Next.js middleware with Solana support pre-configured
@@ -14,6 +14,8 @@ interface X402Config {
14
14
  price?: string | number;
15
15
  /** Network (mainnet-beta or devnet) */
16
16
  network?: 'mainnet-beta' | 'devnet';
17
+ /** RPC URL for local verification (optional, enables self-contained validation) */
18
+ rpcUrl?: string;
17
19
  }
18
20
  /**
19
21
  * Create a specialized Next.js middleware with Solana support pre-configured
@@ -3,15 +3,146 @@ import { x402ResourceServer } from '@x402/core/server';
3
3
  export { x402ResourceServer } from '@x402/core/server';
4
4
  import { HTTPFacilitatorClient } from '@x402/core/http';
5
5
  import { registerExactSvmScheme } from '@x402/svm/exact/server';
6
+ import { Connection } from '@solana/web3.js';
7
+ import { VerifyError, SettleError } from '@x402/core/types';
8
+
9
+ // src/next/index.ts
10
+ var LocalSvmFacilitator = class {
11
+ scheme = "exact";
12
+ caipFamily = "solana:*";
13
+ connection;
14
+ constructor(rpcUrl) {
15
+ this.connection = new Connection(rpcUrl, "confirmed");
16
+ }
17
+ /**
18
+ * Get supported payment kinds
19
+ * Mocking the response of the /supported endpoint
20
+ */
21
+ async getSupported(extensionKeys = []) {
22
+ return {
23
+ kinds: [
24
+ {
25
+ x402Version: 1,
26
+ scheme: "exact",
27
+ network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
28
+ // Devnet
29
+ extra: {}
30
+ },
31
+ {
32
+ x402Version: 1,
33
+ scheme: "exact",
34
+ network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
35
+ // Mainnet
36
+ extra: {}
37
+ }
38
+ ],
39
+ extensions: [],
40
+ signers: {
41
+ "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": [],
42
+ "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": []
43
+ }
44
+ };
45
+ }
46
+ /**
47
+ * Get mechanism-specific extra data
48
+ */
49
+ getExtra(network) {
50
+ return void 0;
51
+ }
52
+ /**
53
+ * Get default signers (not used for local verification usually, but required by interface)
54
+ */
55
+ getSigners(network) {
56
+ return [];
57
+ }
58
+ /**
59
+ * Verify a payment on-chain
60
+ */
61
+ async verify(payload, requirements) {
62
+ try {
63
+ const signature = payload.payload.signature;
64
+ if (!signature) {
65
+ return { isValid: false, invalidReason: "Missing signature in payment payload" };
66
+ }
67
+ const tx = await this.connection.getParsedTransaction(signature, {
68
+ maxSupportedTransactionVersion: 0,
69
+ commitment: "confirmed"
70
+ });
71
+ if (!tx) {
72
+ return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
73
+ }
74
+ const payTo = requirements.payTo;
75
+ const requiredAmount = BigInt(requirements.amount);
76
+ const instructions = tx.transaction.message.instructions;
77
+ let paidAmount = 0n;
78
+ let payer = void 0;
79
+ for (const ix of instructions) {
80
+ if ("program" in ix && ix.program === "system") {
81
+ const parsed = ix.parsed;
82
+ if (parsed.type === "transfer") {
83
+ const info = parsed.info;
84
+ if (info.destination === payTo) {
85
+ paidAmount += BigInt(info.lamports);
86
+ if (!payer) payer = info.source;
87
+ }
88
+ }
89
+ }
90
+ }
91
+ if (paidAmount >= requiredAmount) {
92
+ return {
93
+ isValid: true,
94
+ payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
95
+ };
96
+ }
97
+ return {
98
+ isValid: false,
99
+ invalidReason: `Insufficient payment. Required: ${requiredAmount}, Found: ${paidAmount}`,
100
+ payer
101
+ };
102
+ } catch (error) {
103
+ console.error("[LocalSvmFacilitator] Verify error:", error);
104
+ throw new VerifyError(500, {
105
+ isValid: false,
106
+ invalidReason: error.message
107
+ });
108
+ }
109
+ }
110
+ /**
111
+ * Settle a payment (not applicable for direct chain verification, usually)
112
+ * But we must implement it. For 'exact', settlement is just verification + finality.
113
+ */
114
+ async settle(payload, requirements) {
115
+ const verifyResult = await this.verify(payload, requirements);
116
+ if (!verifyResult.isValid) {
117
+ throw new SettleError(400, {
118
+ success: false,
119
+ errorReason: verifyResult.invalidReason || "Verification failed",
120
+ transaction: payload.payload.signature,
121
+ network: requirements.network
122
+ });
123
+ }
124
+ return {
125
+ success: true,
126
+ payer: verifyResult.payer,
127
+ transaction: payload.payload.signature,
128
+ network: requirements.network
129
+ };
130
+ }
131
+ };
6
132
 
7
133
  // src/next/index.ts
8
134
  function createX402Middleware(config) {
9
- const facilitatorUrl = config.facilitatorUrl || "https://x402.org/facilitator";
10
- const client = new HTTPFacilitatorClient({
11
- url: facilitatorUrl
12
- });
13
- const server = new x402ResourceServer(client);
14
- registerExactSvmScheme(server, {});
135
+ let facilitatorClient;
136
+ if (config.rpcUrl) {
137
+ facilitatorClient = new LocalSvmFacilitator(config.rpcUrl);
138
+ } else {
139
+ const facilitatorUrl = config.facilitatorUrl || "https://x402.org/facilitator";
140
+ facilitatorClient = new HTTPFacilitatorClient({
141
+ url: facilitatorUrl
142
+ });
143
+ }
144
+ const server = new x402ResourceServer(facilitatorClient);
145
+ registerExactSvmScheme(server);
15
146
  return function withMicropay(handler, routeConfig) {
16
147
  const finalConfig = routeConfig || {
17
148
  accepts: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alleyboss/micropay-solana-x402-paywall",
3
- "version": "3.0.6",
3
+ "version": "3.1.0",
4
4
  "description": "Production-ready Solana micropayments library wrapper for official x402 SDK",
5
5
  "author": "AlleyBoss",
6
6
  "license": "MIT",