@alleyboss/micropay-solana-x402-paywall 3.2.1 → 3.3.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.
@@ -13,49 +13,66 @@ var LocalSvmFacilitator = class {
13
13
  caipFamily = "solana:*";
14
14
  connection;
15
15
  constructor(rpcUrl) {
16
+ console.log("[LocalSvmFacilitator] Initialized with RPC:", rpcUrl);
16
17
  this.connection = new web3_js.Connection(rpcUrl, "confirmed");
17
18
  }
18
19
  /**
19
20
  * Get supported payment kinds
20
21
  * Mocking the response of the /supported endpoint
21
22
  */
22
- async getSupported(extensionKeys = []) {
23
- return {
23
+ // Network Constants - CAIP-2 format for x402 v2
24
+ NETWORKS = {
25
+ DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
26
+ MAINNET: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
27
+ };
28
+ // Dummy fee payer address (System Program) - not used in local verification
29
+ // but required by x402 protocol for supported kinds
30
+ DUMMY_FEE_PAYER = "11111111111111111111111111111111";
31
+ /**
32
+ * Get supported payment kinds
33
+ * Returns x402 v2 compatible response with CAIP-2 network identifiers
34
+ */
35
+ async getSupported(_extensionKeys = []) {
36
+ console.log("[LocalSvmFacilitator] getSupported called");
37
+ const supported = {
24
38
  kinds: [
25
39
  {
26
- x402Version: 1,
40
+ x402Version: 2,
27
41
  scheme: "exact",
28
- network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
29
- // Devnet
30
- extra: {}
42
+ network: this.NETWORKS.DEVNET,
43
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
31
44
  },
32
45
  {
33
- x402Version: 1,
46
+ x402Version: 2,
34
47
  scheme: "exact",
35
- network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
36
- // Mainnet
37
- extra: {}
48
+ network: this.NETWORKS.MAINNET,
49
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
38
50
  }
39
51
  ],
40
52
  extensions: [],
41
53
  signers: {
42
- "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": [],
43
- "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": []
54
+ "solana:*": [this.DUMMY_FEE_PAYER]
44
55
  }
45
56
  };
57
+ console.log("[LocalSvmFacilitator] Returning supported:", JSON.stringify(supported));
58
+ return supported;
46
59
  }
47
60
  /**
48
61
  * Get mechanism-specific extra data
49
62
  */
50
- getExtra(network) {
63
+ getExtra(_network) {
51
64
  return void 0;
52
65
  }
53
66
  /**
54
67
  * Get default signers (not used for local verification usually, but required by interface)
55
68
  */
56
- getSigners(network) {
69
+ getSigners(_network) {
57
70
  return [];
58
71
  }
72
+ /**
73
+ * Enable debug logging (disable in production)
74
+ */
75
+ debug = process.env.NODE_ENV === "development";
59
76
  /**
60
77
  * Verify a payment on-chain
61
78
  */
@@ -68,57 +85,89 @@ var LocalSvmFacilitator = class {
68
85
  const payTo = requirements.payTo;
69
86
  const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
70
87
  const requiredAmount = BigInt(amountVal);
71
- console.log(`[LocalSvmFacilitator] Verifying signature: ${signature}`);
72
- console.log(`[LocalSvmFacilitator] Requirements - Amount: ${requiredAmount}, PayTo: ${payTo}`);
73
- console.log(`[LocalSvmFacilitator] Full Requirements:`, JSON.stringify(requirements));
74
- const tx = await this.connection.getParsedTransaction(signature, {
75
- maxSupportedTransactionVersion: 0,
76
- commitment: "confirmed"
77
- });
88
+ if (this.debug) {
89
+ console.log(`[LocalSvmFacilitator] Verifying tx: ${signature.slice(0, 8)}...`);
90
+ }
91
+ const tx = await this.fetchTransactionWithRetry(signature, 3);
78
92
  if (!tx) {
79
- console.error("[LocalSvmFacilitator] Transaction not found or not confirmed");
80
93
  return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
81
94
  }
82
- console.log("[LocalSvmFacilitator] Transaction found. Parsing instructions...");
83
95
  const instructions = tx.transaction.message.instructions;
84
96
  let paidAmount = 0n;
85
97
  let payer = void 0;
86
98
  for (const ix of instructions) {
87
99
  if ("program" in ix && ix.program === "system") {
88
100
  const parsed = ix.parsed;
89
- console.log(`[LocalSvmFacilitator] Inspecting IX:`, JSON.stringify(parsed));
90
- if (parsed.type === "transfer") {
91
- const info = parsed.info;
92
- console.log(`[LocalSvmFacilitator] Found transfer: ${info.lamports} lamports to ${info.destination}`);
93
- if (info.destination === payTo) {
94
- paidAmount += BigInt(info.lamports);
95
- if (!payer) payer = info.source;
101
+ if (parsed?.type === "transfer" && parsed.info?.destination === payTo) {
102
+ paidAmount += BigInt(parsed.info.lamports);
103
+ if (!payer) payer = parsed.info.source;
104
+ }
105
+ }
106
+ if ("program" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
107
+ const parsed = ix.parsed;
108
+ if (parsed?.type === "transferChecked" || parsed?.type === "transfer") {
109
+ if (this.debug) {
110
+ console.log(`[LocalSvmFacilitator] Found SPL transfer`);
96
111
  }
97
112
  }
98
113
  }
99
114
  }
100
- console.log(`[LocalSvmFacilitator] Total Paid Correctly: ${paidAmount}`);
101
115
  if (paidAmount >= requiredAmount) {
102
- console.log("[LocalSvmFacilitator] Verification SUCCESS");
116
+ if (this.debug) {
117
+ console.log(`[LocalSvmFacilitator] Verification SUCCESS for tx: ${signature.slice(0, 8)}...`);
118
+ }
103
119
  return {
104
120
  isValid: true,
105
121
  payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
106
122
  };
107
123
  }
108
- console.error(`[LocalSvmFacilitator] Verification FAILED. Paid: ${paidAmount}, Required: ${requiredAmount}`);
109
124
  return {
110
125
  isValid: false,
111
- invalidReason: `Insufficient payment. Required: ${requiredAmount}, Found: ${paidAmount}`,
126
+ invalidReason: "Insufficient payment amount",
112
127
  payer
113
128
  };
114
129
  } catch (error) {
115
- console.error("[LocalSvmFacilitator] Verify error:", error);
130
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
131
+ if (this.debug) {
132
+ console.error("[LocalSvmFacilitator] Verify error:", errorMessage);
133
+ }
116
134
  throw new types.VerifyError(500, {
117
135
  isValid: false,
118
- invalidReason: error.message
136
+ invalidReason: errorMessage
119
137
  });
120
138
  }
121
139
  }
140
+ /**
141
+ * Fetch transaction with exponential backoff retry
142
+ */
143
+ async fetchTransactionWithRetry(signature, maxRetries = 3) {
144
+ let lastError;
145
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
146
+ try {
147
+ const tx = await this.connection.getParsedTransaction(signature, {
148
+ maxSupportedTransactionVersion: 0,
149
+ commitment: "confirmed"
150
+ });
151
+ if (tx) return tx;
152
+ if (attempt < maxRetries - 1) {
153
+ await this.sleep(Math.pow(2, attempt) * 1e3);
154
+ }
155
+ } catch (error) {
156
+ lastError = error instanceof Error ? error : new Error("RPC error");
157
+ if (attempt < maxRetries - 1) {
158
+ await this.sleep(Math.pow(2, attempt) * 1e3);
159
+ }
160
+ }
161
+ }
162
+ if (lastError) throw lastError;
163
+ return null;
164
+ }
165
+ /**
166
+ * Sleep helper
167
+ */
168
+ sleep(ms) {
169
+ return new Promise((resolve) => setTimeout(resolve, ms));
170
+ }
122
171
  /**
123
172
  * Settle a payment (not applicable for direct chain verification, usually)
124
173
  * But we must implement it. For 'exact', settlement is just verification + finality.
@@ -160,7 +209,7 @@ function createX402Middleware(config) {
160
209
  accepts: {
161
210
  scheme: "exact",
162
211
  payTo: config.walletAddress,
163
- amount: config.price?.toString() || "0",
212
+ price: config.price?.toString() || "0",
164
213
  network: config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
165
214
  }
166
215
  };
@@ -12,49 +12,66 @@ var LocalSvmFacilitator = class {
12
12
  caipFamily = "solana:*";
13
13
  connection;
14
14
  constructor(rpcUrl) {
15
+ console.log("[LocalSvmFacilitator] Initialized with RPC:", rpcUrl);
15
16
  this.connection = new Connection(rpcUrl, "confirmed");
16
17
  }
17
18
  /**
18
19
  * Get supported payment kinds
19
20
  * Mocking the response of the /supported endpoint
20
21
  */
21
- async getSupported(extensionKeys = []) {
22
- return {
22
+ // Network Constants - CAIP-2 format for x402 v2
23
+ NETWORKS = {
24
+ DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
25
+ MAINNET: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
26
+ };
27
+ // Dummy fee payer address (System Program) - not used in local verification
28
+ // but required by x402 protocol for supported kinds
29
+ DUMMY_FEE_PAYER = "11111111111111111111111111111111";
30
+ /**
31
+ * Get supported payment kinds
32
+ * Returns x402 v2 compatible response with CAIP-2 network identifiers
33
+ */
34
+ async getSupported(_extensionKeys = []) {
35
+ console.log("[LocalSvmFacilitator] getSupported called");
36
+ const supported = {
23
37
  kinds: [
24
38
  {
25
- x402Version: 1,
39
+ x402Version: 2,
26
40
  scheme: "exact",
27
- network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
28
- // Devnet
29
- extra: {}
41
+ network: this.NETWORKS.DEVNET,
42
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
30
43
  },
31
44
  {
32
- x402Version: 1,
45
+ x402Version: 2,
33
46
  scheme: "exact",
34
- network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
35
- // Mainnet
36
- extra: {}
47
+ network: this.NETWORKS.MAINNET,
48
+ extra: { feePayer: this.DUMMY_FEE_PAYER }
37
49
  }
38
50
  ],
39
51
  extensions: [],
40
52
  signers: {
41
- "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": [],
42
- "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": []
53
+ "solana:*": [this.DUMMY_FEE_PAYER]
43
54
  }
44
55
  };
56
+ console.log("[LocalSvmFacilitator] Returning supported:", JSON.stringify(supported));
57
+ return supported;
45
58
  }
46
59
  /**
47
60
  * Get mechanism-specific extra data
48
61
  */
49
- getExtra(network) {
62
+ getExtra(_network) {
50
63
  return void 0;
51
64
  }
52
65
  /**
53
66
  * Get default signers (not used for local verification usually, but required by interface)
54
67
  */
55
- getSigners(network) {
68
+ getSigners(_network) {
56
69
  return [];
57
70
  }
71
+ /**
72
+ * Enable debug logging (disable in production)
73
+ */
74
+ debug = process.env.NODE_ENV === "development";
58
75
  /**
59
76
  * Verify a payment on-chain
60
77
  */
@@ -67,57 +84,89 @@ var LocalSvmFacilitator = class {
67
84
  const payTo = requirements.payTo;
68
85
  const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
69
86
  const requiredAmount = BigInt(amountVal);
70
- console.log(`[LocalSvmFacilitator] Verifying signature: ${signature}`);
71
- console.log(`[LocalSvmFacilitator] Requirements - Amount: ${requiredAmount}, PayTo: ${payTo}`);
72
- console.log(`[LocalSvmFacilitator] Full Requirements:`, JSON.stringify(requirements));
73
- const tx = await this.connection.getParsedTransaction(signature, {
74
- maxSupportedTransactionVersion: 0,
75
- commitment: "confirmed"
76
- });
87
+ if (this.debug) {
88
+ console.log(`[LocalSvmFacilitator] Verifying tx: ${signature.slice(0, 8)}...`);
89
+ }
90
+ const tx = await this.fetchTransactionWithRetry(signature, 3);
77
91
  if (!tx) {
78
- console.error("[LocalSvmFacilitator] Transaction not found or not confirmed");
79
92
  return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
80
93
  }
81
- console.log("[LocalSvmFacilitator] Transaction found. Parsing instructions...");
82
94
  const instructions = tx.transaction.message.instructions;
83
95
  let paidAmount = 0n;
84
96
  let payer = void 0;
85
97
  for (const ix of instructions) {
86
98
  if ("program" in ix && ix.program === "system") {
87
99
  const parsed = ix.parsed;
88
- console.log(`[LocalSvmFacilitator] Inspecting IX:`, JSON.stringify(parsed));
89
- if (parsed.type === "transfer") {
90
- const info = parsed.info;
91
- console.log(`[LocalSvmFacilitator] Found transfer: ${info.lamports} lamports to ${info.destination}`);
92
- if (info.destination === payTo) {
93
- paidAmount += BigInt(info.lamports);
94
- if (!payer) payer = info.source;
100
+ if (parsed?.type === "transfer" && parsed.info?.destination === payTo) {
101
+ paidAmount += BigInt(parsed.info.lamports);
102
+ if (!payer) payer = parsed.info.source;
103
+ }
104
+ }
105
+ if ("program" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
106
+ const parsed = ix.parsed;
107
+ if (parsed?.type === "transferChecked" || parsed?.type === "transfer") {
108
+ if (this.debug) {
109
+ console.log(`[LocalSvmFacilitator] Found SPL transfer`);
95
110
  }
96
111
  }
97
112
  }
98
113
  }
99
- console.log(`[LocalSvmFacilitator] Total Paid Correctly: ${paidAmount}`);
100
114
  if (paidAmount >= requiredAmount) {
101
- console.log("[LocalSvmFacilitator] Verification SUCCESS");
115
+ if (this.debug) {
116
+ console.log(`[LocalSvmFacilitator] Verification SUCCESS for tx: ${signature.slice(0, 8)}...`);
117
+ }
102
118
  return {
103
119
  isValid: true,
104
120
  payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
105
121
  };
106
122
  }
107
- console.error(`[LocalSvmFacilitator] Verification FAILED. Paid: ${paidAmount}, Required: ${requiredAmount}`);
108
123
  return {
109
124
  isValid: false,
110
- invalidReason: `Insufficient payment. Required: ${requiredAmount}, Found: ${paidAmount}`,
125
+ invalidReason: "Insufficient payment amount",
111
126
  payer
112
127
  };
113
128
  } catch (error) {
114
- console.error("[LocalSvmFacilitator] Verify error:", error);
129
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
130
+ if (this.debug) {
131
+ console.error("[LocalSvmFacilitator] Verify error:", errorMessage);
132
+ }
115
133
  throw new VerifyError(500, {
116
134
  isValid: false,
117
- invalidReason: error.message
135
+ invalidReason: errorMessage
118
136
  });
119
137
  }
120
138
  }
139
+ /**
140
+ * Fetch transaction with exponential backoff retry
141
+ */
142
+ async fetchTransactionWithRetry(signature, maxRetries = 3) {
143
+ let lastError;
144
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
145
+ try {
146
+ const tx = await this.connection.getParsedTransaction(signature, {
147
+ maxSupportedTransactionVersion: 0,
148
+ commitment: "confirmed"
149
+ });
150
+ if (tx) return tx;
151
+ if (attempt < maxRetries - 1) {
152
+ await this.sleep(Math.pow(2, attempt) * 1e3);
153
+ }
154
+ } catch (error) {
155
+ lastError = error instanceof Error ? error : new Error("RPC error");
156
+ if (attempt < maxRetries - 1) {
157
+ await this.sleep(Math.pow(2, attempt) * 1e3);
158
+ }
159
+ }
160
+ }
161
+ if (lastError) throw lastError;
162
+ return null;
163
+ }
164
+ /**
165
+ * Sleep helper
166
+ */
167
+ sleep(ms) {
168
+ return new Promise((resolve) => setTimeout(resolve, ms));
169
+ }
121
170
  /**
122
171
  * Settle a payment (not applicable for direct chain verification, usually)
123
172
  * But we must implement it. For 'exact', settlement is just verification + finality.
@@ -159,7 +208,7 @@ function createX402Middleware(config) {
159
208
  accepts: {
160
209
  scheme: "exact",
161
210
  payTo: config.walletAddress,
162
- amount: config.price?.toString() || "0",
211
+ price: config.price?.toString() || "0",
163
212
  network: config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
164
213
  }
165
214
  };
@@ -6,12 +6,10 @@ function lamportsToSol(lamports) {
6
6
  }
7
7
 
8
8
  // src/pricing/index.ts
9
- var cachedPrice = null;
10
- var config = {};
11
- var lastProviderIndex = -1;
9
+ var priceCache = null;
10
+ var currentConfig = {};
12
11
  function configurePricing(newConfig) {
13
- config = { ...config, ...newConfig };
14
- cachedPrice = null;
12
+ currentConfig = { ...currentConfig, ...newConfig };
15
13
  }
16
14
  var PROVIDERS = [
17
15
  {
@@ -51,56 +49,75 @@ async function fetchFromProvider(provider, timeout) {
51
49
  if (!price || price <= 0) {
52
50
  throw new Error("Invalid price");
53
51
  }
54
- return price;
52
+ return { price, source: provider.name };
55
53
  } finally {
56
54
  clearTimeout(timeoutId);
57
55
  }
58
56
  }
57
+ async function fetchPriceParallel(timeout) {
58
+ const promises = PROVIDERS.map(
59
+ (provider) => fetchFromProvider(provider, timeout).catch(() => null)
60
+ );
61
+ const results = await Promise.all(promises);
62
+ const validResult = results.find((r) => r !== null);
63
+ if (validResult) {
64
+ return validResult;
65
+ }
66
+ throw new Error("All providers failed");
67
+ }
68
+ async function fetchPriceSequential(timeout) {
69
+ for (const provider of PROVIDERS) {
70
+ try {
71
+ return await fetchFromProvider(provider, timeout);
72
+ } catch {
73
+ continue;
74
+ }
75
+ }
76
+ throw new Error("All providers failed");
77
+ }
59
78
  async function getSolPrice() {
60
- const cacheTTL = config.cacheTTL ?? 6e4;
61
- const timeout = config.timeout ?? 5e3;
62
- if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {
63
- return cachedPrice;
79
+ const cacheTTL = currentConfig.cacheTTL ?? 6e4;
80
+ const timeout = currentConfig.timeout ?? 3e3;
81
+ const useParallel = currentConfig.parallelFetch ?? true;
82
+ const now = Date.now();
83
+ if (priceCache && now - priceCache.timestamp < cacheTTL) {
84
+ return priceCache.data;
64
85
  }
65
- if (config.customProvider) {
86
+ if (currentConfig.customProvider) {
66
87
  try {
67
- const price = await config.customProvider();
88
+ const price = await currentConfig.customProvider();
68
89
  if (price > 0) {
69
- cachedPrice = {
90
+ const data = {
70
91
  solPrice: price,
71
92
  fetchedAt: /* @__PURE__ */ new Date(),
72
93
  source: "custom"
73
94
  };
74
- return cachedPrice;
95
+ priceCache = { data, timestamp: now };
96
+ return data;
75
97
  }
76
98
  } catch {
77
99
  }
78
100
  }
79
- for (let i = 0; i < PROVIDERS.length; i++) {
80
- const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;
81
- const provider = PROVIDERS[idx];
82
- try {
83
- const price = await fetchFromProvider(provider, timeout);
84
- lastProviderIndex = idx;
85
- cachedPrice = {
86
- solPrice: price,
87
- fetchedAt: /* @__PURE__ */ new Date(),
88
- source: provider.name
101
+ try {
102
+ const result = useParallel ? await fetchPriceParallel(timeout) : await fetchPriceSequential(timeout);
103
+ const data = {
104
+ solPrice: result.price,
105
+ fetchedAt: /* @__PURE__ */ new Date(),
106
+ source: result.source
107
+ };
108
+ priceCache = { data, timestamp: now };
109
+ return data;
110
+ } catch {
111
+ if (priceCache) {
112
+ return {
113
+ ...priceCache.data,
114
+ source: `${priceCache.data.source} (stale)`
89
115
  };
90
- return cachedPrice;
91
- } catch {
92
- continue;
93
116
  }
117
+ throw new Error(
118
+ "Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
119
+ );
94
120
  }
95
- if (cachedPrice) {
96
- return {
97
- ...cachedPrice,
98
- source: `${cachedPrice.source} (stale)`
99
- };
100
- }
101
- throw new Error(
102
- "Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
103
- );
104
121
  }
105
122
  async function lamportsToUsd(lamports) {
106
123
  const { solPrice } = await getSolPrice();
@@ -128,8 +145,7 @@ function formatPriceSync(lamports, solPrice) {
128
145
  };
129
146
  }
130
147
  function clearPriceCache() {
131
- cachedPrice = null;
132
- lastProviderIndex = -1;
148
+ priceCache = null;
133
149
  }
134
150
  function getProviders() {
135
151
  return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
@@ -23,8 +23,10 @@ interface PriceConfig {
23
23
  customProvider?: CustomPriceProvider;
24
24
  /** Cache TTL in milliseconds (default: 60000) */
25
25
  cacheTTL?: number;
26
- /** Request timeout in milliseconds (default: 5000) */
26
+ /** Request timeout in milliseconds (default: 3000) */
27
27
  timeout?: number;
28
+ /** Use parallel fetching (default: true, faster but more network calls) */
29
+ parallelFetch?: boolean;
28
30
  }
29
31
  /**
30
32
  * Configure price fetching
@@ -39,19 +41,16 @@ interface PriceConfig {
39
41
  * },
40
42
  * });
41
43
  *
42
- * // Or just adjust cache TTL
43
- * configurePricing({ cacheTTL: 30000 }); // 30 seconds
44
+ * // Or adjust settings
45
+ * configurePricing({ cacheTTL: 30000, parallelFetch: true });
44
46
  * ```
45
47
  */
46
48
  declare function configurePricing(newConfig: PriceConfig): void;
47
49
  /**
48
- * Get SOL price with multi-provider fallback
50
+ * Get SOL price with multi-provider support
49
51
  *
50
- * Provider rotation order:
51
- * 1. CoinCap (primary)
52
- * 2. Binance (backup #1)
53
- * 3. CoinGecko (backup #2)
54
- * 4. Kraken (backup #3)
52
+ * Default behavior: Parallel fetch (all providers race, fastest wins)
53
+ * This is faster and more reliable in serverless environments.
55
54
  *
56
55
  * @example
57
56
  * ```typescript
@@ -23,8 +23,10 @@ interface PriceConfig {
23
23
  customProvider?: CustomPriceProvider;
24
24
  /** Cache TTL in milliseconds (default: 60000) */
25
25
  cacheTTL?: number;
26
- /** Request timeout in milliseconds (default: 5000) */
26
+ /** Request timeout in milliseconds (default: 3000) */
27
27
  timeout?: number;
28
+ /** Use parallel fetching (default: true, faster but more network calls) */
29
+ parallelFetch?: boolean;
28
30
  }
29
31
  /**
30
32
  * Configure price fetching
@@ -39,19 +41,16 @@ interface PriceConfig {
39
41
  * },
40
42
  * });
41
43
  *
42
- * // Or just adjust cache TTL
43
- * configurePricing({ cacheTTL: 30000 }); // 30 seconds
44
+ * // Or adjust settings
45
+ * configurePricing({ cacheTTL: 30000, parallelFetch: true });
44
46
  * ```
45
47
  */
46
48
  declare function configurePricing(newConfig: PriceConfig): void;
47
49
  /**
48
- * Get SOL price with multi-provider fallback
50
+ * Get SOL price with multi-provider support
49
51
  *
50
- * Provider rotation order:
51
- * 1. CoinCap (primary)
52
- * 2. Binance (backup #1)
53
- * 3. CoinGecko (backup #2)
54
- * 4. Kraken (backup #3)
52
+ * Default behavior: Parallel fetch (all providers race, fastest wins)
53
+ * This is faster and more reliable in serverless environments.
55
54
  *
56
55
  * @example
57
56
  * ```typescript