@alleyboss/micropay-solana-x402-paywall 2.3.0 → 2.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 +35 -1
- package/dist/agent/index.cjs +359 -0
- package/dist/agent/index.cjs.map +1 -0
- package/dist/agent/index.d.cts +212 -0
- package/dist/agent/index.d.ts +212 -0
- package/dist/agent/index.js +348 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/index.cjs +299 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +291 -2
- package/dist/index.js.map +1 -1
- package/dist/priority-fees-C-OH4Trr.d.cts +50 -0
- package/dist/priority-fees-C-OH4Trr.d.ts +50 -0
- package/dist/solana/index.d.cts +4 -49
- package/dist/solana/index.d.ts +4 -49
- package/package.json +11 -1
package/dist/index.cjs
CHANGED
|
@@ -1360,10 +1360,300 @@ function clearPriceCache() {
|
|
|
1360
1360
|
function getProviders() {
|
|
1361
1361
|
return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
|
|
1362
1362
|
}
|
|
1363
|
+
var WALLET_REGEX4 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
1364
|
+
function isValidWalletAddress2(address) {
|
|
1365
|
+
if (!address || typeof address !== "string") return false;
|
|
1366
|
+
return WALLET_REGEX4.test(address);
|
|
1367
|
+
}
|
|
1368
|
+
async function executeAgentPayment(params) {
|
|
1369
|
+
const {
|
|
1370
|
+
connection,
|
|
1371
|
+
agentKeypair,
|
|
1372
|
+
recipientAddress,
|
|
1373
|
+
amountLamports,
|
|
1374
|
+
priorityFee,
|
|
1375
|
+
confirmationTimeout = 6e4
|
|
1376
|
+
} = params;
|
|
1377
|
+
if (!isValidWalletAddress2(recipientAddress)) {
|
|
1378
|
+
return {
|
|
1379
|
+
success: false,
|
|
1380
|
+
error: "Invalid recipient address format"
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
if (amountLamports <= 0n) {
|
|
1384
|
+
return {
|
|
1385
|
+
success: false,
|
|
1386
|
+
error: "Amount must be greater than 0"
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
try {
|
|
1390
|
+
const recipientPubkey = new web3_js.PublicKey(recipientAddress);
|
|
1391
|
+
const transferInstruction = web3_js.SystemProgram.transfer({
|
|
1392
|
+
fromPubkey: agentKeypair.publicKey,
|
|
1393
|
+
toPubkey: recipientPubkey,
|
|
1394
|
+
lamports: amountLamports
|
|
1395
|
+
});
|
|
1396
|
+
const { transaction, lastValidBlockHeight } = await buildVersionedTransaction({
|
|
1397
|
+
connection,
|
|
1398
|
+
payer: agentKeypair.publicKey,
|
|
1399
|
+
instructions: [transferInstruction],
|
|
1400
|
+
priorityFee
|
|
1401
|
+
});
|
|
1402
|
+
transaction.sign([agentKeypair]);
|
|
1403
|
+
const signature = await connection.sendTransaction(transaction, {
|
|
1404
|
+
maxRetries: 3,
|
|
1405
|
+
skipPreflight: false
|
|
1406
|
+
});
|
|
1407
|
+
const confirmationPromise = connection.confirmTransaction(
|
|
1408
|
+
{
|
|
1409
|
+
signature,
|
|
1410
|
+
lastValidBlockHeight,
|
|
1411
|
+
blockhash: transaction.message.recentBlockhash
|
|
1412
|
+
},
|
|
1413
|
+
"confirmed"
|
|
1414
|
+
);
|
|
1415
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1416
|
+
setTimeout(() => reject(new Error("Confirmation timeout")), confirmationTimeout);
|
|
1417
|
+
});
|
|
1418
|
+
const confirmation = await Promise.race([confirmationPromise, timeoutPromise]);
|
|
1419
|
+
if (confirmation.value.err) {
|
|
1420
|
+
return {
|
|
1421
|
+
success: false,
|
|
1422
|
+
signature,
|
|
1423
|
+
error: "Transaction failed on-chain"
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
const txDetails = await connection.getTransaction(signature, {
|
|
1427
|
+
commitment: "confirmed",
|
|
1428
|
+
maxSupportedTransactionVersion: 0
|
|
1429
|
+
});
|
|
1430
|
+
return {
|
|
1431
|
+
success: true,
|
|
1432
|
+
signature,
|
|
1433
|
+
confirmedAt: txDetails?.blockTime ?? Math.floor(Date.now() / 1e3),
|
|
1434
|
+
slot: txDetails?.slot ?? confirmation.context.slot,
|
|
1435
|
+
amountLamports,
|
|
1436
|
+
amountSol: Number(amountLamports) / web3_js.LAMPORTS_PER_SOL
|
|
1437
|
+
};
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1440
|
+
return {
|
|
1441
|
+
success: false,
|
|
1442
|
+
error: errorMessage
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
async function getAgentBalance(connection, agentKeypair) {
|
|
1447
|
+
const balance = await connection.getBalance(agentKeypair.publicKey);
|
|
1448
|
+
return {
|
|
1449
|
+
balance: BigInt(balance),
|
|
1450
|
+
balanceSol: balance / web3_js.LAMPORTS_PER_SOL
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
async function hasAgentSufficientBalance(connection, agentKeypair, requiredLamports) {
|
|
1454
|
+
const { balance } = await getAgentBalance(connection, agentKeypair);
|
|
1455
|
+
const totalRequired = requiredLamports + 10000n;
|
|
1456
|
+
return {
|
|
1457
|
+
sufficient: balance >= totalRequired,
|
|
1458
|
+
balance,
|
|
1459
|
+
required: totalRequired
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
function keypairFromBase58(base58Secret) {
|
|
1463
|
+
const bytes = Buffer.from(base58Secret, "base64");
|
|
1464
|
+
if (bytes.length !== 64) {
|
|
1465
|
+
const parts = base58Secret.split(",").map((n) => parseInt(n.trim(), 10));
|
|
1466
|
+
if (parts.length === 64) {
|
|
1467
|
+
return web3_js.Keypair.fromSecretKey(Uint8Array.from(parts));
|
|
1468
|
+
}
|
|
1469
|
+
throw new Error("Invalid secret key format. Expected base58 string or comma-separated bytes.");
|
|
1470
|
+
}
|
|
1471
|
+
return web3_js.Keypair.fromSecretKey(bytes);
|
|
1472
|
+
}
|
|
1473
|
+
function generateAgentKeypair() {
|
|
1474
|
+
const keypair = web3_js.Keypair.generate();
|
|
1475
|
+
const secretBytes = Array.from(keypair.secretKey);
|
|
1476
|
+
return {
|
|
1477
|
+
keypair,
|
|
1478
|
+
secretBase58: secretBytes.join(","),
|
|
1479
|
+
// Comma-separated for easy storage
|
|
1480
|
+
publicKey: keypair.publicKey.toBase58()
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
var MAX_CREDITS = 1e3;
|
|
1484
|
+
var MIN_SECRET_LENGTH2 = 32;
|
|
1485
|
+
function getSecretKey2(secret) {
|
|
1486
|
+
if (!secret || typeof secret !== "string") {
|
|
1487
|
+
throw new Error("Session secret is required");
|
|
1488
|
+
}
|
|
1489
|
+
if (secret.length < MIN_SECRET_LENGTH2) {
|
|
1490
|
+
throw new Error(`Session secret must be at least ${MIN_SECRET_LENGTH2} characters`);
|
|
1491
|
+
}
|
|
1492
|
+
return new TextEncoder().encode(secret);
|
|
1493
|
+
}
|
|
1494
|
+
function validateWalletAddress2(address) {
|
|
1495
|
+
if (!address || typeof address !== "string") return false;
|
|
1496
|
+
const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
1497
|
+
return base58Regex.test(address);
|
|
1498
|
+
}
|
|
1499
|
+
async function createCreditSession(walletAddress, purchaseId, config2) {
|
|
1500
|
+
if (!validateWalletAddress2(walletAddress)) {
|
|
1501
|
+
throw new Error("Invalid wallet address format");
|
|
1502
|
+
}
|
|
1503
|
+
if (config2.initialCredits <= 0 || config2.initialCredits > MAX_CREDITS) {
|
|
1504
|
+
throw new Error(`Credits must be between 1 and ${MAX_CREDITS}`);
|
|
1505
|
+
}
|
|
1506
|
+
if (!config2.durationHours || config2.durationHours <= 0 || config2.durationHours > 8760) {
|
|
1507
|
+
throw new Error("Session duration must be between 1 and 8760 hours (1 year)");
|
|
1508
|
+
}
|
|
1509
|
+
const sessionId = uuid.v4();
|
|
1510
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1511
|
+
const expiresAt = now + config2.durationHours * 3600;
|
|
1512
|
+
const bundleExpiry = config2.bundleExpiryHours ? now + config2.bundleExpiryHours * 3600 : expiresAt;
|
|
1513
|
+
const session = {
|
|
1514
|
+
id: sessionId,
|
|
1515
|
+
walletAddress,
|
|
1516
|
+
unlockedArticles: [purchaseId],
|
|
1517
|
+
siteWideUnlock: false,
|
|
1518
|
+
createdAt: now,
|
|
1519
|
+
expiresAt,
|
|
1520
|
+
credits: config2.initialCredits,
|
|
1521
|
+
bundleExpiry,
|
|
1522
|
+
bundleType: config2.bundleType
|
|
1523
|
+
};
|
|
1524
|
+
const payload = {
|
|
1525
|
+
sub: walletAddress,
|
|
1526
|
+
sid: sessionId,
|
|
1527
|
+
articles: session.unlockedArticles,
|
|
1528
|
+
siteWide: false,
|
|
1529
|
+
credits: config2.initialCredits,
|
|
1530
|
+
bundleExpiry,
|
|
1531
|
+
bundleType: config2.bundleType,
|
|
1532
|
+
iat: now,
|
|
1533
|
+
exp: expiresAt
|
|
1534
|
+
};
|
|
1535
|
+
const token = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(`${config2.durationHours}h`).sign(getSecretKey2(config2.secret));
|
|
1536
|
+
return { token, session };
|
|
1537
|
+
}
|
|
1538
|
+
async function validateCreditSession(token, secret) {
|
|
1539
|
+
if (!token || typeof token !== "string") {
|
|
1540
|
+
return { valid: false, reason: "Invalid token format" };
|
|
1541
|
+
}
|
|
1542
|
+
try {
|
|
1543
|
+
const { payload } = await jose.jwtVerify(token, getSecretKey2(secret));
|
|
1544
|
+
const creditPayload = payload;
|
|
1545
|
+
if (!creditPayload.sub || !creditPayload.sid || !creditPayload.exp) {
|
|
1546
|
+
return { valid: false, reason: "Malformed session payload" };
|
|
1547
|
+
}
|
|
1548
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1549
|
+
if (creditPayload.exp < now) {
|
|
1550
|
+
return { valid: false, reason: "Session expired" };
|
|
1551
|
+
}
|
|
1552
|
+
if (creditPayload.bundleExpiry && creditPayload.bundleExpiry < now) {
|
|
1553
|
+
return { valid: false, reason: "Bundle expired" };
|
|
1554
|
+
}
|
|
1555
|
+
if (!validateWalletAddress2(creditPayload.sub)) {
|
|
1556
|
+
return { valid: false, reason: "Invalid session data" };
|
|
1557
|
+
}
|
|
1558
|
+
const session = {
|
|
1559
|
+
id: creditPayload.sid,
|
|
1560
|
+
walletAddress: creditPayload.sub,
|
|
1561
|
+
unlockedArticles: Array.isArray(creditPayload.articles) ? creditPayload.articles : [],
|
|
1562
|
+
siteWideUnlock: Boolean(creditPayload.siteWide),
|
|
1563
|
+
createdAt: creditPayload.iat ?? 0,
|
|
1564
|
+
expiresAt: creditPayload.exp,
|
|
1565
|
+
credits: creditPayload.credits ?? 0,
|
|
1566
|
+
bundleExpiry: creditPayload.bundleExpiry,
|
|
1567
|
+
bundleType: creditPayload.bundleType
|
|
1568
|
+
};
|
|
1569
|
+
return { valid: true, session };
|
|
1570
|
+
} catch {
|
|
1571
|
+
return { valid: false, reason: "Invalid session" };
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
async function useCredit(token, secret, creditsToUse = 1) {
|
|
1575
|
+
if (creditsToUse <= 0) {
|
|
1576
|
+
return { success: false, remainingCredits: 0, error: "Invalid credit amount" };
|
|
1577
|
+
}
|
|
1578
|
+
const validation = await validateCreditSession(token, secret);
|
|
1579
|
+
if (!validation.valid || !validation.session) {
|
|
1580
|
+
return {
|
|
1581
|
+
success: false,
|
|
1582
|
+
remainingCredits: 0,
|
|
1583
|
+
error: validation.reason || "Invalid session"
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
const session = validation.session;
|
|
1587
|
+
if (session.credits < creditsToUse) {
|
|
1588
|
+
return {
|
|
1589
|
+
success: false,
|
|
1590
|
+
remainingCredits: session.credits,
|
|
1591
|
+
error: "Insufficient credits"
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
const newCredits = session.credits - creditsToUse;
|
|
1595
|
+
const payload = {
|
|
1596
|
+
sub: session.walletAddress,
|
|
1597
|
+
sid: session.id,
|
|
1598
|
+
articles: session.unlockedArticles,
|
|
1599
|
+
siteWide: session.siteWideUnlock,
|
|
1600
|
+
credits: newCredits,
|
|
1601
|
+
bundleExpiry: session.bundleExpiry,
|
|
1602
|
+
bundleType: session.bundleType,
|
|
1603
|
+
iat: session.createdAt,
|
|
1604
|
+
exp: session.expiresAt
|
|
1605
|
+
};
|
|
1606
|
+
const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey2(secret));
|
|
1607
|
+
return {
|
|
1608
|
+
success: true,
|
|
1609
|
+
remainingCredits: newCredits,
|
|
1610
|
+
newToken
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
async function addCredits(token, secret, creditsToAdd) {
|
|
1614
|
+
if (creditsToAdd <= 0 || creditsToAdd > MAX_CREDITS) {
|
|
1615
|
+
return { success: false, error: "Invalid credit amount" };
|
|
1616
|
+
}
|
|
1617
|
+
const validation = await validateCreditSession(token, secret);
|
|
1618
|
+
if (!validation.valid || !validation.session) {
|
|
1619
|
+
return { success: false, error: validation.reason || "Invalid session" };
|
|
1620
|
+
}
|
|
1621
|
+
const session = validation.session;
|
|
1622
|
+
const newCredits = Math.min(session.credits + creditsToAdd, MAX_CREDITS);
|
|
1623
|
+
const payload = {
|
|
1624
|
+
sub: session.walletAddress,
|
|
1625
|
+
sid: session.id,
|
|
1626
|
+
articles: session.unlockedArticles,
|
|
1627
|
+
siteWide: session.siteWideUnlock,
|
|
1628
|
+
credits: newCredits,
|
|
1629
|
+
bundleExpiry: session.bundleExpiry,
|
|
1630
|
+
bundleType: session.bundleType,
|
|
1631
|
+
iat: session.createdAt,
|
|
1632
|
+
exp: session.expiresAt
|
|
1633
|
+
};
|
|
1634
|
+
const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey2(secret));
|
|
1635
|
+
return {
|
|
1636
|
+
success: true,
|
|
1637
|
+
newToken,
|
|
1638
|
+
totalCredits: newCredits
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
async function getRemainingCredits(token, secret) {
|
|
1642
|
+
const validation = await validateCreditSession(token, secret);
|
|
1643
|
+
if (!validation.valid || !validation.session) {
|
|
1644
|
+
return { credits: 0, valid: false };
|
|
1645
|
+
}
|
|
1646
|
+
return {
|
|
1647
|
+
credits: validation.session.credits,
|
|
1648
|
+
valid: true,
|
|
1649
|
+
bundleExpiry: validation.session.bundleExpiry
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1363
1652
|
|
|
1364
1653
|
exports.TOKEN_MINTS = TOKEN_MINTS;
|
|
1365
1654
|
exports.X402_HEADERS = X402_HEADERS;
|
|
1366
1655
|
exports.addArticleToSession = addArticleToSession;
|
|
1656
|
+
exports.addCredits = addCredits;
|
|
1367
1657
|
exports.buildPaymentRequirement = buildPaymentRequirement;
|
|
1368
1658
|
exports.buildSolanaPayUrl = buildSolanaPayUrl;
|
|
1369
1659
|
exports.buildVersionedTransaction = buildVersionedTransaction;
|
|
@@ -1374,6 +1664,7 @@ exports.configurePricing = configurePricing;
|
|
|
1374
1664
|
exports.create402Headers = create402Headers;
|
|
1375
1665
|
exports.create402Response = create402Response;
|
|
1376
1666
|
exports.create402ResponseBody = create402ResponseBody;
|
|
1667
|
+
exports.createCreditSession = createCreditSession;
|
|
1377
1668
|
exports.createMemoryStore = createMemoryStore;
|
|
1378
1669
|
exports.createPaymentFlow = createPaymentFlow;
|
|
1379
1670
|
exports.createPaymentReference = createPaymentReference;
|
|
@@ -1386,20 +1677,26 @@ exports.encodePaymentRequired = encodePaymentRequired;
|
|
|
1386
1677
|
exports.encodePaymentRequirement = encodePaymentRequirement;
|
|
1387
1678
|
exports.encodePaymentResponse = encodePaymentResponse;
|
|
1388
1679
|
exports.estimatePriorityFee = estimatePriorityFee;
|
|
1680
|
+
exports.executeAgentPayment = executeAgentPayment;
|
|
1389
1681
|
exports.fetchLookupTables = fetchLookupTables;
|
|
1390
1682
|
exports.formatPriceDisplay = formatPriceDisplay;
|
|
1391
1683
|
exports.formatPriceSync = formatPriceSync;
|
|
1684
|
+
exports.generateAgentKeypair = generateAgentKeypair;
|
|
1685
|
+
exports.getAgentBalance = getAgentBalance;
|
|
1392
1686
|
exports.getConnection = getConnection;
|
|
1393
1687
|
exports.getConnectionWithFallback = getConnectionWithFallback;
|
|
1394
1688
|
exports.getProviders = getProviders;
|
|
1689
|
+
exports.getRemainingCredits = getRemainingCredits;
|
|
1395
1690
|
exports.getSolPrice = getSolPrice;
|
|
1396
1691
|
exports.getTokenDecimals = getTokenDecimals;
|
|
1397
1692
|
exports.getWalletTransactions = getWalletTransactions;
|
|
1693
|
+
exports.hasAgentSufficientBalance = hasAgentSufficientBalance;
|
|
1398
1694
|
exports.isArticleUnlocked = isArticleUnlocked;
|
|
1399
1695
|
exports.isMainnet = isMainnet;
|
|
1400
1696
|
exports.isNativeAsset = isNativeAsset;
|
|
1401
1697
|
exports.isRetryableRPCError = isRetryableRPCError;
|
|
1402
1698
|
exports.isVersionedTransaction = isVersionedTransaction;
|
|
1699
|
+
exports.keypairFromBase58 = keypairFromBase58;
|
|
1403
1700
|
exports.lamportsToSol = lamportsToSol;
|
|
1404
1701
|
exports.lamportsToUsd = lamportsToUsd;
|
|
1405
1702
|
exports.parsePaymentHeader = parsePaymentHeader;
|
|
@@ -1408,6 +1705,8 @@ exports.resolveMintAddress = resolveMintAddress;
|
|
|
1408
1705
|
exports.solToLamports = solToLamports;
|
|
1409
1706
|
exports.toX402Network = toX402Network;
|
|
1410
1707
|
exports.usdToLamports = usdToLamports;
|
|
1708
|
+
exports.useCredit = useCredit;
|
|
1709
|
+
exports.validateCreditSession = validateCreditSession;
|
|
1411
1710
|
exports.validateSession = validateSession;
|
|
1412
1711
|
exports.verifyPayment = verifyPayment;
|
|
1413
1712
|
exports.verifySPLPayment = verifySPLPayment;
|