facinet 2.3.0 → 2.4.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 CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  > JavaScript SDK and CLI tool for the x402 Facilitator Network
4
4
 
5
- Make gasless USDC payments and manage facilitators on the x402 decentralized payment network. Now with **multichain support** across 4 testnets.
5
+ Make gasless USDC payments and manage facilitators on the x402 decentralized payment network. Now with **multichain support** across 4 testnets with **network-specific facilitator selection**.
6
6
 
7
7
  ## Supported Chains
8
8
 
9
- | Chain | Network ID | Gas Token | Explorer |
10
- |-------|-----------|-----------|----------|
11
- | Avalanche Fuji | `avalanche-fuji` | AVAX | testnet.snowtrace.io |
12
- | Ethereum Sepolia | `ethereum-sepolia` | ETH | sepolia.etherscan.io |
13
- | Base Sepolia | `base-sepolia` | ETH | sepolia.basescan.org |
14
- | Polygon Amoy | `polygon-amoy` | MATIC | amoy.polygonscan.com |
9
+ | Chain | Network ID | Chain ID | Gas Token | Explorer | API URL |
10
+ |-------|-----------|----------|-----------|----------|---------|
11
+ | Avalanche Fuji | `avalanche-fuji` | 43113 | AVAX | testnet.snowtrace.io | x402-avalanche-chi.vercel.app |
12
+ | Ethereum Sepolia | `ethereum-sepolia` | 11155111 | ETH | sepolia.etherscan.io | x402-ethereum-chi.vercel.app |
13
+ | Base Sepolia | `base-sepolia` | 84532 | ETH | sepolia.basescan.org | x402-base-chi.vercel.app |
14
+ | Polygon Amoy | `polygon-amoy` | 80002 | MATIC | amoy.polygonscan.com | x402-polygon-chi.vercel.app |
15
15
 
16
16
  ## Installation
17
17
 
@@ -29,14 +29,18 @@ npm install -g facinet
29
29
 
30
30
  ## SDK Usage
31
31
 
32
+ ### Network-Specific Facilitator Selection
33
+
34
+ The SDK automatically selects **active facilitators** for the **specific network** you're using. Each network has its own facilitator pool, and the SDK ensures you only get facilitators registered for that network.
35
+
32
36
  ### Browser (with MetaMask)
33
37
 
34
38
  ```typescript
35
39
  import { Facinet } from 'facinet';
36
40
 
37
- // Initialize SDK - choose your chain
41
+ // Initialize SDK for Base Sepolia network
38
42
  const facinet = new Facinet({
39
- network: 'base-sepolia', // or 'avalanche-fuji', 'ethereum-sepolia', 'polygon-amoy'
43
+ network: 'base-sepolia', // SDK will use Base Sepolia API and facilitators
40
44
  });
41
45
 
42
46
  // Make a payment (MetaMask will prompt for signature)
@@ -46,8 +50,9 @@ const result = await facinet.pay({
46
50
  });
47
51
 
48
52
  console.log('Payment successful!', result.txHash);
49
- console.log('Processed by:', result.facilitator.name);
50
- console.log('Network:', result.payment.network);
53
+ console.log('Processed by:', result.facilitator.name); // Facilitator name
54
+ console.log('Facilitator ID:', result.facilitator.id);
55
+ console.log('Network:', result.payment.network); // 'base-sepolia'
51
56
  ```
52
57
 
53
58
  ### Node.js (with Private Key)
@@ -58,7 +63,7 @@ import { Facinet } from 'facinet';
58
63
  // Initialize with private key on Polygon Amoy
59
64
  const facinet = new Facinet({
60
65
  privateKey: process.env.PRIVATE_KEY,
61
- network: 'polygon-amoy',
66
+ network: 'polygon-amoy', // SDK will use Polygon Amoy API and facilitators
62
67
  });
63
68
 
64
69
  // Make a payment
@@ -68,6 +73,7 @@ const result = await facinet.pay({
68
73
  });
69
74
 
70
75
  console.log('Transaction:', result.txHash);
76
+ console.log('Facilitator:', result.facilitator.name);
71
77
  ```
72
78
 
73
79
  ### Quick One-Liner
@@ -75,27 +81,94 @@ console.log('Transaction:', result.txHash);
75
81
  ```typescript
76
82
  import { Facinet } from 'facinet';
77
83
 
78
- // Quick payment on any chain
84
+ // Quick payment on Ethereum Sepolia
79
85
  await Facinet.quickPay({
80
86
  amount: '1',
81
87
  recipient: '0xMerchantAddress',
82
88
  privateKey: process.env.PRIVATE_KEY,
83
- network: 'ethereum-sepolia',
89
+ network: 'ethereum-sepolia', // Uses Ethereum Sepolia facilitators
84
90
  });
85
91
  ```
86
92
 
87
- ### Get Available Facilitators
93
+ ### Get Active Facilitators for a Network
88
94
 
89
95
  ```typescript
90
- const facinet = new Facinet();
96
+ import { Facinet } from 'facinet';
91
97
 
92
- // Get all active facilitators
98
+ // Initialize for a specific network
99
+ const facinet = new Facinet({
100
+ network: 'base-sepolia', // Only gets facilitators for Base Sepolia
101
+ });
102
+
103
+ // Get all active facilitators for this network
93
104
  const facilitators = await facinet.getFacilitators();
94
- console.log(`${facilitators.length} active facilitators`);
105
+ console.log(`${facilitators.length} active facilitators on Base Sepolia`);
106
+
107
+ facilitators.forEach(fac => {
108
+ console.log(`- ${fac.name} (${fac.id})`);
109
+ console.log(` Wallet: ${fac.facilitatorWallet}`);
110
+ console.log(` Network: ${fac.network || 'N/A'}`);
111
+ console.log(` Chain ID: ${fac.chainId || 'N/A'}`);
112
+ console.log(` Status: ${fac.status}`);
113
+ });
95
114
 
96
- // Get a random facilitator
115
+ // Get a random active facilitator for this network
97
116
  const randomFacilitator = await facinet.selectRandomFacilitator();
98
117
  console.log('Selected:', randomFacilitator.name);
118
+ console.log('Network:', randomFacilitator.network);
119
+ ```
120
+
121
+ ### Network-Specific Examples
122
+
123
+ #### Avalanche Fuji
124
+
125
+ ```typescript
126
+ const facinet = new Facinet({
127
+ network: 'avalanche-fuji', // Uses Avalanche Fuji facilitators
128
+ });
129
+
130
+ const result = await facinet.pay({
131
+ amount: '1',
132
+ recipient: '0xYourMerchantAddress',
133
+ });
134
+
135
+ console.log('Facilitator:', result.facilitator.name);
136
+ console.log('Network:', result.payment.network); // 'avalanche-fuji'
137
+ ```
138
+
139
+ #### Ethereum Sepolia
140
+
141
+ ```typescript
142
+ const facinet = new Facinet({
143
+ network: 'ethereum-sepolia', // Uses Ethereum Sepolia facilitators
144
+ });
145
+
146
+ const facilitators = await facinet.getFacilitators();
147
+ // Only returns facilitators registered for Ethereum Sepolia (Chain ID: 11155111)
148
+ ```
149
+
150
+ #### Base Sepolia
151
+
152
+ ```typescript
153
+ const facinet = new Facinet({
154
+ network: 'base-sepolia', // Uses Base Sepolia facilitators
155
+ });
156
+
157
+ const facilitator = await facinet.selectRandomFacilitator();
158
+ // Only selects from facilitators registered for Base Sepolia (Chain ID: 84532)
159
+ ```
160
+
161
+ #### Polygon Amoy
162
+
163
+ ```typescript
164
+ const facinet = new Facinet({
165
+ network: 'polygon-amoy', // Uses Polygon Amoy facilitators
166
+ });
167
+
168
+ const result = await facinet.pay({
169
+ amount: '2',
170
+ recipient: '0xYourMerchantAddress',
171
+ });
99
172
  ```
100
173
 
101
174
  ### Get Supported Chains
@@ -106,7 +179,10 @@ import { Facinet } from 'facinet';
106
179
  // List all supported chains
107
180
  const chains = Facinet.getSupportedChains();
108
181
  chains.forEach(chain => {
109
- console.log(`${chain.displayName} (${chain.name}) - Chain ID: ${chain.chainId}`);
182
+ console.log(`${chain.displayName} (${chain.name})`);
183
+ console.log(` Chain ID: ${chain.chainId}`);
184
+ console.log(` Gas Token: ${chain.gasToken}`);
185
+ console.log(` USDC Address: ${chain.usdcAddress}`);
110
186
  });
111
187
 
112
188
  // Get supported network names
@@ -119,18 +195,41 @@ console.log('Networks:', networks);
119
195
 
120
196
  ```typescript
121
197
  interface FacinetConfig {
122
- apiUrl?: string; // Default: 'https://x402-avalanche-chi.vercel.app'
198
+ apiUrl?: string; // Optional: Override API URL (auto-selected by network)
123
199
  privateKey?: string; // For Node.js (not needed in browser)
124
200
  network?: 'avalanche-fuji' | 'ethereum-sepolia' | 'base-sepolia' | 'polygon-amoy';
125
201
  rpcUrl?: string; // Custom RPC URL (optional)
126
202
  }
127
203
  ```
128
204
 
205
+ **Network-specific API URLs** (automatically selected):
206
+ - `avalanche-fuji` → `https://x402-avalanche-chi.vercel.app`
207
+ - `ethereum-sepolia` → `https://x402-ethereum-chi.vercel.app`
208
+ - `base-sepolia` → `https://x402-base-chi.vercel.app`
209
+ - `polygon-amoy` → `https://x402-polygon-chi.vercel.app`
210
+
129
211
  **Legacy aliases** are supported for backwards compatibility:
130
- - `'avalanche'` -> `'avalanche-fuji'`
131
- - `'ethereum'` -> `'ethereum-sepolia'`
132
- - `'polygon'` -> `'polygon-amoy'`
133
- - `'base'` -> `'base-sepolia'`
212
+ - `'avalanche'` `'avalanche-fuji'`
213
+ - `'ethereum'` `'ethereum-sepolia'`
214
+ - `'polygon'` `'polygon-amoy'`
215
+ - `'base'` `'base-sepolia'`
216
+
217
+ ### Facilitator Filtering
218
+
219
+ The SDK automatically filters facilitators by:
220
+
221
+ 1. **Status**: Only `'active'` facilitators are selected
222
+ 2. **Network**: Only facilitators registered for the selected network
223
+ 3. **Chain ID**: Only facilitators matching the chain ID
224
+
225
+ ```typescript
226
+ const facinet = new Facinet({ network: 'base-sepolia' });
227
+
228
+ // This will only return facilitators that are:
229
+ // - Status: 'active'
230
+ // - Network: 'base-sepolia' OR Chain ID: 84532
231
+ const facilitators = await facinet.getFacilitators();
232
+ ```
134
233
 
135
234
  ### TypeScript Support
136
235
 
@@ -153,6 +252,12 @@ const params: PaymentParams = {
153
252
  amount: '1',
154
253
  recipient: '0x...',
155
254
  };
255
+
256
+ // PaymentResult includes facilitator information
257
+ const result: PaymentResult = await facinet.pay(params);
258
+ console.log(result.facilitator.name); // Facilitator name
259
+ console.log(result.facilitator.id); // Facilitator ID
260
+ console.log(result.facilitator.wallet); // Facilitator wallet address
156
261
  ```
157
262
 
158
263
  ### React Example
@@ -164,6 +269,7 @@ import { Facinet } from 'facinet';
164
269
  function PaymentButton() {
165
270
  const [loading, setLoading] = useState(false);
166
271
  const [txHash, setTxHash] = useState('');
272
+ const [facilitatorName, setFacilitatorName] = useState('');
167
273
  const [network] = useState('base-sepolia');
168
274
 
169
275
  const handlePayment = async () => {
@@ -177,7 +283,8 @@ function PaymentButton() {
177
283
  });
178
284
 
179
285
  setTxHash(result.txHash);
180
- alert('Payment successful!');
286
+ setFacilitatorName(result.facilitator.name);
287
+ alert(`Payment successful! Processed by ${result.facilitator.name}`);
181
288
  } catch (error) {
182
289
  console.error('Payment failed:', error);
183
290
  alert('Payment failed');
@@ -191,7 +298,13 @@ function PaymentButton() {
191
298
  <button onClick={handlePayment} disabled={loading}>
192
299
  {loading ? 'Processing...' : 'Pay 1 USDC'}
193
300
  </button>
194
- {txHash && <p>Transaction: {txHash.slice(0, 10)}...</p>}
301
+ {txHash && (
302
+ <div>
303
+ <p>Transaction: {txHash.slice(0, 10)}...</p>
304
+ <p>Facilitator: {facilitatorName}</p>
305
+ <p>Network: {network}</p>
306
+ </div>
307
+ )}
195
308
  </div>
196
309
  );
197
310
  }
@@ -199,11 +312,31 @@ function PaymentButton() {
199
312
 
200
313
  ### How SDK Payments Work
201
314
 
202
- 1. **Initialize SDK** - Create Facinet instance with your config and chain
203
- 2. **Random Facilitator** - SDK automatically picks random active facilitator
204
- 3. **Sign Authorization** - User signs ERC-3009 authorization (gasless!)
205
- 4. **Facilitator Executes** - Facilitator submits transaction and pays gas
206
- 5. **Payment Complete** - USDC transferred to YOUR merchant address
315
+ 1. **Initialize SDK** - Create Facinet instance with your network choice
316
+ 2. **Network Detection** - SDK automatically uses the correct API URL for your network
317
+ 3. **Active Facilitator Selection** - SDK picks a random **active** facilitator **for your network**
318
+ 4. **Sign Authorization** - User signs ERC-3009 authorization (gasless!)
319
+ 5. **Facilitator Executes** - Selected facilitator submits transaction and pays gas
320
+ 6. **Payment Complete** - USDC transferred to YOUR merchant address
321
+
322
+ ### Error Handling
323
+
324
+ ```typescript
325
+ try {
326
+ const facinet = new Facinet({ network: 'base-sepolia' });
327
+ const result = await facinet.pay({
328
+ amount: '1',
329
+ recipient: '0xYourMerchantAddress',
330
+ });
331
+ } catch (error) {
332
+ if (error.message.includes('No active facilitators available')) {
333
+ console.error('No active facilitators found for Base Sepolia');
334
+ console.error('Please check that facilitators are registered for this network');
335
+ } else {
336
+ console.error('Payment failed:', error.message);
337
+ }
338
+ }
339
+ ```
207
340
 
208
341
  ## CLI Usage
209
342
 
@@ -218,23 +351,33 @@ facinet connect
218
351
  ### 2. Make a Payment
219
352
 
220
353
  ```bash
221
- # Pay on Avalanche (default)
354
+ # Pay on Avalanche Fuji (default)
222
355
  facinet pay --amount 1 --to 0xRecipientAddress
223
356
 
224
- # Pay on Base Sepolia
357
+ # Pay on Base Sepolia (uses Base Sepolia facilitators)
225
358
  facinet pay --amount 1 --to 0xRecipientAddress --chain base
226
359
 
227
- # Pay on Polygon Amoy
360
+ # Pay on Polygon Amoy (uses Polygon Amoy facilitators)
228
361
  facinet pay --amount 1 --to 0xRecipientAddress --chain polygon
229
362
 
230
- # Pay on Ethereum Sepolia
363
+ # Pay on Ethereum Sepolia (uses Ethereum Sepolia facilitators)
231
364
  facinet pay --amount 1 --to 0xRecipientAddress --chain ethereum
232
365
  ```
233
366
 
234
367
  ### 3. List Active Facilitators
235
368
 
236
369
  ```bash
370
+ # List all active facilitators (for the configured network)
237
371
  facinet facilitator list
372
+
373
+ # The output shows:
374
+ # - Facilitator name
375
+ # - Facilitator ID
376
+ # - Wallet address
377
+ # - Status (active/inactive/needs_funding)
378
+ # - Network (if available)
379
+ # - Chain ID (if available)
380
+ # - Total payments processed
238
381
  ```
239
382
 
240
383
  ### 4. Check Facilitator Status
@@ -243,6 +386,12 @@ facinet facilitator list
243
386
  facinet facilitator status fac_xyz123
244
387
  ```
245
388
 
389
+ ### 5. Check Facilitator Balance
390
+
391
+ ```bash
392
+ facinet facilitator balance fac_xyz123
393
+ ```
394
+
246
395
  ## Configuration
247
396
 
248
397
  Facinet stores configuration in `~/.facinet/config.json`:
@@ -256,9 +405,24 @@ Facinet stores configuration in `~/.facinet/config.json`:
256
405
  }
257
406
  ```
258
407
 
408
+ **Note**: The `apiUrl` is automatically set based on the `network` parameter. You can override it if needed.
409
+
259
410
  ## How It Works
260
411
 
261
- 1. **Random Selection** - SDK/CLI picks a random active facilitator from the network
412
+ ### Network-Specific Facilitator Selection
413
+
414
+ 1. **Network Selection** - You specify a network (e.g., `'base-sepolia'`)
415
+ 2. **API URL Selection** - SDK automatically uses the correct API endpoint for that network
416
+ 3. **Facilitator Filtering** - SDK fetches facilitators and filters by:
417
+ - Status: Must be `'active'`
418
+ - Network: Must match your selected network (if facilitator has `network` property)
419
+ - Chain ID: Must match your chain ID (if facilitator has `chainId` property)
420
+ 4. **Random Selection** - SDK picks a random facilitator from the filtered list
421
+ 5. **Payment Processing** - Selected facilitator processes your payment
422
+
423
+ ### Payment Flow
424
+
425
+ 1. **Random Selection** - SDK/CLI picks a random active facilitator from the **selected network**
262
426
  2. **Sign Authorization** - You sign an ERC-3009 payment authorization (gasless for you!)
263
427
  3. **Facilitator Executes** - The facilitator submits the transaction and pays gas
264
428
  4. **Payment Complete** - USDC transferred on-chain
@@ -289,7 +453,7 @@ facinet --help
289
453
  facinet-sdk/
290
454
  ├── src/
291
455
  │ ├── sdk/
292
- │ │ ├── Facinet.ts # Main SDK class (multichain)
456
+ │ │ ├── Facinet.ts # Main SDK class (multichain with network-specific facilitators)
293
457
  │ │ └── types.ts # TypeScript types
294
458
  │ ├── commands/
295
459
  │ │ ├── connect.ts # Wallet connection
@@ -297,7 +461,7 @@ facinet-sdk/
297
461
  │ │ └── facilitator.ts # Facilitator management
298
462
  │ ├── utils/
299
463
  │ │ ├── config.ts # Configuration management
300
- │ │ └── api.ts # API client
464
+ │ │ └── api.ts # API client with network filtering
301
465
  │ ├── sdk.ts # SDK exports
302
466
  │ └── index.ts # CLI entry point
303
467
  ├── dist/ # Compiled JavaScript
@@ -307,7 +471,18 @@ facinet-sdk/
307
471
  └── README.md
308
472
  ```
309
473
 
310
- ## What's New in v2.3.0
474
+ ## What's New in v2.4.0
475
+
476
+ - **Network-Specific Facilitator Selection** - SDK automatically filters facilitators by network/chainId
477
+ - **Network-Specific API URLs** - Each network uses its own API endpoint automatically
478
+ - **Enhanced Facilitator Filtering** - Only active facilitators for the selected network are returned
479
+ - **Better Error Messages** - Error messages now include network information
480
+ - **Facilitator Name Display** - Facilitator names are properly displayed in all results
481
+ - **Improved Documentation** - Comprehensive examples for each network
482
+
483
+ ## Previous Versions
484
+
485
+ ### v2.3.0
311
486
 
312
487
  - **Multichain Support** - Now supports 4 chains: Avalanche Fuji, Ethereum Sepolia, Base Sepolia, Polygon Amoy
313
488
  - **Chain-specific ERC-3009 domains** - Correct EIP-712 domain names per chain (USD Coin vs USDC)
package/dist/browser.js CHANGED
@@ -2715,13 +2715,26 @@ var FacinetSDK = (() => {
2715
2715
  "polygon": "polygon-amoy",
2716
2716
  "base": "base-sepolia"
2717
2717
  };
2718
+ var NETWORK_API_URLS = {
2719
+ "avalanche-fuji": "https://x402-avalanche-chi.vercel.app",
2720
+ "ethereum-sepolia": "https://x402-ethereum-chi.vercel.app",
2721
+ "base-sepolia": "https://x402-base-chi.vercel.app",
2722
+ "polygon-amoy": "https://x402-polygon-chi.vercel.app"
2723
+ };
2718
2724
  function resolveNetwork(network) {
2719
2725
  return NETWORK_ALIASES[network] || network;
2720
2726
  }
2727
+ function getApiUrlForNetwork(network, customApiUrl) {
2728
+ if (customApiUrl) {
2729
+ return customApiUrl.replace(/\/$/, "");
2730
+ }
2731
+ const resolvedNetwork = resolveNetwork(network);
2732
+ return NETWORK_API_URLS[resolvedNetwork] || NETWORK_API_URLS["avalanche-fuji"];
2733
+ }
2721
2734
  var Facinet = class _Facinet {
2722
2735
  constructor(config = {}) {
2723
- const apiUrl = (config.apiUrl || "https://x402-avalanche-chi.vercel.app").replace(/\/$/, "");
2724
2736
  const resolvedNetwork = resolveNetwork(config.network || "avalanche-fuji");
2737
+ const apiUrl = getApiUrlForNetwork(resolvedNetwork, config.apiUrl);
2725
2738
  this.config = {
2726
2739
  apiUrl,
2727
2740
  privateKey: config.privateKey || "",
@@ -2892,7 +2905,7 @@ var FacinetSDK = (() => {
2892
2905
  txHash: response.data.txHash,
2893
2906
  facilitator: {
2894
2907
  id: facilitator.id,
2895
- name: facilitator.name,
2908
+ name: facilitator.name || `Facilitator ${facilitator.id.slice(0, 8)}`,
2896
2909
  wallet: facilitator.facilitatorWallet
2897
2910
  },
2898
2911
  payment: {
@@ -2911,29 +2924,56 @@ var FacinetSDK = (() => {
2911
2924
  }
2912
2925
  }
2913
2926
  /**
2914
- * Get all active facilitators
2927
+ * Get all active facilitators for the current network
2915
2928
  */
2916
2929
  async getFacilitators() {
2917
- const response = await axios_default.get(
2918
- `${this.config.apiUrl}/api/facilitator/list`
2919
- );
2920
- if (response.data.success) {
2921
- return response.data.facilitators.filter(
2922
- (f) => f.status === "active"
2930
+ try {
2931
+ const response = await axios_default.get(
2932
+ `${this.config.apiUrl}/api/facilitator/list`,
2933
+ {
2934
+ timeout: 1e4,
2935
+ headers: {
2936
+ "User-Agent": "Facinet-SDK/2.3.0"
2937
+ }
2938
+ }
2939
+ );
2940
+ if (response.data.success && Array.isArray(response.data.facilitators)) {
2941
+ return response.data.facilitators.filter((f) => {
2942
+ if (f.status !== "active") {
2943
+ return false;
2944
+ }
2945
+ if (f.network) {
2946
+ return f.network === this.config.network;
2947
+ }
2948
+ if (f.chainId !== void 0) {
2949
+ return f.chainId === this.chain.chainId;
2950
+ }
2951
+ return true;
2952
+ });
2953
+ }
2954
+ return [];
2955
+ } catch (error) {
2956
+ throw new Error(
2957
+ `Failed to fetch facilitators for ${this.chain.displayName} (${this.config.network}): ${error.message || "Unknown error"}`
2923
2958
  );
2924
2959
  }
2925
- return [];
2926
2960
  }
2927
2961
  /**
2928
- * Select a random active facilitator
2962
+ * Select a random active facilitator for the current network
2929
2963
  */
2930
2964
  async selectRandomFacilitator() {
2931
2965
  const facilitators = await this.getFacilitators();
2932
2966
  if (facilitators.length === 0) {
2933
- throw new Error("No active facilitators available");
2967
+ throw new Error(
2968
+ `No active facilitators available for ${this.chain.displayName} (${this.config.network}, Chain ID: ${this.chain.chainId}). Please check that facilitators are registered for this network. API URL: ${this.config.apiUrl}`
2969
+ );
2934
2970
  }
2935
2971
  const randomIndex = Math.floor(Math.random() * facilitators.length);
2936
- return facilitators[randomIndex];
2972
+ const selectedFacilitator = facilitators[randomIndex];
2973
+ if (!selectedFacilitator.name) {
2974
+ selectedFacilitator.name = `Facilitator ${selectedFacilitator.id.slice(0, 8)}`;
2975
+ }
2976
+ return selectedFacilitator;
2937
2977
  }
2938
2978
  /**
2939
2979
  * Quick payment helper (static method)