facinet 2.2.2 → 2.3.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 +71 -242
- package/dist/browser.js +2720 -27521
- package/dist/browser.js.map +4 -4
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +7 -8
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/facilitator.d.ts +4 -15
- package/dist/commands/facilitator.d.ts.map +1 -1
- package/dist/commands/facilitator.js +24 -28
- package/dist/commands/facilitator.js.map +1 -1
- package/dist/commands/pay.d.ts +1 -8
- package/dist/commands/pay.d.ts.map +1 -1
- package/dist/commands/pay.js +35 -30
- package/dist/commands/pay.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +636 -92
- package/dist/index.js.map +7 -1
- package/dist/sdk/Facinet.d.ts +19 -3
- package/dist/sdk/Facinet.d.ts.map +1 -1
- package/dist/sdk/Facinet.js +107 -52
- package/dist/sdk/Facinet.js.map +1 -1
- package/dist/sdk/types.d.ts +8 -2
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +346 -25
- package/dist/sdk.js.map +7 -1
- package/dist/sdk.mjs +87 -32
- package/dist/sdk.mjs.map +2 -2
- package/dist/utils/api.d.ts +13 -12
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +4 -32
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/config.d.ts +2 -9
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +0 -1
- package/dist/utils/config.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,99 +1,643 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
2
3
|
"use strict";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var
|
|
10
|
-
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// src/index.ts
|
|
28
|
+
var import_commander = require("commander");
|
|
29
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
30
|
+
|
|
31
|
+
// src/commands/pay.ts
|
|
32
|
+
var import_inquirer = __toESM(require("inquirer"));
|
|
33
|
+
var import_chalk = __toESM(require("chalk"));
|
|
34
|
+
var import_ora = __toESM(require("ora"));
|
|
35
|
+
var import_ethers = require("ethers");
|
|
36
|
+
|
|
37
|
+
// src/utils/config.ts
|
|
38
|
+
var import_fs = __toESM(require("fs"));
|
|
39
|
+
var import_path = __toESM(require("path"));
|
|
40
|
+
var import_os = __toESM(require("os"));
|
|
41
|
+
var CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".facinet");
|
|
42
|
+
var CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
|
|
43
|
+
function getConfig() {
|
|
44
|
+
try {
|
|
45
|
+
if (!import_fs.default.existsSync(CONFIG_FILE)) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
const data = import_fs.default.readFileSync(CONFIG_FILE, "utf8");
|
|
49
|
+
return JSON.parse(data);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return {};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function saveConfig(config) {
|
|
55
|
+
try {
|
|
56
|
+
if (!import_fs.default.existsSync(CONFIG_DIR)) {
|
|
57
|
+
import_fs.default.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
const existingConfig = getConfig();
|
|
60
|
+
const newConfig = { ...existingConfig, ...config };
|
|
61
|
+
import_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2), "utf8");
|
|
62
|
+
} catch (error) {
|
|
63
|
+
throw new Error(`Failed to save configuration: ${error.message}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/utils/api.ts
|
|
68
|
+
var import_axios = __toESM(require("axios"));
|
|
69
|
+
async function listFacilitators(apiUrl) {
|
|
70
|
+
try {
|
|
71
|
+
const response = await import_axios.default.get(`${apiUrl}/api/facilitator/list`, {
|
|
72
|
+
timeout: 1e4,
|
|
73
|
+
headers: {
|
|
74
|
+
"User-Agent": "Facinet-CLI/2.3.0"
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (response.data.success) {
|
|
78
|
+
return response.data.facilitators.filter((f) => f.status === "active");
|
|
79
|
+
}
|
|
80
|
+
return [];
|
|
81
|
+
} catch (error) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Failed to fetch facilitators: ${error.message || error.code || "Unknown error"}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function selectRandomFacilitator(apiUrl) {
|
|
88
|
+
const facilitators = await listFacilitators(apiUrl);
|
|
89
|
+
if (facilitators.length === 0) {
|
|
90
|
+
throw new Error("No active facilitators available");
|
|
91
|
+
}
|
|
92
|
+
const randomIndex = Math.floor(Math.random() * facilitators.length);
|
|
93
|
+
return facilitators[randomIndex];
|
|
94
|
+
}
|
|
95
|
+
async function getFacilitatorById(apiUrl, id) {
|
|
96
|
+
try {
|
|
97
|
+
const response = await import_axios.default.get(`${apiUrl}/api/facilitator/list`);
|
|
98
|
+
if (response.data.success) {
|
|
99
|
+
const facilitator2 = response.data.facilitators.find((f) => f.id === id);
|
|
100
|
+
if (!facilitator2) {
|
|
101
|
+
throw new Error("Facilitator not found");
|
|
102
|
+
}
|
|
103
|
+
return facilitator2;
|
|
104
|
+
}
|
|
105
|
+
throw new Error("Failed to fetch facilitator");
|
|
106
|
+
} catch (error) {
|
|
107
|
+
throw new Error(`Failed to get facilitator: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function getFacilitatorStatus(apiUrl, id) {
|
|
111
|
+
return getFacilitatorById(apiUrl, id);
|
|
112
|
+
}
|
|
113
|
+
async function getFacilitatorBalance(apiUrl, id) {
|
|
114
|
+
try {
|
|
115
|
+
const response = await import_axios.default.post(`${apiUrl}/api/facilitator/balance`, {
|
|
116
|
+
facilitatorId: id
|
|
117
|
+
});
|
|
118
|
+
if (response.data.success) {
|
|
119
|
+
return {
|
|
120
|
+
name: response.data.name,
|
|
121
|
+
wallet: response.data.wallet,
|
|
122
|
+
balance: response.data.balance,
|
|
123
|
+
status: response.data.status
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
throw new Error("Failed to fetch balance");
|
|
127
|
+
} catch (error) {
|
|
128
|
+
throw new Error(`Failed to get balance: ${error.message}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function createFacilitator(apiUrl, payload) {
|
|
132
|
+
try {
|
|
133
|
+
throw new Error(
|
|
134
|
+
"Facilitator creation requires payment flow. Please use the web interface at " + apiUrl
|
|
135
|
+
);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
throw new Error(`Failed to create facilitator: ${error.message}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/commands/pay.ts
|
|
142
|
+
var CHAINS = {
|
|
143
|
+
avalanche: {
|
|
144
|
+
name: "Avalanche Fuji",
|
|
145
|
+
rpcUrl: "https://api.avax-test.network/ext/bc/C/rpc",
|
|
146
|
+
usdcAddress: "0x5425890298aed601595a70AB815c96711a31Bc65",
|
|
147
|
+
chainId: 43113
|
|
148
|
+
},
|
|
149
|
+
ethereum: {
|
|
150
|
+
name: "Ethereum Sepolia",
|
|
151
|
+
rpcUrl: "https://ethereum-sepolia-rpc.publicnode.com",
|
|
152
|
+
usdcAddress: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
153
|
+
chainId: 11155111
|
|
154
|
+
},
|
|
155
|
+
base: {
|
|
156
|
+
name: "Base Sepolia",
|
|
157
|
+
rpcUrl: "https://sepolia.base.org",
|
|
158
|
+
usdcAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
159
|
+
chainId: 84532
|
|
160
|
+
},
|
|
161
|
+
polygon: {
|
|
162
|
+
name: "Polygon Amoy",
|
|
163
|
+
rpcUrl: "https://rpc-amoy.polygon.technology",
|
|
164
|
+
usdcAddress: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
|
|
165
|
+
chainId: 80002
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
async function payCommand(options) {
|
|
169
|
+
console.log(import_chalk.default.cyan("\n\u{1F4B3} Make Payment via x402 Network\n"));
|
|
170
|
+
const config = getConfig();
|
|
171
|
+
if (!config.privateKey) {
|
|
172
|
+
console.log(import_chalk.default.red("\u274C No wallet connected. Run `facinet connect` first."));
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
let recipient = options.to;
|
|
176
|
+
if (!recipient) {
|
|
177
|
+
const answer = await import_inquirer.default.prompt([
|
|
178
|
+
{
|
|
179
|
+
type: "input",
|
|
180
|
+
name: "recipient",
|
|
181
|
+
message: "Recipient address:",
|
|
182
|
+
validate: (input) => {
|
|
183
|
+
if (!input.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
184
|
+
return "Invalid Ethereum address";
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
]);
|
|
190
|
+
recipient = answer.recipient;
|
|
191
|
+
}
|
|
192
|
+
const chain = CHAINS[options.chain];
|
|
193
|
+
if (!chain) {
|
|
194
|
+
console.log(import_chalk.default.red(`\u274C Unsupported chain: ${options.chain}. Supported: ${Object.keys(CHAINS).join(", ")}`));
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
console.log(import_chalk.default.gray(`
|
|
198
|
+
\u{1F4CA} Payment Details:`));
|
|
199
|
+
console.log(import_chalk.default.gray(` Amount: ${options.amount} USDC`));
|
|
200
|
+
console.log(import_chalk.default.gray(` To: ${recipient}`));
|
|
201
|
+
console.log(import_chalk.default.gray(` Chain: ${chain.name}`));
|
|
202
|
+
console.log(import_chalk.default.gray(` Your Address: ${config.address}
|
|
203
|
+
`));
|
|
204
|
+
const { confirm } = await import_inquirer.default.prompt([
|
|
205
|
+
{
|
|
206
|
+
type: "confirm",
|
|
207
|
+
name: "confirm",
|
|
208
|
+
message: "Proceed with payment?",
|
|
209
|
+
default: true
|
|
210
|
+
}
|
|
211
|
+
]);
|
|
212
|
+
if (!confirm) {
|
|
213
|
+
console.log(import_chalk.default.yellow("Payment cancelled."));
|
|
214
|
+
process.exit(0);
|
|
215
|
+
}
|
|
216
|
+
let spinner = (0, import_ora.default)("Selecting random facilitator...").start();
|
|
217
|
+
try {
|
|
218
|
+
const facilitator2 = await selectRandomFacilitator(
|
|
219
|
+
config.apiUrl || options.network || "https://x402-avalanche-chi.vercel.app"
|
|
220
|
+
);
|
|
221
|
+
spinner.succeed(`Selected facilitator: ${import_chalk.default.green(facilitator2.name)}`);
|
|
222
|
+
spinner = (0, import_ora.default)("Preparing transaction...").start();
|
|
223
|
+
const wallet = new import_ethers.Wallet(config.privateKey);
|
|
224
|
+
const provider = new import_ethers.JsonRpcProvider(chain.rpcUrl);
|
|
225
|
+
const connectedWallet = wallet.connect(provider);
|
|
226
|
+
const amount = BigInt(parseFloat(options.amount) * 1e6);
|
|
227
|
+
const validAfter = Math.floor(Date.now() / 1e3) - 60;
|
|
228
|
+
const validBefore = validAfter + 3600;
|
|
229
|
+
const nonce = "0x" + Array.from(
|
|
230
|
+
{ length: 64 },
|
|
231
|
+
() => Math.floor(Math.random() * 16).toString(16)
|
|
232
|
+
).join("");
|
|
233
|
+
const domain = {
|
|
234
|
+
name: "USD Coin",
|
|
235
|
+
version: "2",
|
|
236
|
+
chainId: chain.chainId,
|
|
237
|
+
verifyingContract: chain.usdcAddress
|
|
238
|
+
};
|
|
239
|
+
const types = {
|
|
240
|
+
TransferWithAuthorization: [
|
|
241
|
+
{ name: "from", type: "address" },
|
|
242
|
+
{ name: "to", type: "address" },
|
|
243
|
+
{ name: "value", type: "uint256" },
|
|
244
|
+
{ name: "validAfter", type: "uint256" },
|
|
245
|
+
{ name: "validBefore", type: "uint256" },
|
|
246
|
+
{ name: "nonce", type: "bytes32" }
|
|
247
|
+
]
|
|
248
|
+
};
|
|
249
|
+
const value = {
|
|
250
|
+
from: wallet.address,
|
|
251
|
+
to: recipient,
|
|
252
|
+
value: amount,
|
|
253
|
+
validAfter,
|
|
254
|
+
validBefore,
|
|
255
|
+
nonce
|
|
256
|
+
};
|
|
257
|
+
spinner.text = "Signing authorization...";
|
|
258
|
+
const signature = await connectedWallet.signTypedData(domain, types, value);
|
|
259
|
+
spinner.succeed("Authorization signed!");
|
|
260
|
+
spinner = (0, import_ora.default)("Submitting to facilitator...").start();
|
|
261
|
+
const paymentPayload = {
|
|
262
|
+
signature,
|
|
263
|
+
authorization: {
|
|
264
|
+
from: wallet.address,
|
|
265
|
+
to: recipient,
|
|
266
|
+
value: amount.toString(),
|
|
267
|
+
validAfter: validAfter.toString(),
|
|
268
|
+
validBefore: validBefore.toString(),
|
|
269
|
+
nonce
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const axios2 = require("axios");
|
|
273
|
+
const apiUrl = config.apiUrl || options.network || "https://x402-avalanche-chi.vercel.app";
|
|
274
|
+
const response = await axios2.post(`${apiUrl}/api/x402/settle-custom`, {
|
|
275
|
+
facilitatorId: facilitator2.id,
|
|
276
|
+
paymentPayload
|
|
277
|
+
});
|
|
278
|
+
if (!response.data.success) {
|
|
279
|
+
throw new Error(response.data.error || "Payment failed");
|
|
280
|
+
}
|
|
281
|
+
spinner.succeed("Payment submitted!");
|
|
282
|
+
const txHash = response.data.txHash;
|
|
283
|
+
console.log(import_chalk.default.green("\n\u2705 Payment processed successfully!"));
|
|
284
|
+
console.log(import_chalk.default.gray(`
|
|
285
|
+
\u{1F4C4} Payment Details:`));
|
|
286
|
+
console.log(import_chalk.default.gray(` Facilitator: ${facilitator2.name}`));
|
|
287
|
+
console.log(import_chalk.default.gray(` Amount: ${options.amount} USDC`));
|
|
288
|
+
console.log(import_chalk.default.gray(` Recipient: ${recipient}`));
|
|
289
|
+
console.log(import_chalk.default.gray(` Chain: ${chain.name}`));
|
|
290
|
+
console.log(import_chalk.default.gray(` Transaction: ${txHash}
|
|
291
|
+
`));
|
|
292
|
+
console.log(import_chalk.default.cyan(`\u{1F517} View on explorer: ${chain.name.includes("Avalanche") ? `https://testnet.snowtrace.io/tx/${txHash}` : chain.name.includes("Base") ? `https://sepolia.basescan.org/tx/${txHash}` : chain.name.includes("Polygon") ? `https://amoy.polygonscan.com/tx/${txHash}` : `https://sepolia.etherscan.io/tx/${txHash}`}
|
|
293
|
+
`));
|
|
294
|
+
} catch (error) {
|
|
295
|
+
spinner.fail("Payment failed");
|
|
296
|
+
console.log(import_chalk.default.red(`
|
|
297
|
+
\u274C Error: ${error.message}
|
|
298
|
+
`));
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/commands/facilitator.ts
|
|
304
|
+
var import_inquirer2 = __toESM(require("inquirer"));
|
|
305
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
306
|
+
var import_ora2 = __toESM(require("ora"));
|
|
307
|
+
var import_ethers2 = require("ethers");
|
|
308
|
+
async function create(options) {
|
|
309
|
+
console.log(import_chalk2.default.cyan("\n\u{1F680} Create New Facilitator\n"));
|
|
310
|
+
const config = getConfig();
|
|
311
|
+
if (!config.privateKey) {
|
|
312
|
+
console.log(import_chalk2.default.red("\u274C No wallet connected. Run `facinet connect` first."));
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
const answers = await import_inquirer2.default.prompt([
|
|
316
|
+
{
|
|
317
|
+
type: "input",
|
|
318
|
+
name: "name",
|
|
319
|
+
message: "Facilitator name:",
|
|
320
|
+
when: !options.name,
|
|
321
|
+
validate: (input) => {
|
|
322
|
+
if (input.length < 3 || input.length > 50) {
|
|
323
|
+
return "Name must be between 3 and 50 characters";
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
type: "input",
|
|
330
|
+
name: "recipient",
|
|
331
|
+
message: "Payment recipient address:",
|
|
332
|
+
when: !options.recipient,
|
|
333
|
+
default: config.address,
|
|
334
|
+
validate: (input) => {
|
|
335
|
+
if (!input.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
336
|
+
return "Invalid Ethereum address";
|
|
337
|
+
}
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
]);
|
|
342
|
+
const name = options.name || answers.name;
|
|
343
|
+
const recipient = options.recipient || answers.recipient;
|
|
344
|
+
console.log(import_chalk2.default.gray(`
|
|
345
|
+
\u{1F4CB} Facilitator Details:`));
|
|
346
|
+
console.log(import_chalk2.default.gray(` Name: ${name}`));
|
|
347
|
+
console.log(import_chalk2.default.gray(` Recipient: ${recipient}`));
|
|
348
|
+
console.log(import_chalk2.default.gray(` Creator: ${config.address}
|
|
349
|
+
`));
|
|
350
|
+
const { confirm } = await import_inquirer2.default.prompt([
|
|
351
|
+
{
|
|
352
|
+
type: "confirm",
|
|
353
|
+
name: "confirm",
|
|
354
|
+
message: "Create facilitator? (Requires 1 USDC registration fee)",
|
|
355
|
+
default: true
|
|
356
|
+
}
|
|
357
|
+
]);
|
|
358
|
+
if (!confirm) {
|
|
359
|
+
console.log(import_chalk2.default.yellow("Cancelled."));
|
|
360
|
+
process.exit(0);
|
|
361
|
+
}
|
|
362
|
+
const spinner = (0, import_ora2.default)("Creating facilitator...").start();
|
|
363
|
+
try {
|
|
364
|
+
const wallet = new import_ethers2.Wallet(config.privateKey);
|
|
365
|
+
const facilitatorWallet = import_ethers2.Wallet.createRandom();
|
|
366
|
+
spinner.text = "Registering facilitator...";
|
|
367
|
+
const result = await createFacilitator(options.url, {
|
|
368
|
+
name,
|
|
369
|
+
facilitatorWallet: facilitatorWallet.address,
|
|
370
|
+
facilitatorPrivateKey: facilitatorWallet.privateKey,
|
|
371
|
+
paymentRecipient: recipient,
|
|
372
|
+
createdBy: wallet.address
|
|
373
|
+
});
|
|
374
|
+
spinner.succeed("Facilitator created!");
|
|
375
|
+
console.log(import_chalk2.default.green("\n\u2705 Facilitator created successfully!"));
|
|
376
|
+
console.log(import_chalk2.default.gray(`
|
|
377
|
+
\u{1F4C4} Details:`));
|
|
378
|
+
console.log(import_chalk2.default.gray(` ID: ${result.id}`));
|
|
379
|
+
console.log(import_chalk2.default.gray(` Name: ${name}`));
|
|
380
|
+
console.log(import_chalk2.default.gray(` Wallet: ${facilitatorWallet.address}`));
|
|
381
|
+
console.log(import_chalk2.default.gray(` Status: ${result.status}`));
|
|
382
|
+
console.log(import_chalk2.default.yellow(`
|
|
383
|
+
\u26A0\uFE0F IMPORTANT: Save facilitator wallet private key!`));
|
|
384
|
+
console.log(import_chalk2.default.gray(` Private Key: ${facilitatorWallet.privateKey}
|
|
385
|
+
`));
|
|
386
|
+
console.log(import_chalk2.default.cyan("\u{1F4A1} Next steps:"));
|
|
387
|
+
console.log(import_chalk2.default.gray(` 1. Fund facilitator wallet with gas token`));
|
|
388
|
+
console.log(import_chalk2.default.gray(` 2. Check status: facinet facilitator status ${result.id}`));
|
|
389
|
+
console.log(import_chalk2.default.gray(` 3. Monitor balance: facinet facilitator balance ${result.id}
|
|
390
|
+
`));
|
|
391
|
+
} catch (error) {
|
|
392
|
+
spinner.fail("Failed to create facilitator");
|
|
393
|
+
console.log(import_chalk2.default.red(`
|
|
394
|
+
\u274C Error: ${error.message}
|
|
395
|
+
`));
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async function list(options) {
|
|
400
|
+
console.log(import_chalk2.default.cyan("\n\u{1F4CB} Active Facilitators\n"));
|
|
401
|
+
const spinner = (0, import_ora2.default)("Loading facilitators...").start();
|
|
402
|
+
try {
|
|
403
|
+
const facilitators = await listFacilitators(options.url);
|
|
404
|
+
spinner.stop();
|
|
405
|
+
if (facilitators.length === 0) {
|
|
406
|
+
console.log(import_chalk2.default.yellow("No active facilitators found.\n"));
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
console.log(import_chalk2.default.gray(`Found ${facilitators.length} active facilitator(s):
|
|
410
|
+
`));
|
|
411
|
+
facilitators.forEach((fac, index) => {
|
|
412
|
+
console.log(import_chalk2.default.cyan(`${index + 1}. ${fac.name}`));
|
|
413
|
+
console.log(import_chalk2.default.gray(` ID: ${fac.id}`));
|
|
414
|
+
console.log(import_chalk2.default.gray(` Wallet: ${fac.facilitatorWallet}`));
|
|
415
|
+
console.log(
|
|
416
|
+
import_chalk2.default.gray(` Status: ${getStatusEmoji(fac.status)} ${fac.status.toUpperCase()}`)
|
|
417
|
+
);
|
|
418
|
+
console.log(import_chalk2.default.gray(` Payments: ${fac.totalPayments}`));
|
|
419
|
+
console.log(import_chalk2.default.gray(` Created by: ${fac.createdBy}`));
|
|
420
|
+
console.log("");
|
|
421
|
+
});
|
|
422
|
+
} catch (error) {
|
|
423
|
+
spinner.fail("Failed to load facilitators");
|
|
424
|
+
console.log(import_chalk2.default.red(`
|
|
425
|
+
\u274C Error: ${error.message}
|
|
426
|
+
`));
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async function status(id, options) {
|
|
431
|
+
console.log(import_chalk2.default.cyan(`
|
|
432
|
+
\u{1F4CA} Facilitator Status
|
|
433
|
+
`));
|
|
434
|
+
const spinner = (0, import_ora2.default)("Checking status...").start();
|
|
435
|
+
try {
|
|
436
|
+
const fac = await getFacilitatorStatus(options.url, id);
|
|
437
|
+
spinner.stop();
|
|
438
|
+
console.log(import_chalk2.default.cyan(`${fac.name}`));
|
|
439
|
+
console.log(import_chalk2.default.gray(`ID: ${fac.id}
|
|
440
|
+
`));
|
|
441
|
+
console.log(
|
|
442
|
+
import_chalk2.default.gray(
|
|
443
|
+
`Status: ${getStatusEmoji(fac.status)} ${import_chalk2.default.bold(fac.status.toUpperCase())}`
|
|
444
|
+
)
|
|
445
|
+
);
|
|
446
|
+
console.log(import_chalk2.default.gray(`Wallet: ${fac.facilitatorWallet}`));
|
|
447
|
+
console.log(import_chalk2.default.gray(`Recipient: ${fac.paymentRecipient}`));
|
|
448
|
+
console.log(import_chalk2.default.gray(`Total Payments: ${fac.totalPayments}`));
|
|
449
|
+
console.log(import_chalk2.default.gray(`Gas Balance: ${fac.gasBalance || "Unknown"}`));
|
|
450
|
+
console.log(import_chalk2.default.gray(`Created: ${new Date(fac.lastUsed).toLocaleString()}
|
|
451
|
+
`));
|
|
452
|
+
if (fac.status === "needs_funding") {
|
|
453
|
+
console.log(import_chalk2.default.yellow("\u26A0\uFE0F Facilitator needs gas token for fees"));
|
|
454
|
+
console.log(import_chalk2.default.gray(` Send gas token to: ${fac.facilitatorWallet}
|
|
455
|
+
`));
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
spinner.fail("Failed to get status");
|
|
459
|
+
console.log(import_chalk2.default.red(`
|
|
460
|
+
\u274C Error: ${error.message}
|
|
461
|
+
`));
|
|
462
|
+
process.exit(1);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
async function balance(id, options) {
|
|
466
|
+
console.log(import_chalk2.default.cyan(`
|
|
467
|
+
\u{1F4B0} Facilitator Balance
|
|
468
|
+
`));
|
|
469
|
+
const spinner = (0, import_ora2.default)("Checking balance...").start();
|
|
470
|
+
try {
|
|
471
|
+
const result = await getFacilitatorBalance(options.url, id);
|
|
472
|
+
spinner.stop();
|
|
473
|
+
console.log(import_chalk2.default.gray(`Facilitator: ${result.name}`));
|
|
474
|
+
console.log(import_chalk2.default.gray(`Wallet: ${result.wallet}
|
|
475
|
+
`));
|
|
476
|
+
console.log(import_chalk2.default.cyan(`Balance: ${import_chalk2.default.bold(result.balance)}`));
|
|
477
|
+
console.log(
|
|
478
|
+
import_chalk2.default.gray(`Status: ${getStatusEmoji(result.status)} ${result.status.toUpperCase()}
|
|
479
|
+
`)
|
|
480
|
+
);
|
|
481
|
+
if (parseFloat(result.balance) < 0.1) {
|
|
482
|
+
console.log(import_chalk2.default.yellow("\u26A0\uFE0F Low balance! Facilitator may become inactive.\n"));
|
|
483
|
+
}
|
|
484
|
+
} catch (error) {
|
|
485
|
+
spinner.fail("Failed to check balance");
|
|
486
|
+
console.log(import_chalk2.default.red(`
|
|
487
|
+
\u274C Error: ${error.message}
|
|
488
|
+
`));
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function getStatusEmoji(status2) {
|
|
493
|
+
switch (status2) {
|
|
494
|
+
case "active":
|
|
495
|
+
return "\u2705";
|
|
496
|
+
case "needs_funding":
|
|
497
|
+
return "\u26A0\uFE0F";
|
|
498
|
+
case "inactive":
|
|
499
|
+
return "\u274C";
|
|
500
|
+
default:
|
|
501
|
+
return "\u2753";
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
var facilitatorCommand = {
|
|
505
|
+
create,
|
|
506
|
+
list,
|
|
507
|
+
status,
|
|
508
|
+
balance
|
|
11
509
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
510
|
+
|
|
511
|
+
// src/commands/connect.ts
|
|
512
|
+
var import_inquirer3 = __toESM(require("inquirer"));
|
|
513
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
514
|
+
var import_ethers3 = require("ethers");
|
|
515
|
+
var import_ora3 = __toESM(require("ora"));
|
|
516
|
+
async function connectCommand() {
|
|
517
|
+
console.log(import_chalk3.default.cyan("\n\u{1F517} Connect Wallet to Facinet\n"));
|
|
518
|
+
const { method } = await import_inquirer3.default.prompt([
|
|
519
|
+
{
|
|
520
|
+
type: "list",
|
|
521
|
+
name: "method",
|
|
522
|
+
message: "How would you like to connect?",
|
|
523
|
+
choices: [
|
|
524
|
+
{ name: "Enter Private Key (for testing)", value: "privateKey" },
|
|
525
|
+
{ name: "Generate New Wallet", value: "generate" }
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
]);
|
|
529
|
+
if (method === "privateKey") {
|
|
530
|
+
const { privateKey } = await import_inquirer3.default.prompt([
|
|
531
|
+
{
|
|
532
|
+
type: "password",
|
|
533
|
+
name: "privateKey",
|
|
534
|
+
message: "Enter your private key:",
|
|
535
|
+
mask: "*"
|
|
536
|
+
}
|
|
537
|
+
]);
|
|
538
|
+
try {
|
|
539
|
+
const wallet = new import_ethers3.Wallet(privateKey);
|
|
540
|
+
saveConfig({ privateKey, address: wallet.address });
|
|
541
|
+
console.log(import_chalk3.default.green("\n\u2705 Wallet connected successfully!"));
|
|
542
|
+
console.log(import_chalk3.default.gray(`Address: ${wallet.address}`));
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.log(import_chalk3.default.red("\n\u274C Invalid private key"));
|
|
545
|
+
process.exit(1);
|
|
546
|
+
}
|
|
547
|
+
} else {
|
|
548
|
+
const spinner = (0, import_ora3.default)("Generating new wallet...").start();
|
|
549
|
+
const wallet = import_ethers3.Wallet.createRandom();
|
|
550
|
+
spinner.succeed("Wallet generated!");
|
|
551
|
+
console.log(import_chalk3.default.green("\n\u2705 New wallet created!"));
|
|
552
|
+
console.log(import_chalk3.default.yellow("\n\u26A0\uFE0F IMPORTANT: Save your private key securely!"));
|
|
553
|
+
console.log(import_chalk3.default.gray(`
|
|
554
|
+
Address: ${wallet.address}`));
|
|
555
|
+
console.log(import_chalk3.default.gray(`Private Key: ${wallet.privateKey}`));
|
|
556
|
+
console.log(import_chalk3.default.gray(`Mnemonic: ${wallet.mnemonic?.phrase}
|
|
557
|
+
`));
|
|
558
|
+
const { confirm } = await import_inquirer3.default.prompt([
|
|
559
|
+
{
|
|
560
|
+
type: "confirm",
|
|
561
|
+
name: "confirm",
|
|
562
|
+
message: "Have you saved your private key?",
|
|
563
|
+
default: false
|
|
564
|
+
}
|
|
565
|
+
]);
|
|
566
|
+
if (!confirm) {
|
|
567
|
+
console.log(import_chalk3.default.red("\nPlease save your private key before continuing."));
|
|
568
|
+
process.exit(0);
|
|
569
|
+
}
|
|
570
|
+
saveConfig({ privateKey: wallet.privateKey, address: wallet.address });
|
|
571
|
+
console.log(import_chalk3.default.green("\u2705 Configuration saved!"));
|
|
572
|
+
}
|
|
573
|
+
const config = getConfig();
|
|
574
|
+
console.log(import_chalk3.default.cyan("\n\u{1F4E1} Network Configuration:"));
|
|
575
|
+
console.log(import_chalk3.default.gray(`Network: ${config.network || "avalanche-fuji"}`));
|
|
576
|
+
console.log(import_chalk3.default.gray(`API URL: ${config.apiUrl || "http://localhost:3000"}
|
|
577
|
+
`));
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/index.ts
|
|
581
|
+
var program = new import_commander.Command();
|
|
582
|
+
console.log(
|
|
583
|
+
import_chalk4.default.cyan(`
|
|
584
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
585
|
+
\u2551 \u2551
|
|
586
|
+
\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2551
|
|
587
|
+
\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2551
|
|
588
|
+
\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2551
|
|
589
|
+
\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2551
|
|
590
|
+
\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2551
|
|
591
|
+
\u2551 \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2551
|
|
592
|
+
\u2551 \u2551
|
|
593
|
+
\u2551 x402 Facilitator Network CLI \u2551
|
|
594
|
+
\u2551 \u2551
|
|
595
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
596
|
+
`)
|
|
597
|
+
);
|
|
598
|
+
program.name("facinet").description("CLI tool for x402 Facilitator Network").version("2.3.0");
|
|
599
|
+
program.command("connect").description("Connect your wallet to Facinet").action(connectCommand);
|
|
600
|
+
program.command("pay").description("Make a payment via x402 facilitator network").option("-a, --amount <amount>", "Payment amount in USDC", "1").option("-t, --to <address>", "Recipient address").option("-c, --chain <chain>", "Blockchain network (avalanche, ethereum, base, polygon)", "avalanche").option("-n, --network <url>", "Custom network URL").action(payCommand);
|
|
601
|
+
var facilitator = program.command("facilitator").alias("fac").description("Manage facilitators");
|
|
602
|
+
facilitator.command("create").description("Create a new facilitator").option("-n, --name <name>", "Facilitator name").option("-r, --recipient <address>", "Payment recipient address").option(
|
|
603
|
+
"-u, --url <url>",
|
|
604
|
+
"API URL",
|
|
605
|
+
"https://x402-avalanche-chi.vercel.app"
|
|
606
|
+
).action(facilitatorCommand.create);
|
|
607
|
+
facilitator.command("list").description("List all active facilitators").option(
|
|
608
|
+
"-u, --url <url>",
|
|
609
|
+
"API URL",
|
|
610
|
+
"https://x402-avalanche-chi.vercel.app"
|
|
611
|
+
).action(facilitatorCommand.list);
|
|
612
|
+
facilitator.command("status <id>").description("Check facilitator status").option(
|
|
613
|
+
"-u, --url <url>",
|
|
614
|
+
"API URL",
|
|
615
|
+
"https://x402-avalanche-chi.vercel.app"
|
|
616
|
+
).action(facilitatorCommand.status);
|
|
617
|
+
facilitator.command("balance <id>").description("Check facilitator gas balance").option(
|
|
618
|
+
"-u, --url <url>",
|
|
619
|
+
"API URL",
|
|
620
|
+
"https://x402-avalanche-chi.vercel.app"
|
|
621
|
+
).action(facilitatorCommand.balance);
|
|
622
|
+
program.on("--help", () => {
|
|
623
|
+
console.log("");
|
|
624
|
+
console.log(import_chalk4.default.cyan("Examples:"));
|
|
625
|
+
console.log("");
|
|
626
|
+
console.log(" $ facinet connect");
|
|
627
|
+
console.log(" $ facinet pay --amount 1 --to 0x123... --chain base");
|
|
628
|
+
console.log(' $ facinet facilitator create --name "MyNode"');
|
|
629
|
+
console.log(" $ facinet facilitator list");
|
|
630
|
+
console.log(" $ facinet facilitator status fac_xyz123");
|
|
631
|
+
console.log("");
|
|
632
|
+
console.log(import_chalk4.default.cyan("Supported Chains:"));
|
|
633
|
+
console.log(" avalanche - Avalanche Fuji (Testnet)");
|
|
634
|
+
console.log(" ethereum - Ethereum Sepolia (Testnet)");
|
|
635
|
+
console.log(" base - Base Sepolia (Testnet)");
|
|
636
|
+
console.log(" polygon - Polygon Amoy (Testnet)");
|
|
637
|
+
console.log("");
|
|
93
638
|
});
|
|
94
639
|
program.parse(process.argv);
|
|
95
|
-
// Show help if no command provided
|
|
96
640
|
if (!process.argv.slice(2).length) {
|
|
97
|
-
|
|
641
|
+
program.outputHelp();
|
|
98
642
|
}
|
|
99
|
-
//# sourceMappingURL=index.js.map
|
|
643
|
+
//# sourceMappingURL=index.js.map
|