apow-cli 0.4.1 → 0.6.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/.env.example +9 -4
- package/README.md +83 -20
- package/dist/bridge/constants.js +34 -0
- package/dist/bridge/debridge.js +151 -28
- package/dist/bridge/solana.js +13 -0
- package/dist/bridge/squid.js +54 -21
- package/dist/bridge/uniswap.js +184 -0
- package/dist/config.js +1 -0
- package/dist/dashboard.js +6 -2
- package/dist/errors.js +40 -0
- package/dist/fund.js +506 -133
- package/dist/index.js +10 -23
- package/dist/preflight.js +52 -0
- package/dist/wallet.js +24 -2
- package/dist/x402.js +45 -0
- package/package.json +3 -1
- package/skill.md +117 -66
package/dist/fund.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Fund command —
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
2
|
+
// Fund command — unified funding for mining on Base.
|
|
3
|
+
// Accepts deposits in 6 forms across 3 chains, auto-bridges to Base,
|
|
4
|
+
// auto-splits into ETH (gas) + USDC (x402 RPC).
|
|
5
|
+
//
|
|
6
|
+
// Deposit types:
|
|
7
|
+
// 1. Solana SOL → bridge → ETH on Base → swap portion to USDC
|
|
8
|
+
// 2. Solana USDC → bridge → USDC on Base → swap portion to ETH
|
|
9
|
+
// 3. Ethereum ETH → bridge → ETH on Base → swap portion to USDC
|
|
10
|
+
// 4. Ethereum USDC → bridge → USDC on Base → swap portion to ETH
|
|
11
|
+
// 5. Base ETH → (already there) → swap portion to USDC
|
|
12
|
+
// 6. Base USDC → (already there) → swap portion to ETH
|
|
7
13
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
14
|
if (k2 === undefined) k2 = k;
|
|
9
15
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -40,7 +46,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
47
|
exports.runFundFlow = runFundFlow;
|
|
42
48
|
const viem_1 = require("viem");
|
|
49
|
+
const constants_1 = require("./bridge/constants");
|
|
50
|
+
const debridge_1 = require("./bridge/debridge");
|
|
51
|
+
const squid_1 = require("./bridge/squid");
|
|
52
|
+
const uniswap_1 = require("./bridge/uniswap");
|
|
43
53
|
const wallet_1 = require("./wallet");
|
|
54
|
+
const config_1 = require("./config");
|
|
44
55
|
const ui = __importStar(require("./ui"));
|
|
45
56
|
async function fetchPrices() {
|
|
46
57
|
const res = await fetch("https://api.coingecko.com/api/v3/simple/price?ids=solana,ethereum&vs_currencies=usd");
|
|
@@ -51,9 +62,9 @@ async function fetchPrices() {
|
|
|
51
62
|
const solUsd = data.solana.usd;
|
|
52
63
|
return { solPerEth: ethUsd / solUsd, ethPriceUsd: ethUsd, solPriceUsd: solUsd };
|
|
53
64
|
}
|
|
54
|
-
/**
|
|
55
|
-
function
|
|
56
|
-
return targetEth *
|
|
65
|
+
/** Source token amount needed for target ETH worth, with 10% buffer. */
|
|
66
|
+
function amountNeededForEth(targetEth, tokenPriceUsd, ethPriceUsd) {
|
|
67
|
+
return (targetEth * ethPriceUsd / tokenPriceUsd) * 1.1;
|
|
57
68
|
}
|
|
58
69
|
// ---------------------------------------------------------------------------
|
|
59
70
|
// QR code helper
|
|
@@ -77,12 +88,112 @@ async function showQrCode(text) {
|
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
// ---------------------------------------------------------------------------
|
|
80
|
-
//
|
|
91
|
+
// Auto-split: ensure both ETH and USDC minimums are met
|
|
81
92
|
// ---------------------------------------------------------------------------
|
|
82
|
-
async function
|
|
93
|
+
async function autoSplit(depositedAsset, prices, noSwap) {
|
|
94
|
+
if (noSwap)
|
|
95
|
+
return;
|
|
96
|
+
if (!wallet_1.account)
|
|
97
|
+
return;
|
|
98
|
+
const ethBal = Number((0, viem_1.formatEther)(await (0, wallet_1.getEthBalance)()));
|
|
99
|
+
const usdcBal = Number((0, viem_1.formatUnits)(await (0, uniswap_1.getUsdcBalance)(wallet_1.account.address), 6));
|
|
100
|
+
// Already good
|
|
101
|
+
if (ethBal >= constants_1.MIN_ETH && usdcBal >= constants_1.MIN_USDC) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Not enough to cover anything useful
|
|
105
|
+
const totalUsd = ethBal * prices.ethPriceUsd + usdcBal;
|
|
106
|
+
const minTotalUsd = constants_1.MIN_ETH * prices.ethPriceUsd + constants_1.MIN_USDC;
|
|
107
|
+
if (totalUsd < minTotalUsd * 0.5) {
|
|
108
|
+
ui.warn("Balance too low for auto-split. Fund more to cover both ETH (gas) and USDC (x402 RPC).");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (depositedAsset === "eth" && usdcBal < constants_1.MIN_USDC) {
|
|
112
|
+
const usdcNeeded = constants_1.MIN_USDC - usdcBal;
|
|
113
|
+
const ethToSwap = (usdcNeeded / prices.ethPriceUsd) * 1.02; // 2% buffer
|
|
114
|
+
if (ethBal - ethToSwap < constants_1.MIN_ETH * 0.5) {
|
|
115
|
+
ui.warn("Not enough ETH to swap for USDC and keep enough for gas. Skipping auto-split.");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
console.log("");
|
|
119
|
+
ui.table([
|
|
120
|
+
["Auto-split", `Swap ~${ethToSwap.toFixed(6)} ETH → ~${usdcNeeded.toFixed(2)} USDC`],
|
|
121
|
+
["Purpose", "USDC for x402 RPC calls"],
|
|
122
|
+
["Remaining ETH", `~${(ethBal - ethToSwap).toFixed(6)} ETH (gas)`],
|
|
123
|
+
]);
|
|
124
|
+
console.log("");
|
|
125
|
+
const proceed = await ui.confirm("Confirm swap?");
|
|
126
|
+
if (!proceed) {
|
|
127
|
+
console.log(" Skipped auto-split.");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const swapSpinner = ui.spinner("Swapping ETH → USDC on Uniswap V3...");
|
|
131
|
+
const ethWei = (0, viem_1.parseEther)(ethToSwap.toFixed(18));
|
|
132
|
+
const minUsdc = (0, viem_1.parseUnits)((usdcNeeded * (1 - constants_1.SLIPPAGE_BPS / 10000)).toFixed(6), 6);
|
|
133
|
+
try {
|
|
134
|
+
const result = await (0, uniswap_1.swapEthToUsdc)(ethWei, minUsdc);
|
|
135
|
+
swapSpinner.stop(`Swap complete: ${result.usdcReceived} USDC`);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
swapSpinner.fail("Swap failed");
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (depositedAsset === "usdc" && ethBal < constants_1.MIN_ETH) {
|
|
143
|
+
const ethNeeded = constants_1.MIN_ETH - ethBal;
|
|
144
|
+
const usdcToSwap = ethNeeded * prices.ethPriceUsd * 1.02; // 2% buffer
|
|
145
|
+
if (usdcBal - usdcToSwap < constants_1.MIN_USDC * 0.5) {
|
|
146
|
+
ui.warn("Not enough USDC to swap for ETH and keep enough for RPC. Skipping auto-split.");
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
console.log("");
|
|
150
|
+
ui.table([
|
|
151
|
+
["Auto-split", `Swap ~${usdcToSwap.toFixed(2)} USDC → ~${ethNeeded.toFixed(6)} ETH`],
|
|
152
|
+
["Purpose", "ETH for gas"],
|
|
153
|
+
["Remaining USDC", `~${(usdcBal - usdcToSwap).toFixed(2)} USDC (x402 RPC)`],
|
|
154
|
+
]);
|
|
155
|
+
console.log("");
|
|
156
|
+
const proceed = await ui.confirm("Confirm swap?");
|
|
157
|
+
if (!proceed) {
|
|
158
|
+
console.log(" Skipped auto-split.");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const swapSpinner = ui.spinner("Swapping USDC → ETH on Uniswap V3...");
|
|
162
|
+
const usdcRaw = (0, viem_1.parseUnits)(usdcToSwap.toFixed(6), 6);
|
|
163
|
+
const minEth = (0, viem_1.parseEther)((ethNeeded * (1 - constants_1.SLIPPAGE_BPS / 10000)).toFixed(18));
|
|
164
|
+
try {
|
|
165
|
+
const result = await (0, uniswap_1.swapUsdcToEth)(usdcRaw, minEth);
|
|
166
|
+
swapSpinner.stop(`Swap complete: ${result.ethReceived} ETH`);
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
swapSpinner.fail("Swap failed");
|
|
170
|
+
throw err;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// Show final balances
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
async function showFinalBalances() {
|
|
178
|
+
if (!wallet_1.account)
|
|
179
|
+
return;
|
|
180
|
+
const ethBal = Number((0, viem_1.formatEther)(await (0, wallet_1.getEthBalance)()));
|
|
181
|
+
const usdcBal = Number((0, viem_1.formatUnits)(await (0, uniswap_1.getUsdcBalance)(wallet_1.account.address), 6));
|
|
182
|
+
console.log("");
|
|
183
|
+
console.log(` ${ui.green("Ready to mine!")}`);
|
|
184
|
+
ui.table([
|
|
185
|
+
["ETH", `${ethBal.toFixed(6)} ETH (gas)`],
|
|
186
|
+
["USDC", `${usdcBal.toFixed(2)} USDC (x402 RPC)`],
|
|
187
|
+
]);
|
|
188
|
+
console.log(` Next: ${ui.cyan("apow mint")}`);
|
|
189
|
+
console.log("");
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Solana direct bridge (deBridge DLN)
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
async function runSolanaDirectBridge(solanaKeyInput, baseAddress, sourceToken, targetEth) {
|
|
83
195
|
const solanaSpinner = ui.spinner("Checking Solana balance...");
|
|
84
196
|
const solana = await Promise.resolve().then(() => __importStar(require("./bridge/solana")));
|
|
85
|
-
const debridge = await Promise.resolve().then(() => __importStar(require("./bridge/debridge")));
|
|
86
197
|
let kp;
|
|
87
198
|
try {
|
|
88
199
|
kp = await solana.parseSolanaKey(solanaKeyInput);
|
|
@@ -91,26 +202,205 @@ async function runDirectBridge(solanaKeyInput, baseAddress, targetEth) {
|
|
|
91
202
|
solanaSpinner.fail("Invalid Solana key");
|
|
92
203
|
throw err;
|
|
93
204
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
205
|
+
if (sourceToken === "usdc") {
|
|
206
|
+
const usdcBal = await solana.getSplTokenBalance(kp.publicKey, constants_1.TOKENS.solana.usdc);
|
|
207
|
+
solanaSpinner.stop(`Solana USDC balance: ${usdcBal.toFixed(2)} USDC`);
|
|
208
|
+
const priceSpinner = ui.spinner("Fetching prices...");
|
|
209
|
+
const prices = await fetchPrices();
|
|
210
|
+
priceSpinner.stop(`ETH price: $${prices.ethPriceUsd.toFixed(0)}`);
|
|
211
|
+
const usdcAmount = targetEth * prices.ethPriceUsd * 1.1; // 10% buffer
|
|
212
|
+
if (usdcBal < usdcAmount) {
|
|
213
|
+
ui.error(`Insufficient USDC. Need ~${usdcAmount.toFixed(2)} USDC, have ${usdcBal.toFixed(2)} USDC.`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
console.log("");
|
|
217
|
+
ui.table([
|
|
218
|
+
["Bridging", `${usdcAmount.toFixed(2)} USDC → USDC on Base`],
|
|
219
|
+
["Via", "deBridge DLN (~20 seconds)"],
|
|
220
|
+
["From", `${kp.publicKey.slice(0, 4)}...${kp.publicKey.slice(-4)}`],
|
|
221
|
+
["To", `${baseAddress.slice(0, 6)}...${baseAddress.slice(-4)}`],
|
|
222
|
+
]);
|
|
223
|
+
console.log("");
|
|
224
|
+
const proceed = await ui.confirm("Confirm bridge?");
|
|
225
|
+
if (!proceed) {
|
|
226
|
+
console.log(" Cancelled.");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const bridgeSpinner = ui.spinner("Signing bridge transaction...");
|
|
230
|
+
const result = await (0, debridge_1.bridgeFromSolana)(kp.keypair, baseAddress, usdcAmount, debridge_1.ROUTES.sol_usdc_to_base_usdc);
|
|
231
|
+
bridgeSpinner.stop(`Submitted! Order: ${result.orderId.slice(0, 12)}...`);
|
|
232
|
+
const pollSpinner = ui.spinner("Waiting for bridge fulfillment... (~20s)");
|
|
233
|
+
const fulfillment = await (0, debridge_1.pollOrderStatus)(result.orderId, (s) => pollSpinner.update(`Bridge status: ${s}`));
|
|
234
|
+
pollSpinner.stop("Bridge complete! USDC arrived on Base");
|
|
235
|
+
await autoSplit("usdc", prices, false);
|
|
236
|
+
await showFinalBalances();
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// SOL → ETH
|
|
240
|
+
const balance = await solana.getSolanaBalance(kp.publicKey);
|
|
241
|
+
solanaSpinner.stop(`Solana balance: ${balance.toFixed(4)} SOL`);
|
|
242
|
+
const priceSpinner = ui.spinner("Fetching prices...");
|
|
243
|
+
const prices = await fetchPrices();
|
|
244
|
+
const solAmount = amountNeededForEth(targetEth, prices.solPriceUsd, prices.ethPriceUsd);
|
|
245
|
+
priceSpinner.stop(`SOL/ETH rate: ${prices.solPerEth.toFixed(1)} SOL = 1 ETH`);
|
|
246
|
+
if (balance < solAmount) {
|
|
247
|
+
ui.error(`Insufficient SOL. Need ~${solAmount.toFixed(4)} SOL, have ${balance.toFixed(4)} SOL.`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
console.log("");
|
|
251
|
+
ui.table([
|
|
252
|
+
["Bridging", `${solAmount.toFixed(4)} SOL → ~${targetEth.toFixed(4)} ETH on Base`],
|
|
253
|
+
["Via", "deBridge DLN (~20 seconds)"],
|
|
254
|
+
["From", `${kp.publicKey.slice(0, 4)}...${kp.publicKey.slice(-4)}`],
|
|
255
|
+
["To", `${baseAddress.slice(0, 6)}...${baseAddress.slice(-4)}`],
|
|
256
|
+
]);
|
|
257
|
+
console.log("");
|
|
258
|
+
const proceed = await ui.confirm("Confirm bridge?");
|
|
259
|
+
if (!proceed) {
|
|
260
|
+
console.log(" Cancelled.");
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const bridgeSpinner = ui.spinner("Signing bridge transaction...");
|
|
264
|
+
const result = await (0, debridge_1.bridgeFromSolana)(kp.keypair, baseAddress, solAmount, debridge_1.ROUTES.sol_to_eth);
|
|
265
|
+
bridgeSpinner.stop(`Submitted! Order: ${result.orderId.slice(0, 12)}...`);
|
|
266
|
+
const pollSpinner = ui.spinner("Waiting for bridge fulfillment... (~20s)");
|
|
267
|
+
const fulfillment = await (0, debridge_1.pollOrderStatus)(result.orderId, (s) => pollSpinner.update(`Bridge status: ${s}`));
|
|
268
|
+
const received = fulfillment.received
|
|
269
|
+
? (Number(fulfillment.received) / 1e18).toFixed(6)
|
|
270
|
+
: `~${targetEth.toFixed(4)}`;
|
|
271
|
+
pollSpinner.stop(`Bridge complete! ${received} ETH arrived on Base`);
|
|
272
|
+
await autoSplit("eth", prices, false);
|
|
273
|
+
await showFinalBalances();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
// Solana deposit address bridge (Squid Router)
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
async function runSolanaDepositBridge(baseAddress, sourceToken, targetEth) {
|
|
97
280
|
const priceSpinner = ui.spinner("Fetching prices...");
|
|
98
281
|
const prices = await fetchPrices();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
282
|
+
priceSpinner.stop(`ETH price: $${prices.ethPriceUsd.toFixed(0)}`);
|
|
283
|
+
const route = sourceToken === "usdc"
|
|
284
|
+
? squid_1.SQUID_ROUTES.sol_usdc_to_base_usdc
|
|
285
|
+
: squid_1.SQUID_ROUTES.sol_to_eth;
|
|
286
|
+
const amount = sourceToken === "usdc"
|
|
287
|
+
? targetEth * prices.ethPriceUsd * 1.1
|
|
288
|
+
: amountNeededForEth(targetEth, prices.solPriceUsd, prices.ethPriceUsd);
|
|
289
|
+
const tokenLabel = sourceToken === "usdc" ? "USDC" : "SOL";
|
|
290
|
+
const addrSpinner = ui.spinner("Generating deposit address...");
|
|
291
|
+
const squid = await Promise.resolve().then(() => __importStar(require("./bridge/squid")));
|
|
292
|
+
const solana = await Promise.resolve().then(() => __importStar(require("./bridge/solana")));
|
|
293
|
+
let deposit;
|
|
294
|
+
try {
|
|
295
|
+
deposit = await squid.getDepositAddress(baseAddress, amount, route);
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
addrSpinner.fail("Failed to get deposit address");
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
addrSpinner.stop("Deposit address ready");
|
|
302
|
+
console.log("");
|
|
303
|
+
console.log(` ${ui.bold(`Send ${tokenLabel} to this address:`)}`);
|
|
304
|
+
console.log("");
|
|
305
|
+
console.log(` ${ui.cyan(deposit.depositAddress)}`);
|
|
306
|
+
console.log("");
|
|
307
|
+
await showQrCode(deposit.depositAddress);
|
|
308
|
+
console.log("");
|
|
309
|
+
ui.table([
|
|
310
|
+
["Amount", `~${amount.toFixed(sourceToken === "usdc" ? 2 : 4)} ${tokenLabel}`],
|
|
311
|
+
["You'll receive", `~${deposit.expectedReceive} ${sourceToken === "usdc" ? "USDC" : "ETH"} on Base`],
|
|
312
|
+
["Bridge", "Squid Router (Chainflip)"],
|
|
313
|
+
["Time", "~1-3 minutes"],
|
|
314
|
+
]);
|
|
315
|
+
console.log("");
|
|
316
|
+
if (deposit.expiresAt) {
|
|
317
|
+
ui.warn(`Deposit address expires: ${deposit.expiresAt}`);
|
|
318
|
+
console.log("");
|
|
319
|
+
}
|
|
320
|
+
// Poll for deposit
|
|
321
|
+
const depositSpinner = ui.spinner(`Waiting for ${tokenLabel} deposit... (Ctrl+C to cancel)`);
|
|
322
|
+
if (sourceToken === "native") {
|
|
323
|
+
// SOL deposit: poll Solana balance
|
|
324
|
+
const initialBalance = await solana.getAddressBalance(deposit.depositAddress);
|
|
325
|
+
let depositDetected = false;
|
|
326
|
+
const depositDeadline = Date.now() + 600_000;
|
|
327
|
+
while (!depositDetected && Date.now() < depositDeadline) {
|
|
328
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
329
|
+
try {
|
|
330
|
+
const currentBalance = await solana.getAddressBalance(deposit.depositAddress);
|
|
331
|
+
if (currentBalance > initialBalance + 0.001) {
|
|
332
|
+
depositDetected = true;
|
|
333
|
+
depositSpinner.stop(`Deposit received! ${(currentBalance - initialBalance).toFixed(4)} SOL`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// Transient RPC error
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (!depositDetected) {
|
|
341
|
+
depositSpinner.fail(`No ${tokenLabel} deposit detected after 10 minutes`);
|
|
342
|
+
ui.hint("If you sent tokens, check: https://explorer.squidrouter.com");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
// USDC deposit: poll SPL token balance at the deposit address
|
|
348
|
+
let depositDetected = false;
|
|
349
|
+
const depositDeadline = Date.now() + 600_000;
|
|
350
|
+
while (!depositDetected && Date.now() < depositDeadline) {
|
|
351
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
352
|
+
try {
|
|
353
|
+
const bal = await solana.getSplTokenBalance(deposit.depositAddress, constants_1.TOKENS.solana.usdc);
|
|
354
|
+
if (bal > 0.01) {
|
|
355
|
+
depositDetected = true;
|
|
356
|
+
depositSpinner.stop(`Deposit received! ${bal.toFixed(2)} USDC`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
// Transient RPC error
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (!depositDetected) {
|
|
364
|
+
depositSpinner.fail("No USDC deposit detected after 10 minutes");
|
|
365
|
+
ui.hint("If you sent USDC, check: https://explorer.squidrouter.com");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Poll for bridge completion
|
|
370
|
+
const bridgeSpinner = ui.spinner("Bridging to Base... (~1-3 min)");
|
|
371
|
+
const result = await (0, squid_1.pollBridgeStatus)(deposit.requestId, route.dstDecimals, (status) => bridgeSpinner.update(`Bridge status: ${status}`));
|
|
372
|
+
const received = result.received || deposit.expectedReceive;
|
|
373
|
+
const receivedAsset = sourceToken === "usdc" ? "USDC" : "ETH";
|
|
374
|
+
bridgeSpinner.stop(`Bridge complete! ${received} ${receivedAsset} arrived`);
|
|
375
|
+
const outputAsset = (0, constants_1.bridgeOutputAsset)(sourceToken);
|
|
376
|
+
await autoSplit(outputAsset, prices, false);
|
|
377
|
+
await showFinalBalances();
|
|
378
|
+
}
|
|
379
|
+
// ---------------------------------------------------------------------------
|
|
380
|
+
// Ethereum direct bridge (deBridge DLN)
|
|
381
|
+
// ---------------------------------------------------------------------------
|
|
382
|
+
async function runEthereumDirectBridge(baseAddress, sourceToken, targetEth) {
|
|
383
|
+
if (!config_1.config.privateKey) {
|
|
384
|
+
ui.error("No PRIVATE_KEY configured. Your wallet key is used on Ethereum mainnet too.");
|
|
103
385
|
return;
|
|
104
386
|
}
|
|
387
|
+
const priceSpinner = ui.spinner("Fetching prices...");
|
|
388
|
+
const prices = await fetchPrices();
|
|
389
|
+
priceSpinner.stop(`ETH price: $${prices.ethPriceUsd.toFixed(0)}`);
|
|
390
|
+
const route = sourceToken === "usdc"
|
|
391
|
+
? debridge_1.ROUTES.eth_usdc_to_base_usdc
|
|
392
|
+
: debridge_1.ROUTES.eth_to_base_eth;
|
|
393
|
+
const amount = sourceToken === "usdc"
|
|
394
|
+
? targetEth * prices.ethPriceUsd * 1.1
|
|
395
|
+
: targetEth * 1.1;
|
|
396
|
+
const tokenLabel = sourceToken === "usdc" ? "USDC" : "ETH";
|
|
397
|
+
const receivedLabel = sourceToken === "usdc" ? "USDC" : "ETH";
|
|
105
398
|
console.log("");
|
|
106
399
|
ui.table([
|
|
107
|
-
["Bridging", `${
|
|
400
|
+
["Bridging", `${amount.toFixed(sourceToken === "usdc" ? 2 : 6)} ${tokenLabel} → ${receivedLabel} on Base`],
|
|
108
401
|
["Via", "deBridge DLN (~20 seconds)"],
|
|
109
|
-
[
|
|
110
|
-
|
|
111
|
-
`${kp.publicKey.slice(0, 4)}...${kp.publicKey.slice(-4)}`,
|
|
112
|
-
],
|
|
113
|
-
["To", `${baseAddress.slice(0, 6)}...${baseAddress.slice(-4)}`],
|
|
402
|
+
["From", `Ethereum mainnet (${baseAddress.slice(0, 6)}...${baseAddress.slice(-4)})`],
|
|
403
|
+
["To", `Base (same address)`],
|
|
114
404
|
]);
|
|
115
405
|
console.log("");
|
|
116
406
|
const proceed = await ui.confirm("Confirm bridge?");
|
|
@@ -118,51 +408,58 @@ async function runDirectBridge(solanaKeyInput, baseAddress, targetEth) {
|
|
|
118
408
|
console.log(" Cancelled.");
|
|
119
409
|
return;
|
|
120
410
|
}
|
|
121
|
-
const bridgeSpinner = ui.spinner("Signing bridge transaction...");
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
411
|
+
const bridgeSpinner = ui.spinner("Signing bridge transaction on Ethereum...");
|
|
412
|
+
try {
|
|
413
|
+
const result = await (0, debridge_1.bridgeFromEvm)(config_1.config.privateKey, baseAddress, amount, route);
|
|
414
|
+
bridgeSpinner.stop(`Submitted! Order: ${result.orderId.slice(0, 12)}...`);
|
|
415
|
+
const pollSpinner = ui.spinner("Waiting for bridge fulfillment... (~20s)");
|
|
416
|
+
const fulfillment = await (0, debridge_1.pollOrderStatus)(result.orderId, (s) => pollSpinner.update(`Bridge status: ${s}`));
|
|
417
|
+
pollSpinner.stop(`Bridge complete! ${receivedLabel} arrived on Base`);
|
|
418
|
+
const outputAsset = (0, constants_1.bridgeOutputAsset)(sourceToken);
|
|
419
|
+
await autoSplit(outputAsset, prices, false);
|
|
420
|
+
await showFinalBalances();
|
|
421
|
+
}
|
|
422
|
+
catch (err) {
|
|
423
|
+
bridgeSpinner.fail("Bridge failed");
|
|
424
|
+
throw err;
|
|
425
|
+
}
|
|
131
426
|
}
|
|
132
427
|
// ---------------------------------------------------------------------------
|
|
133
|
-
//
|
|
428
|
+
// Ethereum deposit address bridge (Squid Router)
|
|
134
429
|
// ---------------------------------------------------------------------------
|
|
135
|
-
async function
|
|
430
|
+
async function runEthereumDepositBridge(baseAddress, sourceToken, targetEth) {
|
|
136
431
|
const priceSpinner = ui.spinner("Fetching prices...");
|
|
137
432
|
const prices = await fetchPrices();
|
|
138
|
-
|
|
139
|
-
|
|
433
|
+
priceSpinner.stop(`ETH price: $${prices.ethPriceUsd.toFixed(0)}`);
|
|
434
|
+
const route = sourceToken === "usdc"
|
|
435
|
+
? squid_1.SQUID_ROUTES.eth_usdc_to_base_usdc
|
|
436
|
+
: squid_1.SQUID_ROUTES.eth_to_base_eth;
|
|
437
|
+
const amount = sourceToken === "usdc"
|
|
438
|
+
? targetEth * prices.ethPriceUsd * 1.1
|
|
439
|
+
: targetEth * 1.1;
|
|
440
|
+
const tokenLabel = sourceToken === "usdc" ? "USDC" : "ETH";
|
|
140
441
|
const addrSpinner = ui.spinner("Generating deposit address...");
|
|
141
442
|
const squid = await Promise.resolve().then(() => __importStar(require("./bridge/squid")));
|
|
142
|
-
const solana = await Promise.resolve().then(() => __importStar(require("./bridge/solana")));
|
|
143
443
|
let deposit;
|
|
144
444
|
try {
|
|
145
|
-
deposit = await squid.getDepositAddress(baseAddress,
|
|
445
|
+
deposit = await squid.getDepositAddress(baseAddress, amount, route);
|
|
146
446
|
}
|
|
147
447
|
catch (err) {
|
|
148
448
|
addrSpinner.fail("Failed to get deposit address");
|
|
149
449
|
throw err;
|
|
150
450
|
}
|
|
151
451
|
addrSpinner.stop("Deposit address ready");
|
|
152
|
-
// Display deposit info
|
|
153
452
|
console.log("");
|
|
154
|
-
console.log(` ${ui.bold(
|
|
453
|
+
console.log(` ${ui.bold(`Send ${tokenLabel} on Ethereum mainnet to:`)}`);
|
|
155
454
|
console.log("");
|
|
156
455
|
console.log(` ${ui.cyan(deposit.depositAddress)}`);
|
|
157
456
|
console.log("");
|
|
158
457
|
await showQrCode(deposit.depositAddress);
|
|
159
458
|
console.log("");
|
|
160
459
|
ui.table([
|
|
161
|
-
[
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
],
|
|
165
|
-
["You'll receive", `~${deposit.expectedReceive} ETH on Base`],
|
|
460
|
+
["Amount", `~${amount.toFixed(sourceToken === "usdc" ? 2 : 6)} ${tokenLabel}`],
|
|
461
|
+
["Network", "Ethereum mainnet"],
|
|
462
|
+
["You'll receive", `~${deposit.expectedReceive} ${sourceToken === "usdc" ? "USDC" : "ETH"} on Base`],
|
|
166
463
|
["Bridge", "Squid Router (Chainflip)"],
|
|
167
464
|
["Time", "~1-3 minutes"],
|
|
168
465
|
]);
|
|
@@ -171,53 +468,127 @@ async function runDepositBridge(baseAddress, targetEth) {
|
|
|
171
468
|
ui.warn(`Deposit address expires: ${deposit.expiresAt}`);
|
|
172
469
|
console.log("");
|
|
173
470
|
}
|
|
174
|
-
//
|
|
175
|
-
const
|
|
176
|
-
|
|
471
|
+
// Wait for user to send manually — poll Squid status directly
|
|
472
|
+
const bridgeSpinner = ui.spinner(`Send ${tokenLabel} and waiting for bridge... (Ctrl+C to cancel)`);
|
|
473
|
+
// For Ethereum deposits, we rely on Squid status API rather than polling an RPC
|
|
474
|
+
const result = await (0, squid_1.pollBridgeStatus)(deposit.requestId, route.dstDecimals, (status) => bridgeSpinner.update(`Bridge status: ${status}`), 900_000);
|
|
475
|
+
const received = result.received || deposit.expectedReceive;
|
|
476
|
+
const receivedAsset = sourceToken === "usdc" ? "USDC" : "ETH";
|
|
477
|
+
bridgeSpinner.stop(`Bridge complete! ${received} ${receivedAsset} arrived`);
|
|
478
|
+
const outputAsset = (0, constants_1.bridgeOutputAsset)(sourceToken);
|
|
479
|
+
await autoSplit(outputAsset, prices, false);
|
|
480
|
+
await showFinalBalances();
|
|
481
|
+
}
|
|
482
|
+
// ---------------------------------------------------------------------------
|
|
483
|
+
// Base manual send (already on the right chain)
|
|
484
|
+
// ---------------------------------------------------------------------------
|
|
485
|
+
async function runBaseFund(baseAddress, sourceToken, noSwap) {
|
|
486
|
+
const tokenLabel = sourceToken === "usdc" ? "USDC" : "ETH";
|
|
487
|
+
console.log("");
|
|
488
|
+
console.log(` ${ui.bold(`Send ${tokenLabel} on Base to this address:`)}`);
|
|
489
|
+
console.log("");
|
|
490
|
+
console.log(` ${ui.cyan(baseAddress)}`);
|
|
491
|
+
console.log("");
|
|
492
|
+
await showQrCode(baseAddress);
|
|
493
|
+
console.log("");
|
|
494
|
+
console.log(` ${ui.dim("Send from any wallet — Coinbase, MetaMask, Phantom, etc.")}`);
|
|
495
|
+
if (sourceToken === "usdc") {
|
|
496
|
+
console.log(` ${ui.dim("Need at least 2 USDC for x402 RPC + some for ETH swap.")}`);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
console.log(` ${ui.dim("Need ~0.005 ETH to cover gas + USDC swap.")}`);
|
|
500
|
+
}
|
|
501
|
+
console.log("");
|
|
502
|
+
const waitForDeposit = await ui.confirm("Wait for deposit and auto-split?");
|
|
503
|
+
if (!waitForDeposit) {
|
|
504
|
+
console.log(` ${ui.dim("After sending, run:")} ${ui.cyan("apow fund --chain base")} to auto-split.`);
|
|
505
|
+
console.log("");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const prices = await fetchPrices();
|
|
509
|
+
// Poll for balance change
|
|
510
|
+
const depositSpinner = ui.spinner(`Waiting for ${tokenLabel} deposit... (Ctrl+C to cancel)`);
|
|
511
|
+
const initialEth = await (0, wallet_1.getEthBalance)();
|
|
512
|
+
const initialUsdc = wallet_1.account ? await (0, uniswap_1.getUsdcBalance)(wallet_1.account.address) : 0n;
|
|
513
|
+
const depositDeadline = Date.now() + 600_000;
|
|
177
514
|
let depositDetected = false;
|
|
178
|
-
const depositDeadline = Date.now() + 600_000; // 10 min
|
|
179
515
|
while (!depositDetected && Date.now() < depositDeadline) {
|
|
180
516
|
await new Promise((r) => setTimeout(r, 3000));
|
|
181
517
|
try {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
518
|
+
if (sourceToken === "usdc" && wallet_1.account) {
|
|
519
|
+
const currentUsdc = await (0, uniswap_1.getUsdcBalance)(wallet_1.account.address);
|
|
520
|
+
if (currentUsdc > initialUsdc + 100000n) { // > 0.1 USDC
|
|
521
|
+
depositDetected = true;
|
|
522
|
+
depositSpinner.stop(`Deposit received! ${(0, viem_1.formatUnits)(currentUsdc - initialUsdc, 6)} USDC`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
const currentEth = await (0, wallet_1.getEthBalance)();
|
|
527
|
+
if (currentEth > initialEth + (0, viem_1.parseEther)("0.0001")) {
|
|
528
|
+
depositDetected = true;
|
|
529
|
+
depositSpinner.stop(`Deposit received! ${(0, viem_1.formatEther)(currentEth - initialEth)} ETH`);
|
|
530
|
+
}
|
|
186
531
|
}
|
|
187
532
|
}
|
|
188
533
|
catch {
|
|
189
|
-
// Transient RPC error
|
|
534
|
+
// Transient RPC error
|
|
190
535
|
}
|
|
191
536
|
}
|
|
192
537
|
if (!depositDetected) {
|
|
193
|
-
depositSpinner.fail(
|
|
194
|
-
ui.hint("If you sent SOL, check: https://explorer.squidrouter.com");
|
|
538
|
+
depositSpinner.fail(`No ${tokenLabel} deposit detected after 10 minutes`);
|
|
195
539
|
return;
|
|
196
540
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const received = result.ethReceived || deposit.expectedReceive;
|
|
201
|
-
bridgeSpinner.stop(`Bridge complete! ${received} ETH arrived`);
|
|
202
|
-
console.log("");
|
|
203
|
-
console.log(` ${ui.green("Your wallet is funded!")} Next: ${ui.cyan("apow mint")}`);
|
|
204
|
-
console.log("");
|
|
541
|
+
const outputAsset = (0, constants_1.bridgeOutputAsset)(sourceToken);
|
|
542
|
+
await autoSplit(outputAsset, prices, noSwap);
|
|
543
|
+
await showFinalBalances();
|
|
205
544
|
}
|
|
206
545
|
// ---------------------------------------------------------------------------
|
|
207
|
-
//
|
|
546
|
+
// Interactive menus
|
|
208
547
|
// ---------------------------------------------------------------------------
|
|
209
|
-
async function
|
|
548
|
+
async function selectSourceChain() {
|
|
549
|
+
console.log(" Where are your funds?");
|
|
550
|
+
console.log(` ${ui.cyan("1.")} Solana (SOL or USDC)`);
|
|
551
|
+
console.log(` ${ui.cyan("2.")} Ethereum mainnet (ETH or USDC)`);
|
|
552
|
+
console.log(` ${ui.cyan("3.")} Base (send ETH or USDC manually)`);
|
|
210
553
|
console.log("");
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
554
|
+
const choice = await ui.prompt("Choice", "1");
|
|
555
|
+
switch (choice) {
|
|
556
|
+
case "2": return "ethereum";
|
|
557
|
+
case "3": return "base";
|
|
558
|
+
default: return "solana";
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
async function selectSourceToken(chain) {
|
|
562
|
+
const nativeLabel = chain === "solana" ? "SOL" : "ETH";
|
|
216
563
|
console.log("");
|
|
217
|
-
console.log(
|
|
218
|
-
console.log(`
|
|
219
|
-
console.log(`
|
|
564
|
+
console.log(" What token?");
|
|
565
|
+
console.log(` ${ui.cyan("1.")} ${nativeLabel}`);
|
|
566
|
+
console.log(` ${ui.cyan("2.")} USDC`);
|
|
220
567
|
console.log("");
|
|
568
|
+
const choice = await ui.prompt("Choice", "1");
|
|
569
|
+
return choice === "2" ? "usdc" : "native";
|
|
570
|
+
}
|
|
571
|
+
function parseSourceChain(value) {
|
|
572
|
+
if (!value)
|
|
573
|
+
return undefined;
|
|
574
|
+
const v = value.toLowerCase();
|
|
575
|
+
if (v === "solana" || v === "sol")
|
|
576
|
+
return "solana";
|
|
577
|
+
if (v === "ethereum" || v === "eth")
|
|
578
|
+
return "ethereum";
|
|
579
|
+
if (v === "base")
|
|
580
|
+
return "base";
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
function parseSourceToken(value) {
|
|
584
|
+
if (!value)
|
|
585
|
+
return undefined;
|
|
586
|
+
const v = value.toLowerCase();
|
|
587
|
+
if (v === "sol" || v === "eth" || v === "native")
|
|
588
|
+
return "native";
|
|
589
|
+
if (v === "usdc")
|
|
590
|
+
return "usdc";
|
|
591
|
+
return undefined;
|
|
221
592
|
}
|
|
222
593
|
// ---------------------------------------------------------------------------
|
|
223
594
|
// Main entry point
|
|
@@ -228,85 +599,87 @@ async function runFundFlow(options) {
|
|
|
228
599
|
process.exit(1);
|
|
229
600
|
}
|
|
230
601
|
const baseAddress = wallet_1.account.address;
|
|
231
|
-
const
|
|
232
|
-
const
|
|
602
|
+
const ethBalance = Number((0, viem_1.formatEther)(await (0, wallet_1.getEthBalance)()));
|
|
603
|
+
const usdcBalance = Number((0, viem_1.formatUnits)(await (0, uniswap_1.getUsdcBalance)(baseAddress), 6));
|
|
604
|
+
const noSwap = options.swap === false;
|
|
233
605
|
console.log("");
|
|
234
606
|
ui.banner(["Fund Your Mining Wallet"]);
|
|
235
607
|
console.log("");
|
|
236
608
|
ui.table([
|
|
237
|
-
[
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
],
|
|
241
|
-
[
|
|
242
|
-
"Balance",
|
|
243
|
-
`${ethBalance.toFixed(6)} ETH${ethBalance < 0.005 ? " (need ~0.005 ETH to start)" : ""}`,
|
|
244
|
-
],
|
|
609
|
+
["Wallet", `${baseAddress.slice(0, 6)}...${baseAddress.slice(-4)}`],
|
|
610
|
+
["ETH", `${ethBalance.toFixed(6)} ETH${ethBalance < constants_1.MIN_ETH ? ` (need ≥${constants_1.MIN_ETH} for gas)` : ""}`],
|
|
611
|
+
["USDC", `${usdcBalance.toFixed(2)} USDC${usdcBalance < constants_1.MIN_USDC ? ` (need ≥${constants_1.MIN_USDC} for x402 RPC)` : ""}`],
|
|
245
612
|
]);
|
|
246
613
|
console.log("");
|
|
247
|
-
//
|
|
614
|
+
// Already funded?
|
|
615
|
+
if (ethBalance >= constants_1.MIN_ETH && usdcBalance >= constants_1.MIN_USDC) {
|
|
616
|
+
console.log(` ${ui.green("Already funded! Ready to mine.")}`);
|
|
617
|
+
console.log(` Next: ${ui.cyan("apow mint")}`);
|
|
618
|
+
console.log("");
|
|
619
|
+
// Allow explicit re-run if user wants to add more
|
|
620
|
+
const addMore = await ui.confirm("Add more funds?");
|
|
621
|
+
if (!addMore)
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
// Parse target ETH amount
|
|
248
625
|
const targetEth = options.amount ? parseFloat(options.amount) : 0.005;
|
|
249
626
|
if (isNaN(targetEth) || targetEth <= 0) {
|
|
250
627
|
ui.error("Invalid amount. Specify ETH target (e.g., --amount 0.005).");
|
|
251
628
|
return;
|
|
252
629
|
}
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
630
|
+
// Resolve source chain and token (from flags or interactive)
|
|
631
|
+
let chain = parseSourceChain(options.chain);
|
|
632
|
+
let token = parseSourceToken(options.token);
|
|
633
|
+
if (!chain) {
|
|
634
|
+
chain = await selectSourceChain();
|
|
257
635
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const hasKey = await ui.confirm("Do you have your Solana private key?");
|
|
261
|
-
if (hasKey) {
|
|
262
|
-
const key = await ui.promptSecret("Solana private key (base58)");
|
|
263
|
-
if (!key) {
|
|
264
|
-
ui.error("No key provided.");
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
await runDirectBridge(key, baseAddress, targetEth);
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
await runDepositBridge(baseAddress, targetEth);
|
|
271
|
-
}
|
|
272
|
-
return;
|
|
636
|
+
if (!token) {
|
|
637
|
+
token = await selectSourceToken(chain);
|
|
273
638
|
}
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
console.log("");
|
|
280
|
-
const choice = await ui.prompt("Choice", "1");
|
|
281
|
-
switch (choice) {
|
|
282
|
-
case "1": {
|
|
283
|
-
const hasKey = await ui.confirm("Do you have your Solana private key?");
|
|
284
|
-
if (hasKey) {
|
|
285
|
-
const key = await ui.promptSecret("Solana private key (base58)");
|
|
286
|
-
if (!key) {
|
|
287
|
-
ui.error("No key provided.");
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
await runDirectBridge(key, baseAddress, targetEth);
|
|
639
|
+
// Route to the appropriate flow
|
|
640
|
+
switch (chain) {
|
|
641
|
+
case "solana": {
|
|
642
|
+
if (options.key) {
|
|
643
|
+
await runSolanaDirectBridge(options.key, baseAddress, token, targetEth);
|
|
291
644
|
}
|
|
292
645
|
else {
|
|
293
|
-
|
|
646
|
+
console.log("");
|
|
647
|
+
console.log(" Bridge method:");
|
|
648
|
+
console.log(` ${ui.cyan("A.")} Direct signing (~20s, need Solana private key)`);
|
|
649
|
+
console.log(` ${ui.cyan("B.")} Deposit address (~1-3 min, send from any wallet)`);
|
|
650
|
+
console.log("");
|
|
651
|
+
const method = await ui.prompt("Choice", "A");
|
|
652
|
+
if (method.toUpperCase() === "A") {
|
|
653
|
+
const key = await ui.promptSecret("Solana private key (base58)");
|
|
654
|
+
if (!key) {
|
|
655
|
+
ui.error("No key provided.");
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
await runSolanaDirectBridge(key, baseAddress, token, targetEth);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
await runSolanaDepositBridge(baseAddress, token, targetEth);
|
|
662
|
+
}
|
|
294
663
|
}
|
|
295
664
|
break;
|
|
296
665
|
}
|
|
297
|
-
case "
|
|
666
|
+
case "ethereum": {
|
|
298
667
|
console.log("");
|
|
299
|
-
console.log(
|
|
300
|
-
console.log(`
|
|
301
|
-
console.log("");
|
|
302
|
-
console.log(` ${ui.dim("Need ~0.005 ETH to start mining.")}`);
|
|
303
|
-
console.log(` ${ui.dim("After sending, run:")} ${ui.cyan("apow mint")}`);
|
|
668
|
+
console.log(" Bridge method:");
|
|
669
|
+
console.log(` ${ui.cyan("A.")} Direct signing (~20s, uses your PRIVATE_KEY on mainnet)`);
|
|
670
|
+
console.log(` ${ui.cyan("B.")} Deposit address (~1-3 min, send from any wallet)`);
|
|
304
671
|
console.log("");
|
|
672
|
+
const method = await ui.prompt("Choice", "A");
|
|
673
|
+
if (method.toUpperCase() === "A") {
|
|
674
|
+
await runEthereumDirectBridge(baseAddress, token, targetEth);
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
await runEthereumDepositBridge(baseAddress, token, targetEth);
|
|
678
|
+
}
|
|
305
679
|
break;
|
|
306
680
|
}
|
|
307
|
-
case "
|
|
308
|
-
|
|
309
|
-
await runManualFund(baseAddress);
|
|
681
|
+
case "base": {
|
|
682
|
+
await runBaseFund(baseAddress, token, noSwap);
|
|
310
683
|
break;
|
|
311
684
|
}
|
|
312
685
|
}
|