@alleyboss/micropay-solana-x402-paywall 3.2.2 β 3.3.1
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 +45 -0
- package/dist/agent/index.cjs +2 -2
- package/dist/agent/index.d.cts +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +2 -2
- package/dist/client/index.cjs +229 -5
- package/dist/client/index.d.cts +101 -1
- package/dist/client/index.d.ts +101 -1
- package/dist/client/index.js +227 -7
- package/dist/index.cjs +287 -159
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +285 -161
- package/dist/next/index.cjs +91 -28
- package/dist/next/index.js +91 -28
- package/dist/pricing/index.cjs +54 -38
- package/dist/pricing/index.d.cts +8 -9
- package/dist/pricing/index.d.ts +8 -9
- package/dist/pricing/index.js +54 -38
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -166,6 +166,51 @@ if (result.success) {
|
|
|
166
166
|
}
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
+
## π£ React Hooks (New in v3.2.2)
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { usePricing, useFormatPrice } from '@alleyboss/micropay-solana-x402-paywall/client';
|
|
173
|
+
|
|
174
|
+
function PaywallBanner({ priceInLamports }) {
|
|
175
|
+
const { formatted, isLoading } = useFormatPrice(priceInLamports);
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<div className="paywall">
|
|
179
|
+
<span>Unlock for {isLoading ? '...' : formatted}</span>
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## πΊοΈ Roadmap
|
|
186
|
+
|
|
187
|
+
We're actively working on these exciting features:
|
|
188
|
+
|
|
189
|
+
### Core Features
|
|
190
|
+
| Feature | Status | Description |
|
|
191
|
+
|---------|--------|-------------|
|
|
192
|
+
| β‘ **Jupiter Swap-on-Pay** | π Coming Soon | Pay with any token, auto-swap to SOL/USDC |
|
|
193
|
+
| πΌοΈ **NFT/Token-Gating** | π Coming Soon | Verify NFT ownership for access discounts |
|
|
194
|
+
| π **Payment Analytics** | π Coming Soon | Webhooks & callbacks for payment events |
|
|
195
|
+
| π³ **Compressed NFTs** | π Planned | Scalable access tokens via cNFTs |
|
|
196
|
+
| π **Payment Streaming** | π Planned | Pay-as-you-consume for APIs |
|
|
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
|
+
|
|
212
|
+
Want to contribute or sponsor a feature? Open an issue on [GitHub](https://github.com/AlleyBo55/micropay-solana-x402-paywall)!
|
|
213
|
+
|
|
169
214
|
## π Documentation
|
|
170
215
|
|
|
171
216
|
For full documentation:
|
package/dist/agent/index.cjs
CHANGED
|
@@ -146,9 +146,9 @@ async function getAgentBalance(connection, agentKeypair) {
|
|
|
146
146
|
balanceSol: balance / web3_js.LAMPORTS_PER_SOL
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
|
-
async function hasAgentSufficientBalance(connection, agentKeypair, requiredLamports) {
|
|
149
|
+
async function hasAgentSufficientBalance(connection, agentKeypair, requiredLamports, feeBufferLamports = 5000000n) {
|
|
150
150
|
const { balance } = await getAgentBalance(connection, agentKeypair);
|
|
151
|
-
const totalRequired = requiredLamports +
|
|
151
|
+
const totalRequired = requiredLamports + feeBufferLamports;
|
|
152
152
|
return {
|
|
153
153
|
sufficient: balance >= totalRequired,
|
|
154
154
|
balance,
|
package/dist/agent/index.d.cts
CHANGED
|
@@ -88,7 +88,7 @@ declare function getAgentBalance(connection: Connection, agentKeypair: Keypair):
|
|
|
88
88
|
/**
|
|
89
89
|
* Check if agent has sufficient balance for a payment
|
|
90
90
|
*/
|
|
91
|
-
declare function hasAgentSufficientBalance(connection: Connection, agentKeypair: Keypair, requiredLamports: bigint): Promise<{
|
|
91
|
+
declare function hasAgentSufficientBalance(connection: Connection, agentKeypair: Keypair, requiredLamports: bigint, feeBufferLamports?: bigint): Promise<{
|
|
92
92
|
sufficient: boolean;
|
|
93
93
|
balance: bigint;
|
|
94
94
|
required: bigint;
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -88,7 +88,7 @@ declare function getAgentBalance(connection: Connection, agentKeypair: Keypair):
|
|
|
88
88
|
/**
|
|
89
89
|
* Check if agent has sufficient balance for a payment
|
|
90
90
|
*/
|
|
91
|
-
declare function hasAgentSufficientBalance(connection: Connection, agentKeypair: Keypair, requiredLamports: bigint): Promise<{
|
|
91
|
+
declare function hasAgentSufficientBalance(connection: Connection, agentKeypair: Keypair, requiredLamports: bigint, feeBufferLamports?: bigint): Promise<{
|
|
92
92
|
sufficient: boolean;
|
|
93
93
|
balance: bigint;
|
|
94
94
|
required: bigint;
|
package/dist/agent/index.js
CHANGED
|
@@ -140,9 +140,9 @@ async function getAgentBalance(connection, agentKeypair) {
|
|
|
140
140
|
balanceSol: balance / LAMPORTS_PER_SOL
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
-
async function hasAgentSufficientBalance(connection, agentKeypair, requiredLamports) {
|
|
143
|
+
async function hasAgentSufficientBalance(connection, agentKeypair, requiredLamports, feeBufferLamports = 5000000n) {
|
|
144
144
|
const { balance } = await getAgentBalance(connection, agentKeypair);
|
|
145
|
-
const totalRequired = requiredLamports +
|
|
145
|
+
const totalRequired = requiredLamports + feeBufferLamports;
|
|
146
146
|
return {
|
|
147
147
|
sufficient: balance >= totalRequired,
|
|
148
148
|
balance,
|
package/dist/client/index.cjs
CHANGED
|
@@ -182,13 +182,17 @@ function usePaywallResource({
|
|
|
182
182
|
if (wwwAuth) {
|
|
183
183
|
setPaymentHeader(wwwAuth);
|
|
184
184
|
try {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
const { decodePaymentRequiredHeader: decodePaymentRequiredHeader2 } = await import('@x402/core/http');
|
|
186
|
+
const cleanHeader = wwwAuth.replace(/^[Xx]402\s+/, "");
|
|
187
|
+
const decoded = decodePaymentRequiredHeader2(cleanHeader);
|
|
188
|
+
const accepts = Array.isArray(decoded.accepts) ? decoded.accepts[0] : decoded.accepts;
|
|
189
|
+
if (accepts) {
|
|
190
|
+
const amountStr = accepts.amount || accepts.maxAmountRequired || "0";
|
|
191
|
+
setPrice(BigInt(amountStr));
|
|
192
|
+
setRecipient(accepts.payTo);
|
|
189
193
|
}
|
|
190
194
|
} catch (e) {
|
|
191
|
-
console.warn("Failed to parse
|
|
195
|
+
console.warn("[usePaywallResource] Failed to parse x402 header:", e);
|
|
192
196
|
}
|
|
193
197
|
}
|
|
194
198
|
setIsLocked(true);
|
|
@@ -241,9 +245,229 @@ function usePaywallResource({
|
|
|
241
245
|
};
|
|
242
246
|
}
|
|
243
247
|
|
|
248
|
+
// src/pricing/index.ts
|
|
249
|
+
var priceCache = null;
|
|
250
|
+
var currentConfig = {};
|
|
251
|
+
var PROVIDERS = [
|
|
252
|
+
{
|
|
253
|
+
name: "coincap",
|
|
254
|
+
url: "https://api.coincap.io/v2/assets/solana",
|
|
255
|
+
parse: (data) => parseFloat(data.data?.priceUsd || "0")
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "binance",
|
|
259
|
+
url: "https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT",
|
|
260
|
+
parse: (data) => parseFloat(data.price || "0")
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: "coingecko",
|
|
264
|
+
url: "https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd",
|
|
265
|
+
parse: (data) => data.solana?.usd || 0
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "kraken",
|
|
269
|
+
url: "https://api.kraken.com/0/public/Ticker?pair=SOLUSD",
|
|
270
|
+
parse: (data) => parseFloat(data.result?.SOLUSD?.c?.[0] || "0")
|
|
271
|
+
}
|
|
272
|
+
];
|
|
273
|
+
async function fetchFromProvider(provider, timeout) {
|
|
274
|
+
const controller = new AbortController();
|
|
275
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
276
|
+
try {
|
|
277
|
+
const response = await fetch(provider.url, {
|
|
278
|
+
headers: { "Accept": "application/json" },
|
|
279
|
+
signal: controller.signal
|
|
280
|
+
});
|
|
281
|
+
if (!response.ok) {
|
|
282
|
+
throw new Error(`HTTP ${response.status}`);
|
|
283
|
+
}
|
|
284
|
+
const data = await response.json();
|
|
285
|
+
const price = provider.parse(data);
|
|
286
|
+
if (!price || price <= 0) {
|
|
287
|
+
throw new Error("Invalid price");
|
|
288
|
+
}
|
|
289
|
+
return { price, source: provider.name };
|
|
290
|
+
} finally {
|
|
291
|
+
clearTimeout(timeoutId);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async function fetchPriceParallel(timeout) {
|
|
295
|
+
const promises = PROVIDERS.map(
|
|
296
|
+
(provider) => fetchFromProvider(provider, timeout).catch(() => null)
|
|
297
|
+
);
|
|
298
|
+
const results = await Promise.all(promises);
|
|
299
|
+
const validResult = results.find((r) => r !== null);
|
|
300
|
+
if (validResult) {
|
|
301
|
+
return validResult;
|
|
302
|
+
}
|
|
303
|
+
throw new Error("All providers failed");
|
|
304
|
+
}
|
|
305
|
+
async function fetchPriceSequential(timeout) {
|
|
306
|
+
for (const provider of PROVIDERS) {
|
|
307
|
+
try {
|
|
308
|
+
return await fetchFromProvider(provider, timeout);
|
|
309
|
+
} catch {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
throw new Error("All providers failed");
|
|
314
|
+
}
|
|
315
|
+
async function getSolPrice() {
|
|
316
|
+
const cacheTTL = currentConfig.cacheTTL ?? 6e4;
|
|
317
|
+
const timeout = currentConfig.timeout ?? 3e3;
|
|
318
|
+
const useParallel = currentConfig.parallelFetch ?? true;
|
|
319
|
+
const now = Date.now();
|
|
320
|
+
if (priceCache && now - priceCache.timestamp < cacheTTL) {
|
|
321
|
+
return priceCache.data;
|
|
322
|
+
}
|
|
323
|
+
if (currentConfig.customProvider) {
|
|
324
|
+
try {
|
|
325
|
+
const price = await currentConfig.customProvider();
|
|
326
|
+
if (price > 0) {
|
|
327
|
+
const data = {
|
|
328
|
+
solPrice: price,
|
|
329
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
330
|
+
source: "custom"
|
|
331
|
+
};
|
|
332
|
+
priceCache = { data, timestamp: now };
|
|
333
|
+
return data;
|
|
334
|
+
}
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
const result = useParallel ? await fetchPriceParallel(timeout) : await fetchPriceSequential(timeout);
|
|
340
|
+
const data = {
|
|
341
|
+
solPrice: result.price,
|
|
342
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
343
|
+
source: result.source
|
|
344
|
+
};
|
|
345
|
+
priceCache = { data, timestamp: now };
|
|
346
|
+
return data;
|
|
347
|
+
} catch {
|
|
348
|
+
if (priceCache) {
|
|
349
|
+
return {
|
|
350
|
+
...priceCache.data,
|
|
351
|
+
source: `${priceCache.data.source} (stale)`
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
throw new Error(
|
|
355
|
+
"Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/client/hooks.ts
|
|
361
|
+
function usePricing(refreshIntervalMs = 6e4) {
|
|
362
|
+
const [priceData, setPriceData] = react.useState(null);
|
|
363
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
364
|
+
const [error, setError] = react.useState(null);
|
|
365
|
+
const intervalRef = react.useRef(null);
|
|
366
|
+
const fetchPrice = react.useCallback(async () => {
|
|
367
|
+
try {
|
|
368
|
+
setIsLoading(true);
|
|
369
|
+
setError(null);
|
|
370
|
+
const data = await getSolPrice();
|
|
371
|
+
setPriceData(data);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
setError(err instanceof Error ? err.message : "Failed to fetch price");
|
|
374
|
+
} finally {
|
|
375
|
+
setIsLoading(false);
|
|
376
|
+
}
|
|
377
|
+
}, []);
|
|
378
|
+
react.useEffect(() => {
|
|
379
|
+
fetchPrice();
|
|
380
|
+
if (refreshIntervalMs > 0) {
|
|
381
|
+
intervalRef.current = setInterval(fetchPrice, refreshIntervalMs);
|
|
382
|
+
}
|
|
383
|
+
return () => {
|
|
384
|
+
if (intervalRef.current) {
|
|
385
|
+
clearInterval(intervalRef.current);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
}, [fetchPrice, refreshIntervalMs]);
|
|
389
|
+
return {
|
|
390
|
+
solPrice: priceData?.solPrice ?? null,
|
|
391
|
+
source: priceData?.source ?? null,
|
|
392
|
+
fetchedAt: priceData?.fetchedAt ?? null,
|
|
393
|
+
isLoading,
|
|
394
|
+
error,
|
|
395
|
+
refresh: fetchPrice
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
function useLamportsToUsd(lamports) {
|
|
399
|
+
const { solPrice, isLoading } = usePricing();
|
|
400
|
+
if (isLoading || !solPrice || lamports === null) {
|
|
401
|
+
return { usd: null, formatted: null, isLoading };
|
|
402
|
+
}
|
|
403
|
+
const lamportsBigInt = typeof lamports === "number" ? BigInt(lamports) : lamports;
|
|
404
|
+
const sol = Number(lamportsBigInt) / 1e9;
|
|
405
|
+
const usd = sol * solPrice;
|
|
406
|
+
return {
|
|
407
|
+
usd,
|
|
408
|
+
formatted: `$${usd.toFixed(2)}`,
|
|
409
|
+
isLoading: false
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function useMicropay() {
|
|
413
|
+
const [status, setStatus] = react.useState("idle");
|
|
414
|
+
const [error, setError] = react.useState(null);
|
|
415
|
+
const [signature, setSignature] = react.useState(null);
|
|
416
|
+
const reset = react.useCallback(() => {
|
|
417
|
+
setStatus("idle");
|
|
418
|
+
setError(null);
|
|
419
|
+
setSignature(null);
|
|
420
|
+
}, []);
|
|
421
|
+
const pay = react.useCallback(async (_options) => {
|
|
422
|
+
setStatus("pending");
|
|
423
|
+
setError(null);
|
|
424
|
+
try {
|
|
425
|
+
throw new Error(
|
|
426
|
+
"useMicropay requires implementation of onSign/onSend callbacks. See documentation for wallet adapter integration."
|
|
427
|
+
);
|
|
428
|
+
} catch (err) {
|
|
429
|
+
const errorMessage = err instanceof Error ? err.message : "Payment failed";
|
|
430
|
+
setError(errorMessage);
|
|
431
|
+
setStatus("error");
|
|
432
|
+
return { success: false, error: errorMessage };
|
|
433
|
+
}
|
|
434
|
+
}, []);
|
|
435
|
+
return {
|
|
436
|
+
status,
|
|
437
|
+
error,
|
|
438
|
+
signature,
|
|
439
|
+
pay,
|
|
440
|
+
reset
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function useFormatPrice(lamports) {
|
|
444
|
+
const { solPrice, isLoading } = usePricing();
|
|
445
|
+
if (isLoading || !solPrice || lamports === null) {
|
|
446
|
+
return {
|
|
447
|
+
sol: null,
|
|
448
|
+
usd: null,
|
|
449
|
+
formatted: "Loading...",
|
|
450
|
+
isLoading
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const lamportsBigInt = typeof lamports === "number" ? BigInt(lamports) : lamports;
|
|
454
|
+
const sol = Number(lamportsBigInt) / 1e9;
|
|
455
|
+
const usd = sol * solPrice;
|
|
456
|
+
return {
|
|
457
|
+
sol,
|
|
458
|
+
usd,
|
|
459
|
+
formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`,
|
|
460
|
+
isLoading: false
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
244
464
|
exports.buildSolanaPayUrl = buildSolanaPayUrl;
|
|
245
465
|
exports.createPaymentFlow = createPaymentFlow;
|
|
246
466
|
exports.createPaymentReference = createPaymentReference;
|
|
247
467
|
exports.createX402AuthorizationHeader = createX402AuthorizationHeader;
|
|
248
468
|
exports.sendSolanaPayment = sendSolanaPayment;
|
|
469
|
+
exports.useFormatPrice = useFormatPrice;
|
|
470
|
+
exports.useLamportsToUsd = useLamportsToUsd;
|
|
471
|
+
exports.useMicropay = useMicropay;
|
|
249
472
|
exports.usePaywallResource = usePaywallResource;
|
|
473
|
+
exports.usePricing = usePricing;
|
package/dist/client/index.d.cts
CHANGED
|
@@ -219,4 +219,104 @@ interface PaywallState<T> {
|
|
|
219
219
|
*/
|
|
220
220
|
declare function usePaywallResource<T = any>({ url, connection, wallet }: PaywallConfig): PaywallState<T>;
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Hook to fetch and display SOL price with auto-refresh
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* function PriceDisplay() {
|
|
228
|
+
* const { solPrice, source, isLoading, error, refresh } = usePricing();
|
|
229
|
+
*
|
|
230
|
+
* if (isLoading) return <span>Loading...</span>;
|
|
231
|
+
* if (error) return <span>Price unavailable</span>;
|
|
232
|
+
*
|
|
233
|
+
* return <span>SOL: ${solPrice?.toFixed(2)} (via {source})</span>;
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
declare function usePricing(refreshIntervalMs?: number): {
|
|
238
|
+
solPrice: number | null;
|
|
239
|
+
source: string | null;
|
|
240
|
+
fetchedAt: Date | null;
|
|
241
|
+
isLoading: boolean;
|
|
242
|
+
error: string | null;
|
|
243
|
+
refresh: () => Promise<void>;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Format lamports to USD display with live price
|
|
247
|
+
*/
|
|
248
|
+
declare function useLamportsToUsd(lamports: bigint | number | null): {
|
|
249
|
+
usd: null;
|
|
250
|
+
formatted: null;
|
|
251
|
+
isLoading: boolean;
|
|
252
|
+
} | {
|
|
253
|
+
usd: number;
|
|
254
|
+
formatted: string;
|
|
255
|
+
isLoading: boolean;
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Payment status for useMicropay hook
|
|
259
|
+
*/
|
|
260
|
+
type PaymentStatus = 'idle' | 'pending' | 'confirming' | 'success' | 'error';
|
|
261
|
+
/**
|
|
262
|
+
* Hook for client-side micropayment flow state management
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```tsx
|
|
266
|
+
* function PayButton({ articleId, priceInLamports }) {
|
|
267
|
+
* const { status, error, pay, reset } = useMicropay();
|
|
268
|
+
*
|
|
269
|
+
* const handlePay = async () => {
|
|
270
|
+
* const result = await pay({
|
|
271
|
+
* priceInLamports,
|
|
272
|
+
* recipientAddress: 'CREATOR_WALLET',
|
|
273
|
+
* onSign: (tx) => wallet.signTransaction(tx),
|
|
274
|
+
* onSend: (signedTx) => connection.sendTransaction(signedTx),
|
|
275
|
+
* });
|
|
276
|
+
*
|
|
277
|
+
* if (result.success) {
|
|
278
|
+
* // Refresh page or unlock content
|
|
279
|
+
* }
|
|
280
|
+
* };
|
|
281
|
+
*
|
|
282
|
+
* return (
|
|
283
|
+
* <button onClick={handlePay} disabled={status === 'pending'}>
|
|
284
|
+
* {status === 'pending' ? 'Processing...' : 'Pay to Unlock'}
|
|
285
|
+
* </button>
|
|
286
|
+
* );
|
|
287
|
+
* }
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
declare function useMicropay(): {
|
|
291
|
+
status: PaymentStatus;
|
|
292
|
+
error: string | null;
|
|
293
|
+
signature: string | null;
|
|
294
|
+
pay: (_options: {
|
|
295
|
+
priceInLamports: bigint;
|
|
296
|
+
recipientAddress: string;
|
|
297
|
+
onSign: (tx: any) => Promise<any>;
|
|
298
|
+
onSend: (signedTx: any) => Promise<string>;
|
|
299
|
+
onConfirm?: (sig: string) => Promise<void>;
|
|
300
|
+
}) => Promise<{
|
|
301
|
+
success: boolean;
|
|
302
|
+
signature?: string;
|
|
303
|
+
error?: string;
|
|
304
|
+
}>;
|
|
305
|
+
reset: () => void;
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* Hook to format price display in both SOL and USD
|
|
309
|
+
*/
|
|
310
|
+
declare function useFormatPrice(lamports: bigint | number | null): {
|
|
311
|
+
sol: null;
|
|
312
|
+
usd: null;
|
|
313
|
+
formatted: string;
|
|
314
|
+
isLoading: boolean;
|
|
315
|
+
} | {
|
|
316
|
+
sol: number;
|
|
317
|
+
usd: number;
|
|
318
|
+
formatted: string;
|
|
319
|
+
isLoading: boolean;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
export { type PaymentFlowConfig, type PaymentResult, type PaymentStatus, type PaywallConfig, type PaywallState, type SendPaymentParams, type SolanaPayUrlParams, type WalletAdapterInterface, buildSolanaPayUrl, createPaymentFlow, createPaymentReference, createX402AuthorizationHeader, sendSolanaPayment, useFormatPrice, useLamportsToUsd, useMicropay, usePaywallResource, usePricing };
|
package/dist/client/index.d.ts
CHANGED
|
@@ -219,4 +219,104 @@ interface PaywallState<T> {
|
|
|
219
219
|
*/
|
|
220
220
|
declare function usePaywallResource<T = any>({ url, connection, wallet }: PaywallConfig): PaywallState<T>;
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Hook to fetch and display SOL price with auto-refresh
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* function PriceDisplay() {
|
|
228
|
+
* const { solPrice, source, isLoading, error, refresh } = usePricing();
|
|
229
|
+
*
|
|
230
|
+
* if (isLoading) return <span>Loading...</span>;
|
|
231
|
+
* if (error) return <span>Price unavailable</span>;
|
|
232
|
+
*
|
|
233
|
+
* return <span>SOL: ${solPrice?.toFixed(2)} (via {source})</span>;
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
declare function usePricing(refreshIntervalMs?: number): {
|
|
238
|
+
solPrice: number | null;
|
|
239
|
+
source: string | null;
|
|
240
|
+
fetchedAt: Date | null;
|
|
241
|
+
isLoading: boolean;
|
|
242
|
+
error: string | null;
|
|
243
|
+
refresh: () => Promise<void>;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Format lamports to USD display with live price
|
|
247
|
+
*/
|
|
248
|
+
declare function useLamportsToUsd(lamports: bigint | number | null): {
|
|
249
|
+
usd: null;
|
|
250
|
+
formatted: null;
|
|
251
|
+
isLoading: boolean;
|
|
252
|
+
} | {
|
|
253
|
+
usd: number;
|
|
254
|
+
formatted: string;
|
|
255
|
+
isLoading: boolean;
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Payment status for useMicropay hook
|
|
259
|
+
*/
|
|
260
|
+
type PaymentStatus = 'idle' | 'pending' | 'confirming' | 'success' | 'error';
|
|
261
|
+
/**
|
|
262
|
+
* Hook for client-side micropayment flow state management
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```tsx
|
|
266
|
+
* function PayButton({ articleId, priceInLamports }) {
|
|
267
|
+
* const { status, error, pay, reset } = useMicropay();
|
|
268
|
+
*
|
|
269
|
+
* const handlePay = async () => {
|
|
270
|
+
* const result = await pay({
|
|
271
|
+
* priceInLamports,
|
|
272
|
+
* recipientAddress: 'CREATOR_WALLET',
|
|
273
|
+
* onSign: (tx) => wallet.signTransaction(tx),
|
|
274
|
+
* onSend: (signedTx) => connection.sendTransaction(signedTx),
|
|
275
|
+
* });
|
|
276
|
+
*
|
|
277
|
+
* if (result.success) {
|
|
278
|
+
* // Refresh page or unlock content
|
|
279
|
+
* }
|
|
280
|
+
* };
|
|
281
|
+
*
|
|
282
|
+
* return (
|
|
283
|
+
* <button onClick={handlePay} disabled={status === 'pending'}>
|
|
284
|
+
* {status === 'pending' ? 'Processing...' : 'Pay to Unlock'}
|
|
285
|
+
* </button>
|
|
286
|
+
* );
|
|
287
|
+
* }
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
declare function useMicropay(): {
|
|
291
|
+
status: PaymentStatus;
|
|
292
|
+
error: string | null;
|
|
293
|
+
signature: string | null;
|
|
294
|
+
pay: (_options: {
|
|
295
|
+
priceInLamports: bigint;
|
|
296
|
+
recipientAddress: string;
|
|
297
|
+
onSign: (tx: any) => Promise<any>;
|
|
298
|
+
onSend: (signedTx: any) => Promise<string>;
|
|
299
|
+
onConfirm?: (sig: string) => Promise<void>;
|
|
300
|
+
}) => Promise<{
|
|
301
|
+
success: boolean;
|
|
302
|
+
signature?: string;
|
|
303
|
+
error?: string;
|
|
304
|
+
}>;
|
|
305
|
+
reset: () => void;
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* Hook to format price display in both SOL and USD
|
|
309
|
+
*/
|
|
310
|
+
declare function useFormatPrice(lamports: bigint | number | null): {
|
|
311
|
+
sol: null;
|
|
312
|
+
usd: null;
|
|
313
|
+
formatted: string;
|
|
314
|
+
isLoading: boolean;
|
|
315
|
+
} | {
|
|
316
|
+
sol: number;
|
|
317
|
+
usd: number;
|
|
318
|
+
formatted: string;
|
|
319
|
+
isLoading: boolean;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
export { type PaymentFlowConfig, type PaymentResult, type PaymentStatus, type PaywallConfig, type PaywallState, type SendPaymentParams, type SolanaPayUrlParams, type WalletAdapterInterface, buildSolanaPayUrl, createPaymentFlow, createPaymentReference, createX402AuthorizationHeader, sendSolanaPayment, useFormatPrice, useLamportsToUsd, useMicropay, usePaywallResource, usePricing };
|