agentic-x402 0.2.2 → 0.2.4
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/bin/cli.ts +12 -0
- package/package.json +1 -1
- package/scripts/commands/balance.ts +4 -8
- package/scripts/commands/create-link.ts +2 -8
- package/scripts/commands/distribute.ts +201 -0
- package/scripts/commands/pay.ts +2 -1
- package/scripts/commands/routers.ts +183 -0
- package/scripts/core/config.ts +1 -1
package/bin/cli.ts
CHANGED
|
@@ -52,6 +52,16 @@ const commands: Record<string, Command> = {
|
|
|
52
52
|
description: 'Get info about a payment link',
|
|
53
53
|
category: 'links',
|
|
54
54
|
},
|
|
55
|
+
routers: {
|
|
56
|
+
script: 'commands/routers.ts',
|
|
57
|
+
description: 'List routers where your wallet is a beneficiary',
|
|
58
|
+
category: 'links',
|
|
59
|
+
},
|
|
60
|
+
distribute: {
|
|
61
|
+
script: 'commands/distribute.ts',
|
|
62
|
+
description: 'Distribute USDC from a PaymentRouter',
|
|
63
|
+
category: 'links',
|
|
64
|
+
},
|
|
55
65
|
};
|
|
56
66
|
|
|
57
67
|
function showHelp() {
|
|
@@ -73,6 +83,8 @@ Payment Commands:
|
|
|
73
83
|
Link Commands (21cash integration):
|
|
74
84
|
create-link Create a payment link to sell content
|
|
75
85
|
link-info <addr> Get info about a payment link
|
|
86
|
+
routers List routers where your wallet is a beneficiary
|
|
87
|
+
distribute <addr> Distribute USDC from a PaymentRouter
|
|
76
88
|
|
|
77
89
|
Options:
|
|
78
90
|
-h, --help Show this help
|
package/package.json
CHANGED
|
@@ -60,26 +60,22 @@ Shows:
|
|
|
60
60
|
console.log('x402 Wallet Balance');
|
|
61
61
|
console.log('===================');
|
|
62
62
|
console.log('');
|
|
63
|
-
console.log(`Address: ${
|
|
64
|
-
|
|
63
|
+
console.log(`Address: ${address}`);
|
|
64
|
+
const networkName = client.config.chainId === 8453 ? 'Base mainnet' : 'Base Sepolia';
|
|
65
|
+
console.log(`Network: ${networkName} (chain ${client.config.chainId})`);
|
|
65
66
|
console.log('');
|
|
66
67
|
console.log('Balances:');
|
|
67
68
|
console.log(` USDC: ${formatCrypto(usdc.formatted, 'USDC', 2)}`);
|
|
68
69
|
console.log(` ETH: ${formatCrypto(eth.formatted, 'ETH', 6)}`);
|
|
69
70
|
|
|
70
71
|
// Warnings
|
|
71
|
-
console.log('');
|
|
72
72
|
const usdcNum = parseFloat(usdc.formatted);
|
|
73
|
-
const ethNum = parseFloat(eth.formatted);
|
|
74
73
|
|
|
75
74
|
if (usdcNum < 1) {
|
|
75
|
+
console.log('');
|
|
76
76
|
console.log('Warning: Low USDC balance. Fund your wallet to make payments.');
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (ethNum < 0.0001) {
|
|
80
|
-
console.log('Warning: Low ETH balance. You may need ETH for gas fees.');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
79
|
} catch (error) {
|
|
84
80
|
if (jsonOutput) {
|
|
85
81
|
console.log(JSON.stringify({
|
|
@@ -56,7 +56,7 @@ Options:
|
|
|
56
56
|
-h, --help Show this help
|
|
57
57
|
|
|
58
58
|
Environment:
|
|
59
|
-
X402_LINKS_API_URL Base URL of x402-links-server (
|
|
59
|
+
X402_LINKS_API_URL Base URL of x402-links-server (default: https://21.cash)
|
|
60
60
|
|
|
61
61
|
Examples:
|
|
62
62
|
x402 create-link --name "Premium Guide" --price 5.00 --url https://mysite.com/guide.pdf
|
|
@@ -68,12 +68,6 @@ Examples:
|
|
|
68
68
|
|
|
69
69
|
const config = getConfig();
|
|
70
70
|
|
|
71
|
-
if (!config.x402LinksApiUrl) {
|
|
72
|
-
console.error('Error: X402_LINKS_API_URL environment variable is required');
|
|
73
|
-
console.error('Set it to the base URL of your x402-links-server instance');
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
71
|
const name = flags.name as string;
|
|
78
72
|
const price = flags.price as string;
|
|
79
73
|
const gatedUrl = flags.url as string | undefined;
|
|
@@ -129,7 +123,7 @@ Examples:
|
|
|
129
123
|
console.log(` Name: ${name}`);
|
|
130
124
|
console.log(` Price: ${formatUsd(parseFloat(price))}`);
|
|
131
125
|
console.log(` Creator: ${truncateAddress(creatorAddress)}`);
|
|
132
|
-
console.log(` Network: ${config.
|
|
126
|
+
console.log(` Network: ${config.chainId === 8453 ? 'Base mainnet' : 'Base Sepolia'} (chain ${config.chainId})`);
|
|
133
127
|
console.log('');
|
|
134
128
|
}
|
|
135
129
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
// Distribute accumulated USDC from a PaymentRouter
|
|
3
|
+
|
|
4
|
+
import { getClient, getWalletAddress, getEthBalance } from '../core/client.js';
|
|
5
|
+
import { parseArgs, formatCrypto, truncateAddress, formatError } from '../core/utils.js';
|
|
6
|
+
import { getConfig, getUsdcAddress } from '../core/config.js';
|
|
7
|
+
import { formatUnits, parseUnits } from 'viem';
|
|
8
|
+
|
|
9
|
+
const ERC20_BALANCE_ABI = [{
|
|
10
|
+
name: 'balanceOf',
|
|
11
|
+
type: 'function',
|
|
12
|
+
stateMutability: 'view',
|
|
13
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
14
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
15
|
+
}] as const;
|
|
16
|
+
|
|
17
|
+
const PAYMENT_ROUTER_ABI = [{
|
|
18
|
+
name: 'distribute',
|
|
19
|
+
type: 'function',
|
|
20
|
+
stateMutability: 'nonpayable',
|
|
21
|
+
inputs: [
|
|
22
|
+
{ name: 'token', type: 'address' },
|
|
23
|
+
{ name: 'amount', type: 'uint256' },
|
|
24
|
+
],
|
|
25
|
+
outputs: [],
|
|
26
|
+
}] as const;
|
|
27
|
+
|
|
28
|
+
const MIN_ETH_FOR_GAS = 0.0001; // Minimum ETH required for gas
|
|
29
|
+
|
|
30
|
+
async function main() {
|
|
31
|
+
const { positional, flags } = parseArgs(process.argv.slice(2));
|
|
32
|
+
|
|
33
|
+
if (positional.length === 0 || flags.help || flags.h) {
|
|
34
|
+
console.log(`
|
|
35
|
+
x402 distribute - Distribute USDC from a PaymentRouter
|
|
36
|
+
|
|
37
|
+
Usage: x402 distribute <router-address> [options]
|
|
38
|
+
|
|
39
|
+
Arguments:
|
|
40
|
+
router-address The PaymentRouter contract address
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
--amount <amt> Distribute a specific USDC amount (e.g., "10.00"). Defaults to full balance.
|
|
44
|
+
--force Skip gas balance warning
|
|
45
|
+
--json Output as JSON
|
|
46
|
+
-h, --help Show this help
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
x402 distribute 0x1234...5678
|
|
50
|
+
x402 distribute 0x1234...5678 --amount 5.00
|
|
51
|
+
x402 distribute 0x1234...5678 --force --json
|
|
52
|
+
`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const config = getConfig();
|
|
57
|
+
const jsonOutput = flags.json === true;
|
|
58
|
+
const force = flags.force === true;
|
|
59
|
+
const specifiedAmount = flags.amount as string | undefined;
|
|
60
|
+
|
|
61
|
+
// Validate router address
|
|
62
|
+
const routerAddress = positional[0];
|
|
63
|
+
if (!routerAddress.startsWith('0x') || routerAddress.length !== 42) {
|
|
64
|
+
const msg = 'Invalid router address. Must be a 0x-prefixed 40-character hex string.';
|
|
65
|
+
if (jsonOutput) {
|
|
66
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
67
|
+
} else {
|
|
68
|
+
console.error(`Error: ${msg}`);
|
|
69
|
+
}
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const client = getClient();
|
|
75
|
+
const walletAddress = getWalletAddress();
|
|
76
|
+
const usdcAddress = getUsdcAddress(config.chainId);
|
|
77
|
+
const routerAddr = routerAddress as `0x${string}`;
|
|
78
|
+
|
|
79
|
+
// Read router's USDC balance
|
|
80
|
+
const routerBalance = await client.publicClient.readContract({
|
|
81
|
+
address: usdcAddress,
|
|
82
|
+
abi: ERC20_BALANCE_ABI,
|
|
83
|
+
functionName: 'balanceOf',
|
|
84
|
+
args: [routerAddr],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const routerBalanceFormatted = formatUnits(routerBalance, 6);
|
|
88
|
+
|
|
89
|
+
if (routerBalance === 0n) {
|
|
90
|
+
if (jsonOutput) {
|
|
91
|
+
console.log(JSON.stringify({ success: false, error: 'Router has no USDC balance to distribute' }));
|
|
92
|
+
} else {
|
|
93
|
+
console.log('Router has no USDC balance to distribute.');
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Determine amount to distribute
|
|
99
|
+
let distributeAmount: bigint;
|
|
100
|
+
if (specifiedAmount) {
|
|
101
|
+
distributeAmount = parseUnits(specifiedAmount, 6);
|
|
102
|
+
if (distributeAmount > routerBalance) {
|
|
103
|
+
const msg = `Requested amount (${specifiedAmount} USDC) exceeds router balance (${routerBalanceFormatted} USDC)`;
|
|
104
|
+
if (jsonOutput) {
|
|
105
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
106
|
+
} else {
|
|
107
|
+
console.error(`Error: ${msg}`);
|
|
108
|
+
}
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
distributeAmount = routerBalance;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Check ETH for gas
|
|
116
|
+
if (!force) {
|
|
117
|
+
const eth = await getEthBalance();
|
|
118
|
+
const ethNum = parseFloat(eth.formatted);
|
|
119
|
+
if (ethNum < MIN_ETH_FOR_GAS) {
|
|
120
|
+
const msg = `Low ETH balance (${formatCrypto(eth.formatted, 'ETH', 6)}). Need at least ${MIN_ETH_FOR_GAS} ETH for gas. Use --force to skip this check.`;
|
|
121
|
+
if (jsonOutput) {
|
|
122
|
+
console.log(JSON.stringify({ success: false, error: msg }));
|
|
123
|
+
} else {
|
|
124
|
+
console.error(`Warning: ${msg}`);
|
|
125
|
+
}
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const distributeFormatted = formatUnits(distributeAmount, 6);
|
|
131
|
+
|
|
132
|
+
if (!jsonOutput) {
|
|
133
|
+
console.log('Distributing USDC from PaymentRouter');
|
|
134
|
+
console.log('====================================');
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log(`Router: ${routerAddress}`);
|
|
137
|
+
console.log(`Balance: ${formatCrypto(routerBalanceFormatted, 'USDC', 2)}`);
|
|
138
|
+
console.log(`Amount: ${formatCrypto(distributeFormatted, 'USDC', 2)}`);
|
|
139
|
+
console.log(`Caller: ${truncateAddress(walletAddress)}`);
|
|
140
|
+
console.log('');
|
|
141
|
+
console.log('Submitting transaction...');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Call distribute(token, amount)
|
|
145
|
+
const txHash = await client.walletClient.writeContract({
|
|
146
|
+
address: routerAddr,
|
|
147
|
+
abi: PAYMENT_ROUTER_ABI,
|
|
148
|
+
functionName: 'distribute',
|
|
149
|
+
args: [usdcAddress, distributeAmount],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!jsonOutput) {
|
|
153
|
+
console.log(`TX submitted: ${txHash}`);
|
|
154
|
+
console.log('Waiting for confirmation...');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Wait for receipt
|
|
158
|
+
const receipt = await client.publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
159
|
+
|
|
160
|
+
const success = receipt.status === 'success';
|
|
161
|
+
|
|
162
|
+
if (jsonOutput) {
|
|
163
|
+
console.log(JSON.stringify({
|
|
164
|
+
success,
|
|
165
|
+
routerAddress,
|
|
166
|
+
amount: distributeFormatted,
|
|
167
|
+
amountRaw: distributeAmount.toString(),
|
|
168
|
+
transactionHash: txHash,
|
|
169
|
+
blockNumber: receipt.blockNumber.toString(),
|
|
170
|
+
status: receipt.status,
|
|
171
|
+
}));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (success) {
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log('Distribution successful!');
|
|
178
|
+
console.log(`TX: ${txHash}`);
|
|
179
|
+
console.log(`Block: ${receipt.blockNumber}`);
|
|
180
|
+
console.log(`Distributed: ${formatCrypto(distributeFormatted, 'USDC', 2)}`);
|
|
181
|
+
} else {
|
|
182
|
+
console.error('');
|
|
183
|
+
console.error('Transaction reverted.');
|
|
184
|
+
console.error(`TX: ${txHash}`);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (jsonOutput) {
|
|
190
|
+
console.log(JSON.stringify({ success: false, error: formatError(error) }));
|
|
191
|
+
} else {
|
|
192
|
+
console.error('Error:', formatError(error));
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main().catch(err => {
|
|
199
|
+
console.error('Error:', err.message);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|
package/scripts/commands/pay.ts
CHANGED
|
@@ -50,7 +50,8 @@ Examples:
|
|
|
50
50
|
console.log(`Fetching: ${url}`);
|
|
51
51
|
console.log(`Method: ${method}`);
|
|
52
52
|
console.log(`Wallet: ${truncateAddress(client.account.address)}`);
|
|
53
|
-
|
|
53
|
+
const networkName = client.config.chainId === 8453 ? 'Base mainnet' : 'Base Sepolia';
|
|
54
|
+
console.log(`Network: ${networkName} (chain ${client.config.chainId})`);
|
|
54
55
|
console.log('');
|
|
55
56
|
|
|
56
57
|
try {
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
// List routers where the agent's wallet is a beneficiary
|
|
3
|
+
|
|
4
|
+
import { getClient, getWalletAddress } from '../core/client.js';
|
|
5
|
+
import { parseArgs, formatCrypto, formatUsd, truncateAddress, formatError } from '../core/utils.js';
|
|
6
|
+
import { getConfig, getUsdcAddress } from '../core/config.js';
|
|
7
|
+
import { formatUnits } from 'viem';
|
|
8
|
+
|
|
9
|
+
const ERC20_BALANCE_ABI = [{
|
|
10
|
+
name: 'balanceOf',
|
|
11
|
+
type: 'function',
|
|
12
|
+
stateMutability: 'view',
|
|
13
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
14
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
15
|
+
}] as const;
|
|
16
|
+
|
|
17
|
+
interface BeneficiaryLink {
|
|
18
|
+
id: string;
|
|
19
|
+
router_address: string;
|
|
20
|
+
metadata: {
|
|
21
|
+
name: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
chainId?: number;
|
|
24
|
+
chainName?: string;
|
|
25
|
+
};
|
|
26
|
+
amount: string;
|
|
27
|
+
chain_id: number;
|
|
28
|
+
token_address: string;
|
|
29
|
+
beneficiary_percentage: number;
|
|
30
|
+
created_at: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const { flags } = parseArgs(process.argv.slice(2));
|
|
35
|
+
|
|
36
|
+
if (flags.help || flags.h) {
|
|
37
|
+
console.log(`
|
|
38
|
+
x402 routers - List routers where your wallet is a beneficiary
|
|
39
|
+
|
|
40
|
+
Usage: x402 routers [options]
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
--with-balance Fetch on-chain USDC balance for each router
|
|
44
|
+
--json Output as JSON
|
|
45
|
+
-h, --help Show this help
|
|
46
|
+
|
|
47
|
+
Shows:
|
|
48
|
+
- Router address and link name
|
|
49
|
+
- Your beneficiary share percentage
|
|
50
|
+
- On-chain USDC balance (with --with-balance)
|
|
51
|
+
- Estimated withdrawal amount based on your share
|
|
52
|
+
`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const config = getConfig();
|
|
57
|
+
const jsonOutput = flags.json === true;
|
|
58
|
+
const withBalance = flags['with-balance'] === true;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const address = getWalletAddress();
|
|
62
|
+
const apiUrl = `${config.x402LinksApiUrl}/api/links/beneficiary/${address}`;
|
|
63
|
+
|
|
64
|
+
const response = await fetch(apiUrl);
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
|
|
67
|
+
if (!response.ok || !data.success) {
|
|
68
|
+
if (jsonOutput) {
|
|
69
|
+
console.log(JSON.stringify({ success: false, error: data.error || 'Failed to fetch routers' }));
|
|
70
|
+
} else {
|
|
71
|
+
console.error('Error:', data.error || 'Failed to fetch routers');
|
|
72
|
+
}
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const links: BeneficiaryLink[] = data.links;
|
|
77
|
+
|
|
78
|
+
if (links.length === 0) {
|
|
79
|
+
if (jsonOutput) {
|
|
80
|
+
console.log(JSON.stringify({ success: true, routers: [] }));
|
|
81
|
+
} else {
|
|
82
|
+
console.log('No routers found where your wallet is a beneficiary.');
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Optionally fetch on-chain balances
|
|
88
|
+
let balances: Map<string, { raw: bigint; formatted: string }> | null = null;
|
|
89
|
+
|
|
90
|
+
if (withBalance) {
|
|
91
|
+
const client = getClient();
|
|
92
|
+
const usdcAddress = getUsdcAddress(config.chainId);
|
|
93
|
+
balances = new Map();
|
|
94
|
+
|
|
95
|
+
const balancePromises = links.map(async (link) => {
|
|
96
|
+
const routerAddr = link.router_address as `0x${string}`;
|
|
97
|
+
try {
|
|
98
|
+
const balance = await client.publicClient.readContract({
|
|
99
|
+
address: usdcAddress,
|
|
100
|
+
abi: ERC20_BALANCE_ABI,
|
|
101
|
+
functionName: 'balanceOf',
|
|
102
|
+
args: [routerAddr],
|
|
103
|
+
});
|
|
104
|
+
return { router: routerAddr, raw: balance, formatted: formatUnits(balance, 6) };
|
|
105
|
+
} catch {
|
|
106
|
+
return { router: routerAddr, raw: 0n, formatted: '0' };
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const results = await Promise.all(balancePromises);
|
|
111
|
+
for (const r of results) {
|
|
112
|
+
balances.set(r.router.toLowerCase(), { raw: r.raw, formatted: r.formatted });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (jsonOutput) {
|
|
117
|
+
const routers = links.map((link) => {
|
|
118
|
+
const bal = balances?.get(link.router_address.toLowerCase());
|
|
119
|
+
const share = link.beneficiary_percentage / 100;
|
|
120
|
+
return {
|
|
121
|
+
routerAddress: link.router_address,
|
|
122
|
+
name: link.metadata?.name || 'Unnamed',
|
|
123
|
+
chainId: link.chain_id,
|
|
124
|
+
sharePercent: link.beneficiary_percentage,
|
|
125
|
+
...(bal ? {
|
|
126
|
+
balance: bal.formatted,
|
|
127
|
+
balanceRaw: bal.raw.toString(),
|
|
128
|
+
estimatedWithdrawal: (parseFloat(bal.formatted) * share).toFixed(6),
|
|
129
|
+
} : {}),
|
|
130
|
+
createdAt: link.created_at,
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
console.log(JSON.stringify({ success: true, address, routers }));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Human-readable output
|
|
138
|
+
console.log('Your Payment Routers');
|
|
139
|
+
console.log('====================');
|
|
140
|
+
console.log('');
|
|
141
|
+
console.log(`Wallet: ${address}`);
|
|
142
|
+
console.log(`Found: ${links.length} router(s)`);
|
|
143
|
+
console.log('');
|
|
144
|
+
|
|
145
|
+
for (const link of links) {
|
|
146
|
+
const name = link.metadata?.name || 'Unnamed';
|
|
147
|
+
const share = link.beneficiary_percentage;
|
|
148
|
+
|
|
149
|
+
console.log(` ${name}`);
|
|
150
|
+
console.log(` Router: ${link.router_address}`);
|
|
151
|
+
console.log(` Share: ${share}%`);
|
|
152
|
+
|
|
153
|
+
if (balances) {
|
|
154
|
+
const bal = balances.get(link.router_address.toLowerCase());
|
|
155
|
+
if (bal) {
|
|
156
|
+
const balNum = parseFloat(bal.formatted);
|
|
157
|
+
const est = balNum * (share / 100);
|
|
158
|
+
console.log(` Balance: ${formatCrypto(bal.formatted, 'USDC', 2)}`);
|
|
159
|
+
console.log(` Est. withdrawal: ${formatCrypto(est.toFixed(2), 'USDC', 2)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
console.log('');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!withBalance) {
|
|
166
|
+
console.log('Tip: Use --with-balance to see on-chain USDC balances');
|
|
167
|
+
}
|
|
168
|
+
console.log('Use "x402 distribute <router-address>" to withdraw funds');
|
|
169
|
+
|
|
170
|
+
} catch (error) {
|
|
171
|
+
if (jsonOutput) {
|
|
172
|
+
console.log(JSON.stringify({ success: false, error: formatError(error) }));
|
|
173
|
+
} else {
|
|
174
|
+
console.error('Error:', formatError(error));
|
|
175
|
+
}
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
main().catch(err => {
|
|
181
|
+
console.error('Error:', err.message);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
});
|
package/scripts/core/config.ts
CHANGED
|
@@ -71,7 +71,7 @@ export function getConfig(): X402Config {
|
|
|
71
71
|
network,
|
|
72
72
|
chainId,
|
|
73
73
|
facilitatorUrl: getOptionalEnv('X402_FACILITATOR_URL', defaultFacilitator),
|
|
74
|
-
x402LinksApiUrl: process.env.X402_LINKS_API_URL,
|
|
74
|
+
x402LinksApiUrl: process.env.X402_LINKS_API_URL || 'https://21.cash',
|
|
75
75
|
maxPaymentUsd: parseFloat(getOptionalEnv('X402_MAX_PAYMENT_USD', '10')),
|
|
76
76
|
slippageBps: parseInt(getOptionalEnv('X402_SLIPPAGE_BPS', '50'), 10),
|
|
77
77
|
verbose: getOptionalEnv('X402_VERBOSE', '0') === '1',
|