@profullstack/coinpay 0.6.8 → 0.6.11

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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to `@profullstack/coinpay` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.6.11] - 2026-03-19
9
+
10
+ ### Added
11
+ - OAuth client management methods: `listOAuthClients()`, `createOAuthClient()`, `getOAuthClient()`, `deleteOAuthClient()`
12
+ - CLI `coinpay oauth` commands: `list`, `create`, `get`, `delete`
13
+ - OAuth section in SDK documentation
14
+
8
15
  ## [0.2.0] - 2025-01-15
9
16
 
10
17
  ### Added
package/bin/coinpay.js CHANGED
@@ -244,6 +244,12 @@ ${colors.cyan}Commands:${colors.reset}
244
244
  events <id> Get escrow audit log
245
245
  auth <id> Authenticate with escrow token
246
246
 
247
+ ${colors.bright}oauth${colors.reset}
248
+ list List OAuth clients
249
+ create Create a new OAuth client
250
+ get <id> Get OAuth client details
251
+ delete <id> Delete an OAuth client
252
+
247
253
  ${colors.bright}reputation${colors.reset}
248
254
  submit Submit a task receipt
249
255
  query <agent-did> Query agent reputation
@@ -2567,6 +2573,147 @@ async function main() {
2567
2573
  }
2568
2574
 
2569
2575
  try {
2576
+
2577
+ async function handleLightning(subcommand, args, flags) {
2578
+ const client = createClient();
2579
+
2580
+ switch (subcommand) {
2581
+ case 'enable': {
2582
+ const walletId = flags['wallet-id'] || flags['wallet'];
2583
+ if (!walletId) {
2584
+ console.error(colors.red + 'Error: --wallet-id required' + colors.reset);
2585
+ process.exit(1);
2586
+ }
2587
+ const mnemonic = await getDecryptedMnemonic(flags);
2588
+ const result = await client.lightning.enableWallet({
2589
+ wallet_id: walletId,
2590
+ mnemonic,
2591
+ business_id: flags['business-id'],
2592
+ });
2593
+ console.log(colors.green + '⚡ Lightning wallet enabled!' + colors.reset);
2594
+ console.log(JSON.stringify(result, null, 2));
2595
+ break;
2596
+ }
2597
+
2598
+ case 'address': {
2599
+ const walletId = flags['wallet-id'] || flags['wallet'];
2600
+ const username = flags['username'] || args[0];
2601
+ if (!walletId) {
2602
+ console.error(colors.red + 'Error: --wallet-id required' + colors.reset);
2603
+ process.exit(1);
2604
+ }
2605
+ if (!username) {
2606
+ // GET current address
2607
+ const result = await client.lightning.getAddress(walletId);
2608
+ if (result.lightning_address) {
2609
+ console.log(colors.green + '⚡ ' + result.lightning_address + colors.reset);
2610
+ } else {
2611
+ console.log('No Lightning Address registered. Use: coinpay ln address --username <name>');
2612
+ }
2613
+ } else {
2614
+ // POST register address
2615
+ const result = await client.lightning.registerAddress({ wallet_id: walletId, username });
2616
+ console.log(colors.green + '⚡ Registered: ' + result.lightning_address + colors.reset);
2617
+ }
2618
+ break;
2619
+ }
2620
+
2621
+ case 'address-check': {
2622
+ const username = flags['username'] || args[0];
2623
+ if (!username) {
2624
+ console.error(colors.red + 'Error: --username required' + colors.reset);
2625
+ process.exit(1);
2626
+ }
2627
+ const result = await client.lightning.checkAddressAvailable(username);
2628
+ console.log(result.available
2629
+ ? colors.green + '✓ ' + username + ' is available' + colors.reset
2630
+ : colors.red + '✗ ' + username + ' is taken' + colors.reset);
2631
+ break;
2632
+ }
2633
+
2634
+ case 'invoice': {
2635
+ const walletId = flags['wallet-id'] || flags['wallet'];
2636
+ const amount = parseInt(flags['amount'] || args[0]);
2637
+ if (!walletId || !amount) {
2638
+ console.error(colors.red + 'Error: --wallet-id and --amount required' + colors.reset);
2639
+ process.exit(1);
2640
+ }
2641
+ const result = await client.lightning.createInvoice({
2642
+ wallet_id: walletId,
2643
+ amount_sats: amount,
2644
+ description: flags['description'] || flags['desc'] || '',
2645
+ });
2646
+ console.log(colors.green + '⚡ Invoice created' + colors.reset);
2647
+ console.log(JSON.stringify(result, null, 2));
2648
+ break;
2649
+ }
2650
+
2651
+ case 'send': {
2652
+ const walletId = flags['wallet-id'] || flags['wallet'];
2653
+ const destination = flags['to'] || args[0];
2654
+ const amount = flags['amount'] ? parseInt(flags['amount']) : undefined;
2655
+ if (!walletId || !destination) {
2656
+ console.error(colors.red + 'Error: --wallet-id and --to required' + colors.reset);
2657
+ process.exit(1);
2658
+ }
2659
+ const result = await client.lightning.sendPayment({
2660
+ wallet_id: walletId,
2661
+ destination,
2662
+ amount_sats: amount,
2663
+ });
2664
+ console.log(colors.green + '⚡ Payment sent!' + colors.reset);
2665
+ console.log(JSON.stringify(result, null, 2));
2666
+ break;
2667
+ }
2668
+
2669
+ case 'payments': {
2670
+ const walletId = flags['wallet-id'] || flags['wallet'];
2671
+ if (!walletId) {
2672
+ console.error(colors.red + 'Error: --wallet-id required' + colors.reset);
2673
+ process.exit(1);
2674
+ }
2675
+ const result = await client.lightning.listPayments({
2676
+ wallet_id: walletId,
2677
+ direction: flags['direction'],
2678
+ limit: flags['limit'] ? parseInt(flags['limit']) : undefined,
2679
+ });
2680
+ const payments = result.data?.payments || result.payments || [];
2681
+ if (payments.length === 0) {
2682
+ console.log('No Lightning payments found.');
2683
+ } else {
2684
+ for (const p of payments) {
2685
+ const dir = p.direction === 'outgoing' ? colors.red + '↑ SENT' : colors.green + '↓ RECV';
2686
+ const sats = Math.floor((p.amount_msat || 0) / 1000);
2687
+ console.log(`${dir}${colors.reset} ${sats} sats ${p.status} ${p.created_at}`);
2688
+ }
2689
+ }
2690
+ break;
2691
+ }
2692
+
2693
+ case 'balance': {
2694
+ const walletId = flags['wallet-id'] || flags['wallet'];
2695
+ if (!walletId) {
2696
+ console.error(colors.red + 'Error: --wallet-id required' + colors.reset);
2697
+ process.exit(1);
2698
+ }
2699
+ // Use the web-wallet balance endpoint filtered by LN
2700
+ const result = await client.request(`/web-wallet/balance?wallet_id=${walletId}`);
2701
+ const balances = result.data?.balances || result.balances || [];
2702
+ const ln = balances.find(b => b.chain === 'LN' || b.currency === 'LN');
2703
+ if (ln) {
2704
+ console.log(colors.green + '⚡ ' + ln.balance + ' BTC (' + Math.floor(parseFloat(ln.balance) * 100_000_000) + ' sats)' + colors.reset);
2705
+ } else {
2706
+ console.log('No Lightning balance. Enable Lightning first: coinpay ln enable');
2707
+ }
2708
+ break;
2709
+ }
2710
+
2711
+ default:
2712
+ console.log(`Unknown lightning command: ${subcommand}`);
2713
+ showHelp();
2714
+ }
2715
+ }
2716
+
2570
2717
  switch (command) {
2571
2718
  case 'config':
2572
2719
  await handleConfig(subcommand, args);
@@ -2596,6 +2743,11 @@ async function main() {
2596
2743
  await handleEscrow(subcommand, args, flags);
2597
2744
  break;
2598
2745
 
2746
+ case 'ln':
2747
+ case 'lightning':
2748
+ await handleLightning(subcommand, args, flags);
2749
+ break;
2750
+
2599
2751
  case 'webhook':
2600
2752
  await handleWebhook(subcommand, args, flags);
2601
2753
  break;
@@ -2615,6 +2767,14 @@ async function main() {
2615
2767
  case 'reputation':
2616
2768
  await handleReputation(subcommand, args, flags);
2617
2769
  break;
2770
+
2771
+ case 'x402':
2772
+ await handleX402(subcommand, args, flags);
2773
+ break;
2774
+
2775
+ case 'oauth':
2776
+ await handleOAuth(subcommand, args, flags);
2777
+ break;
2618
2778
 
2619
2779
  default:
2620
2780
  print.error(`Unknown command: ${command}`);
@@ -2630,4 +2790,225 @@ async function main() {
2630
2790
  }
2631
2791
  }
2632
2792
 
2793
+ /**
2794
+ * OAuth commands
2795
+ */
2796
+ async function handleOAuth(subcommand, args, flags) {
2797
+ const client = createClient();
2798
+
2799
+ switch (subcommand) {
2800
+ case 'list': {
2801
+ const result = await client.listOAuthClients();
2802
+ const clients = result.clients || [];
2803
+
2804
+ if (clients.length === 0) {
2805
+ print.info('No OAuth clients found.');
2806
+ } else {
2807
+ console.log(`\n${colors.bright}OAuth Clients${colors.reset} (${clients.length})\n`);
2808
+ for (const c of clients) {
2809
+ console.log(` ${colors.bright}${c.name}${colors.reset}`);
2810
+ console.log(` Client ID: ${c.client_id}`);
2811
+ if (c.description) console.log(` Description: ${c.description}`);
2812
+ if (c.redirect_uris) console.log(` Redirect URIs: ${c.redirect_uris.join(', ')}`);
2813
+ if (c.scopes) console.log(` Scopes: ${Array.isArray(c.scopes) ? c.scopes.join(', ') : c.scopes}`);
2814
+ console.log();
2815
+ }
2816
+ }
2817
+
2818
+ if (flags.json) print.json(result);
2819
+ break;
2820
+ }
2821
+
2822
+ case 'create': {
2823
+ const name = flags.name;
2824
+ const redirectUri = flags['redirect-uri'];
2825
+ const scope = flags.scope;
2826
+ const description = flags.description;
2827
+
2828
+ if (!name || !redirectUri) {
2829
+ print.error('Required: --name, --redirect-uri');
2830
+ print.info('Example: coinpay oauth create --name "My App" --redirect-uri https://myapp.com/callback --scope openid,profile');
2831
+ return;
2832
+ }
2833
+
2834
+ const redirectUris = redirectUri.split(',').map(u => u.trim());
2835
+ const scopes = scope ? scope.split(',').map(s => s.trim()) : undefined;
2836
+
2837
+ const result = await client.createOAuthClient({
2838
+ name,
2839
+ redirectUris,
2840
+ scopes,
2841
+ description,
2842
+ });
2843
+
2844
+ print.success('OAuth client created');
2845
+ if (result.client_id) {
2846
+ console.log(`\n ${colors.bright}Client ID:${colors.reset} ${result.client_id}`);
2847
+ }
2848
+ if (result.client_secret) {
2849
+ console.log(` ${colors.bright}Client Secret:${colors.reset} ${colors.yellow}${result.client_secret}${colors.reset}`);
2850
+ console.log();
2851
+ print.warn('Save the client secret — it is only shown once!');
2852
+ }
2853
+
2854
+ if (flags.json) print.json(result);
2855
+ break;
2856
+ }
2857
+
2858
+ case 'get': {
2859
+ const id = args[0];
2860
+ if (!id) {
2861
+ print.error('OAuth client ID required');
2862
+ print.info('Usage: coinpay oauth get <client-id>');
2863
+ return;
2864
+ }
2865
+
2866
+ const result = await client.getOAuthClient(id);
2867
+
2868
+ print.success(`OAuth Client: ${result.name || id}`);
2869
+ if (result.client_id) print.info(` Client ID: ${result.client_id}`);
2870
+ if (result.description) print.info(` Description: ${result.description}`);
2871
+ if (result.redirect_uris) print.info(` Redirect URIs: ${result.redirect_uris.join(', ')}`);
2872
+ if (result.scopes) print.info(` Scopes: ${Array.isArray(result.scopes) ? result.scopes.join(', ') : result.scopes}`);
2873
+ if (result.created_at) print.info(` Created: ${result.created_at}`);
2874
+
2875
+ if (flags.json) print.json(result);
2876
+ break;
2877
+ }
2878
+
2879
+ case 'delete': {
2880
+ const id = args[0];
2881
+ if (!id) {
2882
+ print.error('OAuth client ID required');
2883
+ print.info('Usage: coinpay oauth delete <client-id>');
2884
+ return;
2885
+ }
2886
+
2887
+ await client.deleteOAuthClient(id);
2888
+ print.success(`OAuth client ${id} deleted`);
2889
+ break;
2890
+ }
2891
+
2892
+ default:
2893
+ print.error(`Unknown oauth command: ${subcommand}`);
2894
+ print.info('Available: list, create, get, delete');
2895
+ process.exit(1);
2896
+ }
2897
+ }
2898
+
2899
+ /**
2900
+ * Handle x402 commands
2901
+ */
2902
+ async function handleX402(subcommand, args, flags) {
2903
+ const config = loadConfig();
2904
+
2905
+ if (!subcommand) {
2906
+ console.log(`
2907
+ ${colors.bright}x402 Payment Protocol${colors.reset}
2908
+
2909
+ Usage: coinpay x402 <command> [options]
2910
+
2911
+ Commands:
2912
+ status Check x402 facilitator status
2913
+ test Test x402 flow against an endpoint
2914
+
2915
+ Options:
2916
+ --url <url> Endpoint URL for testing
2917
+ --network <net> Network: base, ethereum, polygon (default: base)
2918
+ --amount <amt> Amount in USDC smallest unit (default: 1000000 = 1 USDC)
2919
+ `);
2920
+ return;
2921
+ }
2922
+
2923
+ switch (subcommand) {
2924
+ case 'status': {
2925
+ const apiKey = flags['api-key'] || config.apiKey;
2926
+ const baseUrl = flags['base-url'] || config.baseUrl || 'https://coinpayportal.com';
2927
+
2928
+ print.info('Checking x402 facilitator status...');
2929
+
2930
+ try {
2931
+ const response = await fetch(`${baseUrl}/api/x402/verify`, {
2932
+ method: 'POST',
2933
+ headers: {
2934
+ 'Content-Type': 'application/json',
2935
+ ...(apiKey ? { 'X-API-Key': apiKey } : {}),
2936
+ },
2937
+ body: JSON.stringify({ payment: { test: true } }),
2938
+ });
2939
+
2940
+ if (response.status === 401) {
2941
+ print.error('API key required or invalid. Set with: coinpay config set apiKey <key>');
2942
+ } else if (response.status === 400) {
2943
+ print.success('x402 facilitator is reachable and responding');
2944
+ print.info(`Facilitator URL: ${baseUrl}/api/x402`);
2945
+ print.info('Networks: Base, Ethereum, Polygon (Solana coming soon)');
2946
+ } else {
2947
+ print.warn(`Unexpected response: HTTP ${response.status}`);
2948
+ }
2949
+ } catch (err) {
2950
+ print.error(`Cannot reach facilitator at ${baseUrl}: ${err.message}`);
2951
+ }
2952
+ break;
2953
+ }
2954
+
2955
+ case 'test': {
2956
+ const url = flags.url || args[0];
2957
+ if (!url) {
2958
+ print.error('URL required: coinpay x402 test --url http://localhost:3000/api/premium');
2959
+ return;
2960
+ }
2961
+
2962
+ const network = flags.network || 'base';
2963
+ const amount = flags.amount || '1000000';
2964
+
2965
+ print.info(`Testing x402 flow against ${url}`);
2966
+
2967
+ // Step 1: Request without payment
2968
+ try {
2969
+ print.info('Step 1: Requesting resource without payment...');
2970
+ const response = await fetch(url);
2971
+
2972
+ if (response.status === 402) {
2973
+ const body = await response.json();
2974
+ print.success('Received HTTP 402 Payment Required');
2975
+
2976
+ if (body.x402Version) {
2977
+ print.success(`x402 version: ${body.x402Version}`);
2978
+ }
2979
+
2980
+ if (body.accepts && body.accepts.length > 0) {
2981
+ print.success(`${body.accepts.length} payment method(s) offered:`);
2982
+ for (const accept of body.accepts) {
2983
+ const label = accept.extra?.label || `${accept.asset} on ${accept.network}`;
2984
+ const symbol = accept.extra?.assetSymbol || accept.asset || '';
2985
+ print.info(` • ${label}`);
2986
+ print.info(` Amount: ${accept.maxAmountRequired} ${symbol}`);
2987
+ print.info(` Pay to: ${accept.payTo || 'not specified'}`);
2988
+ }
2989
+ const facilitator = body.accepts[0]?.extra?.facilitator;
2990
+ if (facilitator) {
2991
+ print.info(` Facilitator: ${facilitator}`);
2992
+ }
2993
+ }
2994
+
2995
+ print.success('x402 endpoint is correctly configured!');
2996
+ print.warn('Note: Full payment test requires a funded wallet. Use the dashboard for end-to-end testing.');
2997
+ } else if (response.status === 200) {
2998
+ print.warn('Endpoint returned 200 OK — no payment required (is x402 middleware active?)');
2999
+ } else {
3000
+ print.warn(`Unexpected status: HTTP ${response.status}`);
3001
+ }
3002
+ } catch (err) {
3003
+ print.error(`Failed to reach ${url}: ${err.message}`);
3004
+ }
3005
+ break;
3006
+ }
3007
+
3008
+ default:
3009
+ print.error(`Unknown x402 command: ${subcommand}`);
3010
+ print.info('Available: status, test');
3011
+ }
3012
+ }
3013
+
2633
3014
  main().then(() => process.exit(0));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/coinpay",
3
- "version": "0.6.8",
3
+ "version": "0.6.11",
4
4
  "description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/auth.js CHANGED
@@ -18,6 +18,9 @@
18
18
  * @returns {Promise<Object>} { success: boolean, merchant: Object, token: string }
19
19
  */
20
20
  export async function registerMerchant(client, { email, password, name }) {
21
+ if (!email) throw new Error('Email is required');
22
+ if (!password) throw new Error('Password is required');
23
+
21
24
  return client.requestUnauthenticated('/auth/register', {
22
25
  method: 'POST',
23
26
  body: JSON.stringify({
@@ -37,6 +40,9 @@ export async function registerMerchant(client, { email, password, name }) {
37
40
  * @returns {Promise<Object>} { success: boolean, merchant: Object, token: string }
38
41
  */
39
42
  export async function loginMerchant(client, { email, password }) {
43
+ if (!email) throw new Error('Email is required');
44
+ if (!password) throw new Error('Password is required');
45
+
40
46
  return client.requestUnauthenticated('/auth/login', {
41
47
  method: 'POST',
42
48
  body: JSON.stringify({
package/src/client.js CHANGED
@@ -3,6 +3,8 @@
3
3
  * Main client class for interacting with the CoinPay API
4
4
  */
5
5
 
6
+ import { LightningClient } from './lightning.js';
7
+
6
8
  const DEFAULT_BASE_URL = 'https://coinpayportal.com/api';
7
9
 
8
10
  /**
@@ -24,6 +26,9 @@ export class CoinPayClient {
24
26
  this.#apiKey = apiKey;
25
27
  this.#baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash
26
28
  this.#timeout = timeout;
29
+
30
+ /** @type {LightningClient} Lightning/BOLT12 operations */
31
+ this.lightning = new LightningClient(this);
27
32
  }
28
33
 
29
34
  /**
@@ -821,6 +826,91 @@ export class CoinPayClient {
821
826
  method: 'DELETE',
822
827
  });
823
828
  }
829
+
830
+ // ── OAuth Client Methods ─────────────────────────────────
831
+
832
+ /**
833
+ * List OAuth clients
834
+ *
835
+ * Returns all OAuth clients registered under your account.
836
+ *
837
+ * @returns {Promise<Object>} List of OAuth clients
838
+ *
839
+ * @example
840
+ * const result = await client.listOAuthClients();
841
+ * for (const app of result.clients) {
842
+ * console.log(app.client_id, app.name);
843
+ * }
844
+ */
845
+ async listOAuthClients() {
846
+ return this.request('/oauth/clients');
847
+ }
848
+
849
+ /**
850
+ * Create a new OAuth client
851
+ *
852
+ * Registers a new OAuth application. Returns the client_id and client_secret.
853
+ * Store the client_secret securely — it is only shown once.
854
+ *
855
+ * @param {Object} params - OAuth client parameters
856
+ * @param {string} params.name - Application name
857
+ * @param {string[]} params.redirectUris - Authorized redirect URIs
858
+ * @param {string[]} [params.scopes] - Requested scopes (e.g., ['openid', 'profile'])
859
+ * @param {string} [params.description] - Application description
860
+ * @returns {Promise<Object>} Created OAuth client with client_id and client_secret
861
+ *
862
+ * @example
863
+ * const app = await client.createOAuthClient({
864
+ * name: 'My App',
865
+ * redirectUris: ['https://myapp.com/callback'],
866
+ * scopes: ['openid', 'profile'],
867
+ * description: 'My awesome application',
868
+ * });
869
+ * console.log('Client ID:', app.client_id);
870
+ * console.log('Client Secret:', app.client_secret);
871
+ */
872
+ async createOAuthClient({ name, redirectUris, scopes, description }) {
873
+ return this.request('/oauth/clients', {
874
+ method: 'POST',
875
+ body: JSON.stringify({
876
+ name,
877
+ redirect_uris: redirectUris,
878
+ scopes,
879
+ description,
880
+ }),
881
+ });
882
+ }
883
+
884
+ /**
885
+ * Get an OAuth client by ID
886
+ *
887
+ * @param {string} id - OAuth client ID
888
+ * @returns {Promise<Object>} OAuth client details
889
+ *
890
+ * @example
891
+ * const app = await client.getOAuthClient('oac_abc123');
892
+ * console.log(app.name, app.redirect_uris);
893
+ */
894
+ async getOAuthClient(id) {
895
+ return this.request(`/oauth/clients/${id}`);
896
+ }
897
+
898
+ /**
899
+ * Delete an OAuth client
900
+ *
901
+ * Permanently removes an OAuth client and revokes all associated tokens.
902
+ *
903
+ * @param {string} id - OAuth client ID
904
+ * @returns {Promise<Object>} Deletion confirmation
905
+ *
906
+ * @example
907
+ * await client.deleteOAuthClient('oac_abc123');
908
+ */
909
+ async deleteOAuthClient(id) {
910
+ return this.request(`/oauth/clients/${id}`, {
911
+ method: 'DELETE',
912
+ });
913
+ }
824
914
  }
825
915
 
826
916
  export default CoinPayClient;
package/src/index.js CHANGED
@@ -147,6 +147,21 @@ import {
147
147
  SubscriptionStatus,
148
148
  } from './subscriptions.js';
149
149
 
150
+ // Lightning
151
+ import { LightningClient } from './lightning.js';
152
+
153
+ // x402 Protocol
154
+ import {
155
+ createX402Middleware,
156
+ verifyX402Payment,
157
+ settleX402Payment,
158
+ buildPaymentRequired,
159
+ convertUsdToAssetAmount,
160
+ PAYMENT_METHODS,
161
+ USDC_CONTRACTS,
162
+ CHAIN_IDS,
163
+ } from './x402.js';
164
+
150
165
  export {
151
166
  // Client
152
167
  CoinPayClient,
@@ -235,11 +250,24 @@ export {
235
250
  linkDid,
236
251
  getMyDid,
237
252
 
253
+ // Lightning
254
+ LightningClient,
255
+
238
256
  // Auth
239
257
  registerMerchant,
240
258
  loginMerchant,
241
259
  getMe,
242
260
 
261
+ // x402 Protocol
262
+ createX402Middleware,
263
+ verifyX402Payment,
264
+ settleX402Payment,
265
+ buildPaymentRequired,
266
+ convertUsdToAssetAmount,
267
+ PAYMENT_METHODS,
268
+ USDC_CONTRACTS,
269
+ CHAIN_IDS,
270
+
243
271
  // Webhook utilities
244
272
  verifyWebhookSignature,
245
273
  generateWebhookSignature,