@alleyboss/micropay-solana-x402-paywall 3.3.0 → 3.3.2

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
@@ -186,6 +186,7 @@ function PaywallBanner({ priceInLamports }) {
186
186
 
187
187
  We're actively working on these exciting features:
188
188
 
189
+ ### Core Features
189
190
  | Feature | Status | Description |
190
191
  |---------|--------|-------------|
191
192
  | ⚡ **Jupiter Swap-on-Pay** | 🔜 Coming Soon | Pay with any token, auto-swap to SOL/USDC |
@@ -194,6 +195,20 @@ We're actively working on these exciting features:
194
195
  | 🌳 **Compressed NFTs** | 🔜 Planned | Scalable access tokens via cNFTs |
195
196
  | 🔄 **Payment Streaming** | 🔜 Planned | Pay-as-you-consume for APIs |
196
197
 
198
+ ### For Solana Power Users
199
+ | Feature | Status | Description |
200
+ |---------|--------|-------------|
201
+ | 🚀 **Jito Bundle Support** | 🔜 Planned | Guaranteed transaction inclusion via MEV |
202
+ | 📡 **WebSocket Confirmations** | 🔜 Planned | Real-time confirmation, no polling |
203
+ | 📋 **Lookup Tables** | 🔜 Planned | Batch payments efficiency for agents |
204
+
205
+ ### For x402 Protocol Ecosystem
206
+ | Feature | Status | Description |
207
+ |---------|--------|-------------|
208
+ | 💳 **Coinbase Commerce** | 🔜 Planned | Accept payments via Coinbase Pay |
209
+ | 🤖 **CDP Agent Wallets** | 🔜 Planned | Coinbase Developer Platform integration |
210
+ | 🔷 **Base Network Support** | 🔜 Planned | EVM x402 payments on Base L2 |
211
+
197
212
  Want to contribute or sponsor a feature? Open an issue on [GitHub](https://github.com/AlleyBo55/micropay-solana-x402-paywall)!
198
213
 
199
214
  ## 📚 Documentation
@@ -179,17 +179,29 @@ function usePaywallResource({
179
179
  const res = await fetch(url, { headers });
180
180
  if (res.status === 402) {
181
181
  const wwwAuth = res.headers.get("WWW-Authenticate");
182
+ console.log("[usePaywallResource] 402 Response. WWW-Authenticate:", wwwAuth);
182
183
  if (wwwAuth) {
183
184
  setPaymentHeader(wwwAuth);
184
185
  try {
185
- const match = wwwAuth.match(/amount="([^"]+)",\s*payTo="([^"]+)"/);
186
- if (match) {
187
- setPrice(BigInt(match[1]));
188
- setRecipient(match[2]);
186
+ const { decodePaymentRequiredHeader: decodePaymentRequiredHeader2 } = await import('@x402/core/http');
187
+ const cleanHeader = wwwAuth.replace(/^[Xx]402\s+/, "");
188
+ const decoded = decodePaymentRequiredHeader2(cleanHeader);
189
+ console.log("[usePaywallResource] Decoded header:", decoded);
190
+ const accepts = Array.isArray(decoded.accepts) ? decoded.accepts[0] : decoded.accepts;
191
+ console.log("[usePaywallResource] Accepts:", accepts);
192
+ if (accepts) {
193
+ const amountStr = accepts.amount || accepts.price || accepts.maxAmountRequired || "0";
194
+ setPrice(BigInt(amountStr));
195
+ setRecipient(accepts.payTo);
196
+ console.log("[usePaywallResource] Set price:", amountStr, "recipient:", accepts.payTo);
197
+ } else {
198
+ console.warn("[usePaywallResource] No accepts found in header");
189
199
  }
190
200
  } catch (e) {
191
- console.warn("Failed to parse 402 details from header", e);
201
+ console.warn("[usePaywallResource] Failed to parse x402 header:", e);
192
202
  }
203
+ } else {
204
+ console.warn("[usePaywallResource] 402 response missing WWW-Authenticate header");
193
205
  }
194
206
  setIsLocked(true);
195
207
  setData(null);
@@ -177,17 +177,29 @@ function usePaywallResource({
177
177
  const res = await fetch(url, { headers });
178
178
  if (res.status === 402) {
179
179
  const wwwAuth = res.headers.get("WWW-Authenticate");
180
+ console.log("[usePaywallResource] 402 Response. WWW-Authenticate:", wwwAuth);
180
181
  if (wwwAuth) {
181
182
  setPaymentHeader(wwwAuth);
182
183
  try {
183
- const match = wwwAuth.match(/amount="([^"]+)",\s*payTo="([^"]+)"/);
184
- if (match) {
185
- setPrice(BigInt(match[1]));
186
- setRecipient(match[2]);
184
+ const { decodePaymentRequiredHeader: decodePaymentRequiredHeader2 } = await import('@x402/core/http');
185
+ const cleanHeader = wwwAuth.replace(/^[Xx]402\s+/, "");
186
+ const decoded = decodePaymentRequiredHeader2(cleanHeader);
187
+ console.log("[usePaywallResource] Decoded header:", decoded);
188
+ const accepts = Array.isArray(decoded.accepts) ? decoded.accepts[0] : decoded.accepts;
189
+ console.log("[usePaywallResource] Accepts:", accepts);
190
+ if (accepts) {
191
+ const amountStr = accepts.amount || accepts.price || accepts.maxAmountRequired || "0";
192
+ setPrice(BigInt(amountStr));
193
+ setRecipient(accepts.payTo);
194
+ console.log("[usePaywallResource] Set price:", amountStr, "recipient:", accepts.payTo);
195
+ } else {
196
+ console.warn("[usePaywallResource] No accepts found in header");
187
197
  }
188
198
  } catch (e) {
189
- console.warn("Failed to parse 402 details from header", e);
199
+ console.warn("[usePaywallResource] Failed to parse x402 header:", e);
190
200
  }
201
+ } else {
202
+ console.warn("[usePaywallResource] 402 response missing WWW-Authenticate header");
191
203
  }
192
204
  setIsLocked(true);
193
205
  setData(null);
package/dist/index.cjs CHANGED
@@ -191,17 +191,29 @@ function usePaywallResource({
191
191
  const res = await fetch(url, { headers });
192
192
  if (res.status === 402) {
193
193
  const wwwAuth = res.headers.get("WWW-Authenticate");
194
+ console.log("[usePaywallResource] 402 Response. WWW-Authenticate:", wwwAuth);
194
195
  if (wwwAuth) {
195
196
  setPaymentHeader(wwwAuth);
196
197
  try {
197
- const match = wwwAuth.match(/amount="([^"]+)",\s*payTo="([^"]+)"/);
198
- if (match) {
199
- setPrice(BigInt(match[1]));
200
- setRecipient(match[2]);
198
+ const { decodePaymentRequiredHeader: decodePaymentRequiredHeader2 } = await import('@x402/core/http');
199
+ const cleanHeader = wwwAuth.replace(/^[Xx]402\s+/, "");
200
+ const decoded = decodePaymentRequiredHeader2(cleanHeader);
201
+ console.log("[usePaywallResource] Decoded header:", decoded);
202
+ const accepts = Array.isArray(decoded.accepts) ? decoded.accepts[0] : decoded.accepts;
203
+ console.log("[usePaywallResource] Accepts:", accepts);
204
+ if (accepts) {
205
+ const amountStr = accepts.amount || accepts.price || accepts.maxAmountRequired || "0";
206
+ setPrice(BigInt(amountStr));
207
+ setRecipient(accepts.payTo);
208
+ console.log("[usePaywallResource] Set price:", amountStr, "recipient:", accepts.payTo);
209
+ } else {
210
+ console.warn("[usePaywallResource] No accepts found in header");
201
211
  }
202
212
  } catch (e) {
203
- console.warn("Failed to parse 402 details from header", e);
213
+ console.warn("[usePaywallResource] Failed to parse x402 header:", e);
204
214
  }
215
+ } else {
216
+ console.warn("[usePaywallResource] 402 response missing WWW-Authenticate header");
205
217
  }
206
218
  setIsLocked(true);
207
219
  setData(null);
package/dist/index.js CHANGED
@@ -185,17 +185,29 @@ function usePaywallResource({
185
185
  const res = await fetch(url, { headers });
186
186
  if (res.status === 402) {
187
187
  const wwwAuth = res.headers.get("WWW-Authenticate");
188
+ console.log("[usePaywallResource] 402 Response. WWW-Authenticate:", wwwAuth);
188
189
  if (wwwAuth) {
189
190
  setPaymentHeader(wwwAuth);
190
191
  try {
191
- const match = wwwAuth.match(/amount="([^"]+)",\s*payTo="([^"]+)"/);
192
- if (match) {
193
- setPrice(BigInt(match[1]));
194
- setRecipient(match[2]);
192
+ const { decodePaymentRequiredHeader: decodePaymentRequiredHeader2 } = await import('@x402/core/http');
193
+ const cleanHeader = wwwAuth.replace(/^[Xx]402\s+/, "");
194
+ const decoded = decodePaymentRequiredHeader2(cleanHeader);
195
+ console.log("[usePaywallResource] Decoded header:", decoded);
196
+ const accepts = Array.isArray(decoded.accepts) ? decoded.accepts[0] : decoded.accepts;
197
+ console.log("[usePaywallResource] Accepts:", accepts);
198
+ if (accepts) {
199
+ const amountStr = accepts.amount || accepts.price || accepts.maxAmountRequired || "0";
200
+ setPrice(BigInt(amountStr));
201
+ setRecipient(accepts.payTo);
202
+ console.log("[usePaywallResource] Set price:", amountStr, "recipient:", accepts.payTo);
203
+ } else {
204
+ console.warn("[usePaywallResource] No accepts found in header");
195
205
  }
196
206
  } catch (e) {
197
- console.warn("Failed to parse 402 details from header", e);
207
+ console.warn("[usePaywallResource] Failed to parse x402 header:", e);
198
208
  }
209
+ } else {
210
+ console.warn("[usePaywallResource] 402 response missing WWW-Authenticate header");
199
211
  }
200
212
  setIsLocked(true);
201
213
  setData(null);
@@ -20,20 +20,48 @@ var LocalSvmFacilitator = class {
20
20
  * Get supported payment kinds
21
21
  * Mocking the response of the /supported endpoint
22
22
  */
23
- // Network Constants - CAIP-2 format for x402 v2
23
+ /**
24
+ * Network Constants - CAIP-2 format for x402 v2
25
+ * These match the official Solana chain IDs used by x402 protocol
26
+ */
24
27
  NETWORKS = {
25
28
  DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
26
29
  MAINNET: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
27
30
  };
28
- // Dummy fee payer address (System Program) - not used in local verification
29
- // but required by x402 protocol for supported kinds
31
+ /**
32
+ * DUMMY_FEE_PAYER Explanation (for auditors):
33
+ *
34
+ * In a HOSTED facilitator (like x402.org), the `feePayer` field in the
35
+ * SupportedResponse.extra specifies which address will pay transaction fees
36
+ * when the facilitator submits transactions on behalf of users.
37
+ *
38
+ * In LOCAL/SELF-SOVEREIGN mode (this implementation):
39
+ * - The USER pays their own transaction fees directly
40
+ * - The facilitator NEVER submits transactions - it only VERIFIES them
41
+ * - Therefore, no fee payer address is actually used
42
+ *
43
+ * However, the x402 protocol REQUIRES this field in the response schema.
44
+ * We use the System Program address (all 1s) as a placeholder because:
45
+ * 1. It's clearly not a real wallet (obvious placeholder)
46
+ * 2. It cannot receive funds or sign transactions
47
+ * 3. It signals to developers that fee paying is handled differently
48
+ *
49
+ * SECURITY NOTE: This is NOT a security risk because:
50
+ * - The fee payer is never used in verify() or settle() methods
51
+ * - Users sign and pay for their own transactions
52
+ * - The address is just a protocol-required placeholder
53
+ *
54
+ * @see https://docs.x402.org for protocol specification
55
+ */
30
56
  DUMMY_FEE_PAYER = "11111111111111111111111111111111";
31
57
  /**
32
58
  * Get supported payment kinds
33
59
  * Returns x402 v2 compatible response with CAIP-2 network identifiers
60
+ *
61
+ * NOTE: The feePayer in extra.feePayer is a placeholder only.
62
+ * In self-sovereign mode, users pay their own transaction fees.
34
63
  */
35
64
  async getSupported(_extensionKeys = []) {
36
- console.log("[LocalSvmFacilitator] getSupported called");
37
65
  const supported = {
38
66
  kinds: [
39
67
  {
@@ -51,10 +79,10 @@ var LocalSvmFacilitator = class {
51
79
  ],
52
80
  extensions: [],
53
81
  signers: {
82
+ // Placeholder - in self-sovereign mode, users are their own signers
54
83
  "solana:*": [this.DUMMY_FEE_PAYER]
55
84
  }
56
85
  };
57
- console.log("[LocalSvmFacilitator] Returning supported:", JSON.stringify(supported));
58
86
  return supported;
59
87
  }
60
88
  /**
@@ -19,20 +19,48 @@ var LocalSvmFacilitator = class {
19
19
  * Get supported payment kinds
20
20
  * Mocking the response of the /supported endpoint
21
21
  */
22
- // Network Constants - CAIP-2 format for x402 v2
22
+ /**
23
+ * Network Constants - CAIP-2 format for x402 v2
24
+ * These match the official Solana chain IDs used by x402 protocol
25
+ */
23
26
  NETWORKS = {
24
27
  DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
25
28
  MAINNET: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
26
29
  };
27
- // Dummy fee payer address (System Program) - not used in local verification
28
- // but required by x402 protocol for supported kinds
30
+ /**
31
+ * DUMMY_FEE_PAYER Explanation (for auditors):
32
+ *
33
+ * In a HOSTED facilitator (like x402.org), the `feePayer` field in the
34
+ * SupportedResponse.extra specifies which address will pay transaction fees
35
+ * when the facilitator submits transactions on behalf of users.
36
+ *
37
+ * In LOCAL/SELF-SOVEREIGN mode (this implementation):
38
+ * - The USER pays their own transaction fees directly
39
+ * - The facilitator NEVER submits transactions - it only VERIFIES them
40
+ * - Therefore, no fee payer address is actually used
41
+ *
42
+ * However, the x402 protocol REQUIRES this field in the response schema.
43
+ * We use the System Program address (all 1s) as a placeholder because:
44
+ * 1. It's clearly not a real wallet (obvious placeholder)
45
+ * 2. It cannot receive funds or sign transactions
46
+ * 3. It signals to developers that fee paying is handled differently
47
+ *
48
+ * SECURITY NOTE: This is NOT a security risk because:
49
+ * - The fee payer is never used in verify() or settle() methods
50
+ * - Users sign and pay for their own transactions
51
+ * - The address is just a protocol-required placeholder
52
+ *
53
+ * @see https://docs.x402.org for protocol specification
54
+ */
29
55
  DUMMY_FEE_PAYER = "11111111111111111111111111111111";
30
56
  /**
31
57
  * Get supported payment kinds
32
58
  * Returns x402 v2 compatible response with CAIP-2 network identifiers
59
+ *
60
+ * NOTE: The feePayer in extra.feePayer is a placeholder only.
61
+ * In self-sovereign mode, users pay their own transaction fees.
33
62
  */
34
63
  async getSupported(_extensionKeys = []) {
35
- console.log("[LocalSvmFacilitator] getSupported called");
36
64
  const supported = {
37
65
  kinds: [
38
66
  {
@@ -50,10 +78,10 @@ var LocalSvmFacilitator = class {
50
78
  ],
51
79
  extensions: [],
52
80
  signers: {
81
+ // Placeholder - in self-sovereign mode, users are their own signers
53
82
  "solana:*": [this.DUMMY_FEE_PAYER]
54
83
  }
55
84
  };
56
- console.log("[LocalSvmFacilitator] Returning supported:", JSON.stringify(supported));
57
85
  return supported;
58
86
  }
59
87
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alleyboss/micropay-solana-x402-paywall",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "description": "Production-ready Solana micropayments library wrapper for official x402 SDK",
5
5
  "author": "AlleyBoss",
6
6
  "license": "MIT",