@darksol/terminal 0.5.2 → 0.5.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/package.json +1 -1
- package/src/services/cards.js +43 -3
- package/src/trading/swap.js +46 -16
package/package.json
CHANGED
package/src/services/cards.js
CHANGED
|
@@ -6,6 +6,42 @@ import { showSection } from '../ui/banner.js';
|
|
|
6
6
|
|
|
7
7
|
const BASE = () => getServiceURL('cards') || 'https://acp.darksol.net';
|
|
8
8
|
|
|
9
|
+
// Verified working ticker/network combos (tested against Trocador API)
|
|
10
|
+
const VALID_CRYPTO = {
|
|
11
|
+
'usdc': { network: 'base', display: 'USDC on Base' },
|
|
12
|
+
'usdc_base': { ticker: 'usdc', network: 'base', display: 'USDC on Base' },
|
|
13
|
+
'usdc_erc20': { ticker: 'usdc', network: 'ERC20', display: 'USDC on Ethereum' },
|
|
14
|
+
'usdt': { network: 'trc20', display: 'USDT on Tron' },
|
|
15
|
+
'usdt_trc20': { ticker: 'usdt', network: 'trc20', display: 'USDT on Tron' },
|
|
16
|
+
'btc': { network: 'Mainnet', display: 'Bitcoin' },
|
|
17
|
+
'eth': { network: 'ERC20', display: 'ETH on Ethereum' },
|
|
18
|
+
'sol': { network: 'Mainnet', display: 'Solana' },
|
|
19
|
+
'xmr': { network: 'Mainnet', display: 'Monero' },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Map user-friendly network names to Trocador-compatible ones
|
|
23
|
+
const NETWORK_MAP = {
|
|
24
|
+
'base': 'base',
|
|
25
|
+
'ethereum': 'ERC20', 'eth': 'ERC20', 'erc20': 'ERC20',
|
|
26
|
+
'tron': 'trc20', 'trc20': 'trc20',
|
|
27
|
+
'mainnet': 'Mainnet', 'btc': 'Mainnet', 'sol': 'Mainnet', 'xmr': 'Mainnet',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function resolveTickerNetwork(ticker, network) {
|
|
31
|
+
const t = (ticker || '').toLowerCase();
|
|
32
|
+
const n = (network || '').toLowerCase();
|
|
33
|
+
|
|
34
|
+
// If just ticker provided, use known defaults
|
|
35
|
+
if (t && !n) {
|
|
36
|
+
const known = VALID_CRYPTO[t];
|
|
37
|
+
if (known) return { ticker: known.ticker || t, network: known.network };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Map network to Trocador format
|
|
41
|
+
const mappedNetwork = NETWORK_MAP[n] || network;
|
|
42
|
+
return { ticker: t, network: mappedNetwork };
|
|
43
|
+
}
|
|
44
|
+
|
|
9
45
|
export async function cardsCatalog() {
|
|
10
46
|
const spin = spinner('Loading card catalog...').start();
|
|
11
47
|
try {
|
|
@@ -58,9 +94,13 @@ export async function cardsOrder(provider, amount, opts = {}) {
|
|
|
58
94
|
amount: Number(amount),
|
|
59
95
|
email: opts.email,
|
|
60
96
|
};
|
|
61
|
-
//
|
|
62
|
-
if (opts.ticker)
|
|
63
|
-
|
|
97
|
+
// Resolve ticker/network to Trocador-compatible values
|
|
98
|
+
if (opts.ticker) {
|
|
99
|
+
const resolved = resolveTickerNetwork(opts.ticker, opts.network);
|
|
100
|
+
body.tickerFrom = resolved.ticker;
|
|
101
|
+
body.networkFrom = resolved.network;
|
|
102
|
+
info(`Payment: ${resolved.ticker.toUpperCase()} on ${resolved.network}`);
|
|
103
|
+
}
|
|
64
104
|
|
|
65
105
|
const data = await fetchJSON(`${BASE()}/api/cards/order`, {
|
|
66
106
|
method: 'POST',
|
package/src/trading/swap.js
CHANGED
|
@@ -58,7 +58,8 @@ const TOKENS = {
|
|
|
58
58
|
OP: '0x4200000000000000000000000000000000000042',
|
|
59
59
|
},
|
|
60
60
|
polygon: {
|
|
61
|
-
|
|
61
|
+
MATIC: ethers.ZeroAddress,
|
|
62
|
+
POL: ethers.ZeroAddress,
|
|
62
63
|
WETH: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
63
64
|
WMATIC: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
64
65
|
USDC: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
|
|
@@ -76,12 +77,20 @@ const ERC20_ABI = [
|
|
|
76
77
|
'function name() view returns (string)',
|
|
77
78
|
];
|
|
78
79
|
|
|
79
|
-
// Uniswap V3 SwapRouter
|
|
80
|
-
|
|
80
|
+
// Uniswap V3 SwapRouter ABIs
|
|
81
|
+
// V1 SwapRouter (ETH, Arb, OP, Polygon) — has deadline IN the struct
|
|
82
|
+
const SWAP_ROUTER_V1_ABI = [
|
|
81
83
|
'function exactInputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 deadline, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96)) external payable returns (uint256 amountOut)',
|
|
84
|
+
];
|
|
85
|
+
// V2 SwapRouter02 (Base) — NO deadline in struct, uses multicall wrapper
|
|
86
|
+
const SWAP_ROUTER_V2_ABI = [
|
|
87
|
+
'function exactInputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96)) external payable returns (uint256 amountOut)',
|
|
82
88
|
'function multicall(uint256 deadline, bytes[] data) external payable returns (bytes[])',
|
|
83
89
|
];
|
|
84
90
|
|
|
91
|
+
// Which chains use V2 SwapRouter02 (no deadline in struct)
|
|
92
|
+
const V2_ROUTER_CHAINS = new Set(['base']);
|
|
93
|
+
|
|
85
94
|
// Uniswap V3 Quoter V2 ABI (for getting expected output)
|
|
86
95
|
const QUOTER_ABI = [
|
|
87
96
|
'function quoteExactInputSingle((address tokenIn, address tokenOut, uint256 amountIn, uint24 fee, uint160 sqrtPriceLimitX96)) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)',
|
|
@@ -232,7 +241,6 @@ export async function executeSwap(opts = {}) {
|
|
|
232
241
|
|
|
233
242
|
// Execute swap
|
|
234
243
|
swapSpin.text = 'Getting quote for slippage protection...';
|
|
235
|
-
const swapRouter = new ethers.Contract(router, SWAP_ROUTER_ABI, signer);
|
|
236
244
|
const actualTokenOut = tokenOutAddr === ethers.ZeroAddress ? TOKENS[chain]?.WETH : tokenOutAddr;
|
|
237
245
|
|
|
238
246
|
const deadline = Math.floor(Date.now() / 1000) + 300; // 5 min
|
|
@@ -276,19 +284,41 @@ export async function executeSwap(opts = {}) {
|
|
|
276
284
|
}
|
|
277
285
|
|
|
278
286
|
swapSpin.text = 'Sending swap transaction...';
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
fee: 3000, // 0.3% fee tier
|
|
283
|
-
recipient: address,
|
|
284
|
-
deadline,
|
|
285
|
-
amountIn,
|
|
286
|
-
amountOutMinimum: amountOutMin,
|
|
287
|
-
sqrtPriceLimitX96: 0,
|
|
288
|
-
};
|
|
289
|
-
|
|
287
|
+
const isV2Router = V2_ROUTER_CHAINS.has(chain);
|
|
288
|
+
const routerABI = isV2Router ? SWAP_ROUTER_V2_ABI : SWAP_ROUTER_V1_ABI;
|
|
289
|
+
const swapRouter = new ethers.Contract(router, routerABI, signer);
|
|
290
290
|
const txOpts = isNativeIn ? { value: amountIn } : {};
|
|
291
|
-
|
|
291
|
+
|
|
292
|
+
let tx;
|
|
293
|
+
if (isV2Router) {
|
|
294
|
+
// SwapRouter02: no deadline in struct, use multicall wrapper
|
|
295
|
+
const swapParams = {
|
|
296
|
+
tokenIn: actualTokenIn,
|
|
297
|
+
tokenOut: actualTokenOut,
|
|
298
|
+
fee: 3000,
|
|
299
|
+
recipient: address,
|
|
300
|
+
amountIn,
|
|
301
|
+
amountOutMinimum: amountOutMin,
|
|
302
|
+
sqrtPriceLimitX96: 0,
|
|
303
|
+
};
|
|
304
|
+
// Encode the swap call, then wrap in multicall with deadline
|
|
305
|
+
const swapIface = new ethers.Interface(SWAP_ROUTER_V2_ABI);
|
|
306
|
+
const swapData = swapIface.encodeFunctionData('exactInputSingle', [swapParams]);
|
|
307
|
+
tx = await swapRouter.multicall(deadline, [swapData], txOpts);
|
|
308
|
+
} else {
|
|
309
|
+
// V1 SwapRouter: deadline is in the struct
|
|
310
|
+
const swapParams = {
|
|
311
|
+
tokenIn: actualTokenIn,
|
|
312
|
+
tokenOut: actualTokenOut,
|
|
313
|
+
fee: 3000,
|
|
314
|
+
recipient: address,
|
|
315
|
+
deadline,
|
|
316
|
+
amountIn,
|
|
317
|
+
amountOutMinimum: amountOutMin,
|
|
318
|
+
sqrtPriceLimitX96: 0,
|
|
319
|
+
};
|
|
320
|
+
tx = await swapRouter.exactInputSingle(swapParams, txOpts);
|
|
321
|
+
}
|
|
292
322
|
|
|
293
323
|
swapSpin.text = 'Waiting for confirmation...';
|
|
294
324
|
const receipt = await tx.wait();
|