@alleyboss/micropay-solana-x402-paywall 2.0.1 β 2.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 +96 -111
- package/dist/client-Blkcv17a.d.cts +63 -0
- package/dist/client-xhJSoeOH.d.ts +63 -0
- package/dist/index.cjs +142 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +136 -6
- package/dist/index.js.map +1 -1
- package/dist/solana/index.cjs +142 -4
- package/dist/solana/index.cjs.map +1 -1
- package/dist/solana/index.d.cts +113 -4
- package/dist/solana/index.d.ts +113 -4
- package/dist/solana/index.js +136 -6
- package/dist/solana/index.js.map +1 -1
- package/dist/x402/index.cjs +12 -4
- package/dist/x402/index.cjs.map +1 -1
- package/dist/x402/index.d.cts +1 -1
- package/dist/x402/index.d.ts +1 -1
- package/dist/x402/index.js +13 -5
- package/dist/x402/index.js.map +1 -1
- package/package.json +12 -6
- package/dist/client-CSZHI8o8.d.ts +0 -32
- package/dist/client-vRr48m2x.d.cts +0 -32
package/README.md
CHANGED
|
@@ -1,165 +1,150 @@
|
|
|
1
1
|
# @alleyboss/micropay-solana-x402-paywall
|
|
2
2
|
|
|
3
|
-
> Production-ready Solana micropayments library implementing the x402 protocol
|
|
3
|
+
> Production-ready Solana micropayments library implementing the x402 protocol.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@alleyboss/micropay-solana-x402-paywall)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://bundlephobia.com/package/@alleyboss/micropay-solana-x402-paywall)
|
|
7
8
|
|
|
8
|
-
##
|
|
9
|
+
## π What It Does
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
- β‘ **Solana Native** β Fast, low-cost SOL & USDC micropayments
|
|
12
|
-
- π **JWT Sessions** β Secure unlock tracking with anti-replay
|
|
13
|
-
- π¦ **Framework Agnostic** β Express, Next.js, Fastify ready
|
|
14
|
-
- π³ **Tree-shakeable** β Import only what you need (35KB full, 1-13KB per module)
|
|
15
|
-
- π° **SPL Tokens** β USDC, USDT, and custom token support
|
|
16
|
-
- π **Retry Logic** β Built-in resilience for RPC failures
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
11
|
+
Turn any content into paid content with **one-time micropayments** on Solana. No subscriptions, no recurring chargesβjust pay to unlock.
|
|
19
12
|
|
|
20
13
|
```bash
|
|
21
14
|
npm install @alleyboss/micropay-solana-x402-paywall @solana/web3.js
|
|
22
15
|
```
|
|
23
16
|
|
|
24
|
-
##
|
|
17
|
+
## β¨ Features
|
|
18
|
+
|
|
19
|
+
| Feature | Description |
|
|
20
|
+
|---------|-------------|
|
|
21
|
+
| π° **SOL & USDC Payments** | Native SOL and SPL tokens (USDC, USDT) |
|
|
22
|
+
| π **x402 Protocol** | HTTP 402 Payment Required standard |
|
|
23
|
+
| π **JWT Sessions** | Secure unlock tracking with anti-replay |
|
|
24
|
+
| π‘οΈ **Signature Store** | Prevent double-spend at app layer |
|
|
25
|
+
| π **Express & Next.js** | Zero-boilerplate middleware |
|
|
26
|
+
| π΅ **Price Conversion** | USDβSOL with multi-provider fallback |
|
|
27
|
+
| π³ **Tree-Shakeable** | Import only what you need |
|
|
28
|
+
| π **RPC Fallback** | Automatic failover on RPC errors |
|
|
29
|
+
| β‘ **Priority Fees** | Land transactions faster |
|
|
30
|
+
| π¦ **Versioned Tx** | Full v0 transaction support |
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
## π¦ Quick Example
|
|
27
33
|
|
|
28
34
|
```typescript
|
|
29
|
-
import { verifyPayment,
|
|
35
|
+
import { verifyPayment, createSession } from '@alleyboss/micropay-solana-x402-paywall';
|
|
30
36
|
|
|
31
|
-
//
|
|
37
|
+
// Verify on-chain payment
|
|
32
38
|
const result = await verifyPayment({
|
|
33
39
|
signature: 'tx...',
|
|
34
40
|
expectedRecipient: 'CreatorWallet',
|
|
35
41
|
expectedAmount: 10_000_000n, // 0.01 SOL
|
|
36
|
-
clientConfig: { network: 'devnet' },
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// USDC payment
|
|
40
|
-
const usdcResult = await verifySPLPayment({
|
|
41
|
-
signature: 'tx...',
|
|
42
|
-
expectedRecipient: 'CreatorWallet',
|
|
43
|
-
expectedAmount: 1_000_000n, // 1 USDC
|
|
44
|
-
asset: 'usdc',
|
|
45
42
|
clientConfig: { network: 'mainnet-beta' },
|
|
46
43
|
});
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Express Middleware (Zero Boilerplate)
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
import express from 'express';
|
|
53
|
-
import { createExpressMiddleware } from '@alleyboss/micropay-solana-x402-paywall/middleware';
|
|
54
|
-
|
|
55
|
-
const app = express();
|
|
56
|
-
|
|
57
|
-
app.use('/api/premium', createExpressMiddleware({
|
|
58
|
-
sessionSecret: process.env.SESSION_SECRET!,
|
|
59
|
-
protectedPaths: ['/**'],
|
|
60
|
-
}));
|
|
61
44
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
45
|
+
// Create session for unlocked content
|
|
46
|
+
if (result.valid) {
|
|
47
|
+
const { token } = await createSession(
|
|
48
|
+
result.from!,
|
|
49
|
+
'article-123',
|
|
50
|
+
{ secret: process.env.SESSION_SECRET!, durationHours: 24 }
|
|
51
|
+
);
|
|
52
|
+
}
|
|
65
53
|
```
|
|
66
54
|
|
|
67
|
-
|
|
55
|
+
## π§ Modules
|
|
56
|
+
|
|
57
|
+
9 tree-shakeable entry points for minimal bundle size:
|
|
68
58
|
|
|
69
59
|
```typescript
|
|
70
|
-
//
|
|
71
|
-
import {
|
|
60
|
+
// Core verification
|
|
61
|
+
import { verifyPayment, verifySPLPayment } from '@alleyboss/micropay-solana-x402-paywall/solana';
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
protectedPaths: ['/api/premium/*', '/api/content/*'],
|
|
76
|
-
});
|
|
63
|
+
// Session management
|
|
64
|
+
import { createSession, validateSession } from '@alleyboss/micropay-solana-x402-paywall/session';
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
// x402 protocol
|
|
67
|
+
import { buildPaymentRequirement } from '@alleyboss/micropay-solana-x402-paywall/x402';
|
|
80
68
|
|
|
81
|
-
|
|
69
|
+
// Express/Next.js middleware
|
|
70
|
+
import { createExpressMiddleware, createPaywallMiddleware } from '@alleyboss/micropay-solana-x402-paywall/middleware';
|
|
82
71
|
|
|
83
|
-
|
|
72
|
+
// Anti-replay signature store
|
|
84
73
|
import { createMemoryStore, createRedisStore } from '@alleyboss/micropay-solana-x402-paywall/store';
|
|
85
74
|
|
|
86
|
-
//
|
|
87
|
-
|
|
75
|
+
// Client-side helpers
|
|
76
|
+
import { createPaymentFlow, buildSolanaPayUrl } from '@alleyboss/micropay-solana-x402-paywall/client';
|
|
88
77
|
|
|
89
|
-
//
|
|
90
|
-
|
|
78
|
+
// Price conversion (4-provider rotation)
|
|
79
|
+
import { getSolPrice, formatPriceDisplay, configurePricing } from '@alleyboss/micropay-solana-x402-paywall/pricing';
|
|
91
80
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
throw new Error('Payment already used');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Mark after successful verification
|
|
98
|
-
await store.markAsUsed(signature, articleId, new Date(Date.now() + 86400000));
|
|
81
|
+
// Retry utilities
|
|
82
|
+
import { withRetry } from '@alleyboss/micropay-solana-x402-paywall/utils';
|
|
99
83
|
```
|
|
100
84
|
|
|
101
|
-
|
|
85
|
+
## π₯ New in v2.1.0
|
|
102
86
|
|
|
103
|
-
|
|
104
|
-
|
|
87
|
+
- **RPC Fallback Support** β Automatic failover on primary RPC failure (configurable, default: off)
|
|
88
|
+
- **Priority Fees** β Compute budget instructions for landing transactions faster (configurable, default: off)
|
|
89
|
+
- **Versioned Transactions** β Full v0 transaction support with lookup tables
|
|
90
|
+
- **TDD Test Suite** β Comprehensive tests with vitest (must pass before npm publish)
|
|
105
91
|
|
|
106
|
-
|
|
92
|
+
```typescript
|
|
93
|
+
// RPC Fallback configuration
|
|
94
|
+
const config = {
|
|
107
95
|
network: 'mainnet-beta',
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// Display price with USD equivalent
|
|
116
|
-
const price = await formatPriceDisplay(10_000_000n);
|
|
117
|
-
// "0.0100 SOL (~$1.50)"
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Module Exports
|
|
121
|
-
|
|
122
|
-
Import only what you need for minimal bundle size:
|
|
96
|
+
rpcUrl: 'https://primary-rpc.com',
|
|
97
|
+
enableFallback: true, // default: false
|
|
98
|
+
fallbackRpcUrls: [
|
|
99
|
+
'https://fallback1.com',
|
|
100
|
+
'https://fallback2.com',
|
|
101
|
+
],
|
|
102
|
+
};
|
|
123
103
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
| `@.../solana` | 13KB | `verifyPayment`, `verifySPLPayment`, `getConnection` |
|
|
127
|
-
| `@.../session` | 4.5KB | `createSession`, `validateSession`, `isArticleUnlocked` |
|
|
128
|
-
| `@.../x402` | 10KB | `buildPaymentRequirement`, `verifyX402Payment` |
|
|
129
|
-
| `@.../middleware` | 8KB | `createExpressMiddleware`, `createPaywallMiddleware` |
|
|
130
|
-
| `@.../store` | 2.6KB | `createMemoryStore`, `createRedisStore` |
|
|
131
|
-
| `@.../client` | 3.3KB | `createPaymentFlow`, `buildSolanaPayUrl` |
|
|
132
|
-
| `@.../pricing` | 2KB | `getSolPrice`, `formatPriceDisplay` |
|
|
133
|
-
| `@.../utils` | 1.7KB | `withRetry`, `isRetryableRPCError` |
|
|
104
|
+
// Priority fees
|
|
105
|
+
import { createPriorityFeeInstructions, estimatePriorityFee } from '@alleyboss/micropay-solana-x402-paywall/solana';
|
|
134
106
|
|
|
135
|
-
|
|
107
|
+
const instructions = createPriorityFeeInstructions({
|
|
108
|
+
enabled: true,
|
|
109
|
+
microLamports: 5000,
|
|
110
|
+
computeUnits: 200_000,
|
|
111
|
+
});
|
|
136
112
|
|
|
137
|
-
|
|
113
|
+
// Versioned transactions
|
|
114
|
+
import { buildVersionedTransaction } from '@alleyboss/micropay-solana-x402-paywall/solana';
|
|
138
115
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
PaywallMiddlewareConfig,
|
|
146
|
-
} from '@alleyboss/micropay-solana-x402-paywall';
|
|
116
|
+
const { transaction } = await buildVersionedTransaction({
|
|
117
|
+
connection,
|
|
118
|
+
payer: wallet.publicKey,
|
|
119
|
+
instructions: [transferIx],
|
|
120
|
+
priorityFee: { enabled: true },
|
|
121
|
+
});
|
|
147
122
|
```
|
|
148
123
|
|
|
149
|
-
## RPC
|
|
124
|
+
## π οΈ RPC Providers
|
|
150
125
|
|
|
151
|
-
|
|
126
|
+
Works with any Solana RPC provider:
|
|
152
127
|
|
|
153
128
|
```typescript
|
|
154
|
-
const
|
|
129
|
+
const config = {
|
|
155
130
|
network: 'mainnet-beta',
|
|
156
|
-
//
|
|
157
|
-
tatumApiKey: 'your-
|
|
158
|
-
//
|
|
159
|
-
rpcUrl: 'https://your-rpc
|
|
131
|
+
// Tatum.io
|
|
132
|
+
tatumApiKey: 'your-key',
|
|
133
|
+
// Or custom (Helius, QuickNode, etc.)
|
|
134
|
+
rpcUrl: 'https://your-rpc.com',
|
|
135
|
+
// Optional: enable fallback
|
|
136
|
+
enableFallback: true,
|
|
137
|
+
fallbackRpcUrls: ['https://backup.rpc.com'],
|
|
160
138
|
};
|
|
161
139
|
```
|
|
162
140
|
|
|
163
|
-
##
|
|
141
|
+
## π Documentation
|
|
142
|
+
|
|
143
|
+
**Full documentation, API reference, and examples:**
|
|
144
|
+
|
|
145
|
+
π **[solana-x402-paywall.vercel.app/docs](https://solana-x402-paywall.vercel.app/docs)**
|
|
146
|
+
|
|
147
|
+
## π License
|
|
164
148
|
|
|
165
149
|
MIT Β© AlleyBoss
|
|
150
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
import { S as SolanaNetwork } from './payment-CTxdtqmc.cjs';
|
|
3
|
+
|
|
4
|
+
/** Configuration for Solana client */
|
|
5
|
+
interface SolanaClientConfig {
|
|
6
|
+
/** Network to connect to */
|
|
7
|
+
network: SolanaNetwork;
|
|
8
|
+
/** Custom RPC URL (optional) */
|
|
9
|
+
rpcUrl?: string;
|
|
10
|
+
/** Tatum.io API key for RPC (optional) */
|
|
11
|
+
tatumApiKey?: string;
|
|
12
|
+
/** Enable RPC fallback on errors (default: false) */
|
|
13
|
+
enableFallback?: boolean;
|
|
14
|
+
/** Fallback RPC URLs to try on primary failure (optional) */
|
|
15
|
+
fallbackRpcUrls?: string[];
|
|
16
|
+
}
|
|
17
|
+
/** RPC connection with fallback support */
|
|
18
|
+
interface RpcConnectionWithFallback {
|
|
19
|
+
/** Primary connection */
|
|
20
|
+
connection: Connection;
|
|
21
|
+
/** Fallback connections (if configured) */
|
|
22
|
+
fallbacks: Connection[];
|
|
23
|
+
/** Whether fallback is enabled */
|
|
24
|
+
fallbackEnabled: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get or create a Solana connection
|
|
28
|
+
* Uses singleton pattern with network-aware caching
|
|
29
|
+
*/
|
|
30
|
+
declare function getConnection(config: SolanaClientConfig): Connection;
|
|
31
|
+
/**
|
|
32
|
+
* Get connection with fallback support
|
|
33
|
+
* Returns both primary and fallback connections for manual failover
|
|
34
|
+
*/
|
|
35
|
+
declare function getConnectionWithFallback(config: SolanaClientConfig): RpcConnectionWithFallback;
|
|
36
|
+
/**
|
|
37
|
+
* Execute an RPC call with automatic fallback on failure
|
|
38
|
+
* Only used when fallback is enabled in config
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const balance = await withFallback(
|
|
43
|
+
* config,
|
|
44
|
+
* (conn) => conn.getBalance(publicKey)
|
|
45
|
+
* );
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare function withFallback<T>(config: SolanaClientConfig, operation: (connection: Connection) => Promise<T>): Promise<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Reset the cached connection
|
|
51
|
+
* Useful for testing or network switching
|
|
52
|
+
*/
|
|
53
|
+
declare function resetConnection(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Check if network is mainnet
|
|
56
|
+
*/
|
|
57
|
+
declare function isMainnet(network: SolanaNetwork): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Convert Solana network to x402 network identifier
|
|
60
|
+
*/
|
|
61
|
+
declare function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet';
|
|
62
|
+
|
|
63
|
+
export { type RpcConnectionWithFallback as R, type SolanaClientConfig as S, getConnectionWithFallback as a, getConnection as g, isMainnet as i, resetConnection as r, toX402Network as t, withFallback as w };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Connection } from '@solana/web3.js';
|
|
2
|
+
import { S as SolanaNetwork } from './payment-CTxdtqmc.js';
|
|
3
|
+
|
|
4
|
+
/** Configuration for Solana client */
|
|
5
|
+
interface SolanaClientConfig {
|
|
6
|
+
/** Network to connect to */
|
|
7
|
+
network: SolanaNetwork;
|
|
8
|
+
/** Custom RPC URL (optional) */
|
|
9
|
+
rpcUrl?: string;
|
|
10
|
+
/** Tatum.io API key for RPC (optional) */
|
|
11
|
+
tatumApiKey?: string;
|
|
12
|
+
/** Enable RPC fallback on errors (default: false) */
|
|
13
|
+
enableFallback?: boolean;
|
|
14
|
+
/** Fallback RPC URLs to try on primary failure (optional) */
|
|
15
|
+
fallbackRpcUrls?: string[];
|
|
16
|
+
}
|
|
17
|
+
/** RPC connection with fallback support */
|
|
18
|
+
interface RpcConnectionWithFallback {
|
|
19
|
+
/** Primary connection */
|
|
20
|
+
connection: Connection;
|
|
21
|
+
/** Fallback connections (if configured) */
|
|
22
|
+
fallbacks: Connection[];
|
|
23
|
+
/** Whether fallback is enabled */
|
|
24
|
+
fallbackEnabled: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get or create a Solana connection
|
|
28
|
+
* Uses singleton pattern with network-aware caching
|
|
29
|
+
*/
|
|
30
|
+
declare function getConnection(config: SolanaClientConfig): Connection;
|
|
31
|
+
/**
|
|
32
|
+
* Get connection with fallback support
|
|
33
|
+
* Returns both primary and fallback connections for manual failover
|
|
34
|
+
*/
|
|
35
|
+
declare function getConnectionWithFallback(config: SolanaClientConfig): RpcConnectionWithFallback;
|
|
36
|
+
/**
|
|
37
|
+
* Execute an RPC call with automatic fallback on failure
|
|
38
|
+
* Only used when fallback is enabled in config
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const balance = await withFallback(
|
|
43
|
+
* config,
|
|
44
|
+
* (conn) => conn.getBalance(publicKey)
|
|
45
|
+
* );
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare function withFallback<T>(config: SolanaClientConfig, operation: (connection: Connection) => Promise<T>): Promise<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Reset the cached connection
|
|
51
|
+
* Useful for testing or network switching
|
|
52
|
+
*/
|
|
53
|
+
declare function resetConnection(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Check if network is mainnet
|
|
56
|
+
*/
|
|
57
|
+
declare function isMainnet(network: SolanaNetwork): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Convert Solana network to x402 network identifier
|
|
60
|
+
*/
|
|
61
|
+
declare function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet';
|
|
62
|
+
|
|
63
|
+
export { type RpcConnectionWithFallback as R, type SolanaClientConfig as S, getConnectionWithFallback as a, getConnection as g, isMainnet as i, resetConnection as r, toX402Network as t, withFallback as w };
|
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,8 @@ var TOKEN_MINTS = {
|
|
|
15
15
|
};
|
|
16
16
|
var cachedConnection = null;
|
|
17
17
|
var cachedNetwork = null;
|
|
18
|
+
var cachedFallbacks = [];
|
|
19
|
+
var cachedFallbackEnabled = false;
|
|
18
20
|
function buildRpcUrl(config2) {
|
|
19
21
|
const { network, rpcUrl, tatumApiKey } = config2;
|
|
20
22
|
if (rpcUrl) {
|
|
@@ -29,19 +31,65 @@ function buildRpcUrl(config2) {
|
|
|
29
31
|
}
|
|
30
32
|
return web3_js.clusterApiUrl(network);
|
|
31
33
|
}
|
|
34
|
+
function createConnection(rpcUrl) {
|
|
35
|
+
return new web3_js.Connection(rpcUrl, {
|
|
36
|
+
commitment: "confirmed",
|
|
37
|
+
confirmTransactionInitialTimeout: 6e4
|
|
38
|
+
});
|
|
39
|
+
}
|
|
32
40
|
function getConnection(config2) {
|
|
33
41
|
const { network } = config2;
|
|
34
42
|
if (cachedConnection && cachedNetwork === network) {
|
|
35
43
|
return cachedConnection;
|
|
36
44
|
}
|
|
37
45
|
const rpcUrl = buildRpcUrl(config2);
|
|
38
|
-
cachedConnection =
|
|
39
|
-
commitment: "confirmed",
|
|
40
|
-
confirmTransactionInitialTimeout: 6e4
|
|
41
|
-
});
|
|
46
|
+
cachedConnection = createConnection(rpcUrl);
|
|
42
47
|
cachedNetwork = network;
|
|
48
|
+
cachedFallbackEnabled = config2.enableFallback ?? false;
|
|
49
|
+
cachedFallbacks = [];
|
|
50
|
+
if (cachedFallbackEnabled && config2.fallbackRpcUrls?.length) {
|
|
51
|
+
cachedFallbacks = config2.fallbackRpcUrls.map(createConnection);
|
|
52
|
+
}
|
|
43
53
|
return cachedConnection;
|
|
44
54
|
}
|
|
55
|
+
function getConnectionWithFallback(config2) {
|
|
56
|
+
const connection = getConnection(config2);
|
|
57
|
+
return {
|
|
58
|
+
connection,
|
|
59
|
+
fallbacks: cachedFallbacks,
|
|
60
|
+
fallbackEnabled: cachedFallbackEnabled
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function withFallback(config2, operation) {
|
|
64
|
+
const { connection, fallbacks, fallbackEnabled } = getConnectionWithFallback(config2);
|
|
65
|
+
try {
|
|
66
|
+
return await operation(connection);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (!fallbackEnabled || fallbacks.length === 0) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
if (!isRetryableError(error)) {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
for (let i = 0; i < fallbacks.length; i++) {
|
|
75
|
+
try {
|
|
76
|
+
return await operation(fallbacks[i]);
|
|
77
|
+
} catch (fallbackError) {
|
|
78
|
+
if (i === fallbacks.length - 1) {
|
|
79
|
+
throw fallbackError;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function isRetryableError(error) {
|
|
87
|
+
if (error instanceof Error) {
|
|
88
|
+
const message = error.message.toLowerCase();
|
|
89
|
+
return message.includes("429") || message.includes("503") || message.includes("502") || message.includes("timeout") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("rate limit");
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
45
93
|
function resetConnection() {
|
|
46
94
|
cachedConnection = null;
|
|
47
95
|
cachedNetwork = null;
|
|
@@ -398,6 +446,88 @@ async function verifySPLPayment(params) {
|
|
|
398
446
|
function isNativeAsset(asset) {
|
|
399
447
|
return asset === "native";
|
|
400
448
|
}
|
|
449
|
+
var DEFAULT_COMPUTE_UNITS = 2e5;
|
|
450
|
+
var DEFAULT_MICRO_LAMPORTS = 1e3;
|
|
451
|
+
function createPriorityFeeInstructions(config2 = {}) {
|
|
452
|
+
const { enabled = false, microLamports, computeUnits } = config2;
|
|
453
|
+
if (!enabled) {
|
|
454
|
+
return [];
|
|
455
|
+
}
|
|
456
|
+
const instructions = [];
|
|
457
|
+
const units = computeUnits ?? DEFAULT_COMPUTE_UNITS;
|
|
458
|
+
instructions.push(web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units }));
|
|
459
|
+
const price = microLamports ?? DEFAULT_MICRO_LAMPORTS;
|
|
460
|
+
instructions.push(web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: price }));
|
|
461
|
+
return instructions;
|
|
462
|
+
}
|
|
463
|
+
async function estimatePriorityFee(connection, accounts = []) {
|
|
464
|
+
try {
|
|
465
|
+
const fees = await connection.getRecentPrioritizationFees({
|
|
466
|
+
lockedWritableAccounts: accounts
|
|
467
|
+
});
|
|
468
|
+
if (fees.length === 0) {
|
|
469
|
+
return DEFAULT_MICRO_LAMPORTS;
|
|
470
|
+
}
|
|
471
|
+
const sortedFees = fees.map((f) => f.prioritizationFee).filter((f) => f > 0).sort((a, b) => a - b);
|
|
472
|
+
if (sortedFees.length === 0) {
|
|
473
|
+
return DEFAULT_MICRO_LAMPORTS;
|
|
474
|
+
}
|
|
475
|
+
const medianIndex = Math.floor(sortedFees.length / 2);
|
|
476
|
+
return sortedFees[medianIndex];
|
|
477
|
+
} catch {
|
|
478
|
+
return DEFAULT_MICRO_LAMPORTS;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function calculatePriorityFeeCost(microLamportsPerCU, computeUnits) {
|
|
482
|
+
return Math.ceil(microLamportsPerCU * computeUnits / 1e6);
|
|
483
|
+
}
|
|
484
|
+
async function buildVersionedTransaction(config2) {
|
|
485
|
+
const {
|
|
486
|
+
connection,
|
|
487
|
+
payer,
|
|
488
|
+
instructions,
|
|
489
|
+
lookupTables = [],
|
|
490
|
+
priorityFee,
|
|
491
|
+
recentBlockhash
|
|
492
|
+
} = config2;
|
|
493
|
+
const priorityIxs = createPriorityFeeInstructions(priorityFee);
|
|
494
|
+
const allInstructions = [...priorityIxs, ...instructions];
|
|
495
|
+
let blockhash;
|
|
496
|
+
let lastValidBlockHeight;
|
|
497
|
+
if (recentBlockhash) {
|
|
498
|
+
blockhash = recentBlockhash;
|
|
499
|
+
const slot = await connection.getSlot();
|
|
500
|
+
lastValidBlockHeight = slot + 150;
|
|
501
|
+
} else {
|
|
502
|
+
const latestBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
503
|
+
blockhash = latestBlockhash.blockhash;
|
|
504
|
+
lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
505
|
+
}
|
|
506
|
+
const message = new web3_js.TransactionMessage({
|
|
507
|
+
payerKey: payer,
|
|
508
|
+
recentBlockhash: blockhash,
|
|
509
|
+
instructions: allInstructions
|
|
510
|
+
}).compileToV0Message(lookupTables);
|
|
511
|
+
const transaction = new web3_js.VersionedTransaction(message);
|
|
512
|
+
return {
|
|
513
|
+
transaction,
|
|
514
|
+
blockhash,
|
|
515
|
+
lastValidBlockHeight
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
async function fetchLookupTables(connection, addresses) {
|
|
519
|
+
const tables = [];
|
|
520
|
+
for (const address of addresses) {
|
|
521
|
+
const result = await connection.getAddressLookupTable(address);
|
|
522
|
+
if (result.value) {
|
|
523
|
+
tables.push(result.value);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return tables;
|
|
527
|
+
}
|
|
528
|
+
function isVersionedTransaction(tx) {
|
|
529
|
+
return tx instanceof web3_js.VersionedTransaction;
|
|
530
|
+
}
|
|
401
531
|
var MAX_ARTICLES_PER_SESSION = 100;
|
|
402
532
|
var MIN_SECRET_LENGTH = 32;
|
|
403
533
|
function getSecretKey(secret) {
|
|
@@ -1177,6 +1307,8 @@ exports.X402_HEADERS = X402_HEADERS;
|
|
|
1177
1307
|
exports.addArticleToSession = addArticleToSession;
|
|
1178
1308
|
exports.buildPaymentRequirement = buildPaymentRequirement;
|
|
1179
1309
|
exports.buildSolanaPayUrl = buildSolanaPayUrl;
|
|
1310
|
+
exports.buildVersionedTransaction = buildVersionedTransaction;
|
|
1311
|
+
exports.calculatePriorityFeeCost = calculatePriorityFeeCost;
|
|
1180
1312
|
exports.checkPaywallAccess = checkPaywallAccess;
|
|
1181
1313
|
exports.clearPriceCache = clearPriceCache;
|
|
1182
1314
|
exports.configurePricing = configurePricing;
|
|
@@ -1186,14 +1318,18 @@ exports.createMemoryStore = createMemoryStore;
|
|
|
1186
1318
|
exports.createPaymentFlow = createPaymentFlow;
|
|
1187
1319
|
exports.createPaymentReference = createPaymentReference;
|
|
1188
1320
|
exports.createPaywallMiddleware = createPaywallMiddleware;
|
|
1321
|
+
exports.createPriorityFeeInstructions = createPriorityFeeInstructions;
|
|
1189
1322
|
exports.createRedisStore = createRedisStore;
|
|
1190
1323
|
exports.createSession = createSession;
|
|
1191
1324
|
exports.decodePaymentRequired = decodePaymentRequired;
|
|
1192
1325
|
exports.encodePaymentRequired = encodePaymentRequired;
|
|
1193
1326
|
exports.encodePaymentResponse = encodePaymentResponse;
|
|
1327
|
+
exports.estimatePriorityFee = estimatePriorityFee;
|
|
1328
|
+
exports.fetchLookupTables = fetchLookupTables;
|
|
1194
1329
|
exports.formatPriceDisplay = formatPriceDisplay;
|
|
1195
1330
|
exports.formatPriceSync = formatPriceSync;
|
|
1196
1331
|
exports.getConnection = getConnection;
|
|
1332
|
+
exports.getConnectionWithFallback = getConnectionWithFallback;
|
|
1197
1333
|
exports.getProviders = getProviders;
|
|
1198
1334
|
exports.getSolPrice = getSolPrice;
|
|
1199
1335
|
exports.getTokenDecimals = getTokenDecimals;
|
|
@@ -1202,6 +1338,7 @@ exports.isArticleUnlocked = isArticleUnlocked;
|
|
|
1202
1338
|
exports.isMainnet = isMainnet;
|
|
1203
1339
|
exports.isNativeAsset = isNativeAsset;
|
|
1204
1340
|
exports.isRetryableRPCError = isRetryableRPCError;
|
|
1341
|
+
exports.isVersionedTransaction = isVersionedTransaction;
|
|
1205
1342
|
exports.lamportsToSol = lamportsToSol;
|
|
1206
1343
|
exports.lamportsToUsd = lamportsToUsd;
|
|
1207
1344
|
exports.parsePaymentHeader = parsePaymentHeader;
|
|
@@ -1215,6 +1352,7 @@ exports.verifyPayment = verifyPayment;
|
|
|
1215
1352
|
exports.verifySPLPayment = verifySPLPayment;
|
|
1216
1353
|
exports.verifyX402Payment = verifyX402Payment;
|
|
1217
1354
|
exports.waitForConfirmation = waitForConfirmation;
|
|
1355
|
+
exports.withFallback = withFallback;
|
|
1218
1356
|
exports.withPaywall = withPaywall;
|
|
1219
1357
|
exports.withRetry = withRetry;
|
|
1220
1358
|
//# sourceMappingURL=index.cjs.map
|