@paynodelabs/sdk-js 1.1.2 → 1.4.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 CHANGED
@@ -41,16 +41,24 @@ The SDK includes a full merchant/agent demonstration in the `examples/` director
41
41
 
42
42
  ```bash
43
43
  cp .env.example .env
44
- # Edit .env with your private key and RPC URLs
44
+ # Edit .env with your PRIVATE_KEY and RPC_URL
45
45
  ```
46
46
 
47
- ### 2. Run the Merchant Server (Express)
47
+ ### 2. Get Test Tokens (Required for Base Sepolia)
48
+
49
+ If you're testing on Sepolia, run the helper script to mint 1,000 mock USDC:
50
+
51
+ ```bash
52
+ npx ts-node examples/mint-test-tokens.ts
53
+ ```
54
+
55
+ ### 3. Run the Merchant Server (Express)
48
56
 
49
57
  ```bash
50
58
  npx ts-node examples/express-server.ts
51
59
  ```
52
60
 
53
- ### 3. Run the Agent Client
61
+ ### 4. Run the Agent Client
54
62
 
55
63
  In another terminal:
56
64
 
package/dist/client.d.ts CHANGED
@@ -7,11 +7,11 @@ export declare class PayNodeAgentClient {
7
7
  private rpcUrls;
8
8
  private ERC20_ABI;
9
9
  private ROUTER_ABI;
10
- constructor(privateKey: string, rpcUrls: string | string[]);
10
+ constructor(privateKey: string, rpcUrls?: string | string[]);
11
11
  requestGate(url: string, options?: RequestOptions): Promise<Response>;
12
12
  private handlePaymentAndRetry;
13
- private executeStandardPay;
14
- private executePermitPay;
13
+ pay(contractAddr: string, tokenAddr: string, merchantAddr: string, amount: bigint, orderId: string): Promise<string>;
14
+ payWithPermit(contractAddr: string, tokenAddr: string, merchantAddr: string, amount: bigint, orderId: string): Promise<string>;
15
15
  signPermit(tokenAddr: string, spenderAddr: string, amount: bigint, deadlineSeconds?: number): Promise<{
16
16
  deadline: number;
17
17
  v: 27 | 28;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,OAAO,CAAW;IAE1B,OAAO,CAAC,SAAS,CAMf;IAEF,OAAO,CAAC,UAAU,CAGhB;gBAEU,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAcpD,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;YA0BjE,qBAAqB;YAwDrB,kBAAkB;YAelB,gBAAgB;IAwBxB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAE,MAAa;;;;;;CAwCxG"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,OAAO,CAAW;IAE1B,OAAO,CAAC,SAAS,CAMf;IAEF,OAAO,CAAC,UAAU,CAGhB;gBAEU,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,GAAG,MAAM,EAAkB;IAcpE,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;YA0BjE,qBAAqB;IA0E7B,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAepH,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB9H,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAE,MAAa;;;;;;CAwCxG"}
package/dist/client.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PayNodeAgentClient = void 0;
4
4
  const ethers_1 = require("ethers");
5
5
  const errors_1 = require("./errors");
6
+ const constants_1 = require("./constants");
6
7
  class PayNodeAgentClient {
7
8
  wallet;
8
9
  provider;
@@ -18,7 +19,7 @@ class PayNodeAgentClient {
18
19
  "function pay(address token, address merchant, uint256 amount, bytes32 orderId) public",
19
20
  "function payWithPermit(address payer, address token, address merchant, uint256 amount, bytes32 orderId, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public"
20
21
  ];
21
- constructor(privateKey, rpcUrls) {
22
+ constructor(privateKey, rpcUrls = constants_1.BASE_RPC_URLS) {
22
23
  this.rpcUrls = Array.isArray(rpcUrls) ? rpcUrls : [rpcUrls];
23
24
  const configs = this.rpcUrls.map((url, index) => ({
24
25
  provider: new ethers_1.ethers.JsonRpcProvider(url),
@@ -49,7 +50,7 @@ class PayNodeAgentClient {
49
50
  catch (error) {
50
51
  if (error instanceof errors_1.PayNodeException)
51
52
  throw error;
52
- throw new errors_1.PayNodeException(`Failed to connect to any provided RPC nodes.`, errors_1.ErrorCode.RpcError, error);
53
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.RpcError, undefined, error);
53
54
  }
54
55
  }
55
56
  async handlePaymentAndRetry(url, options, headers) {
@@ -58,13 +59,29 @@ class PayNodeAgentClient {
58
59
  const amountStr = headers.get('x-paynode-amount');
59
60
  const tokenAddr = headers.get('x-paynode-token-address');
60
61
  const orderIdStr = headers.get('x-paynode-order-id');
62
+ const chainIdStr = headers.get('x-paynode-chain-id');
63
+ const currency = headers.get('x-paynode-currency') || 'USDC';
61
64
  if (!contractAddr || !merchantAddr || !amountStr || !tokenAddr || !orderIdStr) {
62
- throw new errors_1.PayNodeException("Malformed 402 headers: missing metadata", errors_1.ErrorCode.InternalError);
65
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.InternalError, "Malformed 402 headers: missing metadata");
63
66
  }
67
+ // Network safety check (v1.4)
68
+ if (chainIdStr) {
69
+ const network = await this.provider.getNetwork();
70
+ if (BigInt(chainIdStr) !== network.chainId) {
71
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.InvalidReceipt, `Network mismatch: Current ${network.chainId}, Request ${chainIdStr}.`);
72
+ }
73
+ }
74
+ console.log(`💡 [PayNode-JS] Payment request: ${amountStr} ${currency} to ${merchantAddr}`);
64
75
  const amount = BigInt(amountStr);
65
76
  // v1.3 Constraint: Min payment protection
66
77
  if (amount < 1000n) {
67
- throw new errors_1.PayNodeException("Payment amount is below the protocol minimum (1000).", errors_1.ErrorCode.AmountTooLow);
78
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.AmountTooLow);
79
+ }
80
+ // v1.4 Constraint: Token whitelist pre-flight (Anti-FakeToken)
81
+ const resolvedChainId = chainIdStr ? Number(chainIdStr) : 8453;
82
+ const whitelist = constants_1.ACCEPTED_TOKENS[resolvedChainId];
83
+ if (whitelist && whitelist.length > 0 && !whitelist.some(t => t.toLowerCase() === tokenAddr.toLowerCase())) {
84
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.TokenNotAccepted);
68
85
  }
69
86
  let txHash;
70
87
  try {
@@ -74,21 +91,21 @@ class PayNodeAgentClient {
74
91
  tokenContract.allowance(this.wallet.address, contractAddr)
75
92
  ]);
76
93
  if (balance < amount) {
77
- throw new errors_1.PayNodeException("Wallet lacks USDC or ETH for gas.", errors_1.ErrorCode.InsufficientFunds);
94
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.InsufficientFunds);
78
95
  }
79
96
  // Protocol v1.3: Permit-First Execution
80
97
  if (allowance >= amount) {
81
- txHash = await this.executeStandardPay(contractAddr, tokenAddr, merchantAddr, amount, orderIdStr);
98
+ txHash = await this.pay(contractAddr, tokenAddr, merchantAddr, amount, orderIdStr);
82
99
  }
83
100
  else {
84
101
  console.log(`⚡ [PayNode-JS] Insufficient allowance. Attempting Permit-First payment...`);
85
- txHash = await this.executePermitPay(contractAddr, tokenAddr, merchantAddr, amount, orderIdStr);
102
+ txHash = await this.payWithPermit(contractAddr, tokenAddr, merchantAddr, amount, orderIdStr);
86
103
  }
87
104
  }
88
105
  catch (error) {
89
106
  if (error instanceof errors_1.PayNodeException)
90
107
  throw error;
91
- throw new errors_1.PayNodeException(`On-chain transaction reverted or failed.`, errors_1.ErrorCode.TransactionFailed, error);
108
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.TransactionFailed, undefined, error);
92
109
  }
93
110
  console.log(`✅ [PayNode-JS] Payment confirmed on-chain: ${txHash}`);
94
111
  const retryOptions = {
@@ -101,7 +118,7 @@ class PayNodeAgentClient {
101
118
  };
102
119
  return await fetch(url, retryOptions);
103
120
  }
104
- async executeStandardPay(contractAddr, tokenAddr, merchantAddr, amount, orderId) {
121
+ async pay(contractAddr, tokenAddr, merchantAddr, amount, orderId) {
105
122
  const router = new ethers_1.ethers.Contract(contractAddr, this.ROUTER_ABI, this.wallet);
106
123
  const orderIdBytes = ethers_1.ethers.id(orderId);
107
124
  const feeData = await this.provider.getFeeData();
@@ -113,7 +130,7 @@ class PayNodeAgentClient {
113
130
  const receipt = await tx.wait();
114
131
  return receipt.hash;
115
132
  }
116
- async executePermitPay(contractAddr, tokenAddr, merchantAddr, amount, orderId) {
133
+ async payWithPermit(contractAddr, tokenAddr, merchantAddr, amount, orderId) {
117
134
  const sig = await this.signPermit(tokenAddr, contractAddr, amount);
118
135
  const router = new ethers_1.ethers.Contract(contractAddr, this.ROUTER_ABI, this.wallet);
119
136
  const orderIdBytes = ethers_1.ethers.id(orderId);
@@ -1,8 +1,8 @@
1
1
  /** Generated by scripts/sync-config.py */
2
- export declare const PAYNODE_ROUTER_ADDRESS = "0x92e20164FC457a2aC35f53D06268168e6352b200";
3
- export declare const PAYNODE_ROUTER_ADDRESS_SANDBOX = "0xB587Bc36aaCf65962eCd6Ba59e2DA76f2f575408";
2
+ export declare const PAYNODE_ROUTER_ADDRESS = "0x4A73696ccF76E7381b044cB95127B3784369Ed63";
3
+ export declare const PAYNODE_ROUTER_ADDRESS_SANDBOX = "0x24cD8b68aaC209217ff5a6ef1Bf55a59f2c8Ca6F";
4
4
  export declare const BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
5
- export declare const BASE_USDC_ADDRESS_SANDBOX = "0xeAC1f2C7099CdaFfB91Aa3b8Ffd653Ef16935798";
5
+ export declare const BASE_USDC_ADDRESS_SANDBOX = "0x109AEddD656Ed2761d1e210E179329105039c784";
6
6
  export declare const PROTOCOL_TREASURY = "0x598bF63F5449876efafa7b36b77Deb2070621C0E";
7
7
  export declare const PROTOCOL_FEE_BPS = 100;
8
8
  export declare const MIN_PAYMENT_AMOUNT: bigint;
package/dist/constants.js CHANGED
@@ -2,10 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ACCEPTED_TOKENS = exports.BASE_RPC_URLS_SANDBOX = exports.BASE_RPC_URLS = exports.MIN_PAYMENT_AMOUNT = exports.PROTOCOL_FEE_BPS = exports.PROTOCOL_TREASURY = exports.BASE_USDC_ADDRESS_SANDBOX = exports.BASE_USDC_ADDRESS = exports.PAYNODE_ROUTER_ADDRESS_SANDBOX = exports.PAYNODE_ROUTER_ADDRESS = void 0;
4
4
  /** Generated by scripts/sync-config.py */
5
- exports.PAYNODE_ROUTER_ADDRESS = "0x92e20164FC457a2aC35f53D06268168e6352b200";
6
- exports.PAYNODE_ROUTER_ADDRESS_SANDBOX = "0xB587Bc36aaCf65962eCd6Ba59e2DA76f2f575408";
5
+ exports.PAYNODE_ROUTER_ADDRESS = "0x4A73696ccF76E7381b044cB95127B3784369Ed63";
6
+ exports.PAYNODE_ROUTER_ADDRESS_SANDBOX = "0x24cD8b68aaC209217ff5a6ef1Bf55a59f2c8Ca6F";
7
7
  exports.BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
8
- exports.BASE_USDC_ADDRESS_SANDBOX = "0xeAC1f2C7099CdaFfB91Aa3b8Ffd653Ef16935798";
8
+ exports.BASE_USDC_ADDRESS_SANDBOX = "0x109AEddD656Ed2761d1e210E179329105039c784";
9
9
  exports.PROTOCOL_TREASURY = "0x598bF63F5449876efafa7b36b77Deb2070621C0E";
10
10
  exports.PROTOCOL_FEE_BPS = 100;
11
11
  exports.MIN_PAYMENT_AMOUNT = BigInt(1000);
@@ -13,5 +13,5 @@ exports.BASE_RPC_URLS = ["https://mainnet.base.org", "https://base.meowrpc.com",
13
13
  exports.BASE_RPC_URLS_SANDBOX = ["https://sepolia.base.org", "https://base-sepolia-rpc.publicnode.com"];
14
14
  exports.ACCEPTED_TOKENS = {
15
15
  8453: ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"],
16
- 84532: ["0xeAC1f2C7099CdaFfB91Aa3b8Ffd653Ef16935798"]
16
+ 84532: ["0x109AEddD656Ed2761d1e210E179329105039c784"]
17
17
  };
@@ -1,21 +1,22 @@
1
+ /** Generated by scripts/sync-config.py */
1
2
  export declare enum ErrorCode {
2
- RpcError = "RpcError",
3
- InsufficientFunds = "InsufficientFunds",
4
- AmountTooLow = "AmountTooLow",
5
- TokenNotAccepted = "TokenNotAccepted",
6
- TransactionFailed = "TransactionFailed",
7
- DuplicateTransaction = "DuplicateTransaction",
8
- InvalidReceipt = "InvalidReceipt",
9
- InternalError = "InternalError",
10
- TransactionNotFound = "TransactionNotFound",
11
- WrongContract = "WrongContract",
12
- OrderMismatch = "OrderMismatch",
13
- MissingReceipt = "MissingReceipt"
3
+ RpcError = "rpc_error",
4
+ InsufficientFunds = "insufficient_funds",
5
+ AmountTooLow = "amount_too_low",
6
+ TokenNotAccepted = "token_not_accepted",
7
+ TransactionFailed = "transaction_failed",
8
+ DuplicateTransaction = "duplicate_transaction",
9
+ InvalidReceipt = "invalid_receipt",
10
+ InternalError = "internal_error",
11
+ TransactionNotFound = "transaction_not_found",
12
+ WrongContract = "wrong_contract",
13
+ OrderMismatch = "order_mismatch",
14
+ MissingReceipt = "missing_receipt"
14
15
  }
16
+ export declare const ERROR_MESSAGES: Record<string, string>;
15
17
  export declare class PayNodeException extends Error {
16
- message: string;
17
18
  code: ErrorCode;
18
19
  details?: any | undefined;
19
- constructor(message: string, code: ErrorCode, details?: any | undefined);
20
+ constructor(code: ErrorCode, message?: string, details?: any | undefined);
20
21
  }
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,QAAQ,aAAa;IACrB,iBAAiB,sBAAsB;IACvC,YAAY,iBAAiB;IAC7B,gBAAgB,qBAAqB;IACrC,iBAAiB,sBAAsB;IACvC,oBAAoB,yBAAyB;IAC7C,cAAc,mBAAmB;IACjC,aAAa,kBAAkB;IAC/B,mBAAmB,wBAAwB;IAC3C,aAAa,kBAAkB;IAC/B,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;CAClC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACtB,OAAO,EAAE,MAAM;IAAS,IAAI,EAAE,SAAS;IAAS,OAAO,CAAC,EAAE,GAAG;gBAA7D,OAAO,EAAE,MAAM,EAAS,IAAI,EAAE,SAAS,EAAS,OAAO,CAAC,EAAE,GAAG,YAAA;CAIjF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,oBAAY,SAAS;IACnB,QAAQ,cAAc;IACtB,iBAAiB,uBAAuB;IACxC,YAAY,mBAAmB;IAC/B,gBAAgB,uBAAuB;IACvC,iBAAiB,uBAAuB;IACxC,oBAAoB,0BAA0B;IAC9C,cAAc,oBAAoB;IAClC,aAAa,mBAAmB;IAChC,mBAAmB,0BAA0B;IAC7C,aAAa,mBAAmB;IAChC,aAAa,mBAAmB;IAChC,cAAc,oBAAoB;CACnC;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAajD,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,KAAK;IACtB,IAAI,EAAE,SAAS;IAA2B,OAAO,CAAC,EAAE,GAAG;gBAAvD,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,EAAS,OAAO,CAAC,EAAE,GAAG,YAAA;CAM3E"}
@@ -1,31 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PayNodeException = exports.ErrorCode = void 0;
3
+ exports.PayNodeException = exports.ERROR_MESSAGES = exports.ErrorCode = void 0;
4
+ /** Generated by scripts/sync-config.py */
4
5
  var ErrorCode;
5
6
  (function (ErrorCode) {
6
- ErrorCode["RpcError"] = "RpcError";
7
- ErrorCode["InsufficientFunds"] = "InsufficientFunds";
8
- ErrorCode["AmountTooLow"] = "AmountTooLow";
9
- ErrorCode["TokenNotAccepted"] = "TokenNotAccepted";
10
- ErrorCode["TransactionFailed"] = "TransactionFailed";
11
- ErrorCode["DuplicateTransaction"] = "DuplicateTransaction";
12
- ErrorCode["InvalidReceipt"] = "InvalidReceipt";
13
- ErrorCode["InternalError"] = "InternalError";
14
- ErrorCode["TransactionNotFound"] = "TransactionNotFound";
15
- ErrorCode["WrongContract"] = "WrongContract";
16
- ErrorCode["OrderMismatch"] = "OrderMismatch";
17
- ErrorCode["MissingReceipt"] = "MissingReceipt";
7
+ ErrorCode["RpcError"] = "rpc_error";
8
+ ErrorCode["InsufficientFunds"] = "insufficient_funds";
9
+ ErrorCode["AmountTooLow"] = "amount_too_low";
10
+ ErrorCode["TokenNotAccepted"] = "token_not_accepted";
11
+ ErrorCode["TransactionFailed"] = "transaction_failed";
12
+ ErrorCode["DuplicateTransaction"] = "duplicate_transaction";
13
+ ErrorCode["InvalidReceipt"] = "invalid_receipt";
14
+ ErrorCode["InternalError"] = "internal_error";
15
+ ErrorCode["TransactionNotFound"] = "transaction_not_found";
16
+ ErrorCode["WrongContract"] = "wrong_contract";
17
+ ErrorCode["OrderMismatch"] = "order_mismatch";
18
+ ErrorCode["MissingReceipt"] = "missing_receipt";
18
19
  })(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
20
+ exports.ERROR_MESSAGES = {
21
+ "rpc_error": "Failed to connect to any provided RPC nodes.",
22
+ "insufficient_funds": "Wallet lacks USDC or ETH for gas.",
23
+ "amount_too_low": "Payment amount is below the protocol minimum (1000).",
24
+ "token_not_accepted": "The provided token address is not in the whitelist.",
25
+ "transaction_failed": "On-chain transaction reverted or failed.",
26
+ "duplicate_transaction": "This transaction hash has already been consumed.",
27
+ "invalid_receipt": "The provided receipt (TxHash) is malformed or invalid.",
28
+ "internal_error": "An unexpected error occurred.",
29
+ "transaction_not_found": "Transaction not found on-chain.",
30
+ "wrong_contract": "Payment event was not emitted by the official PayNode contract.",
31
+ "order_mismatch": "OrderId in receipt does not match requested ID.",
32
+ "missing_receipt": "Please pay to PayNode contract and provide 'x-paynode-receipt' header.",
33
+ };
19
34
  class PayNodeException extends Error {
20
- message;
21
35
  code;
22
36
  details;
23
- constructor(message, code, details) {
24
- super(message);
25
- this.message = message;
37
+ constructor(code, message, details) {
38
+ const finalMessage = message || exports.ERROR_MESSAGES[code] || "An unexpected error occurred.";
39
+ super(finalMessage);
26
40
  this.code = code;
27
41
  this.details = details;
28
42
  this.name = "PayNodeException";
43
+ this.message = finalMessage;
29
44
  }
30
45
  }
31
46
  exports.PayNodeException = PayNodeException;
package/dist/index.d.ts CHANGED
@@ -4,4 +4,5 @@ export * from './utils/idempotency';
4
4
  export * from './utils/webhook';
5
5
  export * from './client';
6
6
  export * from './errors';
7
+ export * from './constants';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -20,3 +20,4 @@ __exportStar(require("./utils/idempotency"), exports);
20
20
  __exportStar(require("./utils/webhook"), exports);
21
21
  __exportStar(require("./client"), exports);
22
22
  __exportStar(require("./errors"), exports);
23
+ __exportStar(require("./constants"), exports);
@@ -1,16 +1,18 @@
1
- import { Request, NextFunction } from 'express';
1
+ import { Request, Response, NextFunction } from 'express';
2
2
  import { IdempotencyStore } from '../utils/idempotency';
3
3
  export interface PayNodeMiddlewareOptions {
4
- rpcUrls: string | string[];
5
- chainId: number;
6
- contractAddress: string;
7
4
  merchantAddress: string;
8
- tokenAddress: string;
9
- currency: string;
10
5
  price: string;
11
- decimals: number;
6
+ rpcUrls?: string | string[];
7
+ chainId?: number;
8
+ contractAddress?: string;
9
+ tokenAddress?: string;
10
+ currency?: string;
11
+ decimals?: number;
12
12
  store?: IdempotencyStore;
13
13
  generateOrderId?: (req: Request | any) => string;
14
14
  }
15
- export declare const x402_gate: (options: PayNodeMiddlewareOptions) => (req: any, res: any, next: NextFunction) => Promise<any>;
15
+ export declare const x402Gate: (options: PayNodeMiddlewareOptions) => (req: Request | any, res: Response | any, next: NextFunction) => Promise<any>;
16
+ /** @deprecated Use x402Gate instead. */
17
+ export declare const x402_gate: (options: PayNodeMiddlewareOptions) => (req: Request | any, res: Response | any, next: NextFunction) => Promise<any>;
16
18
  //# sourceMappingURL=x402.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../../src/middleware/x402.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAY,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,KAAK,MAAM,CAAC;CAClD;AAED,eAAO,MAAM,SAAS,GAAI,SAAS,wBAAwB,MAiB3C,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,iBAwDrD,CAAC"}
1
+ {"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../../src/middleware/x402.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQxD,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,KAAK,MAAM,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,GAAI,SAAS,wBAAwB,MAwB1C,KAAK,OAAO,GAAG,GAAG,EAAE,KAAK,QAAQ,GAAG,GAAG,EAAE,MAAM,YAAY,iBAwD1E,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,SAAS,YAnFY,wBAAwB,MAwB1C,KAAK,OAAO,GAAG,GAAG,EAAE,KAAK,QAAQ,GAAG,GAAG,EAAE,MAAM,YAAY,iBA2D1C,CAAC"}
@@ -1,26 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.x402_gate = void 0;
3
+ exports.x402_gate = exports.x402Gate = void 0;
4
4
  const errors_1 = require("../errors");
5
5
  const verifier_1 = require("../utils/verifier");
6
6
  const ethers_1 = require("ethers");
7
- const x402_gate = (options) => {
7
+ const constants_1 = require("../constants");
8
+ const x402Gate = (options) => {
9
+ const rpcUrls = options.rpcUrls || constants_1.BASE_RPC_URLS;
10
+ const chainId = options.chainId || 8453;
11
+ const contractAddress = options.contractAddress || constants_1.PAYNODE_ROUTER_ADDRESS;
12
+ const tokenAddress = options.tokenAddress || constants_1.BASE_USDC_ADDRESS;
13
+ const currency = options.currency || 'USDC';
14
+ const decimals = options.decimals !== undefined ? options.decimals : 6;
8
15
  const verifier = new verifier_1.PayNodeVerifier({
9
- rpcUrls: options.rpcUrls,
10
- chainId: options.chainId,
11
- contractAddress: options.contractAddress,
16
+ rpcUrls,
17
+ chainId,
18
+ contractAddress,
12
19
  store: options.store
13
20
  });
14
21
  let rawAmount;
15
22
  try {
16
- rawAmount = (0, ethers_1.parseUnits)(options.price, options.decimals);
23
+ rawAmount = (0, ethers_1.parseUnits)(options.price, decimals);
17
24
  }
18
25
  catch (e) {
19
- rawAmount = BigInt(Math.floor(parseFloat(options.price) * (10 ** options.decimals)));
26
+ rawAmount = BigInt(Math.floor(parseFloat(options.price) * (10 ** decimals)));
20
27
  }
21
28
  const defaultOrderIdGen = (req) => `agent_js_${Date.now()}`;
22
29
  return async (req, res, next) => {
23
- // Compatibility with different mock/real environments
30
+ // ... rest of the logic
24
31
  const getHeader = (name) => {
25
32
  if (req.header && typeof req.header === 'function')
26
33
  return req.header(name);
@@ -36,12 +43,12 @@ const x402_gate = (options) => {
36
43
  if (!receiptHash) {
37
44
  if (res.set) {
38
45
  res.set({
39
- 'x-paynode-contract': options.contractAddress,
46
+ 'x-paynode-contract': contractAddress,
40
47
  'x-paynode-merchant': options.merchantAddress,
41
48
  'x-paynode-amount': rawAmount.toString(),
42
- 'x-paynode-currency': options.currency,
43
- 'x-paynode-token-address': options.tokenAddress,
44
- 'x-paynode-chain-id': options.chainId.toString(),
49
+ 'x-paynode-currency': currency,
50
+ 'x-paynode-token-address': tokenAddress,
51
+ 'x-paynode-chain-id': chainId.toString(),
45
52
  'x-paynode-order-id': orderId
46
53
  });
47
54
  }
@@ -50,13 +57,13 @@ const x402_gate = (options) => {
50
57
  code: errors_1.ErrorCode.MissingReceipt,
51
58
  message: "Please pay to PayNode contract and provide 'x-paynode-receipt' header.",
52
59
  amount: options.price,
53
- currency: options.currency
60
+ currency: currency
54
61
  });
55
62
  }
56
63
  // Phase 2: On-chain Verification
57
64
  const result = await verifier.verifyPayment(receiptHash, {
58
65
  merchantAddress: options.merchantAddress,
59
- tokenAddress: options.tokenAddress,
66
+ tokenAddress: tokenAddress,
60
67
  amount: rawAmount,
61
68
  orderId: orderId
62
69
  });
@@ -74,4 +81,6 @@ const x402_gate = (options) => {
74
81
  }
75
82
  };
76
83
  };
77
- exports.x402_gate = x402_gate;
84
+ exports.x402Gate = x402Gate;
85
+ /** @deprecated Use x402Gate instead. */
86
+ exports.x402_gate = exports.x402Gate;
@@ -1,13 +1,5 @@
1
1
  import { PayNodeException } from '../errors';
2
2
  import { IdempotencyStore } from './idempotency';
3
- /**
4
- * Default accepted token addresses across supported chains.
5
- * SDK will reject any payment involving a token NOT in this whitelist,
6
- * preventing fake-token attacks at the verification layer.
7
- */
8
- export declare const ACCEPTED_TOKENS: Record<string, string[]>;
9
- /** Minimum allowed payment amount to prevent dust exploits (1000 = 0.001 USDC) */
10
- export declare const MIN_PAYMENT_AMOUNT = 1000n;
11
3
  export interface PayNodeVerifierConfig {
12
4
  rpcUrls: string | string[];
13
5
  contractAddress: string;
@@ -1 +1 @@
1
- {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/utils/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CASpD,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,oGAAoG;IACpG,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,KAAK,CAAC,CAAmB;IACjC,OAAO,CAAC,cAAc,CAAC,CAAc;gBAEzB,MAAM,EAAE,qBAAqB;IAmCnC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAC;CAkFxH"}
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../src/utils/verifier.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAA0B,MAAM,eAAe,CAAC;AAGzE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,oGAAoG;IACpG,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,KAAK,CAAC,CAAmB;IACjC,OAAO,CAAC,cAAc,CAAC,CAAc;gBAEzB,MAAM,EAAE,qBAAqB;IAmCnC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAC;CA2FxH"}
@@ -1,25 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PayNodeVerifier = exports.MIN_PAYMENT_AMOUNT = exports.ACCEPTED_TOKENS = void 0;
4
- const errors_1 = require("../errors");
3
+ exports.PayNodeVerifier = void 0;
5
4
  const ethers_1 = require("ethers");
6
- /**
7
- * Default accepted token addresses across supported chains.
8
- * SDK will reject any payment involving a token NOT in this whitelist,
9
- * preventing fake-token attacks at the verification layer.
10
- */
11
- exports.ACCEPTED_TOKENS = {
12
- // Base Mainnet (chainId: 8453)
13
- '8453': [
14
- '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
15
- ],
16
- // Base Sepolia (chainId: 84532)
17
- '84532': [
18
- '0xeAC1f2C7099CdaFfB91Aa3b8Ffd653Ef16935798', // USDC (Sandbox)
19
- ],
20
- };
21
- /** Minimum allowed payment amount to prevent dust exploits (1000 = 0.001 USDC) */
22
- exports.MIN_PAYMENT_AMOUNT = 1000n;
5
+ const errors_1 = require("../errors");
6
+ const idempotency_1 = require("./idempotency");
7
+ const constants_1 = require("../constants");
23
8
  const PAYNODE_ABI = [
24
9
  "event PaymentReceived(bytes32 indexed orderId, address indexed merchant, address indexed payer, address token, uint256 amount, uint256 fee, uint256 chainId)"
25
10
  ];
@@ -32,7 +17,7 @@ class PayNodeVerifier {
32
17
  acceptedTokens;
33
18
  constructor(config) {
34
19
  if (!config.rpcUrls || (Array.isArray(config.rpcUrls) && config.rpcUrls.length === 0)) {
35
- throw new errors_1.PayNodeException("Failed to connect to any provided RPC nodes.", errors_1.ErrorCode.RpcError);
20
+ throw new errors_1.PayNodeException(errors_1.ErrorCode.RpcError);
36
21
  }
37
22
  // Support RpcPool / FallbackProvider
38
23
  if (Array.isArray(config.rpcUrls)) {
@@ -51,13 +36,13 @@ class PayNodeVerifier {
51
36
  }
52
37
  this.contractAddress = config.contractAddress;
53
38
  this.chainId = config.chainId;
54
- this.store = config.store;
39
+ this.store = config.store || new idempotency_1.MemoryIdempotencyStore();
55
40
  let tokenList;
56
41
  if (config.acceptedTokens !== undefined) {
57
42
  tokenList = config.acceptedTokens;
58
43
  }
59
44
  else if (config.chainId) {
60
- tokenList = exports.ACCEPTED_TOKENS[config.chainId.toString()];
45
+ tokenList = constants_1.ACCEPTED_TOKENS[config.chainId];
61
46
  }
62
47
  if (tokenList && tokenList.length > 0) {
63
48
  this.acceptedTokens = new Set(tokenList.map(t => t.toLowerCase()));
@@ -67,27 +52,20 @@ class PayNodeVerifier {
67
52
  try {
68
53
  // 0. Dust Exploit Check (Minimum Payment)
69
54
  const expectedAmount = BigInt(expected.amount);
70
- if (expectedAmount < exports.MIN_PAYMENT_AMOUNT) {
71
- return { isValid: false, error: new errors_1.PayNodeException("Payment amount is below the protocol minimum (1000).", errors_1.ErrorCode.AmountTooLow) };
55
+ if (expectedAmount < constants_1.MIN_PAYMENT_AMOUNT) {
56
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.AmountTooLow) };
72
57
  }
73
58
  // 1. Token Whitelist Check (Anti-FakeToken)
74
59
  if (this.acceptedTokens && !this.acceptedTokens.has(expected.tokenAddress.toLowerCase())) {
75
- return { isValid: false, error: new errors_1.PayNodeException("The provided token address is not in the whitelist.", errors_1.ErrorCode.TokenNotAccepted) };
76
- }
77
- // 1. Idempotency Check
78
- if (this.store) {
79
- const isNew = await this.store.checkAndSet(txHash, 86400);
80
- if (!isNew) {
81
- return { isValid: false, error: new errors_1.PayNodeException("This transaction hash has already been consumed.", errors_1.ErrorCode.DuplicateTransaction) };
82
- }
60
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.TokenNotAccepted) };
83
61
  }
84
62
  // 2. Fetch Receipt
85
63
  const receipt = await this.provider.getTransactionReceipt(txHash);
86
64
  if (!receipt) {
87
- return { isValid: false, error: new errors_1.PayNodeException("The provided receipt (TxHash) is malformed or invalid.", errors_1.ErrorCode.InvalidReceipt) };
65
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.InvalidReceipt) };
88
66
  }
89
67
  if (receipt.status !== 1) {
90
- return { isValid: false, error: new errors_1.PayNodeException("On-chain transaction reverted or failed.", errors_1.ErrorCode.TransactionFailed) };
68
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.TransactionFailed) };
91
69
  }
92
70
  // 3. Parse Logs & Verify Contract Source
93
71
  let paymentLog = null;
@@ -108,32 +86,45 @@ class PayNodeVerifier {
108
86
  }
109
87
  }
110
88
  if (!paymentLog) {
111
- return { isValid: false, error: new errors_1.PayNodeException("No valid PaymentReceived event from official contract found in transaction.", errors_1.ErrorCode.WrongContract) };
89
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.WrongContract) };
112
90
  }
113
91
  const args = paymentLog.parsed.args;
114
- // 4. Verify Merchant
92
+ // 4. Verify OrderId (bytes32 keccak256 hash comparison)
93
+ if (expected.orderId) {
94
+ if (args.orderId !== ethers_1.ethers.id(expected.orderId)) {
95
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.OrderMismatch) };
96
+ }
97
+ }
98
+ // 5. Verify Merchant
115
99
  if (args.merchant.toLowerCase() !== expected.merchantAddress.toLowerCase()) {
116
- return { isValid: false, error: new errors_1.PayNodeException("Payment went to a different merchant.", errors_1.ErrorCode.InvalidReceipt) };
100
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.InvalidReceipt, "Payment went to a different merchant.") };
117
101
  }
118
102
  // 5. Verify Token
119
103
  if (args.token.toLowerCase() !== expected.tokenAddress.toLowerCase()) {
120
- return { isValid: false, error: new errors_1.PayNodeException("Payment used unexpected token.", errors_1.ErrorCode.InvalidReceipt) };
104
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.InvalidReceipt, "Payment used unexpected token.") };
121
105
  }
122
106
  // 6. Verify Amount
123
107
  if (BigInt(args.amount) < BigInt(expected.amount)) {
124
- return { isValid: false, error: new errors_1.PayNodeException("Payment amount is below required price.", errors_1.ErrorCode.InvalidReceipt) };
108
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.InvalidReceipt, "Payment amount is below required price.") };
125
109
  }
126
110
  // 7. Verify ChainId (Cross-chain replay protection)
127
111
  const expectedChainId = BigInt(this.chainId || (await this.provider.getNetwork()).chainId);
128
112
  if (BigInt(args.chainId) !== expectedChainId) {
129
- return { isValid: false, error: new errors_1.PayNodeException("ChainId mismatch. Invalid network.", errors_1.ErrorCode.InvalidReceipt) };
113
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.InvalidReceipt, "ChainId mismatch. Invalid network.") };
114
+ }
115
+ // 8. Idempotency Check
116
+ if (this.store) {
117
+ const isNew = await this.store.checkAndSet(txHash, 86400);
118
+ if (!isNew) {
119
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.DuplicateTransaction) };
120
+ }
130
121
  }
131
122
  return { isValid: true };
132
123
  }
133
124
  catch (e) {
134
125
  if (e instanceof errors_1.PayNodeException)
135
126
  return { isValid: false, error: e };
136
- return { isValid: false, error: new errors_1.PayNodeException(`An unexpected error occurred: ${e.message}`, errors_1.ErrorCode.InternalError) };
127
+ return { isValid: false, error: new errors_1.PayNodeException(errors_1.ErrorCode.InternalError, `An unexpected error occurred: ${e.message}`) };
137
128
  }
138
129
  }
139
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paynodelabs/sdk-js",
3
- "version": "1.1.2",
3
+ "version": "1.4.0",
4
4
  "description": "The official JavaScript/TypeScript SDK for PayNode x402 protocol on Base L2.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",